Keras GRU 模型仅预测 [-0., -0., -0., -0., -0.]

Keras GRU model predicts only [-0., -0., -0., -0., -0.]

我正在尝试根据之前的 50 个输入来预测加密货币的 5 个周期性价格。

>>> X_train.shape, X_test.shape, Y_train.shape, Y_test.shape
((291314, 50, 8), (72829, 50, 8), (291314, 5), (72829, 5))

这里我有 50 个以前的样本 x 8 个特征作为输入样本和 5 个下一个周期的价格作为输出

我用这段代码建立了模型:

from tensorflow.keras.layers import GRU
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation

model = Sequential()
model.add(GRU(units=50, input_shape=X_train.shape[1:], return_sequences=False))
model.add(Activation('tanh'))
model.add(Dropout(0.2))
model.add(Dense(NFS))
model.add(Activation('relu'))
model.compile(loss='mse', optimizer='adam')
model.fit(X_train, Y_train, batch_size=50, validation_data=(X_test, Y_test), epochs=2)

这给了我输出:

Train on 291314 samples, validate on 72829 samples
Epoch 1/2
291314/291314 [==============================] - 487s 2ms/step - loss: 0.0107 - val_loss: 0.2502
Epoch 2/2
291314/291314 [==============================] - 463 2ms/step - loss: 0.0103 - val_loss: 0.2502

在这一步之后,我尝试预测 X_test 的输出,但我得到的不是预测,而是形状正确但全是零的矩阵,而不是任何预测:

>>> model.predict(X_test)
array([[-0., -0., -0., -0., -0.],
       [-0., -0., -0., -0., -0.],
       [-0., -0., -0., -0., -0.],
       ...,
       [-0., -0., -0., -0., -0.],
       [-0., -0., -0., -0., -0.],
       [-0., -0., -0., -0., -0.]], dtype=float32)

为什么我变得这么糟糕?我是否使用正确的方式来做我想做的事?

UPD: Here 是完整的笔记本。

首先,您需要缩放测试 (X_test) 输入。您确实缩放了训练数据 (X_train),但未缩放测试集。

所以你需要像 X_train:

那样缩放它
X_test = preprocessing.MinMaxScaler().fit_transform(X_test.reshape(-1, 50*8)).reshape(-1, 50, 8)

进一步在输出层使用'ReLU'激活是有问题的。因为即使最后一层权重产生负输出,你也总是会得到正输出。

这里的问题是负输出的这些权重不会更新那么多,因为损失非常低。

假设您的权重设置导致输出 -23435235,而您的目标是 0.9。在输出上使用 'ReLU' 激活时,它会从 -23435235 映射到 0,从而导致低损失。但是低损失意味着更少的变化,而高损失则相反会导致您的体重发生很大变化。

所以你想要一个高损失,以便对你的权重进行强有力的修正。因为 -23435235 不是你想要的。

所以最后一层不要用'ReLU',我这里改成了'linear'

所以说(顺便说一句,我将 'tanh' 更改为 'ReLU'。)代码:

#somewhere before you need to normalize your `X_test`
X_test = preprocessing.MinMaxScaler().fit_transform(X_test.reshape(-1, 50*8)).reshape(-1, 50, 8)


from tensorflow.keras.layers import GRU
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Activation

model = Sequential()
model.add(GRU(units=50, input_shape=X_train.shape[1:], return_sequences=False))
model.add(Activation('relu'))
model.add(Dropout(0.2))
model.add(Dense(NFS))
model.add(Activation('linear'))
model.compile(loss='mse', optimizer='adam')
model.fit(X_train, Y_train, batch_size=4000, validation_data=(X_test, Y_test), epochs=15)

输出:

Train on 291314 samples, validate on 72829 samples
Epoch 1/15
291314/291314 [==============================] - 22s 75us/step - loss: 0.1523 - val_loss: 0.2442
Epoch 2/15
291314/291314 [==============================] - 16s 56us/step - loss: 0.0652 - val_loss: 0.2375
Epoch 3/15
291314/291314 [==============================] - 16s 56us/step - loss: 0.0420 - val_loss: 0.2316
Epoch 4/15
291314/291314 [==============================] - 16s 56us/step - loss: 0.0337 - val_loss: 0.2262
Epoch 5/15
291314/291314 [==============================] - 16s 56us/step - loss: 0.0271 - val_loss: 0.2272
Epoch 6/15
291314/291314 [==============================] - 16s 56us/step - loss: 0.0219 - val_loss: 0.2256
Epoch 7/15
291314/291314 [==============================] - 16s 56us/step - loss: 0.0179 - val_loss: 0.2245
Epoch 8/15
291314/291314 [==============================] - 16s 56us/step - loss: 0.0149 - val_loss: 0.2246
Epoch 9/15
291314/291314 [==============================] - 16s 56us/step - loss: 0.0125 - val_loss: 0.2244
Epoch 10/15
291314/291314 [==============================] - 16s 57us/step - loss: 0.0108 - val_loss: 0.2213
Epoch 11/15
291314/291314 [==============================] - 16s 57us/step - loss: 0.0096 - val_loss: 0.2197
Epoch 12/15
291314/291314 [==============================] - 16s 56us/step - loss: 0.0087 - val_loss: 0.2189
Epoch 13/15
291314/291314 [==============================] - 16s 57us/step - loss: 0.0080 - val_loss: 0.2178
Epoch 14/15
291314/291314 [==============================] - 16s 56us/step - loss: 0.0075 - val_loss: 0.2148
Epoch 15/15
291314/291314 [==============================] - 16s 57us/step - loss: 0.0072 - val_loss: 0.2129
<tensorflow.python.keras.callbacks.History at 0x7f8a93637b70>

