学习如何使用孪生BERT网络将句子准确地转化为嵌入向量

介绍
众所周知,变形金刚在自然语言处理领域取得了进化性的进展。基于变形金刚,许多其他机器学习模型也得以发展。其中之一是主要由多个堆叠的变形金刚编码器组成的BERT。除了用于情感分析或问答等一系列不同问题,BERT在构建单词嵌入(用数字向量表示单词的语义含义)方面变得越来越受欢迎。
将单词表示为嵌入的形式带来了巨大的优势,因为机器学习算法无法处理原始文本,但可以处理向量的向量。这样就可以使用欧氏距离或余弦距离等标准度量方法来比较不同单词的相似性。
问题是,在实践中,我们通常需要为整个句子构建嵌入,而不是单个单词。然而,基本的BERT版本只在单词级别上构建嵌入。因此,后来开发了几种类似BERT的方法来解决这个问题,本文将对其进行讨论。通过逐步讨论它们,我们将达到最先进的模型SBERT。
为了深入了解SBERT在幕后的工作原理,建议您已经熟悉BERT。如果还没有,本文的前一部分详细解释了它。
大型语言模型:BERT
了解BERT如何构建最先进的嵌入
towardsdatascience.com
BERT
首先,让我们回顾一下BERT如何处理信息。作为输入,它接收一个[CLS]标记和两个由特殊的[SEP]标记分隔的句子。根据模型配置,这些信息将被多头注意力块处理12或24次。然后将输出进行聚合,并通过简单的回归模型传递以获得最终标签。

有关BERT内部工作的更多信息,请参考本文系列的前一部分:
交叉编码器架构
可以使用BERT计算一对文档之间的相似性。考虑在大型集合中查找最相似的一对句子的目标。为了解决这个问题,将每个可能的句子对放入BERT模型中。这导致推理过程中的二次复杂度。例如,处理n = 10,000个句子需要n * (n-1) / 2 = 49,995,000次BERT计算,这实际上不可扩展。
其他方法
分析交叉编码器架构的低效性,预先为每个句子独立地计算嵌入似乎是合乎逻辑的。之后,我们可以直接在所有文档对上计算所选的距离度量,这比将二次数量的句子对馈送到BERT要快得多。
不幸的是,对于BERT来说,这种方法是不可行的:BERT的核心问题是每次同时传递和处理两个句子,这使得很难获得仅独立表示单个句子的嵌入。
研究人员尝试通过使用[CLS]标记嵌入的输出来消除这个问题,希望它包含足够的信息来表示一个句子。然而,[CLS]对于这个任务来说根本没有用处,因为它最初是在BERT中进行下一个句子预测的预训练。
另一种方法是将单个句子传递给BERT,然后对输出的标记嵌入进行平均。然而,所得结果甚至比简单地对GLoVe嵌入进行平均还要糟糕。
独立生成句子嵌入是BERT的主要问题之一。为了缓解这个问题,开发了SBERT。
SBERT
SBERT引入了孪生网络的概念,意味着每次两个句子独立地通过相同的BERT模型进行处理。在讨论SBERT架构之前,让我们先来了解一下孪生网络的一个细微注意事项:
在科学论文中,孪生网络架构通常被描述为多个模型接收多个输入。实际上,它可以被看作是一个单一的模型,具有相同的配置和共享于多个并行输入的权重。每当模型权重针对一个输入进行更新时,它们也会被相应地更新于其他输入。

