Transformer详解

本文详细介绍了transformer的整体架构以及各个组件。

transformers的总体架构

下面让我们从简单到复杂来深入了解一下transformers的总体架构

黑盒结构

img

以机器翻译为例,每当我们输入一段文本,则会输出一段文本,而transformer就是这一过程的黑盒。

编码器解码器结构

img

而当我们把中间的黑盒在稍微展开一下,就可以看到一个编码器和解码器。可以理解为机器在处理一段文本的时候,是先将初始文本编码成一个更利于机器处理的编码,然后再经过解码器将处理后的编码解码为我们想要得到的结果。

下面我们将编码器和解码器结构再次展开来看。

img

可以发现在整个黑盒中有着多个Encoder和Decoder,所以在整个编码的过程中,是有多个编码器逐层递进的进行编码工作的,好比我们在理解一段文字时也要经历多个过程——从看到到想,而解码过程也是同理。

在了解了编码器和解码器在黑盒中的作用后,让我们来看一看编码器和解码器的内部结构。
img

可以看到编码器在工作过程中,会先经过一个自注意力层(稍后会讲),然后,在经过一个前馈层(全连接层);而解码器和编码器的结构大体相同,唯一不同的点就是,在自注意力层和前馈层的中间还需先经过一个Encoder Decoder Attention层,至于这个层的作用,我们先按住不表,稍后再谈。

计算注意力

在了解了transformers的总体框架后,让我们讨论一下transformer的核心——计算注意力。

计算QKV向量

在计算注意力前我们首先得生成Q(查询)、K(键)和V(值),这是计算注意力的关键。让我们看看计算的具体过程。

在深度学习,特别是自然语言处理(NLP)领域中,Q(查询)、K(键)和V(值)是注意力机制中的三个核心概念。它们首次在Transformer模型中被广泛使用,现在已经是许多高级NLP模型的基础,如BERT、GPT等。
以下是Q、K、V的简单解释:

  1. Q(Query)- 查询
  • 在注意力机制中,"查询"表示当前要处理的词(或序列位置)所发出的信息需求。它用来与所有其他词(或序列位置)的键进行匹配,以确定每个词对当前词的重要性。
  1. K(Key)- 键
  • "键"表示每个词(或序列位置)所携带的信息。在注意力机制中,每个键用来与查询进行匹配,以生成注意力权重,这些权重表示对应值对于当前查询的重要性。
  1. V(Value)- 值
  • "值"代表每个词(或序列位置)的实际信息内容。在确定了查询与键的匹配程度后,这些值会按照相应的注意力权重进行加权求和,以生成最终的注意力输出,这个输出将用于进一步的处理。
    简而言之,注意力机制的工作流程大致如下:
  • 查询(Q)发出信息需求。
  • 查询与所有的键(K)进行比较,确定它们的相关性(通过计算匹配度,通常是点积)。
  • 根据这些相关性分配权重。
  • 将权重应用于相应的值(V),通过加权求和得到最终的结果。
    这个过程使得模型能够在处理序列数据时,更加关注与当前任务相关的部分,从而提高了模型的性能和效率。

img

我们先观察我们的input,可以看到我们的input是两个单词a和b,然后我们再将a和b进行一个Embedding操作。

Embedding操作是一种将离散数据(如单词、类别标签或其他实体)转换为连续向量(通常是在低维空间中的向量)的过程。这个过程是许多机器学习模型,尤其是深度学习模型中的一个关键步骤。以下是embedding操作的简单解释:

基本概念:

  1. 离散数据:指的是类别或标签数据,比如单词、物品分类、用户ID等,这些数据通常是整数或字符串形式。
  2. 连续向量:指的是实数向量,它们在数学上可以用于计算和比较,例如在多维空间中的距离或角度。

Embedding的目的:

  • 降维:将高维的稀疏数据转换为低维的密集向量,便于计算和处理。
  • 表示学习:学习数据的内在表示,使得相似的数据在嵌入空间中彼此接近。
  • 传递信息:为机器学习模型提供一种方式,将原始数据中的有意义的信息传递到模型中。

Embedding操作的过程:

  1. 初始化:通常,embedding操作开始于一个随机初始化的矩阵,这个矩阵的每一行代表一个离散项的初始向量表示。
  2. 学习:在模型的训练过程中,这些向量通过反向传播算法不断更新,以最小化预测误差。
  3. 查找:在实际应用中,给定一个离散项(如一个单词),embedding操作会查找预先训练好的矩阵中对应的行,得到该项的向量表示。

