导航菜单
首页 >  超详细原理篇实战篇一文读懂Transformer  > Transformer 的原理和应用

Transformer 的原理和应用

Tranformer 原理及应用

Transformer由论文《Attention is All YouNeed》提出,这之后这句话也是一直贯穿深度学习的研究当中。简单来说,Transformer的作用就是将一个序列转换为另一个序列,例如说中英文翻译。

下图是 Transformer 用于中英文翻译的整体结构:

example1

在开始之前,我们需要首先知道的是transformer设计之初的目标就是用来做seq2seq任务,也就是序列转换任务。比如说定一个中文序列,它能够将其转换为一个英文序列。当然,transformer可以不止用来做翻译任务,任何可以用来转换成的seq2seq的任务都可以用transformer来完成,这也是tokenlearning的关键。

从one-hot 编码开始

假设现在我们已经有了一串待转换的序列,那么我们任务的第一步就是如何将其转换为数学可计算的,也就是将字符表示转换为数字表示。这样做的理由也很简单,因为计算机只能处理数字而不是我们人类所使用的抽象字符集。

一种简单的做法是选择一个词汇表\(A\),即我们在每个序列中使用的符号集合。在一般的例子中,这将有两组不同的符号,一组用于输入序列,一组用于输出序列。

将单词转换为数字的一种方法是从 1开始计数,为每个单词分配自己的编号。然后,单词序列可以表示为数字的列表。

例如,考虑一种词汇量大小为4的小型语言:I、apple 和 like、banana。每个单词都可以替换为一个数字,也许 I = 1、like = 2 和apple = 3、banana = 4。 然后,由单词序列 [ I, apple , like ,banana ] 组成的句子“I like apple ”可以表示为数字序列 [1,2,3]。

尽管这样的表示方式确实可以将序列转换为数字,但是仍然不够直白,更简单的方式是one-hot编码。在one-hot编码中,符号由一组大部分为零的向量表示,向量的长度与词汇表的长度相同,每个这样的向量都中只有一个元素的值为1。也就是one-hot编码的向量中的每一位都代表着一个具体的单词,也就是看到一个向量,它的哪一位是1代表着它是哪一个单词。

例如在上述的例子中,one-hot编码就可以表示为:

然后,“I like apple”就可以表示为一个矩阵:

example3

但实际上,one-hot编码真正有用的一点是它的dotproduct(点积,也叫标量积)操作,向量的点积即将其相应元素相乘,然后将结果相加。

独热码点积的特性:

独热码与自己的点积结果为1,与其他独热码的点积结果为0独热码与任一同维向量相乘,结果为该向量中独热码为1的位置的元素。

例如:

\[\vec{a} = \begin{bmatrix} 0 \\ 1 \\ 0 \\0 \end{bmatrix}\vec{w} =\begin{bmatrix} 0.3 \\ 0.2 \\ 0.4 \\0.1 \end{bmatrix}\]

\[\vec{a} \cdot \vec{w} = (0 * 0.3) + (1 * 0.2) + (0 * 0.4) + (0 * 0.1) =0.2\]

独热码与矩阵

点积是矩阵乘法的基础,我们将第一个矩阵称为 A,将第二个矩阵称为B。在最简单的情况下,当 A 只有一行且 B只有一列时,矩阵乘法的结果是两者的点积。矩阵乘法需要满足基本要求,即维度相匹配。

当其中一个矩阵是由独热码构成时,其结果就是取出另外一个矩阵对应位置的行向量例如:

\[\begin{bmatrix} 0 & 1 & 0 & 0\\ 0 & 0 & 0 & 1\end{bmatrix} \begin{bmatrix} 0.2 \\ 0.8 \\ 0.9 \\ 0.5\end{bmatrix} =\begin{bmatrix} 0.8 \\ 0.5\end{bmatrix}\]

查找表

根据上述性质,我们就能利用独热码的矩阵乘来构建查找表。

A 矩阵由一堆 one-hot向量组成。它们分别位于第一列、第四列和第三列。当我们进行矩阵乘法时,这将按顺序取出B 矩阵的第一行、第四行和第三行。这种使用 one-hot向量提取矩阵的特定行的技巧是 Transformer 工作原理的核心。

