Press "Enter" to skip to content

简化Transformer:使用您理解的词语进行最先进的自然语言处理——第3部分——注意力

深入探讨LLMs的核心技术——注意力

Transformer在AI领域产生了重大影响,甚至可以说是在整个世界范围内。这种架构由几个组件组成,但由于原始论文的标题是“注意力就是一切”,可以明显看出注意力机制具有特殊的重要性。本系列的第三部分将主要集中讨论注意力以及围绕注意力的功能,以确保Transformer交响乐团协同演奏。

Image from the original paper by Vaswani, A. et al.

注意力

在Transformer的上下文中,注意力指的是一种机制,使模型能够在处理过程中关注输入的相关部分。想象一下手电筒照射在句子的特定部分,允许模型根据上下文为不同部分赋予更多或更少的重要性。我相信例子比定义更有效,因为它们是一种脑力游戏,为大脑提供了桥梁,让它自己理解概念。

当面对句子“那个人拿起椅子然后消失了”时,你自然地给句子的不同部分分配不同程度的重要性(例如注意力)。有点令人惊讶的是,如果我们删除特定的词,意义仍然基本保持不变:“人拿起椅子消失了。”虽然这个版本的英语是有问题的,与原始句子相比,你仍然可以理解信息的本质。有趣的是,三个词(“The”,“the”和“and”)占了句子中43%的词数,但对整体意义没有太大贡献。这个观察结果可能对每个在柏林生活过的人来说都很清楚(你要么学德语,要么快乐,这是你必须做出的决定),但对于ML模型来说却不太明显。

过去,像RNN(循环神经网络)这样的先前架构面临着一个重大挑战:它们难以“记住”出现在输入序列中较远位置的单词,通常超过20个单词。正如你已经知道的,这些模型本质上依赖于数学运算来处理数据。不幸的是,早期架构中使用的数学运算不足以充分地将单词表示传递到序列的远期。

这种对长期依赖性的限制影响了RNN在长时间内保持上下文信息的能力,影响了语言翻译或情感分析等需要理解整个输入序列的任务。然而,具有注意力机制和自注意机制的Transformer能够更有效地解决这个问题。它们可以高效地捕捉输入中的长距离依赖关系,使模型能够保持上下文和相关性,即使是在序列中出现得更早的单词也是如此。因此,Transformer已经成为克服先前架构限制的突破性解决方案,并显着提高了各种自然语言处理任务的性能。

要创建像我们今天遇到的先进聊天机器人这样的卓越产品,将模型赋予区分高低价值词汇并在输入的长距离上保留上下文信息的能力非常重要。Transformers架构中引入的用于解决这些挑战的机制称为注意力

*人类已经开发了很长时间用于区分人类的技术,但尽管它们非常激动人心,我们将不会在这里使用它们。

点积

模型如何从理论上区分不同单词的重要性?在分析句子时,我们的目标是确定彼此之间具有更强关系的词汇。由于单词被表示为向量(数字),我们需要一种测量数字相似性的方法。测量向量相似性的数学术语是“点积”。它涉及两个向量元素的乘积,并产生一个标量值(例如2、16、-4.43),用作它们相似性的表示。机器学习建立在各种数学运算基础之上,其中点积具有特殊重要性。因此,我将花时间详细介绍这个概念。

直觉假设我们为5个单词“florida”、“california”、“texas”、“politics”和“truth”提供了实际表示(嵌入)。由于嵌入只是数字,我们可以将它们在图上绘制出来。然而,由于它们的高维性(用于表示单词的数字数量),可以轻松达到100到1000个,我们无法直接将它们绘制出来。我们无法在2D的计算机/手机屏幕上绘制一个100维的向量。此外,人脑很难理解3维以上的东西。一个4维向量是什么样子?我不知道。

为了克服这个问题,我们使用主成分分析(PCA)技术来减少维度数量。通过应用PCA,我们可以将嵌入投影到二维空间(x、y坐标)。降维有助于在图表上可视化数据。虽然由于降维我们会丢失一些信息,但希望这些降维后的向量仍然能保留足够与原始嵌入相似的相似性,使我们能够获取洞察力并理解单词之间的关系。

这些数字基于GloVe嵌入。