回到SBERT,将句子通过BERT后,会应用一个池化层到BERT嵌入中,以获得它们的较低维度表示:初始的512个768维向量被转换为一个单一的768维向量。对于池化层,SBERT的作者建议选择均值池化层作为默认选项,尽管他们也提到可以使用最大池化策略或仅仅选择[CLS]符号的输出。
当两个句子通过池化层后,我们得到了两个768维向量u和v。通过使用这两个向量,作者提出了三种优化不同目标的方法,下面将进行讨论。
分类目标函数
这个问题的目标是正确分类给定的一对句子属于几个类别中的哪一个。
在生成u和v的嵌入后,研究人员发现从这两个向量派生出另一个向量,即按元素绝对差|u-v|,是有用的。他们也尝试了其他特征工程技术,但这个方法显示出了最好的结果。
最后,三个向量u、v和|u-v|被连接起来,乘以一个可训练的权重矩阵W,乘法结果被输入到softmax分类器中,输出句子对应不同类别的归一化概率。交叉熵损失函数用于更新模型的权重。

这个目标最常用于解决的问题之一是NLI(自然语言推理),其中给定一对定义了假设和前提的句子A和B,需要预测在给定前提的情况下,假设是真(蕴涵)、假(矛盾)还是不确定(中性)。对于这个问题,推理过程与训练过程相同。
正如论文中所述,SBERT模型最初是在SNLI和MultiNLI这两个数据集上进行训练的,这些数据集包含了一百万个句子对以及相应的标签:蕴涵、矛盾或中性。之后,论文的研究人员提到了关于SBERT调优参数的细节:
“我们使用三分类的softmax分类器目标函数对SBERT进行微调一轮。我们使用批量大小为16,Adam优化器,学习率为2e−5,并在训练数据的10%上进行线性学习率预热。我们的默认池化策略是均值池化。”
回归目标函数
在这个公式中,在获得向量u和v之后,它们之间的相似度分数是通过选择的相似度度量直接计算的。预测的相似度分数与真实值进行比较,并使用均方误差损失函数更新模型。默认情况下,作者选择余弦相似度作为相似度度量。

在推断过程中,可以以以下两种方式之一使用这个架构:
- 通过给定的句子对,可以计算相似度分数。推断工作流程与训练完全相同。
- 对于给定的句子,可以提取其句子嵌入(在应用池化层后)。当我们需要计算它们之间的成对相似度分数时,这特别有用。通过仅运行每个句子一次通过BERT提取所有必要的句子嵌入。之后,我们可以直接计算所选的相似度度量之间的所有向量(无疑,仍然需要平方数量的比较,但同时,我们避免了与BERT之前的平方推断计算)。
三元组目标函数
三元组目标引入了一个三元组损失,通常在三个句子上计算,通常称为锚点、正面和负面。假设锚点和正面句子非常接近,而锚点和负面句子非常不同。在训练过程中,模型评估对(锚点,正面)和对(锚点,负面)的接近程度。数学上,最小化以下损失函数:

边缘ε确保正面句子比锚点至少接近ε,而负面句子到锚点的距离。否则,损失将大于0。默认情况下,在这个公式中,作者选择欧几里得距离作为向量范数,参数ε设置为1。
与前两个架构不同,三元组SBERT架构现在并行接受三个输入句子(而不是两个)。

代码
SentenceTransformers是一个用于构建句子嵌入的最先进的Python库。它包含了几个针对不同任务的预训练模型。使用SentenceTransformers构建嵌入向量非常简单,下面的代码片段示例了这一点。

构建的嵌入向量可以用于相似性比较。每个模型都是针对特定任务进行训练的,因此选择适当的相似度度量进行比较时,参考文档非常重要。
结论
我们已经介绍了一种先进的自然语言处理模型,用于获取句子嵌入。通过将平方数量的BERT推断执行减少到线性,SBERT在保持高准确性的同时实现了巨大的速度增长。
为了最终理解这个差异的重要性,只需参考文中描述的例子,研究人员试图在n = 10000个句子中找到最相似的一对。在一台现代的V100 GPU上,使用BERT这个过程大约需要65个小时,而使用SBERT仅需5秒钟!这个例子证明了SBERT在自然语言处理方面的巨大进步。
资源
- Sentence-BERT: 使用Siamese BERT-Network的句子嵌入
- SentenceTransformers文档 | SBERT.net
- 自然语言推理 | Papers with code
除非另有说明,所有图片均为作者所创作