一阶序列转换模型

现在先把矩阵放在一边,回到我们真正关心的东西,即单词序列。想象一下,假设我们在使用电脑时常用的命令有如下三种单词序列:

Show me my directories please.Show me my files please.Show me my photos please.

词汇表:

{directories, files, me, my, photos, please, show}

我们的目的是使用转换模型,对于词汇表中的每个单词,它都会显示下一个单词可能是什么那么如果用户一半时间询问照片,30%时间询问文件,其余时间询问目录,则转换模型将如下所示。

转换模型示例图,图源https://www.zhihu.com/question/471328838/answer/3011638037

这种链式的转换模型称为马尔可夫链,因为它满足马尔可夫性质,即下一个单词的概率仅取决于最近的单词。更具体地说,上述的例子是一阶马尔可夫模型,它只查看单个最近的单词。如果它考虑两个最近的单词,那就是是二阶马尔可夫模型。

马尔可夫链可以方便地用矩阵形式表示。使用与创建 one-hot向量时相同的索引方案,每一行代表词汇表中的一个单词。每一列也是如此。每列中的值显示下一个单词出现的概率。因为矩阵中每个元素的值代表一个概率,所以它们都会落在0 到 1 之间。由于概率总和为 1,因此每行中的值总和为 1。

马尔可夫转移矩阵 图源https://www.zhihu.com/question/471328838/answer/3011638037

利用该矩阵,我们可以重新审视使用矩阵乘法与 one-hot向量来提取与任何给定单词相关的转移概率的技巧。

例如,如果我们只是想得到每个单词出现在 my之后的概率,我们可以创建一个代表单词 my 的 one-hot向量,并将其乘以我们的转换矩阵。这会拉出相关行的行,并向我们显示下一个单词的概率分布。

独热码的作用 图源https://www.zhihu.com/question/471328838/answer/3011638037

仅根据当前单词来预测下一个单词是很困难的。这就像在只给出第一个音符后预测一首曲子的其余部分。如果我们至少能得到两个单词来继续,我们预测的准确率就会好得多,因此我们还可以继续推广为二阶转换模型等等。

到这里,我们发现我们所做的事情其实给定序列的一部分,然后预测序列的其余部分。待会儿,我们会解释为什么需要做这个。

Second order sequencemodel with skips

二阶矩阵为每个单词组合提供单独的行。这意味着如果我们从词汇大小 N开始,那么转换矩阵就有 N^2行。也就是如果单词序列连续出现两个单词时,下一个单词的概率会是多少。

当我们只需回顾两个单词来决定下一个单词时,二阶模型效果很好。当我们必须进一步回顾时该怎么办?我们当然可以考虑三阶和更高阶模型。然而,由于词汇量很大,这需要非常大的计算量和存储空间来实现。八阶模型的简单实现将具有N^8行,这对于任何合理的词汇来说都是一个非常庞大的数字,对计算机来说也是如此。

马尔可夫链面对着这种情况就显得无能为力了,但我们仍然可以表示每对前面的单词和后面的单词之间的关系。也就是说,现在我们并不需要得到所有单词的两两配对,只需要其中一个单词是当前预测词的前一个词,另一个词就是在该词之前出现过的任何词。

举个例子来说,假设我们语料库中有两个句子:

I like apple because I come from the South.I like banana because I come from the North.

现在有一个单词序列

I like apple because I come from the

如何预测下一个单词出现的概率,我们就可以构建一个Second ordersequence model with skips 进行预测,也就是如图所示:

example7

现在,我们不再只查看一行,而是查看所有的行。每行不再代表序列在特定点的状态。相反,每一行代表可以描述特定点处的序列的许多特征之一。矩阵中的每个值不再代表概率,而是代表投票。投票将被汇总并比较以确定下一个单词的预测。也就是,当得到一个序列后,我们会对每个列向下相加求和,对于这个例子,我们计算得到South的值是4,而North的值是3,那么我们就有理由认为下一个词应该是South

另一方面,我们发现4和3的差距并不够明显,倘若数据中出现噪声,很容易就会将这样的差距给掩盖,所以我们会构造掩码来选择我们需要注意的特征,对于这个例子就是只注意apple和banana,忽视其他的值,那么计算得到的结果也就是0和1,差距提升了33%.