florida = [-2.40062016,  0.00478901]california = [-2.54245794, -0.37579669]texas = [-2.24764634, -0.12963368]politics = [3.02004564,  2.88826688]truth = [4.17067881, -2.38762552]

你可能会注意到这些数字中存在一些模式,但我们将把这些数字绘制出来以便更容易理解。

5个二维向量

在这个可视化中,我们看到了五个二维向量(x、y坐标),代表了5个不同的单词。正如你所看到的,这个图表暗示了一些单词与其他单词之间的更强关联。

数学通过一个简单的方程式可以表达向量可视化的数学对应关系。如果你对数学不太感兴趣,并回想起作者将Transformer架构描述为“简单的网络架构”,你可能会认为这就是机器学习人员的情况,他们变得奇怪了。这可能是真的,但在这种情况下,这是简单的。我来解释一下:

点积公式

符号||a||表示向量“a”的大小,表示从原点(点0,0)到向量尖端的距离。大小的计算如下:

向量大小公式

这个计算的结果是一个数字,比如4或12.4。Theta(θ)表示向量之间的夹角(看一下可视化)。Theta的余弦值,表示为cos(θ),就是应用余弦函数到该角度的结果。

代码使用GloVe算法,斯坦福大学的研究人员为实际单词生成了嵌入,正如我们之前讨论的那样。尽管他们有自己创建这些嵌入的特定技术,但其基本概念与我们在本系列的前一部分中讨论的相同。作为示例,我选取了4个单词,将它们的维度降低到2,然后将它们的向量作为直接的x和y坐标绘制出来。

为了使这个过程正确运行,下载GloVe嵌入是必要的先决条件。

*部分代码,尤其是第一个框,受到了我看过的一些代码的启发,但我似乎找不到来源。

import pandas as pdpath_to_glove_embds = 'glove.6B.100d.txt'glove = pd.read_csv(path_to_glove_embds, sep=" ", header=None, index_col=0)glove_embedding = {key: val.values for key, val in glove.T.items()}

words = ['florida', 'california', 'texas', 'politics', 'truth']word_embeddings = [glove_embedding[word] for word in words]print(word_embeddings[0]).shape # 100个数字表示每个单词。---------------------输出:(100,)

pca = PCA(n_components=2) # 将维度从100降低到2。word_embeddings_pca = pca.fit_transform(word_embeddings)

for i in range(5):    print(word_embeddings_pca[i])---------------------输出:[-2.40062016  0.00478901] # florida[-2.54245794 -0.37579669] # california[-2.24764634 -0.12963368] # texas[3.02004564 2.88826688] # politics[ 4.17067881 -2.38762552] # truth

我们现在拥有所有5个单词的真实表示。下一步是进行点乘计算。

向量的大小:

import numpy as npflorida_vector = [-2.40062016,  0.00478901]florida_vector_magnitude = np.linalg.norm(florida_vector)print(florida_vector_magnitude)---------------------output:2.4006249368060817 # 向量 "florida" 的大小为2.4。

两个相似向量的点积。

import numpy as npflorida_vector = [-2.40062016,  0.00478901]texas_vector = [-2.24764634 -0.12963368]print(np.dot(florida_vector, texas_vector))---------------------output:5.395124299364358

两个不相似向量的点积。

import numpy as npflorida_vector = [-2.40062016,  0.00478901]truth_vector = [4.17067881, -2.38762552]print(np.dot(florida_vector, truth_vector))---------------------output:-10.023649994662344

从点积计算中可以看出,它似乎捕捉并反映了不同概念之间的相似性。

缩放点积注意力

直觉现在我们已经掌握了点积,我们可以深入研究注意力。特别是,自注意机制。使用自注意力机制可以使模型能够确定每个单词的重要性,而不管其与单词的“物理”接近程度如何。这使得模型能够根据每个单词的上下文相关性做出明智的决策,从而实现更好的理解。

为了实现这个雄心勃勃的目标,我们创建了由可学习的参数组成的3个矩阵,称为查询、键和值(Q, K, V)。查询矩阵可以被视为包含用户查询或询问的单词(例如,当你询问 chatGPT:“上帝今天下午5点有空吗?” 这就是查询)。键矩阵包含序列中的所有其他单词。通过计算这些矩阵之间的点积,我们可以得到每个单词与当前正在检查的单词之间的相关性程度(例如,翻译或回答查询)。

