如何在堆叠LSTM模型中使用Bahdanau注意力?Keras实现咨询
问题判断
你对x = AdditiveAttention(x, x)写法错误的判断是完全正确的,错误原因包含两点:
- Keras的
AdditiveAttention层入参要求是长度为2的列表输入,格式为[查询(query), 值(value)],直接传两个位置参数会触发语法报错,正确的调用格式是AdditiveAttention()([query, value]) - 即使调整为符合语法的
AdditiveAttention()([x, x]),也不符合你的需求:这种写法属于自注意力计算,而你的需求是解码器侧的状态作为查询、编码器输出的全部隐状态作为值做注意力匹配,二者逻辑完全不同。
符合需求的Keras高层实现代码
你给出的基础代码属于堆叠LSTM的分类结构,要加入编码器-解码器结构的Bahdanau注意力,调整后完整可运行代码如下:
import tensorflow as tf from tensorflow.keras.layers import Input, LSTM, AdditiveAttention, Dense from tensorflow.keras.models import Model # 超参数定义 T = 100 # 输入序列长度 f = 12 # 单时间步输入特征维度 num_neurons1 = 64 # 编码器LSTM神经元数 num_neurons2 = 32 # 解码器LSTM神经元数 input_layer = Input(shape=(T, f)) # 编码器:返回全部时间步隐状态,作为注意力的value输入 encoder_out = LSTM(num_neurons1, return_sequences=True)(input_layer) # 解码器:返回全部时间步隐状态,作为注意力的query输入,每个解码器时间步都会查询编码器全局隐状态 decoder_out = LSTM(num_neurons2, return_sequences=True)(encoder_out) # 加性注意力(Bahdanau)计算 attention_out = AdditiveAttention()([decoder_out, encoder_out]) # 对注意力输出做全局平均池化后送入分类层 x = tf.keras.layers.GlobalAveragePooling1D()(attention_out) output_layer = Dense(1, activation='sigmoid')(x) model = Model(input_layer, output_layer) model.summary()
简化场景适配
如果你的分类任务不需要保留解码器完整序列输出,想对齐你原来的代码结构(第二个LSTM只返回最后一个时间步状态),可以用以下简化写法:
# 编码器部分不变 encoder_out = LSTM(num_neurons1, return_sequences=True)(input_layer) # 解码器只返回最后一个时间步的隐状态 decoder_final = LSTM(num_neurons2, return_sequences=False)(encoder_out) # 为query增加长度为1的时间步维度,匹配注意力层输入维度要求 decoder_final = tf.expand_dims(decoder_final, axis=1) # 注意力计算 attention_out = AdditiveAttention()([decoder_final, encoder_out]) # 去掉多余的时间步维度后送入分类层 x = tf.squeeze(attention_out, axis=1) output_layer = Dense(1, activation='sigmoid')(x)
内容的提问来源于stack exchange,提问作者Mohammad
相关产品推荐
相关产品推荐