通过计算训练中每个单词对/下一个单词转换发生的频率,可以很容易地构建特征权重,但注意力掩码却不然。实际上,这也是Allyou need isattention的做法,Transformer的作用之一就是训练得到这些掩码从而只关注真正有用的特征。

嵌入向量

在我们一般的使用中,对于词汇量过大的词汇表,所产生的中间数据是极其庞大的,对于词汇量N 为 50,000 的情况,所有单词对和所有潜在的下一个单词之间的转换矩阵将具有50,000 列和 50,000 个平方(25 亿)行,总计超过 100 万亿个元素。

另一方面,为了得到稳健的语言模型,我们需要多次提供每个潜在序列的训练数据,而任何一个训练数据集都很难做到这点。

我们可以使用嵌入的方式来解决上述问题。

如上所述,在语言的独热码表示方式中,每个单词都对应一个向量元素。大小为N 的词汇表中,该向量是一个 N维空间。每个单词代表该空间中的一个点,沿着对应的轴移动至距原点一个单位。例如:

\[\vec{a} = \begin{bmatrix} 0 \\ 1 \\ 0 \\0 \end{bmatrix}\]

a表示一个单词,是一个四维向量。

在嵌入向量中,每个独热码向量都被转换到低维空间中。例如,如果将它们嵌入到二维空间中。那么,我们不再需要N 个数字来指定一个单词,而是只需要 2 个数字。这些是新空间中每个点的 (x,y) 坐标。

得到嵌入向量的方式很简单,对于a,只需要和一个2行4列的转换矩阵相乘即可.

\[\mathbf{B} \vec{a} = \begin{bmatrix} b_{11} & b_{12} & b_{13}& b_{14} \\ b_{21} & b_{22} & b_{23} & b_{24}\end{bmatrix} \begin{bmatrix} 0 \\ 1 \\ 0 \\0 \end{bmatrix} =\begin{bmatrix} b_{12} \\ b_{22} \end{bmatrix}\]

使用嵌入的模型可以学习嵌入空间中的模式。每个示例都能提供一点学习效果,并应用到整个单词邻域中。也就是说,一个好的嵌入模型应该将具有相似含义的词语映射到相近的空间。一般来说得到嵌入向量是需要经过训练的,而这样的嵌入模型有很多,主要又是分为两类:CBOW模型和Skipgram模型。

嵌入可以大大减少所需的参数数量。然而,嵌入空间的维数越少,原始词汇的信息就会被丢弃得越多。语言的丰富性仍然需要相当大的维度来体现所有可能的语义,以免它们相互混淆,也就是需要一个有足够维度将它们分散开来的嵌入模型。我们通过选择嵌入空间的大小,尽量用计算负荷来换取模型的准确性。

在Transformer中,嵌入的过程是在这里发生的,而一般的做法是直接用训练好了的嵌入向量。:

位置编码

在处理序列数据时,模型需要能够捕捉到序列中每个元素的位置信息,因为位置信息对于理解序列的含义和结构至关重要。普通的加一个位置信息,词量大时不利于计算,transformer里面用了一种位置编码方式,把位置信息作为词向量的一部分输入信息一起送入网络进行处理,而且获得了不错的效果。

式子如下:

其中:

\[w_i = \frac{1}{1000^{2k/d}}\]

序列中相互可以从几何上理解这种编码,单词在嵌入空间中的位置就像一个圆心。根据单词在词序中的位置,我们会对其进行扰动。在每个位置上,单词都会以不同的角度移动相同的距离,从而在单词序列中形成一个圆形图案。靠近的单词会受到相似的扰动,而相距较远的单词则会受到不同方向的扰动。

由于圆形是一个二维图形,要表示圆形摆动就需要修改嵌入空间的两个维度。如果嵌入空间包含两个以上的维度(几乎总是如此),那么圆周摆动会在所有其他维度对中重复,但角度频率不同,也就是说,每次旋转的次数不同。将所有这些不同频率的圆周摆动结合起来,就能很好地表示出单词在序列中的绝对位置。

2i 表示偶数的维度,2i+1 表示奇数维度 (即 2i≤d,2i+1≤d)。使用这种公式计算 PE(position encoding) 有以下的好处:

