深入浅出Transformer原理与实现

文章目录

来与去

它解决的是哪个领域的问题?这个领域没有它之前是什么样子,有了它之后,这个领域怎么发展?

早期序列学习任务的痛点

机器学习模型有很多种分类方式,其中有一种简单粗暴的:按照输入输出的长度进行分类,分为:

  1. One to One (如输入图片输出类别)
  2. One to Many (如输入图片输出图片描述或者是字幕)
  3. Many to One (如输入微博评论输出情感类别)
  4. Many to Many (分为M to N(如机器翻译) 与 M to M(自编码学习))
    深入浅出Transformer原理与实现
    众所周知,RNN在面对长距离的依赖时,反向传播会因为多项激活函数导数相乘(使得接近于0),相当于过长序列的学习能力不足:梯度消失问题。

根本原因:循环结构,就会导致链式求导时链变长,导致连乘。

那么,怎么不用循环结构,也能做到序列学习?
它带来了两个好处:

  1. 串行改并行了,计算效率和可扩展性大大提升
  2. 彻底解决了梯度消失问题

Transformer是2017年Google brain提出的模型,用注意力机制做到了这一点

; Transformer的发展

Transformer是一种基本模型,可以在它的基础上做各种魔改
如今各种高效Transformer结构如雨后春笋,连每个月的综述都层出不穷,工业界更是早已大规模应用。
不光是应用于语言(NLP)、语音(ASR)等领域(一开始RNN应用在这些NLP ASR领域)
现在更多的用于视觉领域,甚至融合领域(一个模型又会搞NLP又会搞CV)

注意力机制

早期的注意力机制

2014年在Bahdanau的这篇论文里首次提出,解决的是Neural machine translation领域里当时常用模型Seq2Seq的一个瓶颈问题: 随着encoder长度增长,decoder从encoder里获取的信息仍然非常有限。

encoder到decoder的流转例子,这里给出两幅图:

深入浅出Transformer原理与实现

深入浅出Transformer原理与实现

那有了注意力机制之后呢?

深入浅出Transformer原理与实现
详细看看这个attention layer:
深入浅出Transformer原理与实现

可以看到就是在模型输出的时候,构造了一个包含上下文信息的本质是encoder各向量的 权重和向量,这样decoder能从encoder获取到的信息就多了,而且可以想获取哪个多一点就获取哪个多点,学习权重就可以了,权重高代表那个位置的input vector和decoder这个位置的相关度高。

具体细节:主要是3个部分:

  1. Alignment scores
    e t , i = a ( s t − 1 , h i ) e_{t, i} = a(s_{t-1}, h_i)e t ,i ​=a (s t −1 ​,h i ​)
    h i h_i h i ​是encoder的隐状态向量,s t − 1 s_{t-1}s t −1 ​是上一步的decoder的输出,e t , i e_{t,i}e t ,i ​刻画的是这个输入向量和当前位置的输出对齐得有多好
  2. Weights
    α t , i = s o f t m a x ( e t , i ) \alpha_{t, i} = softmax(e_{t, i})αt ,i ​=s o f t m a x (e t ,i ​)
    因为每个时刻t t t其实可以找多个h i h_i h i ​获取想要的信息,所以将上述系数进行归一化,就可知道要去每个encoder的i i i时刻采样的比例了。
  3. Context vector
    c t = ∑ i = 1 T α t , i h i c_t = \sum_{i=1}^T \alpha_{t, i} h_i c t ​=i =1 ∑T ​αt ,i ​h i ​
    上下文信息向量,即 加权隐状态向量和

; 注意力机制的统一形式

注意力机制没有必要只是组合不同步骤的RNN隐状态,而是可以包含任意种类的信息。
这个时候,注意力机制分为3个组件: Q(queries)、K(keys)、V(values)

在早期形式里,Q可以类比为上一步的decoder输出即s t − 1 s_{t-1}s t −1 ​,V可以类比为encoder的隐状态向量h i h_i h i ​ ,整个注意力机制可以描述为用s t − 1 s_{t-1}s t −1 ​去查询key-value对,这里key是向量,value是隐状态向量h i h_i h i ​

  1. 查询向量q = s t − 1 q=s_{t-1}q =s t −1 ​:
    匹配数据库里的key来计算一个分数,匹配过程可以看作一个点积:
    e q , k i = q ⋅ k i e_{q, k_i} = q \cdot k_i e q ,k i ​​=q ⋅k i ​
  2. softmax操作,将分数转化为权重
    α q , k i = s o f t m a x ( e q , k i ) \alpha_{q, k_i} = softmax(e_q, k_i)αq ,k i ​​=s o f t m a x (e q ​,k i ​)
  3. 注意力计算
    a t t e n t i o n ( q , k , V ) = ∑ i α q , k i V k i attention(q, k, V) = \sum_i \alpha_{q, k_i} V_{k_i}a t t e n t i o n (q ,k ,V )=i ∑​αq ,k i ​​V k i ​​

在NMT任务里,输入句子的每个词都对应自身的query, key 和 value向量,是3个参数矩阵(要学习的量)去乘上这个时刻的词的表示(即embedding)得到的,它捕捉的是这个word和序列中其它词的相关性。

注意力机制的实现

代码:

from numpy import array
from numpy import random
from scipy.special import softmax

word1 = array([1, 0, 0])
word2 = array([0, 1, 0])
word3 = array([1, 1, 0])
word4 = array([0, 0, 1])

words = array([word1, word2, word3, word4])

