Прогнозирование многократного прямого временного шага временного ряда с использованием 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, вероятно, никогда не будет хорошей идеей для прогнозирования временных рядов. Открыто и рад услышать другие мнения об этом!