使 PE能够适应比训练集里面所有句子更长的句子,假设训练集里面最长的句子是有 20个单词,突然来了一个长度为 21 的句子,则使用公式计算的方法可以计算出第21 位的 Embedding。可以让模型容易地计算出相对位置,对于固定长度的间距 k,PE(pos+k)可以用 PE(pos) 计算得到。因为 Sin(A+B) = Sin(A)Cos(B) + Cos(A)Sin(B),Cos(A+B) = Cos(A)Cos(B) - Sin(A)Sin(B)。

将单词的词 Embedding 和位置 Embedding 相加,就可以得到单词的表示向量x,x 就是 Transformer 的输入。

更详细的解释可以看参考文献中《The illustratedtransformer》中对位置编码的图解。

在transformer中,位置编码的过程如下:

Transformer的工作流程第一步:获取输入句子的每一个单词的表示向量X,X由单词的 Embedding(可以理解为从原始数据提取出来的Feature)和单词位置的 Embedding 相加得到。第二步:将得到的单词表示向量矩阵传入 Encoder中,经过多个 Encoder block 后可以得到句子所有单词的编码信息矩阵C。单词向量矩阵用 \(X_{n\timesd}\)表示, n 是句子中单词个数,d 是表示向量的维度 (论文中d=512)。每一个 Encoder block 输出的矩阵维度与输入完全一致。第三步:将 Encoder 输出的编码信息矩阵 C传递到Decoder 中,Decoder 依次会根据当前翻译过的单词 1~i 翻译下一个单词i+1。在使用的过程中,翻译到单词 i+1 的时候需要通过 Mask (掩盖)操作遮盖住 i+1 之后的单词。序列模型

Seq2Seq(Sequence-to-sequence)正如字面意思:输入一个序列,输出另一个序列,当然,其中输入序列和输出序列的长度是可变的。

针对Seq2Seq序列问题,比如翻译一句话,可以通过Encoder-Decoder模型来解决。一般这样的任务都是使用编码、解码的框架来完成,也就可以称之为Encoder-Decoder,中间一个向量C传递信息,且C的长度是固定的。为了建模序列问题,RNN引入了隐状态h(hiddenstate)的概念,隐状态h可以对序列形的数据提取特征,接着再转换为输出,可以被看做是同一神经网络的多次复制,每个神经网络模块会把消息传递给下一个.

Encoder(编码器)和Decoder(解码器)之间只有一个「向量C」来传递信息,且C的长度固定。比如翻译一段语句,翻译的句子短还好,句子一长呢?当输入句子比较长时,所有语义完全转换为一个中间语义向量C来表示,单词原始的信息已经消失,可想而知会丢失很多细节信息。所以Encoder-Decoder是有缺陷的,其缺陷在于:当输入信息太长时,会丢失掉一些信息。

而为了解决「信息过长,信息丢失」的问题,Attention机制就应运而生了。Attention 模型的特点是 Eecoder不再将整个输入序列编码为固定长度的「中间向量C」,而是编码成一个向量的序列。

自注意力机制

自注意力层的作用是帮助编码器在对每个单词编码的时候时刻关注句子的其它单词。随着模型处理输入序列的每个单词,自注意力会关注整个输入序列的所有单词,帮助模型对本单词更好地进行编码。在处理过程中,自注意力机制会将对所有相关单词的理解融入到我们正在处理的单词中。

自注意力机制的具体功能是:

序列建模:自注意力可以用于序列数据(例如文本、时间序列、音频等)的建模。它可以捕捉序列中不同位置的依赖关系,从而更好地理解上下文。这对于机器翻译、文本生成、情感分析等任务非常有用。并行计算:自注意力可以并行计算,这意味着可以有效地在现代硬件上进行加速。相比于RNN和CNN等序列模型,它更容易在GPU和TPU等硬件上进行高效的训练和推理。(因为在自注意力中可以并行的计算得分)长距离依赖捕捉:传统的循环神经网络(RNN)在处理长序列时可能面临梯度消失或梯度爆炸的问题。自注意力可以更好地处理长距离依赖关系,因为它不需要按顺序处理输入序列。

Self-Attention 的结构:

example11QKV的生成