示例:

  • 单词嵌入:在自然语言处理(NLP)中,每个单词都可以被嵌入为一个固定长度的向量。例如,单词“猫”可能被嵌入为一个100维的向量。
  • 用户嵌入:在推荐系统中,每个用户都可以被表示为一个向量,这个向量捕捉了用户的兴趣和偏好。

结论:

Embedding操作是深度学习中的一个重要工具,它使得模型能够处理和理解离散数据,并且在多种应用中取得了显著的成功。通过学习有效的数据表示,embedding提高了模型的性能并扩展了它们的应用范围。

通过这个操作将a和b转化为两个词向量x1和x2。然后我们将这两个向量分别与\(W_Q, W_K, W_V\)相乘,就可以分别得到两个词对应的Q,K,V。

在Transformer模型中,\(W_Q, W_K, W_V\) 是可学习的权重矩阵,它们用于将输入词向量转换为注意力机制中的查询(Q)、键(K)和值(V)。
以下是对这些权重矩阵的详细解释:

  1. \(W_Q\) (Query Weight Matrix)
    • \(W_Q\) 是一个矩阵,其作用是将词向量转换为查询向量。在注意力机制中,查询向量用于确定在当前上下文中哪些信息是重要的。
    • 当一个词向量 \(x_1\)(对应于词a)与 \(W_Q\) 相乘时,得到的结果是 \(Q_1\),即词a的查询向量。
  2. \(W_K\) (Key Weight Matrix)
    • \(W_K\) 同样是一个矩阵,它将词向量转换为键向量。键向量用于与其他查询向量进行比较,以计算注意力权重。
    • 词向量 \(x_2\)(对应于词b)与 \(W_K\) 相乘后,得到 \(K_2\),即词b的键向量。
  3. \(W_V\) (Value Weight Matrix)
    • \(W_V\) 是第三个矩阵,它将词向量转换为值向量。值向量包含了实际的信息内容,这些内容将根据计算出的注意力权重进行加权求和。
    • 将词向量 \(x_2\)\(W_V\) 相乘,得到 \(V_2\),即词b的值向量。
      具体操作如下:
  • 给定两个词向量 \(x_1\)\(x_2\),它们分别对应于词a和词b。
  • \(Q_1 = x_1 \times W_Q\)
  • \(K_2 = x_2 \times W_K\)
  • \(V_2 = x_2 \times W_V\)
    这里的“\(\times\)”表示矩阵乘法。通过这种方式,原始的词向量被转换成注意力机制所需的查询、键和值向量。这些向量随后用于计算注意力得分和输出加权求和的结果,这是Transformer模型中多头注意力机制的核心部分。

自主注意力计算流程

接下来,让我们了解一下自注意力的计算流程

img

在上面的图片中,我们有两个词Thinking和Machines,我们先经过Embedding操作将它们转化为两个词向量。然后分别乘以三个学习矩阵,将它们转化为对应的Q,K,V。

然后,我们就要开始计算自注意力了,我们先来计算Thinking的自注意力,首先,我们要分别计算这两个词的Score。

在Transformer模型的自注意力机制中,"Score" 是用来衡量一个序列中各个词对当前词的重要性的一个数值。这个分数决定了在计算最终的注意力输出时,每个词应该被赋予多大的权重。
以下是关于自注意力中的Score的详细解释:

Score的计算:

  1. 点积(Dot Product)
    • Score通常通过当前词的查询向量(Q)与所有词的键向量(K)之间的点积来计算。对于序列中的每个词,都会计算一个Score。
    • 具体来说,假设我们正在计算词 "Thinking" 的自注意力,我们需要计算 "Thinking" 的查询向量 \(Q_{Thinking}\) 与序列中所有词(包括 "Thinking" 自身)的键向量 \(K\) 的点积。
  2. Score公式
    • 对于词 "Thinking",其Score计算公式为:

\[ Score_{Thinking, i} = Q_{Thinking} \cdot K_i \]

  • 其中,\(Q_{Thinking}\) 是 "Thinking" 的查询向量,\(K_i\) 是序列中第 \(i\) 个词的键向量。

