语义相似度怎么算?

访客 自然语言处理 1

本文目录导读:

  1. 核心思路:从“字符匹配”到“语义匹配”
  2. 基于向量空间模型(最经典、最常用)
  3. 经典的非向量方法(适合快速理解或基线对比)
  4. 如何选择?(实用建议)
  5. 具体计算步骤(以最主流的 Sentence-BERT 为例)

语义相似度就是衡量两个文本(词、句子、段落)在“意思”上有多接近,而不是看它们字面上有多少共同字符。

计算语义相似度的方法主要可以分为三代:基于统计的、基于向量空间的、以及基于深度学习的(最主流)。

以下是目前最主流和常见的计算方法:

核心思路:从“字符匹配”到“语义匹配”

  • 传统方法(如编辑距离): 认为“猫吃鱼”和“鱼吃猫”不相似。(字面不同)
  • 语义方法(如词向量): 认为“猫吃鱼”和“猫咪爱吃鱼”很相似。(意思相同)
  • 高级语义方法(如BERT): 认为“猫吃鱼”和“猫咪很享受鱼肉”也相似。(即使字词不同,但意思关联)

基于向量空间模型(最经典、最常用)

这是目前深度学习时代的基础,核心思想是:将文本变成一个高维空间中的“向量”,然后用计算两个向量之间的“距离”或“夹角”来衡量相似度。

词袋模型(Bag of Words, BoW) + TF-IDF

  • 做法: 统计句子中每个词出现的次数或重要性(TF-IDF),形成一个稀疏向量。
  • 缺点: 忽略词序和上下文(“我打你”和“你打我”向量相同),且无法处理同义词(“汽车”和“轿车”被视为完全不同的词)。
  • 相似度计算: 余弦相似度。

静态词向量(Word2Vec / GloVe) —— 里程碑式进步

  • 做法: 预训练好的词向量,每个词被映射到一个稠密向量(如300维)。
  • 如何算句子: 将句子中所有词的向量取平均。
  • 优点: “国王 - 男人 + 女人 = 女王”,能捕捉到词与词之间的关系。
  • 缺点: 无法解决多义词问题(“苹果”手机 vs “苹果”水果,向量是一样的)。
  • 相似度计算: 余弦相似度。

深度上下文向量(BERT / Sentence-BERT) —— 目前最先进方法

  • 做法: 使用预训练语言模型(如BERT),输入“今天天气真不错”和“今天晴空万里”,模型会考虑每个词的上下文。
  • 优点: 完美解决多义词、同义词、语序问题,上述两句话会被认为非常相似。
  • 如何计算:
    • 方法A(传统): 提取BERT的[CLS]标记向量作为句子表示,算余弦相似度,但直接算效果并不好。
    • 方法B(推荐): 使用Sentence-BERT(SBERT),这是一个专门为计算相似度而微调的模型,它将两个句子分别编码成向量,然后输入一个分类器或直接算余弦相似度。这是目前实际应用中的SOTA(State Of The Art,最先进水平)。

经典的非向量方法(适合快速理解或基线对比)

这些方法通常更直观,但精度不如深度模型。

基于字符串的

  • 编辑距离(Levenshtein Distance): 把一个字符串变成另一个需要的最少编辑次数(增、删、改),距离越小,越相似,对拼写错误有效,但对语义完全无效。
  • 杰卡德相似度(Jaccard Similarity): 两个集合(如单词集合)交集大小除以并集大小,对“猫吃鱼”和“鱼吃猫”结果很高,但语义相反。

基于知识的(WordNet / 知网)

  • 做法: 利用大规模语义词典(如WordNet),狗”和“猫”在百科层级中同属“哺乳动物”,路径较短,相似度较高。
  • 缺点: 需要维护庞大的知识库,且对网络新词(“YYDS”、“躺平”)几乎无效。

如何选择?(实用建议)

你的场景 推荐方法 速度 准确度
快速试算、简单理解 TF-IDF + 余弦相似度 极快
拼写校正或模糊匹配 编辑距离 极低(语义无关)
同义词识别(如:高兴 vs 快乐) Word2Vec / GloVe
句子匹配、客服问答、论文查重 Sentence-BERT 中等
情感分析、复杂推理 BERT + 微调分类(如输入两个句子,输出0-1分数) 中等 极高

具体计算步骤(以最主流的 Sentence-BERT 为例)

  1. 安装库: pip install sentence-transformers

  2. 加载模型:

    from sentence_transformers import SentenceTransformer
    # 模型:'all-MiniLM-L6-v2' (快, 轻量) 或 'all-mpnet-base-v2' (慢, 更准)
    model = SentenceTransformer('all-MiniLM-L6-v2')
  3. 编码成向量:

    sentence1 = "我今天心情非常好"
    sentence2 = "今天我的情绪非常愉快"
    embedding1 = model.encode(sentence1)
    embedding2 = model.encode(sentence2)
    # embedding 是一个 384 维的数组
  4. 计算余弦相似度:

    from sklearn.metrics.pairwise import cosine_similarity
    import numpy as np
    similarity = cosine_similarity([embedding1], [embedding2])
    print(similarity[0][0])  # 输出 0.92 (非常相似)
  • 简单场景(仅看字符):用 TF-IDF
  • 语义理解(手机 vs 电话):用 Word2Vec
  • 最佳实践(句子/段落级别):用 Sentence-BERT,它结合了深度上下文理解与高效的向量匹配,是目前工业界和学术界最常用的方案。

如果你有具体的语言(如中文)或算力限制(比如必须在手机端跑),选择会有所不同,需要我进一步介绍中文领域的特殊处理(如分词、中文预训练模型)吗?

标签: 余弦相似度

抱歉,评论功能暂时关闭!