random.seed(2022)
WQ = random.randint(3, size=(3, 3))
WK = random.randint(3, size=(3, 3))
WV = random.randint(3, size=(3, 3))

Q, K, V = words @ WQ, words @ WK, words @ WV

scores = Q @ K.transpose()

weights = softmax(scores / K.shape[1] ** 0.5, axis=1)

attention = weights @ V

print(attention)

手绘的原理阐释…

深入浅出Transformer原理与实现
这个阶段,也叫做self-attention机制,每个词都可以采样下所有词的信息

multi-head attention

有几个head,就有几个W Q , W K , W V WQ,WK,WV W Q ,W K ,W V的集合,也就是说同时存在多个self-attention
这样加强了对不同空间的表示能力
下图为有2个head的multi-head attention,每次注意力机制也会得到两组attention矩阵

深入浅出Transformer原理与实现
得到的多个attention矩阵(下图为Z i Z_i Z i ​),再拼接好,乘上一个新的权重矩阵W O W^O W O,得到一个总的attention矩阵Z Z Z:
深入浅出Transformer原理与实现

; 注意力丢掉的位置信息

使用上述方法去取代原来的seq2seq,还需要有一点需要注意,这里每个词得到了它的上下文相关的信息,但是因为使用的是权重和,仍然丢失掉了词语间的位置信息。
所以引入了一个新的组件叫做: 位置编码

位置可以看作一个维度和词向量embedding的维度大小相同的时序编码向量,将时序信息与词编码向量相加即得到带时序信息的词向量表示:

深入浅出Transformer原理与实现

那么这个时序向量具体长什么样呢,有一些例子直观感受下:

深入浅出Transformer原理与实现
下图是一个可以表示从0到19这20个位置(20行)的位置编码向量,每个格子的颜色值从-1到1,一共有512维(512列,根据实际情况的word embedding维度来)
为什么左右看上去像两张图?因为左边是sin生成的右边是cos生辰的。
深入浅出Transformer原理与实现
可以看到这个位置编码的生成没有太多好的理论支撑,所以后续也有非常多的工作试图提供更好的位置编码信息,比如:
不是简单的左右拼接而是交织在一起
深入浅出Transformer原理与实现

残差模块

Residual模块的主要作用就是用来防止深度网络的退化,它至少能保证深层网络的效果不会比更低层的训练效果更差。
下图是transformer里的encoder结构图,可以看到有个Add & Normalize的结构,其实就是残差结构,即输出Z Z Z和输入X X X相加,并且再进行了一次LayerNorm操作

深入浅出Transformer原理与实现
这里LayerNorm的作用也是想尽可能地让深度学习底层网络做的不是无用功,具体可以看详解深度学习中的Normalization

; encoder + decoder

这里的动图详解了encoder + decoder如何工作:

深入浅出Transformer原理与实现

深入浅出Transformer原理与实现

需要注意的是,解码阶段里,最下面的decoder的输入是所有encoder的输出, 并且会给decoder 输入含位置编码的向量。且在decoder阶段,self-attention层只被允许比t时刻早期的被采样到,所以会用到mask技术

深入浅出Transformer原理与实现
给注意力权重加一个mask,白色的部分即赋值为− ∞ – \infin −∞,即代表在输出阶段,t t t时刻的注意力只能采样< = t 时刻的向量信息(很符合常识,因为> t >t >t时刻的向量还没生成)

“Encoder-Decoder Attention”层工作原理非常类似于多头注意力机制,除了它的查询矩阵Q是从下面的decoder传过来的(而不是前一时刻的s t − 1 s_{t-1}s t −1 ​),还有K和V是来源于encoder的输出

至于最后的输出怎么转化为词,就靠linear + softmax一条龙了:

深入浅出Transformer原理与实现

损失函数

这里和传统的Seq2Seq一样,即比较两个概率分布(预测词的概率分布 vs 真实词的概率分布)的距离,使用交叉熵损失函数或Kullback-Leibler散度函数

Transformer架构一览

深入浅出Transformer原理与实现

使用6个Encoder, 6个Decoder
对每个Encoder: 拥有两个subnet,1个是Multi-Head Attention层,1个是全连接层
每个subnet都加上了Residual block,意味着每个subnet的输出是:
L a y e r N o r m ( x + s u b N e t ( x ) ) LayerNorm(x + subNet(x))L a y e r N o r m (x +s u b N e t (x ))

对每个Decoder:
同样由6个Decoder模块组成,每个Decoder层由两个subent + 1个额外的subnet组成,即在第一个subnet层多了Masked Multi-Head Attention,防止注意力关注后面还没输出的位置的信息,至于具体的处理方法就是上述提到的使用Masked 位置编码向量来实现,保证位置i i i产生的预测只依赖于已知的< i 的输出

注意力机制,即上述提到的self-attention,没有区别:

深入浅出Transformer原理与实现

这里还要除以一个d k \sqrt{d_k}d k ​​,为什么要除以d k \sqrt{d_k}d k ​​呢,是因为点积有可能会产生非常大的数,导致softmax反向传播会把梯度推向一个非常小的区域值,为了对抗这个影响作者决定除以维度大小。

多头注意力机制:
也和上面讲到的没有区别

深入浅出Transformer原理与实现

使用位置编码:

深入浅出Transformer原理与实现

和上面位置编码的第一张图一样,左边sin右边cos,后期有很多优化这方面的工作

Original: https://blog.csdn.net/qq_30219017/article/details/122025555
Author: Alanaker
Title: 深入浅出Transformer原理与实现

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/544966/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球