Score的含义:

  • 相关性度量

    • Score代表了查询词与其他词的相关性或匹配程度。一个高的Score意味着对应的词在当前上下文中对查询词来说非常重要。
  • 注意力权重的基础

    • 这些Score随后会通过softmax函数转换为概率分布,称为注意力权重。这些权重决定了在计算注意力输出时,每个值向量(V)应该被赋予多大的影响。

利用下面的公式计算score

\[Score_{Thinking, Thinking} = Q_{Thinking} \cdot K_{Thinking} \]

然后,我们将这个Score除以8(\(\sqrt{d}\)),至于为什么要除以8,后面再讲。

接下来我们将结果经过一个softmax函数,将其转化为正态分布的数值。

然后再将这个数值分别乘以我们上面得到的Value(值),最后将两个词对应的结果分别相加,得到的就是Thinking的自注意力值,同理也可以得到Machines的自注意力值。

上面的自注意力的过程是在向量的层面上,当我们有多个词向量时就需要用到矩阵运算了,下面是自注意力计算的矩阵形式。

img

单头注意力和多头注意力

我们上面讨论的就是所谓的单头注意力,它只有一组Q、K、V,而多头注意力就是有多组Q、K、V。

img

由上面的讨论我们知道,Q、K、V是由三个学习矩阵与词向量相乘得来的,也就是说如果我们由这样多组的学习矩阵,我们就可以得到多组的Q、K、V。然后对这多组Q、K、V进行注意力计算(缩放点积注意力),将得到的结果进行一个concat操作,这就是多头注意力。

Concat操作的作用:

  1. 融合不同注意力头的信息
    • 每个注意力头通过不同的权重矩阵计算出不同的Q、K、V,并分别进行注意力计算。这些注意力头可能会捕获输入序列的不同特征或关系。
    • 通过concat操作,可以将这些不同头捕获的信息合并起来,形成一个更丰富、多维度的表示。
  2. 增加模型的表达能力
    • 多头注意力允许模型在不同的子空间中学习信息,concat操作将这些子空间的信息结合起来,增加了模型的表达能力和对复杂关系的建模能力。
  3. 保持维度一致
    • 在进行concat操作之前,每个注意力头输出的向量维度是相同的。concat操作将这些向量堆叠起来,形成一个更宽的向量,但其维度仍然是固定的,这保证了模型后续层的输入维度一致性。

下面让我们看一下多头注意力的完整计算过程。

img

从上面的这张图,我们可以看到这里由8组学习矩阵,也就是有8个头。因此,我们也可以得到8组的Q、K、V向量,相对应的我们最后也可以得到8组自注意力层的结果,最后我们将这些注意力组合在一起再乘以一个线性运算层\(W^0\)得到最终的\(Z\)

词向量编码

transformer和Rnn的区别

img

以上面的两句话为例。

左边的两句话,组成的字完全相同但所表达的意思却刚好相反;而右边的两句话,虽然顺序改变了,但语义表达没有任何改变,这就体现了,字的位置对于语句意义的影响。

而Transformer不同于Rnn的地方也是如此,在处理数据时不考虑数据的位置信息,所以需要在数据中加入位置信息,以让处于不同位置的相同数据有所不同,相互区分。

普通编码+位置编码=最终编码

img

因此,编码的过程如上图所示。

位置编码矩阵元素计算公式

在Transformer模型中,位置编码(Positional Encoding)是用来注入序列中词的位置信息的,因为Transformer本身并不具有处理序列顺序的能力。位置编码通常是通过正弦和余弦函数来计算的,其元素的计算公式如下:
给定一个位置 \(pos\) 和维度 \(i\),位置编码 \(P_{pos, 2i}\)\(P_{pos, 2i+1}\) 的计算公式分别是:

\[P_{pos, 2i} = \sin\left(\frac{pos}{10000^{2i/d}}\right) \]

\[P_{pos, 2i+1} = \cos\left(\frac{pos}{10000^{2i/d}}\right) \]

其中:

  • \(pos\) 是词在序列中的位置(从0开始)。
  • \(i\) 是编码向量的维度索引。
  • \(d\) 是编码的总维度。

这些公式表明,位置编码在偶数位置使用正弦函数,在奇数位置使用余弦函数。并且随着维度的增加,正弦和余弦函数的波长会按照几何级数增长。
以下是计算位置编码的一个简单示例:

