LSTM 预测了一条直线

LSTM forecasted a straight line

我在 Keras 中构建了一个 LSTM。它读取 9 个时滞的观察结果,并预测下一个标签。出于某种原因,我训练的模型预测的东西几乎是一条直线。 导致如此糟糕的回归结果的模型架构可能存在什么问题?

输入数据:每小时金融时间序列,有明显上升趋势的1200+条记录

输入数据维度:
- 最初:

X_train.shape (1212, 9)

- 为 LSTM 重塑:

Z_train.shape (1212, 1, 9)


array([[[0.45073171, 0.46783444, 0.46226164, ..., 0.47164819,
         0.47649667, 0.46017738]],

       [[0.46783444, 0.46226164, 0.4553289 , ..., 0.47649667,
         0.46017738, 0.47167775]],

目标数据:y_train

69200    0.471678
69140    0.476364
69080    0.467761
       ...   
7055     0.924937
7017     0.923651
7003     0.906253
Name: Close, Length: 1212, dtype: float64

type(y_train)
<class 'pandas.core.series.Series'>

LSTM 设计:

my = Sequential()
my.add(LSTM((20),batch_input_shape=(None,1,9), return_sequences=True))
my.add(LSTM(20, return_sequences=True))
my.add(LSTM(20, return_sequences=True))
my.add(LSTM(1))

9个节点的输入层。 3 个隐藏层,每层 20 个单元。 1 个单元的 1 个输出层。

The Keras default is return_sequences=False

模型编译时带有 mse 损失和 adamsgd 优化器。

curr_model.compile(optimizer=optmfunc, loss="mse")

模型以这种方式拟合。 batch是32,shuffle可以是True/False

curr_model.fit(Z_train, y_train,
                           validation_data=(Z_validation,y_validation),
                           epochs=noepoch, verbose=0,
                           batch_size=btchsize,
                           shuffle=shufBOOL)

配置和权重已保存到磁盘。由于我正在训练多个模型,所以我会在之后加载它们以测试某些性能指标。

spec_model.model.save_weights(mname_trn)
mkerascfg = spec_model.model.to_json()
    with open(mname_cfg, "w") as json_file:
        json_file.write(mkerascfg)


当我训练 MLP 时,我在验证集上得到了这个结果:

我已经训练了几个 LSTM,但针对验证集的结果如下所示:

第二个图(LSTM 图)是验证数据。这是 y_validation 与 Z_validation 上的预测。它们是各自数组中的最后 135 条记录。这些是从完整数据(即验证)中分离出来的,并且具有与 Z_train 和 y_train 相同的 type/properties。 x 轴只是索引的编号 0 到 134,y 轴是 y_validation 或预测的值。两个数组中的单位都已归一化。所以所有的单位都是一样的。 "straight" 行是预测。

对于为什么会发生这种情况,您有什么建议? - 我改变了批量大小。类似的结果。 - 我试过更改 return_sequences,但它会导致后续层的形状等出现各种错误。

MSE损失的LSTM进展信息

训练了 4 个模型,当然都有同样的问题。 我们只关注 3 个隐藏层,每层 20 个单元,定义为 LSTM上面。(小批量大小为 32,混洗被禁用。但启用没有任何改变)。

这是第一个模型(adam 优化器)的损失进程的略微放大图像

据我所知,通过弄乱指数,损失值的反弹(形成厚区域)在 500 年代之后开始。

您的代码有一个严重问题:维数改组。 LSTM 期望输入的形状为 (batch_size, timesteps, channels)(或 (num_samples, timesteps, features))——而您正在用九个通道提供 one 时间步长。甚至从未发生过时间反向传播。

Fix:将输入重塑为 (1212, 9, 1)


建议:阅读。它很长,但可以节省您数小时的调试时间;此信息在其他地方无法以如此紧凑的形式获得,我希望我在开始使用 LSTM 时已经掌握了它。

的回答也可能有用 - 但以前的 link 更重要。

OverLordGoldDragon 是对的:问题出在输入的维数上。

正如您在 Keras documentation 中看到的那样,所有循环层都希望输入是具有形状的 3D 张量:(batch_size, timesteps, input_dim).

你的情况:

  • 输入有9个时间滞后需要按顺序送入LSTM,所以它们是timesteps
  • 时间序列只包含一种金融工具,所以input_dim是1

因此,重塑它的正确方法是:(1212, 9, 1)

此外,请确保遵守数据馈送到 LSTM 的顺序。对于预测问题,最好提供从最古老到最近的滞后,因为我们要预测最近之后的下一个值。

由于 LSTM 从左到右读取输入,因此 9 个值的顺序应为:x_t-9, x_t-8, ...., x_t-1 从左到右,即输入和输出张量应如下所示:

Z = [[[0], [1], [2], [3], [4], [5], [6], [7], [8]],
     [[1], [2], [3], [4], [5], [6], [7], [8], [9]],
     ...
    ]
y = [9, 10, ...]

如果它们不是这样定向的,您始终可以设置 LSTM 标志 go_backwards=True 以使 LSTM 从右向左读取。

此外,确保传递 numpy 数组而不是 pandas 系列作为 Xy,因为 Keras 有时会被 Pandas 混淆。

有关使用 Keras 进行时间序列预测的完整示例,请查看 this notebook