在 Tensorflow 2.0 中的简单 LSTM 层之上添加注意力
Posted
技术标签:
【中文标题】在 Tensorflow 2.0 中的简单 LSTM 层之上添加注意力【英文标题】:Adding Attention on top of simple LSTM layer in Tensorflow 2.0 【发布时间】:2020-03-16 21:51:05 【问题描述】:我有一个由一个 LSTM 和两个 Dense 层组成的简单网络:
model = tf.keras.Sequential()
model.add(layers.LSTM(20, input_shape=(train_X.shape[1], train_X.shape[2])))
model.add(layers.Dense(20, activation='sigmoid'))
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(loss='mean_squared_error')
为了分类目的,它对具有 3 个输入(归一化 0 到 1.0)和 1 个输出(二进制)的数据进行训练。数据是时间序列数据,其中时间步长之间存在关系。
var1(t) var2(t) var3(t) var4(t)
0 0.448850 0.503847 0.498571 0.0
1 0.450992 0.503480 0.501215 0.0
2 0.451011 0.506655 0.503049 0.0
模型是这样训练的:
history = model.fit(train_X, train_y, epochs=2800, batch_size=40, validation_data=(test_X, test_y), verbose=2, shuffle=False)
model.summary()
给出模型总结:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
lstm (LSTM) (None, 20) 1920
_________________________________________________________________
dense (Dense) (None, 20) 420
_________________________________________________________________
dense_1 (Dense) (None, 1) 21
=================================================================
Total params: 2,361
Trainable params: 2,361
Non-trainable params: 0
该模型运行良好。现在我正在尝试用注意力层替换 Dense(20) 层。在线的所有示例、教程等(包括 TF 文档)都是针对在输入层具有嵌入层的 seq2seq 模型。我了解 TF v1.x 中的 seq2seq 实现,但我找不到任何我想要做的文档。我相信新的 API (v2.0) 我需要做这样的事情:
lstm = layers.LSTM(20, input_shape=(train_X.shape[1], train_X.shape[2]), return_sequences=True)
lstm = tf.keras.layers.Bidirectional(lstm)
attention = layers.Attention() # this does not work
model = tf.keras.Sequential()
model.add(lstm)
model.add(attention)
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(loss='mean_squared_error')
当然我得到错误“必须在输入列表上调用注意力层,即[查询,值]或[查询,值,键]”
我不明白版本 (2.0) 和这种情况下的解决方案(具有固定长度输入的时间序列数据)。欢迎任何关于增加对此类问题的关注的想法。
【问题讨论】:
这里有一个简单的解决方案来增加关注:***.com/questions/62948332/… 【参考方案1】:我最终从 pypi.org 上的库中找到了该问题的两个答案。第一个是self-attention,可以用Keras(Keras的TF 2.0前集成版)实现如下...
model = keras.models.Sequential()
model.add(keras.layers.LSTM(cfg.LSTM, input_shape=(cfg.TIMESTEPS,
cfg.FEATURES),
return_sequences=True))
model.add(SeqSelfAttention(attention_width=cfg.ATTNWIDTH,
attention_type=SeqSelfAttention.ATTENTION_TYPE_MUL,
attention_activation='softmax',
name='Attention'))
model.add(keras.layers.Dense(cfg.DENSE))
model.add(keras.layers.Dense(cfg.OUTPUT, activation='sigmoid'))
第二种方法是more general solution,它与 TF 2.0 后集成的 Keras 一起使用,如下所示...
model = tf.keras.models.Sequential()
model.add(layers.LSTM(cfg.LSTM, input_shape=(cfg.SEQUENCES,
train_X.shape[2]),
return_sequences=True))
model.add(Attention(name='attention_weight'))
model.add(layers.Dense(train_Y.shape[2], activation='sigmoid'))
它们各自的行为略有不同,并产生非常不同的结果。自注意力库将维度从 3 减少到 2,并且在预测时您会得到每个输入向量的预测。一般注意力机制维护 3D 数据并输出 3D,并且在预测时您只能获得每批的预测。如果您希望对每个输入向量进行预测,您可以通过将预测数据重塑为批量大小为 1 来解决此问题。
就结果而言,self-attention 确实比单独的 LSTM 产生了更好的结果,但并不比其他增强功能(例如 dropout 或更密集的层等)更好。一般的注意力似乎没有为 LSTM 模型增加任何好处在许多情况下,情况会变得更糟,但我仍在调查。
无论如何,它是可以做到的,但到目前为止,是否应该这样做是值得怀疑的。
【讨论】:
感谢这篇文章和相应的答案。我面临同样的问题并尝试了第二个通用解决方案。但是,它现在给了我一种完全不同的错误——IndexError: list index out of range [指向我添加注意力层的行]。我想补充一点,注意层之前的层是 LSTM 层,而注意层之后的层是密集层(n_outputs,activation = 'softmax')。任何帮助将不胜感激。提前致谢。以上是关于在 Tensorflow 2.0 中的简单 LSTM 层之上添加注意力的主要内容,如果未能解决你的问题,请参考以下文章
python tensorflow 2.0 不使用 Keras 搭建简单的 LSTM 网络