seq2seq tensorflow实现 以及attention机制带来的影响

###占位
raw_enc_input = tf.placeholder(tf.int32,(batch,None))
raw_dec_input = tf.placeholder(tf.int32,(batch,None))
raw_output = tf.placeholder(tf.int32,(batch,None))
enc_sen = tf.placeholder(tf.int32,(None))
dec_sen = tf.placeholder(tf.int32,(None))

###EMBED
##encoder
enc_embed = tf.Variable(tf.random_uniform((enc_vocab,enc_dim),-1,1))
enc_input = tf.nn.embedding_lookup(enc_embed,raw_enc_input)
ch_enc_input = tf.layers.dense(enc_input,enc_dim,use_bias=False)

##decoder
dec_embed = tf.Variable(tf.random_uniform((dec_vocab,dec_dim),-1,1))
dec_input = tf.nn.embedding_lookup(dec_embed,raw_dec_input)
ch_dec_input = tf.layers.dense(dec_input,dec_dim,use_bias=False)

#real output
query_lis = [1.0] * dec_vocab
query_embed = tf.Variable(tf.matrix_diag(query_lis),trainable=False)
real_output = tf.nn.embedding_lookup(query_embed,raw_output)

###RNN_CELL
##encoder
with tf.name_scope('encoder'):
    enc_cell = tf.nn.rnn_cell.MultiRNNCell([tf.nn.rnn_cell.BasicRNNCell(enc_units) for _ in range(3)])
    #enc_cell = tf.nn.rnn_cell.BasicRNNCell(enc_units)
    enc_h0 = enc_cell.zero_state(batch,tf.float32)
    enc_output,enc_out_state = tf.nn.dynamic_rnn(enc_cell,ch_enc_input,initial_state=enc_h0,sequence_length=enc_sen,scope='encoder')
#enc_output -> (batch,len,enc_units)

##decoder
with tf.name_scope('decoder'):
    dec_cell = tf.nn.rnn_cell.MultiRNNCell([tf.nn.rnn_cell.BasicRNNCell(dec_units) for _ in range(3)])
    #dec_cell = tf.nn.rnn_cell.BasicRNNCell(dec_units)
    dec_h0 = dec_cell.zero_state(batch,tf.float32)
    dec_output,dec_out_state = tf.nn.dynamic_rnn(dec_cell,ch_dec_input,initial_state=enc_out_state,sequence_length=dec_sen,scope='decoder')
#dec_out_state -> (batch,dec_units)


###ATTENTION
shuf = tf.expand_dims(dec_output,-1) #(batch,len,enc_units,1)
enc_output_shuf = tf.tile(tf.expand_dims(enc_output,1),[1,max_len,1,1]) #(batch,len,len,enc_units)
soft = tf.nn.softmax(tf.matmul(enc_output_shuf,shuf))#(batch,len,len,1)
enc_out_shuf = tf.transpose(enc_output_shuf,[0,1,3,2])#(batch,len,enc_units,len)
attention = tf.matmul(enc_out_shuf,soft)#(batch,len,enc_units,1)
fin_attention = tf.squeeze(attention,-1) #(batch,len,enc_units)

###concat
fin_out = tf.tanh(tf.concat((fin_attention,dec_output),-1)) #(batch,len,2 * enc_units)

###ln
# mean, variance = tf.nn.moments(fin, [-1], keep_dims=True)
# normalized = (fin - mean) / ((variance + 0.000001) ** (.5))
# fin_out = tf.layers.dense(
#     normalized,(dec_units+enc_units),
#     kernel_initializer = tf.initializers.zeros(),
#     bias_initializer = tf.initializers.ones(),
#     activation=None
# )

#output
output = tf.layers.dense(fin_out,
                         dec_vocab,
                         activation = None,
                         bias_initializer = tf.initializers.zeros(),
                         kernel_initializer = tf.initializers.random_uniform(-0.1,0.1),
                         kernel_regularizer = tf.contrib.layers.l2_regularizer(0.0003),
)



loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=output,labels=real_output),-1)+ tf.add_n(tf.get_collection('regularization_losses'))


train = tf.train.AdamOptimizer(0.001).minimize(loss)

实在不是写文章的料直接总结了。

总结

1.没有attention的seq2seq和seq2seq是两个东西(从翻译效果上来看)
2.序列倒着输入更好

就三句话做测试
i love father -> 我爱爸爸
i am your father -> 我是你的爸爸
i am your mother -> 我是你的妈妈

seq2seq测试单个单词结果
father 单词输出为 我爱爸爸
mother 输出为 我是你的妈妈

seq2seq + attention测试结果
father 单词输出为 爸爸爸
mother 输出为 妈妈妈

可以看出没有attention的seq2seq更像是一个分类器,有点像 “序列到一句话” 而不是“序列到序列”
当然batch太小也是诱因之一,不能很好的获得单词间的关系。

但是同样的样本下,带attention的,才真的是“序列到序列”。

很久以前刚提出seq2seq的时候google也提到序列倒着进去比较好。在实现attention的时候发现了确实如此,因为先计算了点积,所以encoder的末状态,也就是decoder 初始状态最后的attention的softmax得到的比重肯定大,能很好的建立attention。
还有一层原因,也是猜测,decoder其实有点像语言模型,我给出前两个字第三个字大概率是什么,因此,如果你前面翻译的越准确,如果样本足够多后面猜测的字也更准。所以序列倒着进去,让翻译的开头信息尽可能的少的损失。

TensorFlow 2.x 中,tf.contrib.seq2seq.AttentionWrapper 已被弃用。相反,可以使用 tf.keras.layers.Attention 类来实现注意力机制。 下面是一个使用 tf.keras.layers.Attention 的示例: ```python import tensorflow as tf # 定义一个 Attentionattention = tf.keras.layers.Attention() # 输入序列的形状为 (batch_size, seq_len, embedding_dim) encoder_inputs = tf.keras.Input(shape=(None, embedding_dim)) decoder_inputs = tf.keras.Input(shape=(None, embedding_dim)) # 编码器 LSTM 层 encoder_lstm = tf.keras.layers.LSTM(units=hidden_size, return_sequences=True, return_state=True) encoder_outputs, state_h, state_c = encoder_lstm(encoder_inputs) # 解码器 LSTM 层 decoder_lstm = tf.keras.layers.LSTM(units=hidden_size, return_sequences=True, return_state=True) decoder_outputs, _, _ = decoder_lstm(decoder_inputs, initial_state=[state_h, state_c]) # 注意力机制 context_vector, attention_weights = attention([decoder_outputs, encoder_outputs]) # 输出层 output = tf.keras.layers.Dense(vocab_size, activation='softmax')(context_vector) # 定义模型 model = tf.keras.Model(inputs=[encoder_inputs, decoder_inputs], outputs=output) ``` 在上面的代码中,我们首先定义了一个 tf.keras.layers.Attention 层。然后,我们定义了编码器和解码器 LSTM 层,并使用它们分别对编码器输入和解码器输入进行编码。 接下来,我们使用注意力层对解码器输出和编码器输出进行注意力计算,得到上下文向量和注意力权重。 最后,我们使用一个全连接层对上下文向量进行预测,得到输出结果。 希望这个例子可以帮助你理解如何在 TensorFlow 2.x 中使用注意力机制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值