首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与伯特的字符串比较似乎忽略了句子中的"not“

与伯特的字符串比较似乎忽略了句子中的"not“
EN

Stack Overflow用户
提问于 2021-09-07 16:18:05
回答 2查看 520关注 0票数 3

我使用SentenceTransformers和BERT实现了一个字符串比较方法,如下所示

代码语言:javascript
复制
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity

model = SentenceTransformer('sentence-transformers/all-distilroberta-v1')

sentences = [
    "I'm a good person",
    "I'm not a good person"
]

sentence_embeddings = model.encode(sentences)

cosine_similarity(
    [sentence_embeddings[0]],
    sentence_embeddings[1:]
)

请注意我的句子示例是如何非常相似的,但却有相反的含义。问题是余弦相似度返回0.9,表明这两个字符串在上下文中非常相似,当我期望它返回接近于零的东西时,因为它们具有相反的含义。

如何调整代码以返回更准确的结果?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-09-20 21:20:39

TL;DR: NLI是你所需要的

首先,余弦相似度相当高,因为句子在以下意义上是相似的:

  • 他们是关于同一个话题的(对一个人的评价)
  • 他们是关于同一个主题(“我”)和同样的财产(“做一个好人”)。
  • 它们的句法结构相似。
  • 他们的词汇量几乎相同。

因此,从形式上看,它们应该被认为是相似的。此外,从实际角度来看,它们往往应被视为类似的。例如,如果你在谷歌上搜索“转基因导致癌症”,你可能会发现标签"GMO不是致癌“的文本是相关的。

第二,如果要度量句子之间的逻辑联系,嵌入的余弦相似性只是不够表达。这是因为嵌入包含了大量的语义风格、词汇和句法信息,但是它们是固定大小的(在你的例子中是768维的),所以它们不能包含关于这两个句子的意义的完整信息。因此,您需要另一个具有以下属性的模型:

  1. 它同时编码两个文本,所以它比较文本本身,而不仅仅是它们固定大小的嵌入。
  2. 它被明确地训练用来评估句子之间的逻辑联系。

评价文本之间的逻辑联系的任务称为自然语言推理(NLI),其最常见的表述形式是识别文本蕴涵(RTE):这是一个预测第一句是否包含第二句的问题。

在Huggingface中有很多模型为这个任务进行了培训,罗伯塔-大型mnli是一个很好的模型。你可以用它来评估两个文本的等价性。如果每一篇课文都包含另一篇文章,它们是等价的,所以你可以用两个方向的包含分数的乘积来估计等值的程度。

代码语言:javascript
复制
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification

tokenizer = AutoTokenizer.from_pretrained("roberta-large-mnli")
model = AutoModelForSequenceClassification.from_pretrained("roberta-large-mnli")

def test_entailment(text1, text2):
    batch = tokenizer(text1, text2, return_tensors='pt').to(model.device)
    with torch.no_grad():
        proba = torch.softmax(model(**batch).logits, -1)
    return proba.cpu().numpy()[0, model.config.label2id['ENTAILMENT']]

def test_equivalence(text1, text2):
    return test_entailment(text1, text2) * test_entailment(text2, text1)

print(test_equivalence("I'm a good person", "I'm not a good person"))  # 2.0751484e-07
print(test_equivalence("I'm a good person", "You are a good person"))  # 0.49342492
print(test_equivalence("I'm a good person", "I'm not a bad person"))   # 0.94236994
票数 6
EN

Stack Overflow用户

发布于 2021-09-08 22:07:44

结果并不令人惊讶。你已经通过了两个句子,它们非常相似,但却有相反的意思。句子嵌入是从一个在一般语料库上训练的模型中得到的,因此,如果句子相似的话,模型给出的嵌入一般都是相互接近的。这就是正在发生的事情,余弦相似性表明嵌入彼此很接近,句子也是如此。这个例子中的句子可能有相反的意思,但它们是相似的。

如果你期望两句意思相反的相似句子远离对方,那么你必须用一种分类模型对模型进行微调(比如情感分析,如果你的例子是基于积极和消极的情绪)。或者其他相关的任务。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69091576

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档