1、简介

transformer模型完全基于attention, attention原本是用在RNN上的, 这里把RNN去掉, 只保留attention。

transformer是一种很新的模型, 2017年才发表, 比attention晚两年。论文的名字叫做attention is all you need。这里讲解transformer的模型结构, transformer模型很复杂, 这里主要重点解释attention模块。

transformer模型是一种seq2seq模型, 它有一个encoder和一个decoder。很适合做机器翻译, transformer不是循环神经网络。transformer没有循环结构, 只有attention和全连接层。transformer的实验效果非常惊人, 可以完爆最好的RNN+transformer。 机器翻译问题已经没有人使用RNN了, 业界都是用transformer+bert。

现在告诉你, 可以去掉RNN, 只保留attention, 然后用attention来搭建一个深度神经网络来代替RNN。那么你会怎么做, 现在按照这个思路, 从0开始搭建一个基于attention的神经网络。

2、RNN+attention回顾

这里先从之前学过的RNN+attention模型入手。剥离RNN保留attention, 然后搭建attention层与Self-Attention层。然后将这些层组装起来, 搭建出来的模型就是transformer。

之前用attention改进seq2seq模型, seq2seq模型有一个encoder和一个decoder, encoder的输入是m个向量x1到xm。encoder把这些信息压缩到状态向量h中, 最后一个状态hm是对所有输入的概括。

decoder是一个文本生成器, 依次生成状态s, 然后根据状态s生成单词。把新生成的单词记为下一个输入x’。如果用attention的话, 还要计算context vector c, 每计算一个状态s就得到一个c。

具体是这样计算context vector c的, 首先把decoder当前状态sj与encoder所有m个状态h1到hn做对比, 用align函数计算它们的相关性。把计算的数值αij作为权重。这里的i是encoder的状态h的下标, j是decoder的状态h的下标。

image-20231206145554018

每计算一个context vector c, 就要计算出m个权重αij到αmj, 每个α对应一个状态h。

image-20231206150058170

首先看一下α权重是如何计算的。权重是hi与sj的函数, 把向量hi乘到矩阵Wk上, 得到向量k:i, 把向量sj乘到WQ上, 得到向量q:j。

image-20231206150335721

Wk和WQ是align函数的参数, 参数需要从训练数据中学习。

把sj这个向量与encoder所有m个状态向量h做对比。有m个hi向量, 所以有m个ki向量。用这些ki向量组成大的k矩阵, 每个ki向量都是矩阵k的列。

image-20231206150908029

计算矩阵大K转置与向量q:j的乘积, 结果是m维的向量, 用softmax函数输出m维的向量α:j。

image-20231206151152386

把α:j的m个元素即α1j, α2j, 一直到αmj, 这些元素全部介于0到1之间,而且它们它们相加等于1, 这样得到m个权重。

上面把decoder的状态sj以及encoder状态h分别做线性变换, 得到向量q:j与k:i,它们被称为query和key。 query的意思是用来匹配key值, key的意思是用来被query匹配。我们拿一个query向量q:j去对比所有m个k向量, 算出m个权重αij。这个m个α说明query和每个key的匹配程度, 匹配程度越高, 权重α越大。

除此之外还要计算value向量vi, 把hi乘到矩阵Wv上, 得到向量vi。矩阵Wv也是个参数矩阵, attention中一共有三个参数矩阵, Wq, Wk, Wv。

image-20231206152114762

上面提到的query, key和value, 这三个向量是怎么计算的。先把decoder当前状态sj映射到query向量, 具体是将参数矩阵Wq与decoder状态sj相乘, 得到query向量qj。

然后把encoder所有m的状态h1到hm映射到m个k向量。用参数矩阵Wk与第i个状态hi相乘得到k个向量ki。对于h1到hm所有m个状态向量做这种变换,得到m个k向量。 把这m个k向量表示为矩阵大k向量, 向量ki是矩阵大ki的第ki列。

