attention和transformer都是面试重点。
文章目录
- 3 seq2seq+Attention
- 3.1 Sequence to Sequence Model
- 3.1.2 模型介绍
- 3.1.2 模型训练
- 3.2注意力机制
- 3.2.1介绍
- 3.2.1“Bahdanau” style attention
- 3.2.2“Luong” style attention
- 4 Transformer
- 4.1 Multi-head Attention
- 4.1.1 自注意力机制
- 4.1.2 自注意力机制加强版
- 4.1.3 Multi-head Attention
- 4.2 残差链接
- 4.3 layer norm
- 4.4 前馈神经网络以及后续操作
- 4.5解码器部分
3 seq2seq+Attention
3.1 Sequence to Sequence Model
3.1.2 模型介绍
Sequence to Sequence Model解决y=f(x)的问题。
x是一个序列,y是一个序列。
最常应用于翻译问题。
模型包含编码器和解码器2部分。
编码器:输入序列编码为隐变量 。用RNN作为大体结构。得到一个隐变量h。
解码器:auto-regressive自回归解码套路
对于一个序列使用前t-1个输出,预测第t个输出,这种方式称为自回归
第一步:输入编码器得到的隐变量h,以及特殊字符<SOS> start of sentence输出解码得到的词y1,以及隐状态h0假设词库有10万个词,h0是一个10万维的向量,在这一时刻哪个词的可能性最大,则这个位置的概率最大。y1 是概率最大的那个词第二步:输入y1,h0输出y2,以及隐状态h1第三步:输入y2,h1是输出y3,以及隐状态h2......一直到解码出来特殊字符例如EOS停止解码,或者解码到一定长度停止。解码器只能是单向的,但是可以堆叠多层的网络
模型中包含的参数
1 解码器参数 θ1\theta_1θ1
2 解码器参数 θ2\theta_2θ2
3 词向量矩阵 θ3\theta_3θ3 ,随机初始化(这个词向量可以用skip-gram模型学出来的值吗?)
4 h0′h_0'h0′,h1′h_1'h1′…映射到词表上的那个矩阵 θ4\theta_4θ4
3.1.2 模型训练
- 要点1:模型是一个求条件概率的过程
y=F(x) 等价于 P(Y|X) 就是拟合了一个条件概率分布
P(Y∣X)=P(y1,y2...yn∣X)=P(y1∣X)P(y2∣y1,X)P(y3∣y1,y2,X)...=∏i=1nP(yi∣y1,y2...yi−1,X)P(Y|X) =P(y_1,y_2...y_n|X) = P(y_1|X)P(y_2|y_1,X)P(y_3|y_1,y_2,X)...=\prod_{i=1}^nP(y_i|y_1,y_2...y_{i-1},X)P(Y∣X)=P(y1,y2...yn∣X)=P(y1∣X)P(y2∣y1,X)P(y3∣y1,y2,X)...=∏i=1nP(yi∣y1,y2...yi−1,X)
预测y2: P(y2∣y1,h)=P(y2∣y1,X)P(y_2|y_1,h) = P(y2|y1,X)P(y2∣y1,h)=P(y2∣y1,X),hhh是由X决定的。
每一个时间步,做的是条件概率分布,做一个分类,损失函数交叉熵损失。所有时间的损失加起来就是整个loss。
- 要点2:输入词向量和输出词向量绑定
参数θ3\theta_3θ3称为输入词向量
参数θ4\theta_4θ4称为输出词向量
假如词库有10万词,词向量的维度是100。
参数θ4\theta_4θ4是一个10万x100的矩阵,h0′h_0'h0′是 一个100维的向量, θ4\theta_4θ4xh0′h_0'h0′=10万维的向量,得到每个词的概率分布。
参数θ3\theta_3θ3 和参数θ4\theta_4θ4 维度一样。可以共享。可以降低计算量。 换句话说 输入词向量和输出词向量绑定。
- 要点3:teacher forcing
在第二个位置预测出一个错误的词,怎么办?
每次给下一阶段的词都是正确的词,称为teacher forcing
每次使用预测出来的词给下一阶段,称为非teacher forcing 。这样的模型具有纠错功能
3.2注意力机制
3.2.1介绍
注意力机制是seq2seq带给nlp最好的礼物。
上面模型的问题是,只有编码器的最后一个输出,作为解码器的输入。这样会导致前面的输入会忘记,影响力会低。
我们希望h1,h2,h3,h4h_1,h_2,h_3,h_4h1,h2,h3,h4都能参与到解码器的计算中。这样就需要给他们分配一个权重,那这个权重怎么学习呢?
我们把编码器的输出变量h1,h2,h3,h4h_1,h_2,h_3,h_4h1,h2,h3,h4称为value。
把解码器的每一步输出hi′h_i'hi′称为query。
使用(query,key)对计算权重。key就是h1,h2,h3,h4h_1,h_2,h_3,h_4h1,h2,h3,h4。
上一步得到的权重与value(这里仍然是h1,h2,h3,h4h_1,h_2,h_3,h_4h1,h2,h3,h4)加权平均得到注意力输出。
这样的模式可以推广到所有需要注意力模型的地方。
value通常是上一个阶段的输出,key和value是一样的。
query通常是另外的一个向量。
使用 (query,key) 进行加权求和,得到的值作为权重,再对value进行加权求和。
这样的话在decoder阶段,每一步的输入会有3个变量:编码器经过注意力加权后的输出h(这个时候的query是hi−1′h_{i-1}'hi−1′),解码器上一步的隐状态hi−1′h_{i-1}'hi−1′,上一步的输出yi−1y_{i-1}yi−1。
这里的公式可以参考第八课 RNN条件生成与Attention机制的2.2。
3.2.1“Bahdanau” style attention
论文:Dzmitry Bahdanau, KyungHyun Cho, Yoshua Bengio. Neural Machine Translation by Jointly Learning to Align and Translation
Bahdanau是注意力机制的一种计算方法,也是现在很多工具包中的实现方法。
输入是X1,X2...XTX_1,X_2...X_TX1,X2...XT,经过RNN之后得到多个隐状态h1,h2,...hTh_1,h_2,...h_Th1,h2,...hT。
我们使用这里的隐状态作为key和value,使用解码器的上一步隐状态si−1s_{i-1}si−1作为query。
如何计算第i步,每个隐状态的权重呢?
P(yi∣y1,y2...yi−1,X)=g(yi−1,si,ci)P(y_i|y_1,y_2...y_{i-1},X) = g(y_{i-1},s_i,c_i)P(yi∣y1,y2...yi−1,X)=g(yi−1,si,ci) 在计算第i步的输出的时候,与上一步的输出,这一步的隐状态以及第i步的contex有关系。
si=f(si−1,yi−1,ci)s_i=f(s_{i-1},y_{i-1},c_i)si=f(si−1,yi−1,ci) 第i步的隐状态是关于上一步的隐状态,上一步的输出以及第i步的contex的函数。
ci=∑j=1Txαijhjc_i=\sum_{j=1}^{T_x}\alpha_{ij}h_jci=∑j=1Txαijhj 第i步的context是解码器所有隐状态的加权平均。
αij=exp(eij)∑j=1Txexp(eik)\alpha_{ij}=\dfrac{exp(e_{ij})}{\sum_{j=1}^{T_x}exp(e_{ik})}αij=∑j=1Txexp(eik)exp(eij)
eij=a(si−1,hj)e_{ij}=a(s_{i-1,h_j})eij=a(si−1,hj)
加权平均的参数αij\alpha_{ij}αij是这样计算的:解码器上一步的隐状态拼接hjh_jhj得到一个2n维的向量,使用一个2nx1维度的矩阵乘以这个向量得到eije_{ij}eij,对eije_{ij}eij过softmax得到权重参数。
对上面的过程再做一次梳理:
当前处于解码器中的第i步
在解码器中上一步的隐状态si−1s_{i-1}si−1,上一步的输出yi−1y_{i-1}yi−1,这一步的上下文向量cic_ici
在编码器中的最后输出的隐状态为h1h_1h1,h2h_2h2,h3h_3h3,h4h_4h4
为了计算cic_ici,需要使用注意力机制来解决。
value : h1h_1h1,h2h_2h2,h3h_3h3,h4h_4h4
query : si−1s_{i-1}si−1
key : h1h_1h1,h2h_2h2,h3h_3h3,h4h_4h4
我们会使用(query,key)计算value的权重。对于其中第j个权重的计算方式是这样的:
eij=a(si−1,hj)e_{ij}=a(s_{i-1,h_j})eij=a(si−1,hj) # 这里是将两个向量拼接
αij=exp(eij)∑j=1Txexp(eik)\alpha_{ij}=\dfrac{exp(e_{ij})}{\sum_{j=1}^{T_x}exp(e_{ik})}αij=∑j=1Txexp(eik)exp(eij) #这里会保证权重和为1。这里Tx=4{T_x}=4Tx=4
ci=∑j=1Txαijhjc_i=\sum_{j=1}^{T_x}\alpha_{ij}h_jci=∑j=1Txαijhj #计算得到上下文向量,Tx=4{T_x}=4Tx=4
si=f(si−1,yi−1,ci)s_i=f(s_{i-1},y_{i-1},c_i)si=f(si−1,yi−1,ci) #得到第i步的隐状态
P(yi∣y1,y2...yi−1,X)=g(yi−1,si,ci)P(y_i|y_1,y_2...y_{i-1},X) = g(y_{i-1},s_i,c_i)P(yi∣y1,y2...yi−1,X)=g(yi−1,si,ci) #得到第i步的输出
3.2.2“Luong” style attention
在解码器计算第i步的时候:
先用ht−1h_{t-1}ht−1和yt−1y_{t-1}yt−1计算得到hth_tht,使用hth_tht作为query。而在Bahdanau中是使用ht−1h_{t-1}ht−1作为query的。
编码器的隐状态作为key和value。计算得到cic_ici。
拼接cic_ici和hth_tht,作为输入,去预测得到h~i\tilde{h}_ih~i,再用h~i\tilde{h}_ih~i预测得到yiy_iyi。
这样做的好处是,可以在解码的时候堆叠很多层。让解码做得更好。
对(query,key)的处理,文章中提到了多种。
文章中还提供了local attention机制。随着算力提升,这种策略也不再流行了。
4 Transformer
2017年某一天,有人提出将seq2seq中的RNN去掉,只留下attention。这样的模型就是Transformer。
论文:Attention is All You Need
transformer由编码器和解码器两部分构成。
这里有很重要的三种操作是Multi-head Attention、残差链接和Add&Norm(层正则化)。
4.1 Multi-head Attention
Multi-head Attention是自注意力机制的一种特殊情况。
4.1.1 自注意力机制
自注意力机制是指注意力机制中的query不是别的向量,而是自己序列本身。
例如在学习x2x_2x2的权重参数值时候,使用x2x_2x2作为query,x1,x3,x4x_1,x_3,x_4x1,x3,x4作为key和value。
对每个位置都计算得到权重参数,然后加权平均得到y2y_2y2。
同理y3,y4,y1y_3,y_4,y_1y3,y4,y1的计算也是一样。
dkd_kdk是embedding的维度。在归一化之前会对每一个分数除以定值(embedding的维度开根号)。这样可以让softmax的分布更加平滑。
4.1.2 自注意力机制加强版
增强版的自注意力机制是
1 不使用x2x_2x2作为query,而是先对x2x_2x2做线性变换:Wqx2W_qx_2Wqx2,之后的向量作query。
2 x1,x3,x4x_1,x_3,x_4x1,x3,x4不直接作为key和value,而是先做线性变换之后再做key和value。Wkx1W_kx_1Wkx1作为key,Wvx1W_vx_1Wvx1作为value。
其余步骤相同。
这样的模型有更多的参数,模型性能也更加强大。
4.1.3 Multi-head Attention
在每一步计算的时候,对于向量映射之后再输入到模型。例如xix_ixi是一个100维的向量。h=5,那就是对query,key,value做5次映射,将其转换到一个20维的空间。将query、key、value都做这样的拆分。分别在5组向量上面做self-attention。得到5个20维的向量,然后拼接起来称为一个100维的向量。
不同head的长度一样,但是映射参数是不一样的。
这5次映射参数不同。
公式如下:
输入X,包含token embedding和position embedding
- 对X做变换
Qi=QWiQQ^i=QW^Q_iQi=QWiQ,Ki=KWiKK^i=KW^K_iKi=KWiK,Vi=VWiVV^i=VW^V_iVi=VWiV
每一次映射不共享参数,每一次映射会有WiQ,WiK,WiV)W^Q_i,W^K_i,W^V_i)WiQ,WiK,WiV)三个参数。
- 对多头中的某一组做attention
Attention(Qi,Ki,Vi)=KiQiTdkViAttention(Q_i,K_i,V_i)=\dfrac{K_iQ_i^T}{\sqrt{d_k}}V_iAttention(Qi,Ki,Vi)=dkKiQiTVi
headi=Attention(Qi,Ki,Vi)head_i=Attention(Q_i,K_i,V_i)headi=Attention(Qi,Ki,Vi)
h组并行计算
- 拼接之后输出
MultiHead(Q,K,V)=Concat(head1,head2,...head5)MultiHead(Q,K,V)=Concat(head_1,head_2,...head_5)MultiHead(Q,K,V)=Concat(head1,head2,...head5)
经过multi-head之后,得到h1,h2,h3,h4h_1,h_2,h_3,h_4h1,h2,h3,h4。
4.2 残差链接
残差链接是这样的。
将输入x加到multi-head的输出h上。这样可以加快训练。
这一步得到的结果记为h1′,h2′,h3′,h4′h_1',h_2',h_3',h_4'h1′,h2′,h3′,h4′。
4.3 layer norm
层正则化,是对残差链接的结果做正则化。
对h1′,h2′,h3′,h4′h_1',h_2',h_3',h_4'h1′,h2′,h3′,h4′这4个向量分别计算每个向量的均值μ\muμ和方差σ\sigmaσ。
γ\gammaγ和β\betaβ是共享的参数,在模型中需要训练。
γ\gammaγ和β\betaβ可以在一定程度上抵消掉正则的操作。为什么正则了又要抵消呢?
这样做可以让每一个时间步的值更平均一些,差异不会特别大。
这一步的输出是h1′′,h2′′,h3′′,h4′′h_1'',h_2'',h_3'',h_4''h1′′,h2′′,h3′′,h4′′。
4.4 前馈神经网络以及后续操作
对于上一步的结果加一个前馈神经网络。
FFN(x)=max(0,xW1+b1)W2+b2FFN(x) = max(0, xW_1 + b_1 )W_2 + b_2FFN(x)=max(0,xW1+b1)W2+b2
在每一个时间步会做一个y=F(x)的变化,得到另外的100维的向量。
对这一步的结果再加一个残差链接和层正则化。
这样就得到一个transformer block。
4.5解码器部分
解码器和编码器差不多。
解码器有一个master multi head attention。就是说在解码的时候,每一个时间步只能看到它前面的状态。例如在计算x2x_2x2的参数时候,x2x_2x2作为query,能作为key和value的只有x1x_1x1。
还有一点不同是
这里是以解码器的输出作为key和value,这一时间步的输出作为query计算attention。
假设两层encoder+两层decoder组成一个transformer block,其结构如下:
例如在t=3时刻,decoder的输入有t=1,t=2时刻的输出,先过一个self-attention+add & Formlalize,得到输出output3output_3output3
解码器的输出,作为key和value,output3output_3output3作为query,做attention。
经过一个add & Formlalize。
做一层linear&softmax,输出在这个时刻,在每个词上的概率。
重点阅读链接:
https://jalammar.github.io/illustrated-transformer/
中文翻译