值矩阵为序列中的每个单词提供“干净”的表示。为什么我将其称为“干净”,而其他两个矩阵以类似的方式形成?因为值矩阵保持其原始形式,我们在乘以另一个矩阵或通过某个值进行归一化后不再使用它。这种区别使值矩阵与众不同,确保它保留了原始的嵌入,不受额外计算或转换的影响。

所有3个矩阵的大小都是 word_embedding(512)。然而,它们被划分为“头”。在论文中,作者使用了8个头,导致每个矩阵的大小为 sequence_length 乘以 64。你可能想知道为什么要使用相同的操作在1/8的数据上执行8次,而不是一次性使用所有数据。这种方法的理论基础是,通过使用8组不同的权重进行相同的操作(这些权重是可学习的),我们可以利用数据中固有的多样性。每个头可以关注输入中的特定方面,总体上,这可以提高性能。

*在大多数实现中,我们实际上并没有将主要矩阵划分为8个部分。通过索引实现划分,可以为每个部分进行并行处理。然而,这些只是实现细节。从理论上讲,我们也可以使用8个矩阵来做到基本相同的效果。

将 Q 和 K 进行乘法(点积),然后通过维度的平方根进行归一化。我们将结果通过 Softmax 函数传递,并将结果乘以矩阵 V。归一化结果的原因是 Q 和 K 是以某种随机方式生成的矩阵。它们的维度可能完全不相关(独立),独立矩阵之间的乘法可能导致非常大的数字,这可能对学习造成损害,稍后我将在本部分解释。然后,我们使用一个名为 Softmax 的非线性变换,使所有数字在0到1之间,并且总和为1。结果类似于概率分布(因为有从0到1的数字,总和为1)。这些数字示例化了序列中每个单词与其他单词的相关性。最后,我们将结果乘以矩阵 V,然后,我们得到了自注意力分数。

编码器实际上是由N(在论文中,N=6)个相同的层构建而成的,每个层都从前一层获取输入并执行相同的操作。最后一层将数据传递给解码器(我们将在本系列的后面部分讨论)和编码器的上层。

下面是自注意力的可视化。它就像教室里的一群朋友。有些人与一些人的联系更密切,而有些人与任何人的联系都不太紧密。

Vaswani等人的原始论文中的图像

数学 Q、K和V矩阵是通过对嵌入矩阵进行线性变换得到的。线性变换在机器学习中非常重要,如果你有兴趣成为机器学习专业人员,我建议你进一步学习它们。我不会深入讲解,但我会说线性变换是一种数学运算,它将一个向量(或矩阵)从一个空间移动到另一个空间。听起来比实际情况复杂一些。想象一个箭头指向一个方向,然后转到右边30度。这就是线性变换的示例。进行线性变换需要满足一些条件,但现在并不重要。关键是它保留了许多原始向量的属性。

自注意力层的整个计算是通过应用以下公式来完成的:

Vaswani等人的原始论文中的缩放点积注意力图像

计算过程如下:1. 我们将Q与K的转置(翻转)相乘。2. 我们将结果除以矩阵K的维度的平方根。3. 现在我们有了描述每个单词与其他单词相似程度的“注意力矩阵分数”。我们将每一行传递给Softmax(一种非线性)变换。Softmax有三个有趣和相关的特点:a. 它将所有数字缩放到0到1之间。b. 它使所有数字的和为1。c. 它突出了差距,使得略微更重要的事物变得更加重要。因此,我们现在可以轻松地区分模型对单词x1与x2、x3、x4等之间的连接程度的不同。4. 我们将分数与V矩阵相乘。这是自注意力操作的最终结果。

掩码

在本系列的前一篇文章中,我解释了我们使用虚拟标记来处理句子中的特殊情况,例如句子中的第一个单词、最后一个单词等。其中一个标记,表示为<PADDING>,表示没有实际数据,但我们需要在整个过程中保持一致的矩阵大小。为了确保模型理解这些是虚拟标记,在自注意力计算过程中不应考虑它们,我们将这些标记表示为负无穷大(例如非常大的负数,例如-153513871339)。掩码值被添加到Q乘以K的乘积结果中。然后,Softmax将这些数字转换为0。这使我们能够在注意机制中有效地忽略虚拟标记,同时保持计算的完整性。