用矩阵大k与向量qj计算m维的权重。

image-20231206152852828

向量αj, 向量αj的m个元素分别是α1j, α2j一直到αmj, 每一个元素对应一个h向量。

接下来计算value向量vi, 拿encoder的第i个状态hi与参数矩阵Wv相乘, 得到一个value向量vi, 把所有的m个状态h1到hm都做这种变换, 得到m个value向量, 每个vi对应一个encoder状态hi。

image-20231206153443180

现在有了m个权重α以及m个value向量v, 用α做权重。把m个value向量v做加权平均, 把结果作为新的context vector cj。

image-20231206153627435

context vector cj等于α1j乘以vi一直加到αj乘以vm, 这种计算权重α和context vector cj的方法就是transformer中的attention。

image-20231206153815163

3、剥离RNN只保留attention

attention原本是用在RNN上, 如何剥离RNN只保留attention。

先来设计一个attention层, 用于seq2seq模型。我们移除了RNN, 现在开始搭建attention。还是考虑seq2seq模型, 它有一个encoder和一个decoder。encoder的输入向量是x1到xm, decoder的输入是x‘1到x’t。举个例子, 要把英语翻译成德语, 英语句子里面有m个单词, 变成了词向量x1到xm。 decoder依次生成德语单词x‘1到x’t, 把当前生成的德语单词作为下一轮的输入。现在已经生成了t个德语单词, 把它们作为输入来生成下一个单词,新生成的德语单词会作为第t+1个输入。

image-20231206160019959

我们不用RNN只用attention, 首先拿encoder的输入x1, x2到xm计算key和value, 用矩阵Wk把向量xi变成ki, 用矩阵Wv把向量xi变成vi。

于是xi就变成了向量ki和vi。

image-20231206160429890

然后把decoder的输入x‘t,x’2一直到x‘t做线性变换, 用矩阵Wq把x’j映射到q:j。

image-20231206160615507

decoder有t个输入向量, 所以得到t个query向量。q1、q2、q3一直到qt。 注意一下, 一共有三个参数,encoder有两个,分别是矩阵Wk, Wv用来计算key和value。decoder中有一个, 用来计算query。

现在开始计算权重α。拿第一个query向量q1与所有m个k向量做对比, 通过比较q1与k1、k2、k3、…一直到km这m个向量的相关性。算出m个权重值即为这个m维的向量α1。具体是这样计算的:把所有m个k向量表示为矩阵大k, 大k的转置乘以向量q1, 再做softmax变换得到这个m维的向量α1。

image-20231206161353638

然后计算context vector c1, 需要用到权重向量α1与所有m个value向量v1、v2、v3一直到vm。c1是指m个v向量的加权平均权重, 权重就是α1向量的m个元素。分别是α11, α21, 一直到αm1。把向量v1到vm作为矩阵大v的列, 那么这个加权平均就可写成矩阵大v乘以向量α1。

image-20231206161726037

现在计算权重向量α2, 要用到第二个query向量q2以及所有m个k向量k1, k2, k3一直到km。

image-20231206161944923

然后计算context vector c2, 要用到权重α2, 以及所有m个value向量v1、v2、v3一直到vm。 c2是m个v向量的加权平均权重, 权重就是向量α2的m个元素。

image-20231206162143868

依次类推计算所有的context vector c, 每个c对应一个x‘, decoder输入一共有t个x’向量, 所以计算出t个c向量。

image-20231206162344590

这t个context vector c就是最终的输出,可以用矩阵大C来表示这些向量, c1、c2、c3一直到ct都是矩阵大c的列。

image-20231206162533643

要计算一个向量cj, 要用到所有的v, 所有的k以及一个qj向量。比如向量c2依赖于q2以及所有的k向量和v向量。c2依赖于decoder的一个输入x‘2以及encoder全部输入x1, x2一直到xm。