自注意力层会从每个编码器的输入向量(每个单词的词向量,即Embedding后的结果)中生成三个向量,即查询向量、键向量和一个值向量。这三个向量是通过词嵌入与三个权重矩阵即\(W^Q , W^K , W^V\)相乘后创建出来的。新向量在维度上往往比词嵌入向量更低。将以上所得到的查询向量、键向量、值向量组合起来就可以得到三个向量矩阵,即矩阵Q(查询),K(键值),V(值)。

在实际中,Self-Attention 接收的是输入(单词的表示向量\(x\)组成的矩阵\(X\)) 或者上一个 Encoder block的输出。而\(Q,K,V\)正是通过Self-Attention 的输入进行线性变换得到的。

这里举一个简单的例子: 例如我们得到的一个词向量矩阵\(X\),每一行都是一个单独的单词的词向量表示。那么我们可以得到:Q、K、V中的每一行即为一个词向量对应的查询向量、键向量、值向量。

计算注意力值

接下来,我们对每个单词需要计算其他单词对其的得分,假设我们在为这个例子中的第一个词“I”计算自注意力向量,我们需要拿输入句子中的每个单词对“I”打分。这些分数是通过所有输入句子的单词的键向量与“I”的查询向量相点积来计算的。

也就是说,对于单词“I”,我们分别需要计算\(q_1\cdot k_1\), \(q_1 \cdot k_2\),\(q_1\cdot k_3\), \(q_1 \cdot k_4\). 之后将分数除以\(\sqrt{d}\)(d是论文中使用的键向量的维数,这可以让梯度更稳定。) 也就是公式:

\[\frac{Q \cdot K^T}{\sqrt{d}}\]

然后通过softmax传递结果。softmax的作用是使所有单词的分数归一化,得到的分数都是正值且和为1。随着模型处理输入序列的每个单词,自注意力会关注整个输入序列的所有单词,帮助模型对本单词更好地进行编码。

最后得到的结果决定了每个单词对编码当下位置(“I”)的贡献。我们可以看到,所谓并行就是指每个单词所代表的向量都可以独立地进行注意力计算得到注意力得分,而不是必须由前一个单词计算完成后才能计算下一个单词。

弱化无关量

直觉上我们是希望关注语义上相关的单词,并弱化不相关的单词。那么我们就需要通过在我们的值向量上乘以上述得到的注意力得分。$ softmax() $的结果是一个矩阵,对于这个矩阵的第i行,其上的n维对应的值,我们可以理解为其是第i个词向量与n个单词的注意力得分。

例如第i个行向量\(\begin{matrix}[ a, &b, & c, & d ]\end{matrix}\),其中\(a\)则表示第i个单词中与第1个单词的注意力得分,\(c\)则表示与第三个单词的注意力得分。现在我们用这个结果来与得到的V矩阵相乘,也就相当于是对V矩阵中各个行向量进行了加权求和得到最后的结果。

多头注意力机制

由上述推论,我们已经知道怎么通过 Self-Attention 计算得到输出矩阵Z,而Multi-Head Attention 包含多个 Self-Attention层,首先将输入X分别传递到 h 个不同的 Self-Attention 中,计算得到 h个输出矩阵Z。如下图所示:

对应h=8的情况,我们最后可以得到 8 个输出矩阵,Multi-Head Attention将它们拼接在一起 (Concat),然后传入一个Linear层,得到 Multi-HeadAttention 最终的输出Z。可以看到 Multi-Head Attention输出的矩阵Z与其输入的矩阵X的维度是一样的。

总结一下多头注意力机制的功能:

扩展了模型专注于不同位置的能力。有多个查询/键/值权重矩阵集合,并且每一个都是随机初始化的。每个注意力头都是用矩阵\(X\)乘以\(W^Q、W^K、W^V\)来产生查询、键、值矩阵。多个注意力头会注意到不同的内容,我们对各种注意到的部分进行组合,就能避免某些可能存在的情况被忽视。

