bahdanau注意力
bahdanau注意力机制的初心
本意是为了seq2seq学习而设计出的编码器解码器架构,有个弊端。
对于编码器:
h(t) = f ( x(t), h(t-1) ),每一时间步的隐状态由前一步的隐状态,和输入x(t) 决定。
c = g( h(t), h(t-1), h(t-2), …. , h(1) ), 最终得到的上下文变量由隐藏状态决定。
ps: 一般而言这个g函数,就是选择最后一个隐状态。
对于解码器:
s(t) = g( y(t-1), s(t-1), c ), 每一时间步的隐状态由前一步隐状态, 和输出y(t-1), 和由编码器来的上下文变量c决定。
y(t) = o( s(t), c), 输出y(t)由当前隐状态和上下文变量决定。
这就是编码解码器架构,简单的四个公式决定。
但是这里有个问题,这个c,上下文变量在解码的过程中,从来没有变过。
Attention = Sum( a(q, k) * v ),注意力汇聚公式:
c(t) = Sum( a(s(t-1), h(t) ) * h(t) ), 为了改善c从来没变过的事实:把query设置为解码器的隐变量s(t-1),key和value设置为编码器隐变量h(t)。
这个时候c(t)蕴含了X(t1, t2,….t), Y(t1, t2,… t-1)的信息,非常利于预测下一个时间步的值。
举个例子:X(t1, t2,….t) = “l love you”, Y(t1, t2,… t-1)=”我爱“, 下一个时间步预测出”你“
代码
基本seq2seq基类
1 | import torch |
训练代码
1 | def sequence_mask(X, valid_len, value=0): |
注意力评分函数
1 | class AdditiveAttention(nn.Module): |
注意力seq2seq模型,bahdanau注意
1 | class AttentionDecoder(d2l.Decoder): |
测试形状
1 | encoder = d2l.Seq2SeqEncoder(vocab_size=10, embed_size=8, num_hiddens=16, |
训练
1 | embed_size, num_hiddens, num_layers, dropout = 32, 32, 2, 0.1 |
运行结果
1 | engs = ['go .', "i lost .", 'he\'s calm .', 'i\'m home .'] |