举个例子, 把英语翻译成德语。所以显然可以用attention layer代替RNN, attention layer的好处是不会遗忘。向量c2是直接用所有m个英文词向量x1到xm算出来的, 所以c2知道整句英语。

image-20231206163112769

把attention层记为函数attn, 输入是矩阵x和x’, x的列是encoder的m个输入向量x1、x2…xm。x‘的列是x’1、x‘2, …, x’t。 attention层有三个参数矩阵, Wq, Wk, Wv,它们通过训练数据来学习。attention层的输出是矩阵C, 它的列向量是c1, c2, c3…ct。

可以这样表示attention层, 有两个输入序列, x和x’。 有一个输出序列cm, 每个c向量对应一个x‘向量。

image-20231206163714309

上面研究了seq2seq模型, 删掉了RNN并且搭建了一个attention层。可以用attention层来做机器翻译。接下来搭建一个self attention层。原理完全一样, 可以用Self-Attention代替RNN。

4、用Self-Attention代替RNN

下图是上面搭建的attention层, attention层用于seq2seq, 它有两个输入序列, x和x’, 用attn函数表示attention层。

image-20231206164109220

Self-Attention层不是seq2seq模型, 它只有一个输入序列。这就像普通的RNN一样。Self-Attention层也可以用attn函数来表示。这个函数跟前面的attn完全一样, 区别在于函数的输入。 attention层的输入是x和x‘, 而Self-Attention层的输入只有x, 两个输入都是x, 输出序列是c1到cm。输出序列的长度跟输入是一样的, 都是m。 每个c向量对应一个x向量, 但要注意ci并非只依赖于xi, 而是依赖于所有m个x向量。改变任何一个x, ci都会发生变化。

image-20231206164859036

Self-Attention层的原理跟前面的attention层完全一样, 只是输入不一样。

image-20231206165038130

原理是这样的, 第一步做三种变换, 把xi映射到qi, ki和vi, 参数矩阵还是WQ, Wk, Wv。

线性变换之后x1被映射到q1, k1, v1, q2, k2, v2。

image-20231206165346732

然后计算权重向量α, 公式还是一样的, 矩阵k转置乘以qj向量, 然后做softmax, 得到m维向量αj。α1依赖于q1以及所有的k向量, k1, k2, k3, …,km。

image-20231206165705515

同理权重向量α2依赖于q2以及所有的k向量, k1, k2, …, km

image-20231206165854360

依次类推, 计算出所有的权重α, 一共有m个α向量, 每个向量都是m维的。

image-20231206170211842

现在开始计算context vector c, c1是所有m维v向量的加权平均, 权重都是α。 c1依赖于权重向量α:1以及所有m个v向量。

image-20231206170448475

依次类推得到m个c向量, 得到c1, c2, …, cm

image-20231206170542090

这m个c向量就是Self-Attention层的输出。

第j个输出cj是这样计算出来的,它依赖于矩阵V, 矩阵K以及向量qj。

image-20231206170841530

因为cj依赖于所有的k和所有的v, 所以cj依赖于所有m个x向量x1到xm。

image-20231206171031066

上面介绍了Self-Attention, 输入是一个序列。Self-Attention层有三个参数矩阵, 三个矩阵把每个x映射到q, k, v三个向量, 输出也是一个序列, 从c1到cm这m个向量。

image-20231206171243465

5、总结

1、attention最早出现在2015年的论文中, 用于改进seq2seq。

2、如果只有一个RNN网络, attention就叫做Self-Attention。 Self-Attention最早出现在2016年的论文中。

image-20231206172038846

3、再后来发现去掉RNN单独用attention效果反而更好。2017年的论文attention is all you need中提到了transformer模型。

4、首先从RNN+attention下手, 剥离RNN, 只保留attention。这样就搭建了attention层, 可以代替RNN做机器翻译。然后把attention变成Self-Attention, 不局限于seq2seq。

image-20231206172049386