Dropout

在自注意力层之后,应用了一次Dropout操作。Dropout是机器学习中广泛使用的正则化技术。正则化的目的是在训练过程中对模型施加约束,使其更难依赖于特定的输入细节。结果,模型学习更加稳健,提高了泛化能力。实际实现涉及随机选择一些激活(来自不同层的数字)并将它们置为零。在同一层的每次传递中,不同的激活将被置为零,防止模型找到特定于其接收到的数据的解决方案。实质上,Dropout有助于增强模型处理多样输入的能力,并使模型更难针对数据中的特定模式进行调整。

跳连接

Transformer架构中的另一个重要操作被称为跳连接。

Vaswani等人的原始论文中的图像

跳连接是一种在不进行任何转换的情况下传递输入的方式。举个例子,想象我向我的经理汇报,然后我的经理向他的经理汇报。即使有着使报告更有用的非常纯净的意图,当另一个人(或ML层)处理时,输入现在经过一些修改。在这个类比中,跳连接就是我直接向我的经理的经理汇报。因此,高级经理可以通过我的经理(处理过的数据)和我直接(未处理的数据)接收到输入。然后,高级经理可以做出更好的决策。采用跳连接的原理是解决梯度消失等潜在问题,我将在下一节中解释。

加和规范化层

直觉“加和规范化”层执行加和和规范化操作。我将从加和开始,因为它更简单。基本上,我们将自注意力层的输出与原始输入(通过跳连接接收)进行加和。这种加和是逐元素进行的(每个数与相同位置的数相加)。然后对结果进行规范化。

我们之所以进行规范化,是因为每个层都进行了大量的计算。多次相乘可能会导致意外的情况发生。例如,如果我取一个分数,比如0.3,然后将其与另一个分数,比如0.9相乘,得到的结果是0.27,比起初始值要小。如果我多次这样做,可能会得到非常接近0的结果。这可能会导致深度学习中的一个问题,称为梯度消失。我现在不会深入探讨,以免阅读本文所需时间过长,但是思路是,如果数值接近0,模型将无法有效学习。现代机器学习的基础是计算梯度并使用这些梯度(和其他一些因素)来调整权重。如果这些梯度接近0,模型将很难有效学习。

相反,还会出现另一种现象,称为梯度爆炸。当非分数的数字与非分数相乘时,导致值变得过大。结果,模型在学习过程中面临权重和激活的巨大变化,可能导致不稳定和发散。

机器学习模型有点像小孩子,它们需要保护。保护这些模型免受数字过大或过小的一种方式是进行规范化。

数学规范化层的操作看起来很可怕(一如既往),但实际上相对简单。

Pytorch提供的图片,来自此处

在规范化层的操作中,我们对每个输入执行以下简单步骤:

  1. 从输入中减去其均值。
  2. 除以方差的平方根,并添加一个epsilon(一个很小的数),用于避免除以零。
  3. 将得到的得分乘以一个可学习的参数gamma(γ)。
  4. 添加另一个可学习的参数beta(β)。

这些步骤确保均值接近0,标准差接近1。规范化过程增强了训练的稳定性、速度和整体性能。

代码

# x是输入。(x - mean(x)) / sqrt(variance(x) + epsilon) * gamma + beta

总结:

到目前为止,我们对编码器的主要内部工作原理有了扎实的理解。此外,我们还探讨了跳连接,这是机器学习中一项纯技术(且重要)的技术,可以提高模型的学习能力。

尽管本节内容有点复杂,但您已经在整个Transformer架构方面获得了相当多的理解。随着系列的进展,这种理解将有助于您理解其余部分。请记住,这是一个复杂领域的最新技术。这不是一件容易的事情。即使您仍然不完全理解100%的内容,也要为取得这样的进展而感到骄傲!

接下来将介绍机器学习中一个基础(且较简单)的概念,即前馈神经网络。

Vaswani, A.等人原始论文中的图片
Leave a Reply

Your email address will not be published. Required fields are marked *