我想通过从Bengio 等人的《 Learning Long-Term Dependencies with Gradient Descent is Difficult》一文中重做一个实验,更好地理解为什么 LSTM 可以比普通/简单循环神经网络 (SRNN) 记住更长的时间。1994 年。
参见那张纸上的图 1 和图 2。任务很简单,给定一个序列,如果它以高值(例如1)开始,那么输出标签为1;如果它以低值(例如 -1)开始,则输出标签为 0。中间是噪声。这个任务被称为信息锁存,因为模型需要在通过中间噪声时记住起始值才能输出正确的标签。它使用单个神经元 RNN 来构建表现出这种行为的模型。图 2(b) 显示了结果,训练这种模型的成功频率随着序列长度的增加而急剧下降。LSTM 没有结果,因为它在 1994 年还没有发明。
所以,我变得好奇,想看看 LSTM 是否真的能更好地完成这样的任务。同样,我为 vanilla 和 LSTM 单元构建了单个神经元 RNN,以对信息锁存进行建模。令人惊讶的是,我发现 LSTM 的表现更差,我不知道为什么。谁能帮我解释一下,或者我的代码有什么问题吗?
这是我的结果:
这是我的代码:
import matplotlib.pyplot as plt
import numpy as np
from keras.models import Model
from keras.layers import Input, LSTM, Dense, SimpleRNN
N = 10000
num_repeats = 30
num_epochs = 5
# sequence length options
lens = [2, 5, 8, 10, 15, 20, 25, 30] + np.arange(30, 210, 10).tolist()
res = {}
for (RNN_CELL, key) in zip([SimpleRNN, LSTM], ['srnn', 'lstm']):
res[key] = {}
print(key, end=': ')
for seq_len in lens:
print(seq_len, end=',')
xs = np.zeros((N, seq_len))
ys = np.zeros(N)
# construct input data
positive_indexes = np.arange(N // 2)
negative_indexes = np.arange(N // 2, N)
xs[positive_indexes, 0] = 1
ys[positive_indexes] = 1
xs[negative_indexes, 0] = -1
ys[negative_indexes] = 0
noise = np.random.normal(loc=0, scale=0.1, size=(N, seq_len))
train_xs = (xs + noise).reshape(N, seq_len, 1)
train_ys = ys
# repeat each experiments multiple times
hists = []
for i in range(num_repeats):
inputs = Input(shape=(None, 1), name='input')
rnn = RNN_CELL(1, input_shape=(None, 1), name='rnn')(inputs)
out = Dense(2, activation='softmax', name='output')(rnn)
model = Model(inputs, out)
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
hist = model.fit(train_xs, train_ys, epochs=num_epochs, shuffle=True, validation_split=0.2, batch_size=16, verbose=0)
hists.append(hist.history['val_acc'][-1])
res[key][seq_len] = hists
print()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(pd.DataFrame.from_dict(res['lstm']).mean(), label='lstm')
ax.plot(pd.DataFrame.from_dict(res['srnn']).mean(), label='srnn')
ax.legend()
我的结果也显示在notebook中,如果您想复制结果会很方便。仅使用 CPU 在我的机器上运行实验花了一天多的时间。在支持 GPU 的机器上它可能会更快。
2018-04-18 更新:
我试图在 RNN 的景观上重现一个图,灵感来自于训练递归神经网络的难度中的图 6 。我发现随着重复/时间步长/序列长度的增加,在损失情况中看到悬崖的形成很有趣,这可能与解释此处观察到的长序列训练困难有关。更多详细信息可在此处获得。
2018-04-19 更新
扩展@shimao 的实验。似乎 LSTM 和 GRU 不太擅长锁定信息。但是切换到不同的任务,我称之为位中继(@shimao 的任务 2),GRU 表现更好,而 SRNN 和 LSTM 同样糟糕。
现在,我倾向于认为细胞类型的性能可能是特定于任务的。
任务 1:信息锁存(1 个单元;10 次重复;10 个 epoch)
任务 2:位中继(8 个单元;10 次重复;10 个 epoch)
误差线是标准偏差。
然后,一个有趣的问题是为什么 LSTM 不能用于信息锁存。鉴于任务的简单性,它应该能够工作,不是吗?可能与景观(例如悬崖)的梯度有关。