You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Sentence Transformers余弦度量时句子相似度准确率异常求助

长转写文本与短预定义句子相似度偏低的解决办法

我在使用Sentence Transformers结合余弦度量计算句子相似度时遇到问题:将音频转写的长文本与预定义短句集对比,即便预定义句子完整出现在转写文本中,相似度得分仍偏低。推测是转写文本过长、包含大量无关内容导致的,相关代码如下:

for rs in red_section:
    for s in split:
        logging.info(f'{s} " --vs-- " {rs}')
        # score = sentence_similarity_model.get_score(sentence, rs, metric="cosine")
        sentences = [rs, s]
        embeddings = sent_model.encode([rs, s], convert_to_tensor=True)
        cosine_scores = util.cos_sim(embeddings, embeddings)
        pairs = []
        for i in range(len(cosine_scores) - 1):
            for j in range(i + 1, len(cosine_scores)):
                pairs.append({'index': [i, j], 'score': cosine_scores[i][j]})

        pairs = sorted(pairs, key=lambda x: x['score'], reverse=True)

        for pair in pairs[0:10]:
            i, j = pair['index']
            logging.info(f'{sentences[i]} --vs-- {sentences[j]}')
            score = round(pair["score"].item() * 100)
        logging.info(f'Score ---> {score} %')

        if score >= 80:
            logging.info(f"Red Confidence in similarity -> {round(score * 100)} %")

for ys in yellow_section:
    for s in split:
        logging.info(f'{s} " --vs-- " {ys}')
        # score = sentence_similarity_model.get_score(sentence, ys, metric="cosine")
        sentences = [ys, s]
        embeddings = sent_model.encode([ys, s], convert_to_tensor=True)
        cosine_scores = util.cos_sim(embeddings, embeddings)
        pairs = []
        for i in range(len(cosine_scores) - 1):
            for j in range(i + 1, len(cosine_scores)):
                pairs.append({'index': [i, j], 'score': cosine_scores[i][j]})

        pairs = sorted(pairs, key=lambda x: x['score'], reverse=True)

        for pair in pairs[0:10]:
            i, j = pair['index']
            logging.info(f'{sentences[i]} --vs-- {sentences[j]}')
            score = round(pair["score"].item() * 100)
        logging.info(f'Score ---> {score} %')

        if score >= 80:
            logging.info(f"Yellow Confidence in similarity -> {score} %")

for gs in green_section:
    for s in split:
        logging.info(f'{s} " --vs-- " {gs}')
        # score = sentence_similarity_model.get_score(sentence, gs, metric="cosine")
        sentences = [gs, s]
        embeddings = sent_model.encode([gs, s], convert_to_tensor=True)
        cosine_scores = util.cos_sim(embeddings, embeddings)
        pairs = []
        for i in range(len(cosine_scores) - 1):
            for j in range(i + 1, len(cosine_scores)):
                pairs.append({'index': [i, j], 'score': cosine_scores[i][j]})

        pairs = sorted(pairs, key=lambda x: x['score'], reverse=True)
        logging.info(f'Pairsssssss ---> {pairs}')

        for pair in pairs[0:10]:
            logging.info(f'Pairrrrrr ---> {pair}')
            i, j = pair['index']
            logging.info(f'{sentences[i]} --vs-- {sentences[j]}')
            score = round(pair["score"].item() * 100)
        logging.info(f'Score ---> {score} %')

        if score >= 80:
            logging.info(f"Green Confidence in similarity -> {score} %")

问题根源

Sentence Transformers生成的句向量是整句语义的加权平均,长文本里的无关内容会稀释目标句子的语义权重,导致和预定义短句的向量余弦相似度被拉低——相当于把目标句子“淹没”在无关信息里了。

解决思路与优化方案

1. 拆分长文本,用局部片段匹配

不用拿整个长文本去算相似度,先把转写文本拆成小的语义单元(分句、固定长度片段),再用每个片段和预定义句子比对,取最高得分。这样能避开无关内容的干扰,聚焦到包含目标句子的局部片段。

2. 换用匹配专用的模型

Sentence Transformers里有针对短文本匹配/问答任务优化的模型,比如multi-qa-MiniLM-L6-cos-v1或者all-MiniLM-L6-v2,这些模型对短长文本的语义匹配更敏感,替换现有模型能直接提升得分精度。

3. 改用CrossEncoder做直接打分

CrossEncoder模型会直接对句子对进行相似度打分,不像BiEncoder(你现在用的)先生成向量再算余弦,它能更好捕捉局部匹配的语义,适合这种“短句子在长文本里”的场景。

优化后的代码示例

下面是用“拆分长文本+取最高得分”的方式优化后的代码,逻辑更简洁,效果更准确:

from sentence_transformers import SentenceTransformer, util
import logging
from nltk.tokenize import sent_tokenize
import nltk

# 先下载分句所需的语料
nltk.download('punkt')

# 替换为匹配专用模型
sent_model = SentenceTransformer('multi-qa-MiniLM-L6-cos-v1')

def get_max_similarity(short_sent, long_text):
    # 把长文本拆成独立句子
    long_sents = sent_tokenize(long_text)
    if not long_sents:
        return 0
    # 编码短句子和所有长文本分句
    embeddings = sent_model.encode([short_sent] + long_sents, convert_to_tensor=True)
    # 计算短句子与每个长分句的余弦相似度
    cos_scores = util.cos_sim(embeddings[0], embeddings[1:])
    # 取最高得分并转成百分比
    max_score = round(cos_scores.max().item() * 100)
    return max_score

# 处理red_section
for rs in red_section:
    for s in split:
        logging.info(f'{s} --vs-- {rs}')
        score = get_max_similarity(rs, s)
        logging.info(f'Score ---> {score} %')
        if score >= 80:
            logging.info(f"Red Confidence in similarity -> {score} %")

# yellow_section和green_section直接复用上面的逻辑即可
for ys in yellow_section:
    for s in split:
        logging.info(f'{s} --vs-- {ys}')
        score = get_max_similarity(ys, s)
        logging.info(f'Score ---> {score} %')
        if score >= 80:
            logging.info(f"Yellow Confidence in similarity -> {score} %")

for gs in green_section:
    for s in split:
        logging.info(f'{s} --vs-- {gs}')
        score = get_max_similarity(gs, s)
        logging.info(f'Score ---> {score} %')
        if score >= 80:
            logging.info(f"Green Confidence in similarity -> {score} %")

额外小技巧

  • 转写文本常有口语化冗余或错别字,先做简单清洗(比如去掉“嗯”“啊”这类语气词,修正常见错别字)能进一步提升匹配精度。
  • 如果转写文本没有明显分句,可以用固定长度的滑动窗口截取片段,再逐个计算相似度。

内容的提问来源于stack exchange,提问作者Niceboy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 04:25:36