该系列的Jupyter放在下方:
RNN训练速度较慢,请选择算力较强的计算机。
书接上回:我们在第二部分中成功搭建了由单个神经元构成的简单RNN,预测值与真实值的误差如下:

大体趋势预测的差不多,但误差还是有的。这篇文章我们尝试搭建多层的RNN网络来进行预测。
搭建3层SimpleRNN层
首先搭建一个3层的SimpleRNN层:
由于自己笔记本的算力有限,模型训练使用的实验室电脑,然后直接将训练模型的history导进自己的程序。
np.random.seed(42)
tf.random.set_seed(42)
model = keras.models.Sequential([
keras.layers.SimpleRNN(20, return_sequences=True, input_shape=[None, 1]),
keras.layers.SimpleRNN(20, return_sequences=True),
keras.layers.SimpleRNN(1)
])
model.compile(loss="mse", optimizer="adam")
history = model.fit(X_train, y_train, epochs=20,
validation_data=(X_valid, y_valid))
评估均方误差:
model.evaluate(X_valid, y_valid)
绘制损失曲线:

使用深度RNN进行预测后目标值和预测值如下:
可以看到相比于单层神经元,有了很大改进。
但是多层RNN有如下注意事项:
确保为所有的循环层设置了return_sequences=True
。如果我们只关注最后一个输出,则最后一个循环层可以不写。
如果不这么写,模型会输出一个2维数组(只包含最后一个时间步长的输出)。而不是一个三维数组(包含所有步长的输出),且下一个循环层会因格式不匹配而报错。
输出层优化:
- 由于我们预测的是一个单变量时间序列,所以每个时间步长都必须有一个输出值。但最后一层如果只有一个循环神经元,说明隐藏状态只是一个数字,这个隐藏状态没什么用。
- SimpleRNN默认使用
tanh
激活函数,因此预测值必须在[-1,1]区间。所以也就没法使用其他激活函数了。
基于以上两点原因,可以把输出层替换成Dense层。优点如下:
- 运行速度会稍微加快,但精度大致不变
- 可以选择其他的激活函数了。
注意修改最后一层为Dense层以后,要确保前一个循环层的return_sequences=True
删掉。
np.random.seed(42)
tf.random.set_seed(42)
# 搭建模型
np.random.seed(42)
tf.random.set_seed(42)
# 搭建模型
model = keras.models.Sequential([
keras.layers.SimpleRNN(20, return_sequences=True, input_shape=[None, 1]),
keras.layers.SimpleRNN(20),
keras.layers.Dense(1)
])
评估均方误差:
model.evaluate(X_valid, y_valid)
绘制损失函数:
plot_learning_curves(history["loss"], history["val_loss"])
plt.show()

预测结果如下:

Comments | NOTHING