具体来说,在《the illustratedtransformer》中已经提到,因为不同的初始化参数,训练后得到的注意力得分是不一样的。也就意味着可能对于同一个词在不同的头上会注意到不同的位置。也就是如下图所示:当计算“it”的注意力得分时,八列不同颜色的表格指示了八个头不同的注意到的位置,当对“it”一词进行编码时,一个注意力头最关注的是“animals”,而另一个是专注于“tired”——从某种意义上说,模型对“it”一词的表示在“animals”和“tired”的一些表示中提取得到。

Add&Normalize

在经过多头注意力机制得到矩阵Z之后,并没有直接传入全连接神经网络,而是经过了Add&Normalize层,该层由两个部分组成,即Add和 Norm 两部分组成,其计算公式如下:

\[LayerNorm(X+MultiHeadAttention(X))\]

其中 X表示 Multi-Head Attention的输入,MultiHeadAttention(X) 表示输出(输出与输入 X 维度是一样的)。

Add指X+MultiHeadAttention(X),是一种残差连接,通常用于解决多层网络训练的问题,可以让网络只关注当前差异的部分.Norm指 Layer Normalization,通常用于 RNN 结构,Layer Normalization会将每一层神经元的输入都转成均值方差都一样的,这样可以加快收敛。Add

这里用到了残差连接的思想,即

加入残差块的目的是为了防止在深度神经网络的训练过程中发生退化的问题,退化的意思就是深度神经网络通过增加网络的层数,Loss逐渐减小,然后趋于稳定达到饱和,然后再继续增加网络层数,Loss反而增大。对于多余的层,我们需要保证多出来的网络进行恒等映射。只有进行了恒等映射之后才能保证这多出来的神经网络不会影响到模型的效果。恒等映射,即让F(X)=0就可以了。x经过线性变换(随机初始化权重一般偏向于0),输出值明显会偏向于0,而且经过激活函数Relu会将负数变为0,过滤了负数的影响。这样当网络自己决定哪些网络层为冗余层时,使用ResNet的网络很大程度上解决了学习恒等映射的问题,用学习残差F(x)=0更新该冗余层的参数来代替学习h(x)=x更新冗余层的参数。

Normalize

归一化目的: 1、加快训练速度 2、提高训练的稳定性Transformer使用到的归一化方法是LayerNormalization。

LayerNormalization(层归一化):是在同一个样本中不同神经元之间进行归一化。

BatchNormalization(批量归一化):是在同一个batch中不同样本之间的同一位置的神经元之间进行归一化。

层归一化的计算不依赖于其他样本,而批量归一化的计算则依赖于整个batch的样本。在处理序列数据(如文本)时,每个样本的长度可能会有所不同,这使得批量归一化在实践中难以应用。在处理变长序列时,批量归一化需要对每个序列进行填充或截断以形成一个固定大小的batch,这可能会引入额外的噪声。而层归一化则可以直接处理变长序列,不需要进行填充或截断。

全连接层Feed Forward

Feed Forward 层比较简单,是一个两层的全连接层,第一层的激活函数为Relu,第二层不使用激活函数,对应的公式如下。

\[max(0,XW_1+b_1)W_2+b_2\]

也就是先线性变换,然后ReLU非线性,再线性变换。这两层网络就是为了将输入的Z映射到更加高维的空间中然后通过非线性函数ReLU进行筛选,筛选完后再变回原来的维度。

至此,一个完整的Encoder就完成了,在Transformer中总共有6个Encoder块,每一个Encoder得到的输出输入到下一个Encoder中,最终的结果在传入到Decoder中。

Decoder结构

上图红色部分为 Transformer 的 Decoder block 结构,与 Encoder block相似,但是存在一些区别:

包含两个 Multi-Head Attention 层。第一个 Multi-Head Attention 层采用了 Masked 操作。第二个 Multi-Head Attention 层的K, V矩阵使用 Encoder的编码信息矩阵C进行计算,而Q使用上一个 Decoder block 的输出计算。最后有一个 Softmax 层计算下一个翻译单词的概率。Masked Multi-Head Attention

与Encoder的Multi-HeadAttention计算原理一样,只是多加了一个mask码。mask表示掩码,它对某些值进行掩盖,使其在参数更新时不产生效果。Transformer模型里面涉及两种 mask,分别是 padding mask 和 sequence mask。

padding mask