假设我们的模型维度 \(d\) 是512,我们想要计算位置 \(pos=1\) 的位置编码向量:

  • 对于 \(i=0\)(第一个维度):

\[P_{1, 0} = \sin\left(\frac{1}{10000^{0/512}}\right) = \sin(1) \]

\[P_{1, 1} = \cos\left(\frac{1}{10000^{0/512}}\right) = \cos(1) \]

  • 对于 \(i=1\)(第二个维度):

\[P_{1, 2} = \sin\left(\frac{1}{10000^{2/512}}\right) = \sin\left(\frac{1}{10000^{1/256}}\right) \]

\[P_{1, 3} = \cos\left(\frac{1}{10000^{2/512}}\right) = \cos\left(\frac{1}{10000^{1/256}}\right) \]

  • 以此类推,直到 \(i=255\)(第512维的一半),计算所有的正弦和余弦值。

最后,将计算出的正弦和余弦值组合起来,就形成了位置 \(pos=1\) 的位置编码向量。这个向量将会与对应的词向量相加,以提供序列中词的位置信息。

根据上面的公式我们可以把PE的矩阵计算出来,如下图:

img

可以发现随着编码的进行位置编码的波动再逐渐减小。位置编码中的波动逐渐减小是因为随着维度的增加,指数增长函数的递减效应使得输入到正弦和余弦函数的角度增长速度减慢,从而导致波动的减小。这种设计有助于模型在处理序列数据时,既能捕捉到局部位置信息,也能捕捉到长距离的位置关系。

Mask

再了解了词向量编码后,我们再来了解一下transformer的另一个关键步骤掩码(mask)

PAD MASK

首先我们先了解一下PAD MASK。

在自然语言处理(NLP)任务中,尤其是在使用基于序列的模型(如RNN、LSTM或Transformer)时,PAD MASK是一种用于处理序列长度不一致问题的技术。

简单介绍:

PAD MASK 是一个与输入序列等长的二进制掩码(binary mask),它用于指示序列中的填充(PAD)位置。在处理批量数据时,由于每个序列的长度可能不同,通常需要将较短的序列通过填充(PAD)操作扩展到与批次中最长序列相同的长度。
以下是PAD MASK的几个关键点:

  1. 填充(Padding)
    • 为了使一个批次中的所有序列长度一致,较短的序列通常会在末尾添加特殊的填充字符(如"")。
  2. 掩码(Mask)
    • PAD MASK是一个与序列等长的向量,其中填充位置标记为1(或True),非填充位置标记为0(或False)。
  3. 用途
    • 在模型计算中,PAD MASK用于确保填充位置不被计算在内,防止它们影响模型的学习和输出。
    • 在注意力机制中,PAD MASK可以用来屏蔽填充位置的注意力权重,确保模型只关注实际的数据。

举个简单的例子:

假设我们有以下三个单词序列,需要将它们填充到相同长度:

序列1: ["我", "是"]
序列2: ["你", "是", "谁"]
序列3: ["他", "们", "是", "学生"]

填充后,我们得到:

序列1: ["我", "是", "<PAD>", "<PAD>"]
序列2: ["你", "是", "谁", "<PAD>"]
序列3: ["他", "们", "是", "学生"]

对应的PAD MASK将是:

序列1: [0, 0, 1, 1]
序列2: [0, 0, 0, 1]
序列3: [0, 0, 0, 0]

在这个例子中,"1" 表示该位置是填充位置,"0" 表示该位置是实际的数据。
通过使用PAD MASK,模型可以在训练和推理过程中正确地处理序列数据,忽略填充部分,从而提高模型性能和结果的准确性。

Pad Mask的特点是不参与注意力的计算,如下图:

img

注意:当pad和pad进行相乘时,不做处理。

上三角MASK

上三角MASK(Upper Triangular Mask)是Transformer模型中用于处理自注意力机制的一种特殊类型的掩码(mask)。它的主要目的是在处理序列数据时,确保模型在计算当前位置的注意力时只能看到当前位置之前的词语,而不能看到当前位置之后的词语。这在处理序列数据时特别有用,例如在语言模型中,它可以帮助模型维持因果顺序,即在预测序列中的下一个词时,模型不能“看到”未来的词。

