在自然语言处理(NLP)中,文本相似度是衡量两个文本之间语义或结构相似程度的一个重要概念。计算文本相似度的方法多种多样,适应不同的应用场景和需求。以下是一些常见的文本相似度计算方法:
1、余弦相似度:
通过将文本转换为向量表示(例如,使用词袋模型、TF-IDF 或 word2vec、GloVe 等词嵌入技术),然后计算这两个向量之间的余弦夹角来评估相似度。
余弦相似度值范围从-1到1,值越接近1,代表两个向量越相似。
2、Jaccard相似度:
对于分词后的文档集合,可以计算它们的交集与并集的比例,以此作为相似度指标。
3、编辑距离(Levenshtein距离)或其它字符串距离:
用于衡量两个字符串变换成另一个所需的最少单字符编辑操作次数(插入、删除、替换)。
编辑距离较小,表明文本更相似。
4、词重叠度:
计算两篇文档共有的词汇数量及其权重占比。
5、TF-IDF cosine similarity:
使用TF-IDF对每个词语的重要性进行加权后计算余弦相似度。
6、Word Mover’s Distance (WMD):
基于地球 mover 距离的概念,考虑词语之间的语义关系,在词嵌入空间中计算距离。
7、BERT等预训练模型:
利用如BERT这样的Transformer架构的预训练模型,可以直接获取句子级别的向量表示,然后计算这些向量之间的相似度。
8、Siamese Networks 和 Sentence-BERT (SBERT):
训练网络以学习将文本映射到一个固定大小的向量空间,其中相似的文本对应相近的向量,从而可以直接比较向量间的距离或相似度得分。
具体可根据任务的需求和数据特性,可以选择合适的文本相似度计算方法。随着深度学习的发展,基于神经网络的模型因其能够捕捉到更深层次的语义信息而成为近年来越来越流行的选择。
下面介绍使用transformers解决文本相似度任务的一个简单流程。
# 文本相似度任务 **ForSequenceClassification
from datasets import load_dataset
from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
from transformers import DataCollatorWithPadding
# 加载数据
dataset = load_dataset("json", data_files="./sentence_similarity/train_pair_1w.json", split="train")
print(dataset[:3])
# 划分数据集
datasets = dataset.train_test_split(test_size=0.2)
print(datasets)
# 数据处理
tokenizer = AutoTokenizer.from_pretrained("../models/chinese-macbert-base")
# 数据处理函数
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)
# 创建模型
model = AutoModelForSequenceClassification.from_pretrained("../models/chinese-macbert-base", num_labels=1)
# 创建评估函数
import evaluate
acc_metric = evaluate.load("../metrics/accuracy")
f1_metirc = evaluate.load("../metrics/f1")
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]
# predictions = predictions.argmax(axis=-1)
acc = acc_metric.compute(predictions=predictions, references=labels)
f1 = f1_metirc.compute(predictions=predictions, references=labels)
acc.update(f1)
return acc
# 配置训练参数
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=5, # log 打印的频率
evaluation_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) # 训练完成后加载最优模型
# 创建训练器
trainer = Trainer(model=model,
args=train_args,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["test"],
data_collator=DataCollatorWithPadding(tokenizer=tokenizer),
compute_metrics=eval_metric)
# 模型训练
trainer.train()
# 模型预测
from transformers import pipeline
pipe = pipeline("text-classification", model=model, tokenizer=tokenizer)
result = pipe({"text": "重庆是个旅游的好地方", "text_pair": "重庆是经常被推荐去的旅游地方"}, function_to_apply="none")
result["label"] = "相似" if result["score"] > 0.5 else "不相似"
print(result)