因为每个批次输入序列长度是不一样的也就是说,我们要对输入序列进行对齐。具体来说,就是在较短的序列后面进行填充0,如果输入的序列太长,则是截取左边的内容,把多余的直接舍弃。但是这些填充的位置,其实是没什么意义的,经过softmax操作也会有对应的输出,attention机制不应该把注意力放在这些位置上,所以我们需要进行一些处理。具体的做法是,把这些位置的值加上一个非常大的负数(负无穷),这样的话,经过softmax,这些位置的概率就会无限接近0!

sequence mask

sequence mask 是为了使得 decoder 不能看见未来的信息。对于一个序列,在time_step 为 t 的时刻,我们的解码输出应该只能依赖于 t时刻之前的输出,而不能依赖 t 之后的输出。因此我们需要想一个办法,把 t之后的信息给隐藏起来。这在训练的时候有效,因为训练的时候每次我们是将target数据完整输入进decoder中地,预测时不需要,预测的时候我们只能得到前一时刻预测出的输出。具体的做法就是产生一个上三角矩阵,上三角的值全为0。把这个矩阵作用在每一个序列上,就可以达到我们的目的。

实际上,在Encoder中的Multi-HeadAttention也是需要进行mask的,只不过Encoder中只需要paddingmask即可,而Decoder中需要padding mask和sequence mask。

Multi-Head Attention

Decoder block 第二个 Multi-Head Attention 变化不大,主要的区别在于其中 Self-Attention 的 K, V矩阵不是使用上一个 Decoderblock 的输出计算的,而是使用 Encoder 的编码信息矩阵 C 计算的。根据Encoder 的输出 C计算得到 K, V,根据上一个 Decoder block 的输出 Z 计算 Q(如果是第一个 Decoder block 则使用输入矩阵 X进行计算),后续的计算方法与之前描述的一致。这样做的好处是在 Decoder的时候,每一位单词都可以利用到 Encoder 所有单词的信息 (这些信息无需Mask)。

Softmax预测输出单词

Decoder block 最后的部分是利用 Softmax预测下一个单词,在之前的网络层我们可以得到一个最终的输出 Z,Softmax根据输出矩阵的每一行预测下一个单词:

具体来说,这个输出层接收 Decoder的最后一个输出,然后通过一个全连接层(也就是一个线性变换)将其转换为一个向量,这个向量的长度等于词汇表的大小。然后,这个向量通过Softmax 函数转换为一个概率分布。Softmax 函数可以确保所有的输出值都在 0和 1 之间,并且所有值的总和为1,因此可以被解释为概率。这个概率分布表示了模型对下一个词是词汇表中每个词的概率的预测。在实际应用中,我们通常选择概率最高的词作为下一个词的预测。

总结数据的产生

现在我们回顾一下上述的流程,首先我们介绍了独热码,这是一种用来表示不同词的手段,实际上我们一般会将其当作一个索引向量然后和嵌入矩阵相乘然后才会得到真正的词向量。注意到这里的嵌入矩阵是可以训练的,也就是说模型会通过训练从而得到更好的词向量表示,语义接近的词的词向量也会是接近的。接下来,我们介绍了位置编码的嵌入,Transformer本身是不能利用单词的顺序信息的,因此需要在输入中添加位置Embedding。其完全基于self-attention,对于词语位置之间的信息有一定的丢失,加入了positionalencoding在一定程度上能够解决这个问题。通过上述这两个过程,我们才真正得到了真正拿来训练用的数据。

训练过程

我们以中英文翻译的任务为例子,假设我们有一一对应的中英文序列,那么我们首先会将中文序列输入到EncoderBlock中,对应的英文序列输入到Decoder Block中,在这个过程中Transformer模型可以一次处理整个序列,并且可以并行计算所有位置的输出。这是因为在训练阶段,我们已经知道整个目标序列的信息,所以可以将整个目标序列(经过"shift right" 操作)一次性输入到 Decoder 中。

shift right" 的操作是将目标序列(target sequence)向右移动一位,并在序列的开始插入一个新的符号,通常是``(start of sequence)符号。这样做的目的是让模型在预测第 t 个词时,只能看到 t-1 个词,而不能看到第 t 个词和之后的词,从而确保模型在预测时不会看到未来的信息。例如,如果我们的目标序列是 [Hello, World, !, ``],那么 "shift right" 操作后的序列就会变成 [``, Hello, World, !]。这是一种技巧,用于确保当前时间步的预测不会受到未来时间步的影响。

