简介
检索机器人是一种能够自动搜索和提供信息的系统,它可以帮助我们快速找到需要的信息。这类机器人通常使用自然语言处理(NLP)技术来理解用户的查询,并利用搜索引擎或数据库来获取相关信息。
那么我们要通过transforme实现什么样的检索机器人了。一个简化版的检索机器人,本地知识库+文本相似度(自然语言处理(NLP))。
本地知识库使用到了向量模型,文本相似度就是自然语言处理技术了。
检索机器人计划用三篇文章进行讲解。
文本相似度训练
文本相似度简介
文本相似度模型是用来衡量两个或多个文本片段之间的相似程度的工具。这些模型在许多应用场景中都非常有用,例如信息检索、推荐系统、文档去重、问答系统等。
1. 基本概念
- 文本相似度:衡量两段文本内容上的接近程度。相似度可以是基于词汇、语法结构、语义等多个维度。
- 向量表示:将文本转换为数值向量,以便于计算相似度。
2. 常用方法
a. 基于词频的方法
- TF-IDF (Term Frequency-Inverse Document Frequency):通过计算每个词在文档中的频率(TF)和逆文档频率(IDF)来表示文本。然后使用余弦相似度或其他距离度量方法来计算相似度。
- BoW (Bag of Words):将文本表示成词袋模型,忽略词序,只考虑词频。然后计算向量间的相似度。
b. 基于词嵌入的方法
- Word Embeddings (如Word2Vec, GloVe):将每个词映射到一个高维向量空间中,使得语义相似的词在向量空间中距离较近。可以通过平均词向量或加权平均词向量来表示整个句子。
- Sentence Embeddings (如Universal Sentence Encoder, BERT):直接将整个句子映射到一个向量,捕获句子的语义信息。这些模型通常使用预训练的神经网络,能够更好地理解上下文。
c. 基于深度学习的方法
- Siamese Networks:使用相同的网络结构对两个输入进行编码,然后比较它们的输出向量。常用于孪生网络结构,通过对比损失函数来训练模型。
- Transformer-based Models (如BERT, RoBERTa):利用Transformer架构的强大表征能力,生成高质量的文本向量。这些模型通常在大规模语料上进行预训练,并可以在特定任务上进行微调。
3. 计算相似度
- 余弦相似度 (Cosine Similarity):计算两个向量之间的夹角余弦值,范围在-1到1之间,值越接近1表示越相似。
- 欧氏距离 (Euclidean Distance):计算两个向量之间的直线距离,值越小表示越相似。
- 曼哈顿距离 (Manhattan Distance):计算两个向量在各维度上的绝对差值之和,值越小表示越相似。
- Jaccard相似度 (Jaccard Similarity):适用于集合数据,计算两个集合的交集与并集的比值。
4. 应用示例
假设我们有两个句子:
句子A: "我喜欢吃苹果"
句子B: "我爱吃水果"
a. 基于词嵌入的方法
使用预训练的词嵌入模型(如GloVe)将每个词转换为向量。
计算每个句子的平均词向量。
使用余弦相似度计算两个句子向量之间的相似度。
python
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
# 假设我们已经得到了每个词的词向量
word_vectors = {
'我': [0.1, 0.2, 0.3],
'喜欢': [0.4, 0.5, 0.6],
'吃': [0.7, 0.8, 0.9],
'苹果': [0.2, 0.1, 0.3],
'爱': [0.5, 0.6, 0.7],
'水果': [0.3, 0.4, 0.5]
}
# 计算句子A和句子B的平均词向量
sentence_A_vector = np.mean([word_vectors[word] for word in "我喜欢吃苹果".split()], axis=0)
sentence_B_vector = np.mean([word_vectors[word] for word in "我爱吃水果".split()], axis=0)
# 计算余弦相似度
similarity = cosine_similarity([sentence_A_vector], [sentence_B_vector])[0][0]
print(f"相似度: {similarity:.4f}")
b. 基于预训练模型的方法
使用预训练的句子嵌入模型(如Universal Sentence Encoder)。
直接获取句子的嵌入向量。
计算余弦相似度。
python
from sentence_transformers import SentenceTransformer
import torch
# 加载预训练模型
model = SentenceTransformer('paraphrase-MiniLM-L6-v2')
# 获取句子嵌入
sentence_A_embedding = model.encode("我喜欢吃苹果")
sentence_B_embedding = model.encode("我爱吃水果")
# 计算余弦相似度
cosine_sim = torch.nn.functional.cosine_similarity(
torch.tensor(sentence_A_embedding).unsqueeze(0),
torch.tensor(sentence_B_embedding).unsqueeze(0)
)
print(f"相似度: {cosine_sim.item():.4f}")
文本相似度模型通过将文本转换为向量,并使用各种距离度量方法来计算相似度。从简单的基于词频的方法到复杂的基于深度学习的方法,选择合适的模型取决于具体的应用场景和需求。现代预训练模型如BERT和Sentence Transformers提供了强大的语义理解能力,使得文本相似度计算更加准确和高效。
训练文本相似度
简介中介绍了文本相似度一些基础知识,核心点是将文本向量化,在计算两个向量之间的距离来帮别相似度。实际上文本相似你也可以看做是文本分类,两个话是否为一类,是不是一样的。
那么这次的训练就使用BERT来进行。
在写训练代码前,先考虑对数据集处理,怎么样的数据方便模型进行训练。使用BERT那么处理就是
[CLS] ............ [SEP] ........ [SEP]
如果数据集是这种一对一的:
SentenceA | SentenceB | Label |
---|---|---|
找一部小时候的动画片 | 求一部小时候的动画片。谢了 | 1 |
等一下马上来 | 马上来 | 1 |
不对明天不是37度 | 明天要做什么了 | 0 |
这事什么给忘了 | 路口有个红蓝房子 | 0 |
可以使用这种方式对数据进行处理和评估进行训练。
数据进行这样的整理
评估就计算softmax就可以了。
如果数据是一对多的如:
SentenceA | SentenceB | Label |
---|---|---|
找一部小时候的动画片 | 求一部小时候的动画片。谢了 | 1 |
找一部小时候的动画片 | 马上来 | 0 |
找一部小时候的动画片 | 明天要做什么了 | 0 |
这事什么给忘了 | 路口有个红蓝房子 | 0 |
那么用刚才的数据处理方式效率就比较低了,可以使用这种方式。 |
两个改动的地方不多,一个是模型,一个评估的处理,其它都是一致的。
代码实现
python
# 文本相似度实例
# Step1 导入相关包
from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
from datasets import load_dataset
import evaluate
from transformers import DataCollatorWithPadding
from transformers import pipeline, TextClassificationPipeline
# Step2 加载数据集
dataset = load_dataset("json", data_files="./train_pair_1w.json", split="train")
print(dataset)
#第一条数据
s = dataset[0]
print(s)
# Step3 划分数据集(训练数据和测试数据)
datasets = dataset.train_test_split(test_size=0.2)
print(datasets)
# Step4 数据集预处理
tokenizer = AutoTokenizer.from_pretrained("chinese-macbert-large")
def process_function(examples):
tokenized_examples = tokenizer(examples["sentence1"], examples["sentence2"], max_length=128, truncation=True)
tokenized_examples["labels"] = [float(label) for label in examples["label"]]
return tokenized_examples
tokenized_datasets = datasets.map(process_function, batched=True, remove_columns=datasets["train"].column_names)
print(tokenized_datasets)
print(tokenized_datasets["train"][0])
# Step5 创建模型
model = AutoModelForSequenceClassification.from_pretrained("chinese-macbert-large", num_labels=1)
# Step6 创建评估函数
acc_metric = evaluate.load("./metric_accuracy.py")
f1_metirc = evaluate.load("./metric_f1.py")
def eval_metric(eval_predict):
predictions, labels = eval_predict
predictions = [int(p > 0.5) for p in predictions]
labels = [int(l) for l in labels]
acc = acc_metric.compute(predictions=predictions, references=labels)
f1 = f1_metirc.compute(predictions=predictions, references=labels)
acc.update(f1)
return acc
# Step7 创建TrainingArguments
train_args = TrainingArguments(output_dir="./cross_model", # 输出文件夹
per_device_train_batch_size=32, # 训练时的batch_size
per_device_eval_batch_size=32, # 验证时的batch_size
logging_steps=10, # log 打印的频率
eval_strategy="epoch", # 评估策略
save_strategy="epoch", # 保存策略
save_total_limit=3, # 最大保存数
learning_rate=2e-5, # 学习率
weight_decay=0.01, # weight_decay
metric_for_best_model="f1", # 设定评估指标
load_best_model_at_end=True) # 训练完成后加载最优模型
train_args
# Step8 创建Trainer
trainer = Trainer(model=model,
args=train_args,
tokenizer=tokenizer,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["test"],
data_collator=DataCollatorWithPadding(tokenizer=tokenizer),
compute_metrics=eval_metric)
# Step9 模型训练
trainer.train()
# Step10 模型评估
trainer.evaluate(tokenized_datasets["test"])
# Step11 模型预测
model.config.id2label = {0: "不相似", 1: "相似"}
pipe = pipeline("text-classification", model=model, tokenizer=tokenizer, device=0)
result = pipe({"text": "我喜欢长沙", "text_pair": "天气怎样"}, function_to_apply="none")
result["label"] = "相似" if result["score"] > 0.5 else "不相似"
print(result)
这里我使用本地模型进行训练,直接使用这段代码是跑不起来的,需要将chinese-macbert-large替换为hfl/chinese-macbert-base,网络需要kexue上网。如果不能进行kexue上网,那么可以到这个地址下载模型到本地: 地址