Вопрос или проблема
Я пытаюсь использовать модель LSTM для бинарной классификации; однако, когда я обучаю модель, значение функции потерь остается около 0.69 (т.е. –$\ln(0.5)$), а точность на уровне 0.5, что наводит меня на мысль, что модель не учится, так как эти значения указывают на случайное угадывание. Я пробовал изменять скорость обучения, количество блоков и объединять несколько LSTM, но мне кажется, что я что-то упускаю из виду при использовании состояния, хотя я и не уверен, что именно.
Мои временные ряды имеют форму $t = [x_0, …, x_N]$, и я хочу использовать скользящее окно с шагом 10 для использования 100 элементов для предсказания знака следующего элемента. Например, я хочу использовать элементы с 0 по 99 для предсказания знака 100-го элемента; затем использовать элементы с 10 по 109 для предсказания 110-го и так далее.
Поэтому я сформировал обучающий набор следующим образом:
$X = \begin{bmatrix}
x_{0} & x_{1} & x_{2} & \dots & x_{99} \\
x_{10} & x_{11} & x_{12} & \dots & x_{109} \\
…\\
\end{bmatrix}$
и мой вектор-цель, где положительный знак x – это 1, а отрицательный – 0.
$y = \begin{bmatrix}
\text{sgn}(x_{100}) \\
\text{sgn}(x_{110}) \\
\vdots \\
\end{bmatrix}
$
В моем случае $N = 1047700$, так что у меня есть $10477$ последовательностей длиной $100$. Моя идея состоит в том, чтобы использовать LSTM с следующим кодом:
model = Sequential()
model.add(LSTM(32, activation='tanh',input_shape=(X.shape[1],1)))
model.add(Dense(1,activation='sigmoid'))
adm = Adam(lr=0.001)
model.compile(loss="binary_crossentropy", optimizer=adm, metrics=['accuracy'])
model.fit(train_array,classified_returns, epochs=200, verbose=1,
shuffle=False, validation_split=0.1)
Вот сводка модели:
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
lstm_2 (LSTM) (None, 32) 4608
_________________________________________________________________
dense_13 (Dense) (None, 1) 33
=================================================================
Total params: 4,641
Trainable params: 4,641
Non-trainable params: 0
_________________________________________________________________
Вот извлечение результатов обучения:
Train on 9429 samples, validate on 1048 samples
Epoch 1/200
9429/9429 [==============================] - 18s 2ms/step - loss: 0.6932 - acc: 0.5002 - val_loss: 0.6931 - val_acc: 0.503849
Epoch 2/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6933 - acc: 0.4984 - val_loss: 0.6931 - val_acc: 0.5048
Epoch 3/200
9429/9429 [==============================] - 15s 2ms/step - loss: 0.6932 - acc: 0.4994 - val_loss: 0.6930 - val_acc: 0.5048
Epoch 4/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4992 - val_loss: 0.6930 - val_acc: 0.5048
Epoch 5/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4987 - val_loss: 0.6930 - val_acc: 0.5048
Epoch 6/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4980 - val_loss: 0.6930 - val_acc: 0.5048
Epoch 7/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4978 - val_loss: 0.6930 - val_acc: 0.5038
Epoch 8/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4984 - val_loss: 0.6930 - val_acc: 0.5048
Epoch 9/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4986 - val_loss: 0.6930 - val_acc: 0.5048
Epoch 10/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4977 - val_loss: 0.6930 - val_acc: 0.5057
Epoch 11/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4980 - val_loss: 0.6930 - val_acc: 0.5057
Epoch 12/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4981 - val_loss: 0.6930 - val_acc: 0.5067
Epoch 13/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4987 - val_loss: 0.6930 - val_acc: 0.5076
Epoch 14/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4978 - val_loss: 0.6930 - val_acc: 0.5076
Epoch 15/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4974 - val_loss: 0.6930 - val_acc: 0.5076
Epoch 16/200
9429/9429 [==============================] - 15s 2ms/step - loss: 0.6932 - acc: 0.4976 - val_loss: 0.6930 - val_acc: 0.5076
Epoch 17/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4968 - val_loss: 0.6930 - val_acc: 0.5076
Epoch 18/200
9429/9429 [==============================] - 16s 2ms/step - loss: 0.6932 - acc: 0.4971 - val_loss: 0.6930 - val_acc: 0.5076
Как мы видим, модель не учится. Может кто-то указать мне правильное направление использования состояния?
Как использовать stateful LSTMs хорошо задокументировано в официальной документации Keras. Также есть хороший блог пост здесь.
В разделе о рекуррентных слоях есть заметка:
Примечание по использованию состояния в RNNs
Вы можете установить RNN слои в состояние ‘stateful’, что означает, что состояния, вычисленные для образцов в одном пакете, будут повторно использоваться как начальные состояния для образцов в следующем пакете. Это предполагает одно к одному сопоставление между образцами в различных последовательных пакетах.
Чтобы включить состояние: – укажите
stateful=True
в конструкторе слоя. – укажите фиксированный размер пакета для вашей модели, передав при использовании последовательной модели:batch_input_shape=(...)
в первый слой вашей модели. в противном случае для функциональной модели с 1 или более входными слоями:batch_shape=(...)
во все первые слои вашей модели. Это ожидаемая форма ваших входных данных, включая размер пакета. Это должен быть кортеж целых чисел, напр.(32, 10, 100)
. – укажитеshuffle=False
при вызове fit().Чтобы сбросить состояния вашей модели, вызовите
.reset_states()
либо для конкретного слоя, либо для всей вашей модели.
Небольшое затруднение
Небольшая трудность, которую вы должны исправить самостоятельно, заключается в том, чтобы убедиться, что количество ваших образцов является целым кратным вашего размера пакета: num_samples % batch_size == 0
. Вы должны убедиться в этом вручную, так как Keras просто возьмет оставшиеся образцы для последнего пакета, и это обычно меньше, чем желаемый размер пакета.
.
Ответ или решение
Использование LSTM для бинарной классификации может быть непростой задачей, особенно если точность застряла на уровне 50%, что указывает на случайные угаданные результаты. Для достижения прогресса, прежде чем переходить к stateful LSTM, необходимо проанализировать некоторые ключевые аспекты модели и данных.
Анализ задачи
-
Предварительная подготовка данных:
Убедитесь, что данные правильно нормализованы (например, в диапазоне от 0 до 1) и что в них нет аномалий, которые могут повлиять на обучение модели. -
Проверка модели:
- Архитектура модели должна быть адекватна сложности задачи. Возможно, стоит увеличить количество нейронов или слоев в сети для повышения выразительной способности модели.
- Убедитесь, что функция активации и функция потерь соответствуют бинарной классификации.
-
Гиперпараметры:
- Настройка скорости обучения: попробуйте различные значения, чтобы найти оптимальную скорость обучения.
- Измените размеры batches и количества epoch для более тщательного поиска.
Использование Statefulness в LSTM
Если уверены, что данные и архитектура модели подготовлены правильно, можно рассмотреть использование stateful LSTM для улучшения результатов.
Внедрение Stateful LSTM
-
Изменение параметров слоя LSTM:
Установите параметрstateful=True
в конструкторе слоя LSTM. Это позволит сохранять состояние между последовательными batches. -
Настройка формы ввода:
Поскольку вы планируете использовать stateful LSTM, вам потребуется зафиксировать размер batches. Например, задайтеbatch_input_shape=(batch_size, timesteps, features)
для первого слоя в модели. -
Контроль размера batches:
Убедитесь, что размер вашей обучающей выборки делится нацело на размер batches (num_samples % batch_size == 0
). В противном случае последние batches могут содержать меньшее количество данных, что повредит обучению. -
Настройки обучения:
Убедитесь, что при вызове методаfit
установлен параметрshuffle=False
, чтобы последовательные batches обеспечивали непрерывность данных. -
Сброс состояния:
После завершения одной эпохи обучения, используйтеmodel.reset_states()
, чтобы избежать накопления состояний, которые могут привести к неожиданным результатам на последующих эпохах. -
Оптимизация и настройка:
Можно экспериментировать с различными комбинациями гиперпараметров и архитектуры модели. Это включает в себя вариации количества нейронов, уровней dropout, изменения активаций и так далее.
Заключение
Использование stateful LSTM может значительно улучшить результаты, если модель тщательно настроена, и данные обработаны должным образом. Перейдите на statefulness только после того, как вы полностью изучили и оптимизировали текущую модель. Это позволить учесть временные зависимости в данных, особенно если предыдущие состояния влияют на последующие предсказания.