为了使训练中止,一般回收型对语句进行tokenize化,加上起始和终止的标签。这样当decoder解码到特定标签时,就知道翻译已经结束了。举个例子,比如说我们翻译"Ihave anapple"时,训练的过程中会学到单词"apple"之后就是终止标记,所以在推理时得到“apple”后就结束了推理过程。

测试过程

在测试阶段,Decoder的输入包括两部分:一部分是已经生成的目标语言的序列,另一部分是来自Encoder 的输出。

已经生成的目标语言的序列开始时通常只包含一个开始符号。然后,我们将这个序列和 Encoder的输出一起输入到 Decoder中,得到第一个词的预测。然后,我们将这个预测的词添加到目标语言的序列中,再将更新后的序列和Encoder 的输出一起输入到 Decoder中,得到第二个词的预测。这个过程会一直重复,直到生成一个结束符号 或达到某个最大长度。

所以,测试阶段的 Decoder输入是逐步生成的,每一步都依赖于前一步的输出。

Transformer的应用自然语言处理(NLP):Transformer 在 NLP领域的应用非常广泛,包括机器翻译、文本摘要、情感分析、命名实体识别、问答系统、对话系统等。其中,BERT、GPT、T5等知名模型都是基于 Transformer 构建的。语音识别:Transformer也被用于语音识别任务,例如,将语音转换为文字。图像处理:最近,Transformer也开始被应用到图像处理领域,例如,ViT(Vision Transformer)模型就是用Transformer 进行图像分类的。生物信息学:Transformer也被用于处理生物序列数据,例如,预测蛋白质结构。推荐系统:Transformer可以处理用户的行为序列,从而进行个性化推荐。时间序列预测:Transformer可以处理时间序列数据,用于股票预测、气候预测等任务。

Transformer的主要精髓就是其提出了注意力机制,利用该机制我们可以在多种任务上取得不错的效果。

以下是机器学习大作业一个使用Transformer的例子

题目描述:

通过多模态数据(音频、文本、视频等)对会话情绪进行识别。利用给定的特征数据集,通过对三种模态数据的融合,建立稳定的情感识别模型,预测出会话时的情绪状态,包括happy,sad,angry,excited,neutral and frustrated六种情绪类别。

项目参见

我们使用了一种基于Transformer-based编码器的模型,综合考虑数据集中的三种特征,文本、音频和图像。具体来说就是在模态编码器中引入模态内和模态间的Transformer编码器来捕获模态内和模态间的相互作用,并将位置和说话人嵌入作为这些Transformer编码器的额外输入来捕获上下文和说话人性别的信息。

在提取了话语级单模态特征后,Transformer-based模型设计了单个捕获模态内和模态间交互的模态编码器,并借鉴GRU的门控机制对输出进行处理,并拼接后通过一个线性层,得到每个模块的输出信息。然后我们通过一种分层门控融合策略,动态融合来自多种模态的信息。最后,通过一个线性映射,将每个模态的输出和融合后的分别输出映射到类别维度,后者用于得到预测情感的label,前者则与后者一起参与loss的计算.

实际上,在这里对transformer的使用中,并未用到解码器层,我们只使用编码器层来进行预测。

Transformer的自注意力机制天然适用于多模态信息之间的处理,所以我们是将每两个模态的特征作为输入,处理后分别作为transformer编码层的Q和K,V得到输出(一个模态的数据得到Q,K,另一个模态作为V)。这样一共会得到9个输出(一共三个模态,所以9个),下一步再把与每个模态有关的输出综合得到每个模态的最终输出,最后再综合这三个模态各自的输出,经过分类器降维后得到模型的最终输出。

最终测试的结果是:基于Transformer编码器的模型的泛化能力非常好,能达70%左右的正确率,在情感识别任务中,这已经是一个非常高的正确率。我们觉得一个重要原因是Transformer的具有很强的表达能力,且其自注意力机制,使得模型能够在不同位置关注输入序列的不同部分,更好地捕捉长距离依赖关系。

参考文献:

读到这里,

相关推荐: