Transformer 模型

Transformer模型是由谷歌首先提出并应用于机器翻译的神经网络模型结构。Transformer结构完全通过注意力机制完成对源语言序列转换到目标语言序列的全局依赖的建模。当前几乎全部大语言模型都是通过基于Transformer结构进行训练。

嵌入表示层

对于输入文本序列,首先需要通过输入嵌入层(Input Embedding)将每个单词转换为所对应的向量表示。通常直接对每个单词创建一个向量表示,这些向量的方向与互相之间的夹角就代表着对应词语的语意和它们之间的相关程度

由于Transformer模型不再使用基于循环的方式建模文本输入,所以序列中不再包含任何信息能够提示模型单词之间的位置关系。因此,在送入编码器之前,我们需要在词嵌入中还要加入一个位置编码(Position Encoding)特征,具体来说,就是将序列中每一个单词所在的位置都对应一个向量。这个向量会与单词表示相加后送入到后续模块进行下一步的处理。在训练的过程中,模型会自动学习到如何利用这些被传入的位置信息。

为了得到不同位置的对应的位置编码,Transformer模型使用的不同频率的正余弦函数如下所示:

在公式中,pos代表了单词所在的位置,2i和2i+1代表位置编码向量中的对应维度,d则对应位置编码的总维度。

要注意,位置编码本身并不是为了告诉机器这些单词的前后顺序,它只是作为一个位置标识,被同时传入到模型中,使得训练时同时能够被机器学习到,所以不必纠结机器是如何从位置编码中得到先后顺序,因为其根本与位置的先后顺序无关

下面有两个问题需要进行解答:

为什么将原有的词向量和位置编码向量简单相加就能传递位置信息而几乎不改变原有词向量所保有的信息呢?这是因为通过这个函数得出的位置编码向量在与原有的词向量相加时,其只会在高维空间对原向量进行平移,而不会过多影响词向量的方向特征。方向特征受到的影响很小,也就代表词向量所表示的词语信息没有造成太大的改变。

那么为什么正余弦函数能够得到不影响词向量基本方向的位置编码向量呢?首先,正余弦函数的范围是在[-1, +1]的范围内,这个范围相对很小,这使得导出的位置编码与原来的词嵌入相加不会使得结果偏离过远而破坏单词原有的语义信息。其次,根据三角函数的基本性质(恒等变换),可以得知pos+k个位置的编码可以从第pos个位置通过线性组合来表示,这就意味着位置编码中蕴含着单词之间的距离信息。

注意力层

自注意力(Self-Attention)机制,又称为内部注意力机制,顾名思义,是一种将单个序列的不同位置关联起来,以计算同一序列的表示的注意机制。通俗些来讲,Self-Attention只关注输入本身or只关注目标对象本身;Attention机制与自身还有关注对象都有关系

举一个简单例子,我们来看下面一个句子。假设我们尝试将它作为输入,并准备翻译这句话。
The animal didn't cross the street because it was too tired

这句话中的单词”it”指的是什么呢?它是指“street”还是“animal”呢?对于我们人来说,这个问题非常简单。但对一个算法来说,这并不简单。

此时,自注意力机制就发挥了很大的作用。当模型正在处理单词“it”的时候,自注意力机制允许单词“it”结合单词“animal”一起处理。也就是说,在注意力及之中,模型可以结合上下文的单词来处理当前单词。从其它单词中找寻“线索”,可以帮助模型更好的编码当前单词。引入Self Attention后会更容易捕获句子中长距离的相互依赖的特征

在自注意力机制的计算过程中我们会用到以下公式:

在自注意力机制的公式中,K、Q、V分别代表Key(键)、Query(查询)和Value(值)。为了用简单易懂的语言解释它们的作用,我们可以使用一个类比来理解:

想象你有一个图书馆,里面有很多书籍(可以看作是输入序列中的各个元素),每本书都有自己的标题(Key)、内容摘要(Value)以及一些关键词(Query)用于检索。

  • Key (K):就像是书的标题或索引标签。它提供了关于这本书的一些基本信息,使得当你想要找到与某个特定主题相关的书籍时,可以通过这些标题或标签快速定位。
  • Query (Q):可以类比为读者用来搜索的关键词。当你带着一个问题或者一个主题进入图书馆,并希望找到相关的书籍时,你会用到这个关键词去匹配书架上的标题。
  • Value (V):相当于书的内容摘要或者是整本书的价值所在。一旦你通过Query和Key找到了感兴趣的书,你真正想要获取的信息就是Value——即这本书对你问题的答案或价值。

在自注意力机制的实际操作中,对于输入序列中的每一个元素,我们都会计算出一组对应的Key、Query和Value向量。接下来,我们需要计算Query与所有Keys之间的相似度,通常使用点积后接softmax函数得到权重,这给出了当前元素对其他元素的关注程度。接着,我们将这些权重应用于Values上,以获得加权后的输出,该输出就反映当前元素基于整个序列上下文的信息。

那么K(Key)、Q(Query)和V(Value) 这些值是从哪里来的呢?这些向量是通过将输入序列中的每个元素分别乘以三个不同的权重矩阵得到的。这三个用于控制和调整K(Key)、Q(Query)和V(Value) 的值的权重矩阵就是通过机器学习的过程动态调整的,它们不是预先设定好的,而是通过大量的数据和反复的训练逐步学习得到的最佳参数组合。

现在公式中还有一个不明确的值:d,这个值是作为一个缩放因子。当我们计算两个向量的点积时,结果可能会变得非常大,特别是在高维空间中。为了使得Softmax函数的结果更加平滑,保持在一个合理的梯度范围内,我们需要使用该缩放因子去控制Q和K的点积。d 通常取键(Key) 向量的维度,即 K 的维度。

Softmax 函数是一种常用的激活函数,它将一组任意实数映射到一个概率分布上,使得输出的每个元素都在 (0,1) 范围内,并且所有元素之和为 1。经过softmax函数处理后的得分变成了一系列介于 0 和 1 之间的数值,它们表示了对于某个特定查询而言,各个键的重要性。由于softmax函数的性质,这些权重加起来总是等于 1,形成了一个有效的概率分布。也就是我们常说的“归一化”。

最后,让我们来关注一下这个公式本身的意义。
在公式中,我们注意到,抛去其他对数据的特殊处理,公式的核心即是Q点积K的转置之后再去点积V。我们先抛开Q、K、V三个矩阵不谈,self-attention最原始的形态其实长这样:

\large Softmax(XX^T)X

那么这个公式到底什么意思呢?

首先,让我们考虑一个矩阵乘以它的转置的意义,矩阵可以看作由一些向量组成,一个矩阵乘以它自己转置的运算,其实可以看成这些向量分别与其他向量计算内积。向量内积的几何意义:表征两个向量的夹角,表征一个向量在另一个向量上的投影。结合词向量的embedding,我们不难推断出,投影值越大,意味两个向量相关度高。如果两个向量夹角是90°,那么这两个向量线性无关,代表两个单词之间完全没有相关性。 也就是说,这个投影值就代表了两个单词之间的相关性高低,即,关注a词的时候,是否需要给予b词更高的注意。

到这里还没全部结束,经过归一化处理后,最后进行的一次点积有什么意义呢?在计算所得到的新的向量中,每一个维度的数值都是由词向量在这一维度的数值加权求和得来的,这个新的行向量就是该词向量经过注意力机制加权求和之后的表示。 也就是说,我们根据一系列的计算推导终于得出了元素X和该序列中的每一个元素的相关性。

其实我们所提到的Q、K、V矩阵、查询向量之类的字眼,其来源都是当前序列中的元素X与该矩阵的乘积,本质上都是X的线性变换。那么为什么不直接使用X而要对其进行线性变换呢?当然是为了提升模型的拟合能力,权重矩阵W都是可以训练的,起到一个缓冲的效果。到这里,我们已经能够理解这个自注意力机制的最核心的计算公式。

前馈层

在Transformer模型中,前馈层是每个编码器和解码器块中的一个关键组件。它接受自注意力子层的输出作为输入,并通过一个带有ReLU激活函数的两层全连接网络对输入进行非线性变换

也就是说,经过上一层的处理之后,会产生一个矩阵,其中每一行代表序列中的一个位置,每一列代表该位置的特征向量。前馈层从注意力层得到这个矩阵,并继续进行下一步的处理,这其中会经过两层全连接网络和名为ReLU的激活函数的处理。

以上是在前馈层需要使用到的一个重要公式,其中x代表序列中的元素,w代表权重矩阵,b代表偏置项。让我们先暂时熟悉这个公式,一步一步分析它的具体作用。在Transformer 模型的前馈层中,需要经过以下几步的处理:

  1. 第一层全连接网络:接受自注意力子层的输出,并将其映射到一个更大的中间维度中,目的是增加模型的表达能力,通过映射到更高的维度,模型能够学习更复杂的特征表示。(对应公式中第一次使用脚标为1的参数进行计算)
  2. 通过ReLU 激活函数进行处理。
  3. 第二层全连接网络:接受经过ReLU激活后的隐状态 h,其维度为与第一层的输出相同。第二层需要将高维特征重新映射回原始维度,以便与自注意力子层的输出进行残差连接和层归一化。(对应公式中第二次使用脚标为2的参数进行处理)

不难得知,以上三步就是公式中所做的所有事情。让我们逐步看看它们具体做了哪些处理,有什么具体的作用,以及为什么要这么做。

全连接网络(Fully Connected Network, FCN):是神经网络中的一种基本结构,其中每一层的每个神经元都与前一层的所有神经元相连。这种结构使得每个神经元都能接收前一层所有神经元的输出,并通过权重矩阵和偏置项进行线性变换,然后通常会应用一个激活函数来引入非线性。

全连接网络具有输入、隐藏、输出等层次,其中输入输出顾名思义,是接收原始数据作为输入和生成该层最终预测和分类结果的层次,而隐藏层可以有多个,每个隐藏层的输出通常是经过激活函数处理后的结果。这里的隐藏层即起到了增大前馈子层隐状态的维度和将维度调整回原样的作用。

ReLU 激活函数 :这个函数的数学形式非常简单:

也就是将所有负值处理为0,使得数据中不出现负数即可。那么我们为什么要在这里使用这个激活函数来进行处理呢?

首先,ReLU激活函数通过将所有负值设为0,保留正值不变,从而引入了非线性。这种简单的操作之所以能够引入非线性,是因为它打破了输入和输出之间的线性关系。在这个函数的x<0段求导不难发现其斜率为0,因此该函数是一个分段线性的函数,也正是因为分段线性,使得整个函数变为了非线性函数。非线性的模型学习能力更强,这是因为实际问题中的很多数据是线性不可分的,即无法通过一条直线或超平面将不同类别的数据分开,非线性激活函数使得神经网络能够学习到更复杂的决策边界,从而更好地处理这些复杂的数据分布。非线性激活函数还可以帮助模型更好地拟合训练数据,并且在未见过的数据上也能表现良好。这是因为非线性模型能够学习到数据中的细微结构和模式,而不仅仅是简单的线性关系。因此,也能提高泛化能力

此外,ReLU在正区间内的导数是1,避免了梯度消失问题,使得深层网络能够有效训练。这也使得梯度下降过程更加稳定和高效。相比于其他激活函数,ReLU通常能更快地收敛到最优解。从生物学角度来看,ReLU的行为类似于大脑中神经元的激活方式。神经元只有在接收到足够的刺激时才会激活,否则保持静默。这种行为与ReLU的特性相似。

再回头来看公式,这其中的权重矩阵W和偏置项b是机器在时需要学习并得到的参数,即为我们训练出的一部分内容。顺带提一句这里的偏置项b,是为了使我们训练的模型更为灵活,它能使得我们训练的函数获得平移的能力,而不必每次都经过坐标系的原点,使得模型能够学习更复杂的函数和模式。通过调整偏置项,模型可以更好地适应训练数据中的各种特征。

残差连接与层归一化

由 Transformer 结构组成的网络结构通常都是非常庞大的。编码器和解码器均由很多层基本的Transformer 块组成,每一层当中都包含复杂的非线性映射,这就导致模型的训练比较困难。因此,
研究者们在 Transformer 块中进一步引入了残差连接层归一化技术以进一步提升训练的稳定性。

残差连接主要是指使用一条直连通道直接将对应子层的输入连接到输出上去,从而避免由于网络过深在优化过程中潜在的梯度消失问题。说的更加直白一些,就是将上一个层级的原始数据不做任何处理,直接与本层经过处理的结果相加,得到残差连接的结果。

不难看出这个公式代表的就是获取到第l层的输出后,将经过处理和未处理的结果相加输出给l+1层。

为什么残差连接能够使得训练的稳定性提升呢?我们知道,在一定程度上,网络越深表达能力越强,性能越好。不过,随着网络深度的增加,也带来了诸如梯度消失和梯度爆炸的问题。残差连接通过提供一条直接路径,使得梯度可以直接传递到较早的层,从而缓解这些问题。这意味着即使上一层没有学到任何有用的信息,模型仍然可以通过残差连接传递​之前传来的信息。在一定程度上,引入残差后的映射对输出的变化更敏感,而我们模型的输出是什么?正是反应了与真值的误差。

层归一化是一种归一化技术,它对每个样本的特征进行归一化,而不是对整个批次的数据进行归一化。层归一化通过对每一层的激活值进行归一化,使得每一层的输出具有零均值和单位方差,从而稳定训练过程。

在Transformer模型中,这两者的结合使用,使得模型能够在处理长序列和复杂任务时更加稳定和高效。

Breeze Wang

  • Bachelor of Software Engineering, School of Computer Science, Central South University.
  • Certified System Architect with the Qualification Certificate of Computer and Software Technology Proficiency.
  • Developer in the domain of vertical applications for Large Language Models. Experience in optimizing PROMPT for large language models
  • Backend Java Software Development Engineer.