Преамбула
В настоящее время я работаю над проблемой машинного обучения, когда нам поручено использовать прошлые данные о продажах продуктов, чтобы прогнозировать объемы продаж в будущем (чтобы магазины могли лучше планировать свои запасы). Мы имеем по существу данные временных рядов, где для каждого продукта мы знаем, сколько единиц было продано в какие дни. У нас также есть информация о том, какая погода была, был ли государственный праздник, если какой-либо из продуктов был продан и т.д.
Мы с успехом смоделировали это с использованием MLP с плотными слоями и просто использовали подход с раздвижным окном, чтобы включить объемы продаж из окружающих дней. Однако мы полагаем, что мы сможем получить гораздо лучшие результаты с помощью подхода временного ряда, такого как LSTM.
Данные
По существу, мы имеем следующие данные:
( EDIT: для ясности столбца "Время" на приведенном выше рисунке неверно. У нас есть входы один раз в день, а не один раз в месяц, но в остальном структура одна и та же!)
Итак, данные X имеют форму:
(numProducts, numTimesteps, numFeatures) = (50 products, 1096 days, 90 features)
И данные Y имеют форму:
(numProducts, numTimesteps, numTargets) = (50 products, 1096 days, 3 binary targets)
Итак, у нас есть данные в течение трех лет (2014, 2015, 2016) и мы хотим тренироваться на этом, чтобы сделать прогнозы на 2017 год. (Это, конечно, не на 100% верно, поскольку у нас есть данные до октября 2017 года, но пусть просто игнорировать это сейчас)
Проблема
Я хотел бы создать LSTM в Keras, который позволяет мне делать эти прогнозы. Есть несколько мест, где я застрял. Итак, у меня есть шесть конкретных вопросов (я знаю, что один должен попытаться ограничить пост Stackoverflow одним вопросом, но все они переплетаются).
Во-первых, , как бы я нарезал свои данные для партий? Поскольку у меня есть три полных года, имеет смысл просто пропустить три партии, каждый раз размером один год? Или имеет смысл делать меньшие партии (скажем, 30 дней), а также использовать раздвижные окна? То есть вместо 36 партий по 30 дней каждый, я использую 36 * 6 партий по 30 дней каждый, каждый раз скользящий с 5 днями? Или это не так, как следует использовать LSTM? (Обратите внимание, что в данных имеется довольно немного сезонности, мне тоже нужно поймать этот долгосрочный тренд).
Во-вторых, имеет смысл использовать return_sequences=True
здесь? Другими словами, я сохраняю свои данные Y как (50, 1096, 3)
, так что (насколько я понял) на каждом временном шаге есть прогноз, по которому может быть рассчитана потеря по целевым данным? Или мне было бы лучше с return_sequences=False
, так что для оценки потери использовалось только окончательное значение каждой партии (т.е. При использовании годовых партий, то в 2016 году для продукта 1 мы оцениваем значение ).
В-третьих, как я должен работать с 50 различными продуктами?. Они разные, но все еще сильно коррелированы, и мы видели с другими подходами (например, MLP с простыми временными окнами), что результаты лучше, когда все продукты рассматриваются в одной и той же модели. Некоторые идеи, которые в настоящее время находятся на столе:
- изменить целевую переменную не только на 3 переменные, но 3 * 50 = 150; т.е. для каждого продукта есть три цели, каждая из которых обучается одновременно.
- разделить результаты после слоя LSTM на 50 плотных сетей, которые вводят в качестве входных данных из LSTM, а также некоторые функции, характерные для каждого продукта, то есть мы получаем многозадачную сеть с 50 функциями потерь, которые мы затем оптимизируем вместе. Это будет безумие?
- рассматривают продукт как одно наблюдение и включают специфические для продукта функции уже на уровне LSTM. Используйте только этот слой, за которым следует выпадающий слой размером 3 (для трех целей). Пропустите каждый продукт в отдельной партии.
В-четвертых, как я могу работать с данными проверки? Обычно я просто оставил случайно выбранный образец для проверки, но здесь нам нужно сохранить порядок времени на месте. Поэтому я думаю, что лучше всего просто оставить несколько месяцев в стороне?
В-пятых, и это часть, которая, вероятно, самая неясная для меня - , как я могу использовать фактические результаты для выполнения прогнозов? Скажем, я использовал return_sequences=False
, и я тренировался все три года в три партии (каждый раз до ноября) с целью обучения модели предсказать следующее значение (декабрь 2014, декабрь 2015, декабрь 2016 года). Если я хочу использовать эти результаты в 2017 году, как это работает? Если бы я понял это правильно, единственное, что я могу сделать в этом случае, - это то, что я буду кормить модель всеми точками данных за период с января по ноябрь 2017 года, и это вернет мне прогноз на декабрь 2017 года. Это правильно? Однако, если бы я использовал return_sequences=True
, а затем тренировался по всем данным до декабря 2016 года, смог бы я получить прогноз на январь 2017 года, просто предоставив модели функции, наблюдаемые в январе 2017 года? Или мне нужно также предоставить его за 12 месяцев до января 2017 года? Что же касается февраля 2017 года, я должен дополнительно указать значение для 2017 года, а еще 11 месяцев до этого? (Если это звучит, как будто я смущен, это потому, что я!)
Наконец, в зависимости от структуры, которую я должен использовать, как это сделать в Keras? То, что я имею в виду в данный момент, это что-то в следующих строках: (хотя это будет только для одного продукта, поэтому не решает, что все продукты в одной модели):
Код Keras
trainX = trainingDataReshaped #Data for Product 1, Jan 2014 to Dec 2016
trainY = trainingTargetReshaped
validX = validDataReshaped #Data for Product 1, for ??? Maybe for a few months?
validY = validTargetReshaped
numSequences = trainX.shape[0]
numTimeSteps = trainX.shape[1]
numFeatures = trainX.shape[2]
numTargets = trainY.shape[2]
model = Sequential()
model.add(LSTM(100, input_shape=(None, numFeatures), return_sequences=True))
model.add(Dense(numTargets, activation="softmax"))
model.compile(loss=stackEntry.params["loss"],
optimizer="adam",
metrics=['accuracy'])
history = model.fit(trainX, trainY,
batch_size=30,
epochs=20,
verbose=1,
validation_data=(validX, validY))
predictX = predictionDataReshaped #Data for Product 1, Jan 2017 to Dec 2017
prediction=model.predict(predictX)