21

我正在使用 HuggingFace Transformers 包来访问预训练模型。由于我的用例需要英语和阿拉伯语的功能,我使用的是bert-base-multilingual- cased 预训练模型。我需要能够使用诸如余弦相似度之类的东西来比较句子的相似度。要使用它,我首先需要为每个句子获取一个嵌入向量,然后可以计算余弦相似度。

首先,从 BERT 模型中提取语义嵌入的最佳方法是什么?在输入句子后获取模型的最后一个隐藏状态就足够了吗?

import torch
from transformers import BertModel, BertTokenizer

model_class = BertModel
tokenizer_class = BertTokenizer
pretrained_weights = 'bert-base-multilingual-cased'

tokenizer = tokenizer_class.from_pretrained(pretrained_weights)
model = model_class.from_pretrained(pretrained_weights)

sentence = 'this is a test sentence'

input_ids = torch.tensor([tokenizer.encode(sentence, add_special_tokens=True)])
with torch.no_grad():
    output_tuple = model(input_ids)
    last_hidden_states = output_tuple[0]

print(last_hidden_states.size(), last_hidden_states)

其次,如果这是从我的句子中获取嵌入的充分方法,那么我现在遇到另一个问题,即嵌入向量的长度取决于原始句子的长度。输出的形状是[1, n, vocab_size],其中n可以有任何值。

为了计算两个向量的余弦相似度,它们需要具有相同的长度。我怎么能在这里做到这一点?像第一次求和这样幼稚的事情axis=1还能奏效吗?我还有什么其他选择?

4

3 回答 3

19

除了一个已经很好接受的答案之外,我想指出你sentence-BERT,它更详细地讨论了特定指标(如余弦相似度)的相似性方面和含义。他们也有一个非常方便的在线实现。这里的主要优点是,与“幼稚”的句子嵌入比较相比,它们似乎获得了很多处理速度,但我对实现本身还不够熟悉。

重要的是,您想要查看的相似性通常还有更细粒度的区别。为此,在SemEval 2014的一篇任务论文(SICK 数据集)中也有很好的讨论,其中对此进行了更详细的讨论。根据您的任务描述,我假设您已经在使用来自后来的 SemEval 任务之一的数据,这也将其扩展到多语言相似性。

于 2020-03-03T09:31:58.820 回答
11

您可以使用[CLS]标记作为整个序列的表示。此标记通常在预处理步骤中添加到您的句子中。该标记通常用于分类任务(参见BERT 论文中的图 2 和第 3.2 段)。

它是嵌入的第一个标记。

或者,您可以采用序列的平均向量(就像您在第一个(?)轴上所说的那样),根据huggingface 文档(第三个技巧)可以产生更好的结果。

请注意,BERT 并不是为使用余弦距离的句子相似性而设计的,尽管根据我的经验,它确实产生了不错的结果。

于 2020-03-02T16:36:36.230 回答
0

您不应该将 BERT 的输出用作语义相似性的句子嵌入。BERT 没有针对语义相似性进行预训练,这将导致结果不佳,甚至比简单的 Glove Embeddings 还要差。请参阅下面 Jacob Devlin(BERT 论文的第一作者)的评论和 Sentence-BERT 论文中的一篇文章,其中详细讨论了句子嵌入。

Jacob Devlin 的评论:我不确定这些向量是什么,因为 BERT 不会生成有意义的句子向量。似乎这是对单词标记进行平均池化以获得句子向量,但我们从未建议这会生成有意义的句子表示。即使它们在输入为下游任务训练的 DNN 时是不错的表示,但这并不意味着它们在余弦距离方面有意义。(因为余弦距离是一个线性空间,其中所有维度的权重均等)。(https://github.com/google-research/bert/issues/164#issuecomment-441324222

来自 Sentence-BERT 论文:结果表明,直接使用 BERT 的输出会导致性能相当差。对 BERT 嵌入进行平均后,平均相关性仅为 54.81,而使用 CLS 令牌输出的平均相关性仅为 29.19。两者都比计算平均 GloVe 嵌入更差。(https://arxiv.org/pdf/1908.10084.pdf

您应该改用专门针对句子相似度进行预训练的模型,例如 Sentence-BERT。Sentence-BERT 和其他几个用于句子相似性的预训练模型在 sentence-transformers 库 ( https://www.sbert.net/docs/pretrained_models.html ) 中可用,它与令人惊叹的 HuggingFace 转换器库完全兼容。使用这些库,您只需一行代码即可获得句子嵌入。

于 2022-02-28T19:41:37.090 回答