https://www.bilibili.com/video/BV1pu411o7BE
序列转录模型是从一个序列生成另一个序列。Transformer 仅利用注意力机制(attention),并且在机器翻译领域取得很好的成功。
Transformer 重要贡献之一提出:multi-head self-attention。
RNN 计算一个序列的方法:把这个序列从左往右一步一步往前做运算。假如序列是一个句子,RNN 会一个词一个词地向后看;对第 t 个词,会计算一个输出 h t h_t ht(隐藏状态)。 h t h_t ht 由前一个词的隐藏状态 h t − 1 h_{t-1} ht−1 与当前第 t 个词本身决定。通过这么做, h t h_t ht 可以把前面学到的历史信息通过 h t − 1 h_{t-1} ht−1 放在当下,与当前词做计算,进行输出。这也是 RNN 能有效处理时序信息的一个关键所在——把之前的信息全部放在隐藏状态里,然后一个一个进行下去。(第二段)
这样做的问题是:①、RNN 是一步一步的计算过程,难以并行。例如:算 h t h_t ht 时,必须等 h t − 1 h_{t-1} ht−1 计算完成。假设句子有100个词,时序上计算100步。②、序列的历史信息是一步一步往后传递的。如果时序很长,早期的时序信息在后面的时候可能会丢掉。如果不想丢掉, h t h_t ht 会比较大,导致后续节点的隐藏状态也很大,从而使 内存开销很大。(第二段)
使用 CNN 替换 RNN,减少时序的计算。问题是 CNN 难以对长序列建模。因为卷积做计算时,每次看(关注)一个小的窗口,比如看一个 3 ∗ 3 3*3 3∗3 的像素块。如果两个像素间隔很远,则需要用很多卷积,一层一层上去,最后才能把这两个相隔很远的像素融合。但是如果使用 Transformer 的注意力机制,每一次能看到所有像素,一层便能看完整个序列。卷积的一个好处是可以做多个输出通道(一个输出通道可以认为是识别不同的模式)Transformer 也想达到这个效果,所以提出 Multi-Head Attention。(第一段)
利用前人的成果——self-attention。(第二段)
Transformer 是第一个只依赖自注意力做 encoder 到 decoder 的架构的模型。(第四段–最后一段)
序列模型里比较好的架构是 encoder-decoder structure。encoder 将一个输入序列 ( x 1 , . . . , x n ) (x_1,\ ...,\ x_n) (x1, ..., xn) 转化为一个输出 z = ( z 1 , . . . , z n ) \pmb{z}=(z_1,\ ...,\ z_n) z=(z1, ..., zn) ,其中 z t z_t zt 对应的是 x t x_t xt 的一个向量表示 ( t ∈ { 1 , . . . , n } ) (t\in\{1,...,n\}) (t∈{1,...,n})。encoder 将原始的输入转变为机器学习可以理解的一系列的向量。《|》 对 decoder 而言,拿到编码器的输出,生成一个长为 m 的序列 ( y 1 , . . . , y m ) (y_1,\ ...,\ y_m) (y1, ..., ym) 。注意: n ≠ m 或 n = m n \neq m\ 或\ n = \ m n=m 或 n= m 。decoder 与 encoder 不同的是, y t y_t yt 是一个一个生成的,而 encoder 可能会一次看完整个序列。这种形式的模式被称为 a u t o − r e g r e s s i v e auto-regressive auto−regressive ——模型的输出又可以是模型的输入:最开始给定 z \pmb{z} z ,生成第一个输出 y 1 y_1 y1;拿到 y 1 y_1 y1 后,生成 y 2 y_2 y2 ;如果要生成 y t y_t yt,前面的 y 1 到 y t − 1 y_1\ 到\ y_{t-1} y1 到 yt−1 要全部拿到。《|》 更具体的来说,Transformer 是将 self-atttion 与 point-wise 全连接层,然后一个一个堆在一起。(第一段)
encoder 输入是序列 ( x 1 , . . . , x n ) (x_1,\ ...,\ x_n) (x1, ..., xn),输出是 z = ( z 1 , . . . , z n ) \pmb{z}=(z_1,\ ...,\ z_n) z=(z1, ..., zn)
decoder 输入是 z = ( z 1 , . . . , z n ) \pmb{z}=(z_1,\ ...,\ z_n) z=(z1, ..., zn),输出是 ( y 1 , . . . , y m ) (y_1,\ ...,\ y_m) (y1, ..., ym)
左半部分是 encoder,右半部分是 decoder。
Encoder:由 6 个相同的 layer 组成。每个 layer 有两个 sub-layers: ①. multi-head self-attention mechanism, ②. position-wise fully connected feed-forward network(实际上是一个 MLP)。而且对每个 sub-layer 使用残差连接, 并做 layer normalization 处理。即每个 sub-layer 的输出是 L a y e r N o r m ( x + S u b l a y e r ( x ) ) LayerNorm(x+Sublayer(x)) LayerNorm(x+Sublayer(x))。Transformer 的所有子层和嵌入层的输出都是 512 维。
扩展: Batch Norm 与 Layer Norm
通常在变长的应用中, 不使用 Batch Norm。
在二维情况下,如图所示, 行是样本,列是该 batch 内所有样本的同一特征。Batch Norm 是对某列归一化(减去 mean 均值,除以 std 方差)处理。Layer Norm 是对某行归一化处理。特别地,Layer Norm 可以看作先转置,再做 Batch Norm,最后转置。
在三维情况下,如图所示。在变长的序列中,Layer Norm 用的更多。一个原因是在这些序列里每个样本的长度可能发生变化(图中有表示,Batch Norm、Layer Norm 的处理也如图)。Batch Norm 时,如果样本长度变化很大,每次小批量计算出来的 mean 均值、std 方差的抖动相对来说是比较大的。而且,做预测时,要把全局的 mean 与 std 记录下来。如果全局的 mean 与 std 碰到新的预测样本(该预测样本的长度很长),很有可能是不那么好用的。Layer Norm 时,则没有这个限制,不需要存下一个全局的 mean、std。因为 mean 与 std 是基于每个样本的算出来的。
Decoder:有 6 个相同的 layer。每个 layer 有两个 sub-layer 与 encoder 的相同,第三个 sub-layer 实现 multi-head attention。Decoder 也使用残差链接与 Layer Norm。《|》 decoder 做的是自回归 ——— 当前输出的输入集是之前一些时刻的输出。这也意味着做预测时,不能看到之后那些时刻的输出。然而在注意力机制中,每次能看到整个完整的输入;因此,要避免前述问题的发生。也意味着:Decoder 训练时,预测第 t 个时刻的输出时,不应该看到 t 时刻以后的那些输入。Transformer 的做法是通过一个带掩码的注意力机制 ———— 保证输入进来时,在 t 时间不会看到 t 时间以后的那些输入,进而保证训练与预测的一致。
attention func 是将 query 与 key-value 对映射为一个 output(输出)的函数(query、keys、values、output 都是向量)。output 是 values 的加权和;而每个 value 的权重是由该 value 的 key 与 query 的相似度算来的(相似度的计算依靠 compatibility func)。
举例:
上图给出 3 对 k-v。黄色 query 与 value①、value② 离得近,与 key①、key② 计算得来的相似度就高,黄色 query 的输出便是三个相似度的相加;同理,绿色 query 与 ②③ 离得近,相似度就高(相似度由线的粗细程度表示)。
(不同的 attention func 导致不一样的注意力版本。这节作者讲解 Transformer 的注意力机制。)
query 与 key 等长度,记为: d k d_k dk,value 的长度记为: d v d_v dv(output 的长度也是 d v d_v dv)。具体计算是每个 query 与所有 key 做内积运算,再除以 d k \sqrt{d_k} dk,再做 softmax func,最后得到 values 的权重。(第一段)
在本小节第二段,作者给出公式一(如下)从矩阵运算的角度描述第一段的算法。
A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d k ) V Attention(\pmb{Q},\pmb{K},\pmb{V})=softmax(\frac{\pmb{Q}\pmb{K}^T}{\sqrt{d_k}})\pmb{V} Attention(Q,K,V)=softmax(dkQKT)V
两种常见的 attention func:additive attention(容易处理 query 与 key 不等长的情况)、dot-product (multi-plicative) attention。dot-product attention 与本文的一致,除了本文的除去 d k \sqrt{d_k} dk。上述两种 attention func 差不多,但是本文选用 dot-product。因为 dot-product attention 实现简单,且运算高效。(第三段)
当 d k d_k dk 很小时,两种 dot-product attention 性能相似。但是 d k d_k dk 较大(query 与 key 很长)时,点积运算的结果可能很大,再做 softmax 出来的结果的最大值会更加靠近 1,剩下的值接近于 0(结果向两端靠拢)。此时计算出的梯度比较小。 《|》 因为理论上 softmax 最后的结果应该是最后的结果置信地方尽量靠近 1,不置信的地方靠近 0;这表示收敛已经差不多了,表现为梯度小,跑不动了。再者 Transformer 用的 d k d_k dk 比较大( d k = 512 d_k=512 dk=512)。所以,除以 d k \sqrt{d_k} dk 是一个不错的选择。(第四段)
与其做一个单个的 attention func,不如把 queries、keys、values 投影到低维,投影 h 次;然后再做 h 次的 attention func;最后,把每个函数的输出并在一起,再投影得到最终的输出(第一段)。下图是论文中对 Multi-Head Attention 的介绍
为何要做 Multi-Head Attention 呢?细看 Scaled Dot-Porduct Attention 可知,这里面没有什么可学的参数。但是为了识别不同的模式,希望有不同的计算像素的办法。此时的操作是投影到低维,投影的 W \pmb{W} W 是可以学习的。投影 h 次,希望学到不同的投影方法,使得再投影进去的度量空间里,能够匹配不同模式需要的相似函数。最后,把它们拼接,再做一次投影,得到最终的结果。
M u l t i H e a d ( Q , K , V ) = C o n c a t ( h e a d 1 , . . . , h e a d h ) W O MultiHead(\pmb{Q}, \pmb{K}, \pmb{V}) = Concat(head_1,...,head_h)\pmb{W}^O MultiHead(Q,K,V)=Concat(head1,...,headh)WO
w h e r e h e a d i = A t t e n t i o n ( Q W i Q , K W i K , V W i V ) where\ head_i = Attention(\pmb{QW}_i^Q,\pmb{KW}_i^K,\pmb{VW}_i^V) where headi=Attention(QWiQ,KWiK,VWiV)
(在本小节,论文阐述在 Transformer 里如何使用注意力)
解释说明第一幅图的三个 attention。
前馈网络本质上是一个 MLP。Position-wise Feed-Forward Networks 中的 “position” 是输入序列的一个词,一个词是一个 position。该 sub-layer 是用同一个 MLP 对每个词作用一次。(第一段)
F F N ( x ) = m a x ( 0 , x W 1 + b 1 ) W 2 + b 2 FFN(x) = max(0,x\pmb{W}_1 + b_1)\pmb{W}_2 + b_2 FFN(x)=max(0,xW1+b1)W2+b2
上面的公式表明该网络由两个线性层组成。 x x x 是 query 对应的 output,即 x x x 的维度是 512 。第一层放大四倍后,最后一层在缩小为 512 。(第二段)
Transformer(简化版)与 RNN 对比:
从上图可以看出来,RNN 与 Transformer 类似,都是用一个线性层或者 MLP 做语义空间的转换;不同的是传递序列信息的方式:RNN 是把上一个时刻的信息作为输入,输出传入到下一时刻;Transformer 是通过一个 attention 层全局地拉取整个序列里面的信息,然后用 MLP 做语义转换。类似地,它们的关注点都是如何有效使用序列的信息。
输入是一个个的词( t o k e n token token),做计算时需要把它们映射为对应的向量。embedding 的作用是给定任何一个词学习一个长为 d d d 的向量表示它(此处的 d = 512 d=512 d=512)。encoder、decoder 的输入前面都需要有一个 embedding;softmax 前面的线性层也需要有一个 embeding。而且这三个 embedding 的权重是相同的。这些权重还要乘以 d \sqrt{d} d (因为在学 embedding 时,可能会把向量的 L 2 N o r m (欧氏距离) L2\ Norm(欧氏距离) L2 Norm(欧氏距离) 学得相对来说比较小,比如说学成 1,不管维度多大,最后的值都会等于 1。如果此时维度变大,学到的权重值会变小。但是之后还要加上 Positional Encoding,它不会随着维度的变大而固定 L 2 N o r m L2\ Norm L2 Norm。权重乘以 d \sqrt{d} d 后,保证相加的二者在 scale 上差不多)。
attention 没有时序信息 —— output 是 values 的加权和。而权重是 query 与 key 之间的距离,它跟时序信息无关。即: 不关注 k-v 对位于序列的何处。意味着给一句顺序被打乱的话,attention 的结果都是一样的。处理时序数据,顺序变化,而结果不变,这是错误的。所以,需要在 attention 中加入时序信息。RNN 时序信息的加入是把上一个时刻的输出作为下一个时刻的输入来传递历史的信息。RNN 本身就是一个时序的东西,而 attention 不是!attention 的做法是在输入里面加入时序信息 —— 用数字表示词所在的位置,并将其加入输入中。论文中把这种方法称为 Position Encoding 。
(论文中有具体的关于 position encoding 的算法内容)
这一章解释为何使用 self-attention。论文的内容主要是说相对于用循环层或者卷积层的时候,self-attention 的效果很好。
(Table 1 讲解的时间段:1:06:21~~1:12:50)
使用 attention 关注的是特别长的序列,它能够把整个信息揉得比较好一点。