内容纲要
一、引言
“如何判断两段文本是否表达了相同的意思?”这是 NLP 世界里的“灵魂三问”之一,出现在搜索引擎、智能问答、推荐系统、对话系统等大量场景中。为此,研究者们提出了许多计算文本相似度的方法。从最早的统计词频方法到如今强大的预训练语言模型,每一代技术都有它的独特优势和适用场景。
本文将全面解析主流的文本相似度计算方法,帮助你快速选型并灵活落地。
二、文本相似度的定义与分类
文本相似度主要分为两类:
- 语法层面(Shallow Similarity):基于词面、词频统计,如 TF-IDF、Jaccard、编辑距离等。
- 语义层面(Semantic Similarity):基于上下文和意义的理解,如 Word2Vec、BERT、Siamese 网络等。
三、主流文本相似度计算方法全景图
方法 | 类型 | 是否考虑语义 | 代表模型或算法 | 优点 | 缺点 |
---|---|---|---|---|---|
TF-IDF | 词频统计型 | 否 | TF-IDF | 简单高效,可解释性强 | 无法理解语义 |
Word2Vec | 词嵌入型 | 是 | CBOW / Skip-gram | 能表示词语语义 | 静态向量,OOV 问题 |
平均词向量 | 聚合向量型 | 是 | Word2Vec/GloVe | 快速聚合词语语义 | 忽略词序、上下文 |
Siamese 网络 | 神经结构型 | 是 | Bi-LSTM/GRU + 对比损失 | 表示上下文序列语义 | 训练成本高,需要标注数据 |
BERT | 预训练模型 | 是(动态) | Transformer/BERT | 语义理解最强 | 计算开销大,部署成本高 |
四、方法逐一剖析与代码示例
1. TF-IDF + 余弦相似度(基准方法)
适用于文本较短,或计算资源有限的场景。
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
texts = ["我爱自然语言处理", "自然语言处理是人工智能的分支"]
vec = TfidfVectorizer()
tfidf = vec.fit_transform(texts)
similarity = cosine_similarity(tfidf[0], tfidf[1])
print(f"相似度:{similarity[0][0]:.4f}")
2. Word2Vec 平均向量 + 余弦相似度
每个词转换为向量,取平均表示整个句子。
import numpy as np
from gensim.models import Word2Vec
from sklearn.metrics.pairwise import cosine_similarity
model = Word2Vec([["我", "爱", "自然", "语言", "处理"]], vector_size=100, min_count=1)
def sentence_vector(sentence):
words = sentence.split()
vectors = [model.wv[w] for w in words if w in model.wv]
return np.mean(vectors, axis=0).reshape(1, -1)
vec1 = sentence_vector("我爱自然语言处理")
vec2 = sentence_vector("自然语言处理是人工智能的分支")
sim = cosine_similarity(vec1, vec2)
print(f"相似度:{sim[0][0]:.4f}")
3. Siamese 双塔网络(Bi-LSTM 示例)
适合大规模匹配任务,如搜索召回、意图识别。
思路流程:
输入句对 → 两个共享权重的 Bi-LSTM → 得到句向量 → 计算欧氏距离或余弦相似度 → 相似度评分
框架上常用 Siamese-BERT
、Sentence-BERT
等封装库。下面用 Sentence-BERT 举个例:
from sentence_transformers import SentenceTransformer, util
model = SentenceTransformer('paraphrase-MiniLM-L6-v2')
sentence1 = "我爱自然语言处理"
sentence2 = "自然语言处理是人工智能的重要分支"
embedding1 = model.encode(sentence1, convert_to_tensor=True)
embedding2 = model.encode(sentence2, convert_to_tensor=True)
sim = util.pytorch_cos_sim(embedding1, embedding2)
print(f"相似度:{sim.item():.4f}")
4. BERT CLS 向量 + 相似度计算
使用 BERT 模型的 [CLS]
向量作为句向量进行匹配。
from transformers import BertTokenizer, BertModel
import torch
tokenizer = BertTokenizer.from_pretrained('bert-base-chinese')
model = BertModel.from_pretrained('bert-base-chinese')
def get_cls_embedding(text):
inputs = tokenizer(text, return_tensors='pt', truncation=True, padding=True)
outputs = model(**inputs)
return outputs.last_hidden_state[:, 0, :] # CLS向量
v1 = get_cls_embedding("我爱自然语言处理")
v2 = get_cls_embedding("自然语言处理是人工智能的重要分支")
cos = torch.nn.functional.cosine_similarity(v1, v2)
print(f"相似度:{cos.item():.4f}")
五、选型建议
应用场景 | 推荐方法 |
---|---|
简单关键词相似匹配 | TF-IDF + 余弦相似度 |
通用语义近似、短文本匹配 | Word2Vec + 平均向量 |
大规模语义召回 / 推理任务 | Siamese 网络 / SBERT |
高质量语义理解、推理 | BERT / RoBERTa 等预训练模型 |
六、总结
文本相似度是一项基础但关键的 NLP 技术。随着预训练语言模型的发展,语义匹配已不再依赖传统规则,而进入了“理解为王”的时代。但 TF-IDF 和 Word2Vec 并未过时,它们在轻量级、快速部署等场景中依然可靠。
作为开发者,我们应当理解每种方法背后的原理、优劣和适用边界,做到“选得准、用得巧”。
引用资料
- Reimers, N., & Gurevych, I. (2019). Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks. arXiv preprint arXiv:1908.10084
- scikit-learn 文档:https://scikit-learn.org/stable/modules/feature_extraction.html
- Gensim 文档:https://radimrehurek.com/gensim/models/word2vec.html
- Hugging Face Transformers:https://huggingface.co/docs/transformers
- Google BERT 原论文:https://arxiv.org/abs/1810.04805