以下是上三角MASK的几个关键点:

  1. 矩阵形式
    • 上三角MASK是一个方形矩阵,其大小与输入序列的长度相同。在这个矩阵中,所有位于主对角线以上的元素(即上三角区域)都被设置为某个特定的值(通常是负无穷大或一个非常大的负数),而主对角线及其以下的元素则被设置为0(或False)。
  2. 作用
    • 在自注意力计算中,上三角MASK用于屏蔽当前位置之后的所有词语,使得在计算当前位置的注意力得分时,只有当前位置之前的词语会被考虑。
    • 这对于保持序列的因果性至关重要,尤其是在语言建模和机器翻译等任务中。
  3. 应用
    • 在计算注意力得分后,将上三角MASK与得分矩阵相加(或通过其他方式结合),以确保后续的softmax操作不会为被屏蔽的位置分配非零的注意力权重。

举个例子:

假设我们有一个长度为4的序列,其上三角MASK如下所示:

0  -inf  -inf  -inf
0   0    -inf  -inf
0   0     0    -inf
0   0     0     0

在这个矩阵中,"-inf" 表示负无穷大,"0" 表示当前位置或之前的词语可以被看到。当这个掩码应用于注意力得分矩阵时,它会确保在计算第一个位置的注意力时,只能看到第一个词;在计算第二个位置的注意力时,只能看到第一个和第二个词,以此类推。
通过使用上三角MASK,Transformer模型能够在处理序列数据时保持因果顺序,这对于许多序列生成任务来说是非常重要的。

与Pad Mask类似上三角Mask不参与对未来词的注意力计算。

img

整合两种MASK

img

有上面的讨论可知,我们最终只需要将两种mask取并集即可,如上图。

计算流程

接下来,让我们来了解一下transformers的具体计算流程。

首先,让我们来看一下下面的Encoder。

img

我们将上图的两个词通过词向量编码转换为x1和x2,接着与位置编码(PE)矩阵相乘,为x1和x2添加位置信息。随后,我们通过一个自注意力层得到z1和z2。接着,将z与原始的x通过跳跃连接(Shortcuts)相加,并进行层归一化(Layer Normalization),即对数据进行标准化处理。这样,我们得到了经过处理的z1和z2。这两个向量随后分别被送入两个前馈网络(Feedforward Networks),最后将两个前馈网络的输出结果相加并再次进行标准化处理。
以下是对专有名词的解释:

  • 词向量编码:将词汇映射为固定长度的实数向量,这些向量能够捕捉词汇的语义信息。
  • 位置编码(PE)矩阵:一个矩阵,用于给词汇向量添加位置信息,以保留序列中词汇的顺序。
  • 自注意力层:一种注意力机制,它能够根据序列中词与词之间的关系为每个词分配不同的权重。
  • 跳跃连接(Shortcuts):一种网络连接方式,允许信息直接从网络的一层传递到另一层,有助于缓解梯度消失问题,提高训练效率。
  • 层归一化(Layer Normalization):一种数据标准化技术,用于对网络层内的数据进行归一化处理,有助于加速网络训练。
  • 前馈层:神经网络中的一层,其中每个神经元都与前一层中的所有神经元相连接,但没有循环连接或层间连接。

我们将计算流程再放大:

img

可以看到,词经过多个Encoder后传输到Decoder中进行解码。而Decoder只是比Encoder多了一个Encoder-Decoder Attention层。其实这一层和self-Attention层是完全一样的,唯一的区别是这一层将Encoder计算完了的结果当作K和V,把Decoder前面的计算结果当作Q。

再经过多个Decoder后,最后再进行一个Linear层的全连接输出,并对结果进行softmax操作。

下面我们来看一下Decoder的生成过程:

img

这里就不过多解释了(累了)

transformer整体架构

img

实验数据生成策略

我们知道transform是用于文本翻译的,那么我们先生成一些文本。

img

这里我们先使用x语言生成方式。

x它有一个词表,包含了这种语言的所有词汇。以上图为例,这种语言只有7个词,我们对这种语言进行随机采样,但不同词的采样概率不同。采样长度也是随机的。

接下来看一下y的生成方式。

img

img

这个图表示,y可以由x进行表示。这里的规则为对x进行逆序并字母大写,数字用10减去本身,y的第一个词取决于最后一位的x。

然后添加前后标志位,补pad到固定长度:

img

数据样例

img

posted @ 2024-08-08 00:44  codersgl  阅读(6)  评论(0编辑  收藏  举报