进一步 X_test 结果:

代码:

prediction = model.predict(X_test[:10])
prediction

输出:

array([[0.03562379, 0.06016447, 0.0987532 , 0.01986726, 0.0336756 ],
       [0.03518523, 0.06041833, 0.0983481 , 0.01864071, 0.03437094],
       [0.03487844, 0.06067847, 0.09811568, 0.0175517 , 0.03480709],
       [0.03491565, 0.05986937, 0.09927133, 0.02029082, 0.03347992],
       [0.03466946, 0.06018706, 0.09859383, 0.01869587, 0.03432   ],
       [0.03459518, 0.06030918, 0.09850594, 0.01805007, 0.03444977],
       [0.03448001, 0.06019764, 0.09864715, 0.01818896, 0.034256  ],
       [0.03450274, 0.05936757, 0.10001318, 0.02131432, 0.03305689],
       [0.03424717, 0.05954869, 0.09983289, 0.0208826 , 0.03378636],
       [0.03426195, 0.05959999, 0.09991242, 0.02090426, 0.03394405]],
      dtype=float32)

如上所述,我使用你的笔记本和数据来训练模型。

如您所见,验证损失在第 15 轮仍在减少,而且测试输出现在看起来非常接近目标。


请注意 - 我还没有完成笔记本中的所有预处理代码,但在我看来你使用的是绝对值。

如果是这种情况,您应该考虑使用百分比变化(例如从当前时间点到未来的预测点)。这也会为您进行缩放。 (10% 的变化 = 0.1)

进一步的绝对值变化太大了。如果十个月前的价格是 ~5.4324,而今天的价格是 ~50.5534,那么这些数据对您来说毫无用处,而价格变化的相关模式可能仍然有效。

这只是一个旁注 - 希望对您有所帮助。

好吧,我认为@blue-phoenox 的回答中建议的规范化方案是有缺陷的。那是因为你应该 NEVER EVER 独立地标准化测试数据(即使用不同的统计数据)。相反,您 应该使用训练数据标准化期间计算的统计数据来标准化测试数据 。所以一定是这样的:

mms = preprocessing.MinMaxScaler()
X_train = mms.fit_transform(X_train)
X_test = mms.transform(X_test) # you should not use fit_transform

这是有道理的,因为考虑以下场景,您已经训练了模型,现在将其部署到生产中以供实际使用。现在用户给它喂了一个新样本。您需要首先标准化这个新样本,但是如何呢?你不能独立地缩放它的值,因为它只是一个样本(即,如果你使用最小-最大缩放器,它们都将是一或零)。相反,您将使用(在使用最小-最大缩放器的情况下)在训练数据上计算的 "min" 和 "max" 值来规范化此新测试数据。

这在图像模型中很常见,像这样:

X_train /= 255.
X_test /= 255.

请注意,我们将训练数据和测试数据除以相同的数字(即 255)。或者更复杂的归一化方案:

X_mean = X_train.mean(axis=0)
X_std = X_train.std(axis=0)
X_train -= X_mean
X_train /= X_std + 1e-8   # add a small constant to prevent division by zero

# Now to normalize test data we use the same X_mean and X_std already computed
X_test -= X_mean
X_test /= X_std + 1e-8

旁注(正如我在 ): if you are running the training on a GPU then you can consider using CuDNNGRU 而不是 GRU(或 CuDNNLSTM 而不是 LSTM 中提到的),因为它专门针对 GPU 进行了优化并加快了速度训练过程。

对于任何有相同输出错误并且甚至现在还在搜索这个的人,为了扩展@MBT 提供的优秀答案,你也可以尝试使用 Leaky ReLU 作为激活。

只需将 model.add(Activation("relu" 更改为 model.add(LeakyReLU(alpha=[enter alpha, default is 0.3])) 并确保 from keras.layers.advanced_activations import LeakyReLU

我在这里找到了这个解决方案:https://github.com/keras-team/keras/issues/3687