Прогнозирование многократного прямого временного шага временного ряда с использованием LSTM
Я хочу предсказать определенные значения, которые можно прогнозировать на неделю (низкий SNR). Мне нужно предсказать весь временной ряд года, образованный неделями года (52 значения - рисунок 1)
![Figure 1: Year time series by week]()
Моей первой идеей было разработать модель LSTM "многие ко многим" (рисунок 2) с использованием Keras поверх TensorFlow. Я тренирую модель с 52 входным слоем (данный временной ряд предыдущего года) и 52 прогнозируемым выходным слоем (временной ряд следующего года). Форма train_X (X_examples, 52, 1), другими словами, X_examples для обучения, 52 временных шага по 1 объекту каждый. Я понимаю, что Keras будет рассматривать 52 входа как временной ряд одного и того же домена. Форма train_Y одинакова (y_examples, 52, 1). Я добавил слой TimeDistributed. Я думал, что алгоритм будет предсказывать значения как временные ряды, а не изолированные значения (я прав?)
Код модели в Керасе:
y = y.reshape(y.shape[0], 52, 1)
X = X.reshape(X.shape[0], 52, 1)
# design network
model = Sequential()
model.add(LSTM(n_neurons, input_shape=(X.shape[1], X.shape[2]), return_sequences=True))
model.add(TimeDistributed(Dense(1)))
model.compile(loss='mean_squared_error', optimizer='adam')
# fit network
model.fit(X, y, epochs=n_epochs, batch_size=n_batch, verbose=2)
![Figure 2: Many-to-many LSTM architecture]()
Проблема в том, что алгоритм не изучает пример. Он предсказывает значения, очень похожие на значения атрибутов. Правильно ли я моделирую проблему?
Второй вопрос: другая идея состоит в том, чтобы обучить алгоритм с 1 входом и 1 выходом, но затем во время теста, как я буду прогнозировать весь временной ряд 2015 года, не обращаясь к "1 входу"? Тестовые данные будут иметь другую форму, чем тренировочные данные.
Ответы
Ответ 1
Делая то же самое из-за недостатка данных, вы можете сделать это следующим образом.
Во-первых, было бы неплохо сохранить ваши значения между -1 и +1, поэтому я сначала нормализовал бы их.
Для модели LSTM вы должны убедиться, что вы используете return_sequences=True
.
В вашей модели нет ничего "неправильного", но для достижения желаемого может потребоваться больше или меньше слоев или единиц. (Хотя нет четкого ответа на этот вопрос).
Обучение модели прогнозировать следующий шаг:
Все, что вам нужно, это передать Y как сдвинутый X:
entireData = arrayWithShape((samples,52,1))
X = entireData[:,:-1,:]
y = entireData[:,1:,:]
Тренируйте модель, используя это.
Предсказание будущего:
Теперь для прогнозирования будущего, поскольку нам нужно использовать прогнозируемые элементы в качестве входных данных для более прогнозируемых элементов, мы собираемся использовать цикл и сделать модель stateful=True
.
Создайте модель, равную предыдущей, с этими изменениями:
- Все слои LSTM должны иметь
stateful=True
- Форма пакетного ввода должна быть
(batch_size,None, 1)
- это допускает переменную длину
Скопируйте веса ранее обученной модели:
newModel.set_weights(oldModel.get_weights())
Прогнозируйте только один образец за раз и никогда не забывайте вызывать model.reset_states()
перед запуском любой последовательности.
Сначала сделайте прогноз, используя последовательность, которую вы уже знаете (это обеспечит правильную подготовку своих состояний для прогнозирования будущего).
model.reset_states()
predictions = model.predict(entireData)
Кстати, как мы тренировались, последний шаг в предсказаниях будет первым элементом будущего:
futureElement = predictions[:,-1:,:]
futureElements = []
futureElements.append(futureElement)
Теперь мы делаем цикл, где этот элемент является входным. (Из-за состояния, модель поймет это новый шаг ввода предыдущей последовательности вместо новой последовательности)
for i in range(howManyPredictions):
futureElement = model.predict(futureElement)
futureElements.append(futureElement)
Эта ссылка содержит полный пример, предсказывающий будущее двух функций: https://github.com/danmoller/TestRepo/blob/master/TestBookLSTM.ipynb
Ответ 2
У меня есть данные от 10 лет. Если мой набор учебных данных: значения от 4 недель до предсказания 5-го, и я продолжаю перекладывать, у меня может быть почти 52 X 9 примеров для обучения модели и 52 для прогнозирования (в прошлом году)
Это на самом деле означает, что у вас есть только 9 учебных примеров с 52 функциями каждый (если вы не хотите тренироваться с сильно перекрывающимися входными данными). В любом случае, я не думаю, что этого достаточно, чтобы заслужить обучение LSTM
.
Я бы предложил попробовать более простую модель. Ваши входные и выходные данные имеют фиксированный размер, поэтому вы можете попробовать sklearn.linear_model.LinearRegression, который обрабатывает несколько функций ввода (в вашем случае 52) за обучение пример и несколько целей (также 52).
Обновление: Если вы должны использовать LSTM, взгляните на LSTM Neural Network для прогнозирования временных рядов, a Keras
LSTM
, которая поддерживает несколько будущих предсказаний сразу или итеративно, подавая каждое предсказание обратно в качестве входных данных. Основываясь на ваших комментариях, это должно быть именно то, что вы хотите.
Архитектура сети в этой реализации:
model = Sequential()
model.add(LSTM(
input_shape=(layers[1], layers[0]),
output_dim=layers[1],
return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(
layers[2],
return_sequences=False))
model.add(Dropout(0.2))
model.add(Dense(
output_dim=layers[3]))
model.add(Activation("linear"))
Однако я бы по-прежнему рекомендовал использовать линейную регрессию или, возможно, простую сеть прямой передачи с одним скрытым слоем и сравнить точность с LSTM. Особенно, если вы прогнозируете один выход за раз и подаете его обратно в качестве входных данных, ваши ошибки могут легко накапливаться, давая вам очень плохие прогнозы дальше.
Ответ 3
Я хотел бы добавить к этому вопросу
Я добавил слой TimeDistributed. Я думал, что алгоритм будет предсказывать значения как временные ряды, а не изолированные значения (я прав?)
поскольку мне самому было довольно трудно понять функциональность слоя Keras TimeDistributed.
Я бы сказал, что ваша мотивация правильна - не изолировать расчеты для прогноза временных рядов. В частности, вы не хотите, чтобы характеристики и взаимозависимости всей серии были объединены при прогнозировании его будущей формы.
Однако это в точности противоположно тому, для чего предназначен слой TimeDistributed. Это для изоляции расчетов на каждом временном шаге. Почему это полезно, спросите вы? Для совершенно разных задач, например, маркировка последовательности, когда у вас есть последовательный ввод (i1, i2, i3,..., i_n)
и вы (i1, i2, i3,..., i_n)
выводить метки (label1, label2, label1,..., label2)
для каждого временного шага отдельно,
Imho лучшее объяснение можно найти в этом посте и в документации Keras.
По этой причине, я бы сказал, что несмотря на всю интуицию, добавление слоя TimeDistributed, вероятно, никогда не будет хорошей идеей для прогнозирования временных рядов. Открыто и рад услышать другие мнения об этом!