Модель Keras GRU предсказывает только [-0., -0., -0., -0., -0.]

Я пытаюсь предсказать 5 периодических цен на криптовалюту на основе предыдущих 50 входных данных.

>>> 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: здесь полный блокнот.


person Vassily    schedule 22.08.2018    source источник
comment
Упс. Судя по названию, я предполагаю, что сборщики долгов уже в пути.   -  person Mad Physicist    schedule 22.08.2018
comment
как вы масштабировали входные и выходные цены?   -  person modesitt    schedule 22.08.2018
comment
Кроме того, пытались ли вы изменить оптимизатор или его параметры (например, скорость обучения) или увеличить количество эпох (конечно, при условии, что вы правильно нормализовали свои данные)?   -  person today    schedule 22.08.2018
comment
Кстати, если наши комментарии помогли вам обучить модель, которая точно предсказывает цены, не могли бы вы поделиться ею с нами в качестве благодарственного подарка? :)) Я просто шучу!   -  person today    schedule 22.08.2018
comment
В конец вопроса добавлена ​​ссылка на полный блокнот. Я использовал sklearn.MinMaxScaler. И я понятия не имею, какой параметр я должен настроить. Я просто следую этому руководству: medium.com /@huangkh19951228/   -  person Vassily    schedule 22.08.2018
comment
Вы понимаете, что не можете предсказать будущее?   -  person Terry Carmen    schedule 22.08.2018
comment
Вы уверены, что оно полное нулей? Вывод показывает, что часть матрицы не была показана, так что, возможно, есть какие-то ненулевые значения?   -  person ForceBru    schedule 22.08.2018
comment
Я вру. Раньше было 5 эпох, но 3-я, 4-я и 5-я не изменили потери, и я уменьшил количество эпох до 2.   -  person Vassily    schedule 22.08.2018
comment
Терри, я не уверен. Я перезапускаю блокнот и через 10 минут дам вам точный ответ о наличии ненулей в прогнозе   -  person Vassily    schedule 22.08.2018
comment
Теперь я уверен, что в предсказании все нули. Файл с данными добавлен в репозиторий   -  person Vassily    schedule 22.08.2018


Ответы (3)


Что ж, я думаю, что схема нормализации, предложенная в ответе @ blue-phoenox, ошибочна. Это потому, что вы не должны НИКОГДА нормализовать тестовые данные независимо друг от друга (т. е. с другой статистикой). Вместо этого вам следует использовать статистику, вычисленную во время нормализации обучающих данных, для нормализации тестовых данных. Так должно быть так:

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

Это имеет смысл, поскольку рассмотрим следующий сценарий, когда вы обучили свою модель и теперь развернули ее в рабочей среде для реального использования. Теперь пользователь загружает его одним новым образцом. Вам нужно сначала нормализовать этот новый образец, но как? Вы не можете масштабировать его значения независимо, так как это только одна выборка (т.е. все они будут равны единице или нулю, если вы используете мин-макс масштабатор). Вместо этого вы должны использовать (в случае использования мин-макс масштабатора) значения «минимум» и «максимум», вычисленные по обучающим данным, чтобы нормализовать эти новые тестовые данные.

Это очень распространено в моделях изображений, например:

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

Дополнительное примечание (как я упоминал в моем комментарий): если вы проводите обучение на графическом процессоре, вы можете рассмотреть возможность использования CuDNNGRU< /a> вместо GRU (или CuDNNLSTM вместо LSTM), так как он специально оптимизирован для GPU и ускоряет процесс обучения.

person today    schedule 30.08.2018

Сначала вам нужно масштабировать входные данные теста (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, то эти данные для вас бесполезны, а относительные закономерности изменения цены еще могут быть в силе.

Это просто примечание - я надеюсь, что это поможет.

person MBT    schedule 29.08.2018
comment
Ты. Находятся. Потрясающий. - person Vassily; 30.08.2018
comment
@VassiliyVorobyov И еще одно примечание: если вы проводите обучение на графическом процессоре, вы можете рассмотреть возможность использования CuDNNGRU< /a> вместо GRU (или CuDNNLSTM вместо LSTM), так как он специально оптимизирован для GPU и ускоряет процесс обучения. - person today; 30.08.2018

Для тех, кто имеет ту же ошибку вывода и искал ее даже сейчас, чтобы немного расширить отличный ответ, предоставленный @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

person Kevin    schedule 10.06.2020