文本生成:加入注意力( Attention )机制的 Seq2Seq
1. 加入Attention机制的Seq2Seq模型注意力层(Attention)添加到解码器与输出层之间,它负责从编码器输出序列中挑选出任务相关的信息,将其与解码器输出序列最后时刻状态一起传入输出层,供文本生成预测使用。如下图所示:图1加入Attention机制的Seq2Seq 模型Attention机制在计算注意力分布之前,引入由编码器(Encoder)输入序列长度决定的mask矩阵与注意力得
1. 模型原理
注意力(Attention)层添加在解码器与输出层之间,它负责从编码器输出序列中挑选出与任务相关的信息,和解码器输出序列最终时刻状态一起作为文本生成的特征,传递给输出层。如下图所示:
图中注意力(Attention)层中,在计算注意力分布之前添加inputs_padding_mask操作,来消除输入序列中padding值带来的噪声干扰。
它为注意力得分(attention score)矩阵添加一个 inputs_padding_mask 矩阵乘数项,令两矩阵元素对位相乘(矩阵数乘)后再给所有0值元素添加一个无穷小项,使经过softmax计算后:注意力分布(attention distribution)中,所有padding添加位置的元素的概率都为0,且所有真实长度位置的元素的概率之和为1。
值得注意的是,如果将inputs_padding_mask操作添加到计算注意力分布之后(即:将inputs_padding_mask矩阵与注意力分布矩阵元素对位相乘)那么虽可保证所有padding添加位置的元素的概率都为0,但所有真实长度位置的元素的概率之和不为1;这可以理解为一部分注意力被平白消散了,(注意力)没有全部集中于输入序列的有效位置元素之上。
2. 代码实现
2.1 基于TensorFlow框架的实现
from EncoderDecoder import *
from Attention import *
class Seq2Seq(EncoderDecoder):
"""readme:
v1.0 初代版本,实现了基础版本的Seq2Seq模型,并引入了注意力机制(选用点积打分函数)
v1.1 更新掩码矩阵生成成方法,令其可以满足多头注意力机制和多头自注意力机制的任务需求
"""
def __init__(self, vocab_size, embed_size, word2index, index2word,
num_hiddens, num_encds=1, num_decds=1,
enc_dropout=0, enc_rtseq=True, enc_rtstate=True,
dec_dropout=0, dec_rtseq=True, dec_rtstate=True,
**kwargs):
super().__init__(**kwargs)
self.word2index = word2index
self.index2word = index2word
self.Hidden = tf.keras.layers.GRU
# model
self.Embed = layers.Embedding(vocab_size, embed_size)
self.Encoders = [
self.Hidden(num_hiddens, dropout=enc_dropout, return_sequences=enc_rtseq, return_state=enc_rtstate) for i in
range(num_encds)]
self.Decoders = [
self.Hidden(num_hiddens, dropout=dec_dropout, return_sequences=dec_rtseq, return_state=dec_rtstate) for i in
range(num_decds)]
self.Attention = Attention()
self.Output = layers.Dense(vocab_size, activation='Softmax')
def call(self, X, **kwargs):
"""
Input:
:X_len: 样本特征序列的实际长度
:y: 采用序号编码的样本标签序列
:y_len: 样本标签序列的实际长度
Output:
:y_hat: a
:outputs: a
"""
X_len = kwargs['X_len']
y = kwargs['y']
enc_hiddens = []
last_enc_hidden = None
dec_hiddens = []
last_dec_hidden = None
outputs = []
# Encoder
enc_hiddens = self.Embed(X)
for Encd in self.Encoders:
enc_hiddens, last_enc_hidden = Encd(enc_hiddens)
# Decoder
y_hat = tf.constant([self.word2index['<bos>']] * y.shape[0], shape=[y.shape[0], 1], dtype=y.dtype)
for _ in range(y.shape[1]):
dec_hiddens = self.Embed(y_hat)
for Decd in self.Decoders:
dec_hiddens, last_dec_hidden = Decd(dec_hiddens, initial_state=last_enc_hidden)
# Attention
attention = self.Attention(enc_hiddens, queries=last_dec_hidden, input_len=X_len)
output_features = tf.concat([last_dec_hidden, attention], axis=1)
# Output
output = self.Output(output_features)
token = tf.cast(tf.reshape(tf.argmax(output, axis=1), shape=[-1, 1]), dtype=y.dtype)
y_hat = tf.concat([y_hat, token], axis=1)
outputs.append(tf.reshape(output, shape=[output.shape[0], 1, output.shape[1]]))
y_hat = y_hat[:, 1:]
outputs = tf.concat(outputs, axis=1)
return y_hat, outputs
2.2 基于Pytorch框架的实现

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐
所有评论(0)