Как использовать модели глубокого обучения для прогнозирования временных рядов? - PullRequest
7 голосов
/ 30 января 2020

У меня есть сигналы, записанные с машин (m1, m2, so on) в течение 28 дней. (Примечание: каждый сигнал каждого дня имеет длину 360).

machine_num, day1, day2, ..., day28
m1, [12, 10, 5, 6, ...], [78, 85, 32, 12, ...], ..., [12, 12, 12, 12, ...]
m2, [2, 0, 5, 6, ...], [8, 5, 32, 12, ...], ..., [1, 1, 12, 12, ...]
...
m2000, [1, 1, 5, 6, ...], [79, 86, 3, 1, ...], ..., [1, 1, 12, 12, ...]

Я хочу предсказать последовательность сигналов каждой машины на следующие 3 дня. то есть в day29, day30, day31. Однако у меня нет значений для дней 29, 30 и 31. Итак, мой план был следующим с использованием LSTM модели.

Первый шаг - получить сигналы для day 1 и попросить предсказать сигналы для day 2, затем на следующем шаге получить сигналы для days 1, 2 и попросить предсказать сигналы для day 3, et c, поэтому, когда я достигаю day 28,, в сети есть все сигналы вплоть до 28, и меня просят предсказать сигналы для day 29 и т. Д. c.

Я пытался сделать однофакторную модель LSTM следующим образом.

# univariate lstm example
from numpy import array
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
# define dataset
X = array([[10, 20, 30], [20, 30, 40], [30, 40, 50], [40, 50, 60]])
y = array([40, 50, 60, 70])
# reshape from [samples, timesteps] into [samples, timesteps, features]
X = X.reshape((X.shape[0], X.shape[1], 1))
# define model
model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(3, 1)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
# fit model
model.fit(X, y, epochs=1000, verbose=0)
# demonstrate prediction
x_input = array([50, 60, 70])
x_input = x_input.reshape((1, 3, 1))
yhat = model.predict(x_input, verbose=0)
print(yhat)

Однако этот пример очень прост, поскольку он не имеет длинных последовательностей, подобных моему. Например, мои данные для m1 будут выглядеть следующим образом.

m1 = [[12, 10, 5, 6, ...], [78, 85, 32, 12, ...], ..., [12, 12, 12, 12, ...]]

Более того, мне нужен прогноз дня 29, 30, 31. В этом случае я не уверен, как изменить этот пример, чтобы удовлетворить мои потребности. Я хочу узнать, правильно ли выбранное мной направление. Если да, то как это сделать.

Я с удовольствием предоставлю более подробную информацию, если это необходимо.

РЕДАКТИРОВАТЬ:

Я упомянул model.summary().

enter image description here

Ответы [ 2 ]

2 голосов
/ 21 февраля 2020

Модель и формы

Поскольку это последовательности в последовательностях, вам необходимо использовать ваши данные в другом формате.

Хотя вы можете просто go например (machines, days, 360) и просто рассматривать 360 как функции (которые могут работать до некоторой точки), для надежной модели (тогда, возможно, есть проблема со скоростью), вы бы нужно рассматривать обе вещи как последовательности.

Тогда я бы go с данными типа (machines, days, 360, 1) и двумя уровнями рекуррентности.

Тогда наши модели input_shape будут (None, 360, 1)

Случай модели 1 - Только дневная рекуррентность

Форма данных: (machines, days, 360)
Применить некоторую нормализацию к данные.

Здесь приведен пример, но модели могут быть гибкими, поскольку вы можете добавить больше слоев, попробовать свертки и т. Д. c:

inputs = Input((None, 360)) #(m, d, 360)
outs = LSTM(some_units, return_sequences=False, 
            stateful=depends_on_training_approach)(inputs)  #(m, some_units)
outs = Dense(360, activation=depends_on_your_normalization)(outs) #(m, 360)
outs = Reshape((1,360)) #(m, 1, 360) 
    #this reshape is not necessary if using the "shifted" approach - see time windows below
    #it would then be (m, d, 360)

model = Model(inputs, outs)

В зависимости от сложности внутридневных последовательностей , они могли бы получить хорошие прогнозы с этим, но если они развиваются сложным образом, то следующая модель будет немного лучше.

Всегда помните, что вы можете создавать больше слоев и исследовать вещи, чтобы увеличить возможности эта модель, это только небольшой пример

Пример модели 2 - Двухуровневая рекуррентность

Форма данных: (machines, days, 360, 1)
Применить некоторую нормализацию к данным.

Существует много способов экспериментировать, как это сделать, но вот простой.

inputs = Input((None, 360, 1)) #(m, d, 360, 1)

#branch 1
inner_average = TimeDistributed(
                    Bidirectional(
                        LSTM(units1, return_sequences=True, stateful=False),
                        merge_mode='ave'
                    )
                )(inputs) #(m, d, 360, units1)
inner_average = Lambda(lambda x: K.mean(x, axis=1))(inner_average) #(m, 360, units1)


#branch 2
inner_seq = TimeDistributed(
                LSTM(some_units, return_sequences=False, stateful=False)
            )(inputs) #may be Bidirectional too
            #shape (m, d, some_units)

outer_seq = LSTM(other_units, return_sequences = False, 
                 stateful=depends_on_training_approach)(inner_seq) #(m, other_units)

outer_seq = Dense(few_units * 360, activation = 'tanh')(outer_seq) #(m, few_units * 360)
    #activation = same as inner_average 


outer_seq = Reshape((360,few_units))(outer_seq) #(m, 360, few_units)


#join branches

outputs = Concatenate()([inner_average, outer_seq]) #(m, 360, units1+few_units)
outputs = LSTM(units, return_sequences=True, stateful= False)(outputs) #(m, 360,units)
outputs = Dense(1, activation=depends_on_your_normalization)(outputs) #(m, 360, 1)
outputs = Reshape((1,360))(outputs) #(m, 1, 360) for training purposes

model = Model(inputs, outputs)

Это одна попытка, я сделал среднее число дней, но я мог бы вместо inner_average сделать что-то вроде:

#branch 1
daily_minutes = Permute((2,1,3))(inputs) #(m, 360, d, 1)
daily_minutes = TimeDistributed(
                    LSTM(units1, return_sequences=False, 
                         stateful=depends_on_training_approach)
                )(daily_minutes) #(m, 360, units1)

Многие другие способы изучение данных возможно, это очень креативное поле. Например, вы могли бы использовать подход daily_minutes сразу после inner_average, исключая K.mean лямбда-слой .... у вас есть идея.

Время windows подход

Ваш подход звучит хорошо. Дайте один шаг, чтобы предсказать следующий, дайте два шага, чтобы предсказать 1151 * третий, дайте три шага, чтобы предсказать четвертый.

Приведенные выше модели подходят для этого подхода.

Имейте в виду, что очень короткие входы могут быть бесполезны и могут ухудшить вашу модель. (Постарайтесь представить, сколько шагов будет достаточно для того, чтобы начать прогнозирование следующих шагов)

Предварительно обработайте данные и разделите их на группы:

  • группа с длиной = 4 ( например)
  • группа с длиной = 5
  • ...
  • группа с длиной = 28

Вам потребуется ручное обучение l oop где в каждой эпохе вы кормите каждую из этих групп (вы не можете кормить разные длины все вместе).


Другой подход заключается в том, чтобы все этапы заставляли модель предсказывать смещенную последовательность, например:

  • inputs = original_inputs[:, :-1] # исключая последний тренировочный день
  • outputs = original_inputs[:, 1:] # исключить первый тренировочный день

Для того, чтобы сделать приведенные выше модели подходящими для этого подхода, вам нужно return_sequences=True в каждом LSTM, который использует измерение дня в качестве шагов (не inner_seq). (Метод inner_average потерпит неудачу, и вам придется прибегнуть к подходу daily_minutes с return_sequences=True и другим Permute((2,1,3)) сразу после.

Shapes будет:

  • branch1: (m, d, 360, units1)
  • branch2: (m, d, 360, few_units) - для этого нужно отрегулировать Reshape
    • Изменение формы с использованием 1 временного шага будет ненужным, измерение days заменит 1.
    • Вам может понадобиться использовать Lambda слои для изменения формы с учетом размера партии и переменного количества дней (если нужны подробности, пожалуйста, сообщите мне)

Обучение и прогнозирование

(Извините, что сейчас нет времени на детализацию)

Затем вы можете следовать упомянутым подходам здесь и здесь также более полный с несколькими ссылками . (Будьте внимательны с выходными формами, хотя, по вашему вопросу, мы всегда сохраняем размер шага по времени, даже если он может быть 1)

Важное Очки:

  • Если вы выберете stateful=False:
    • это означает легкую тренировку с fit (если вы не использовали подход «разной длины»);
    • это также означает, что вам нужно будет построить новую модель с stateful=True, скопировать веса обученной модели;
    • затем вы делаете пошаговое ручное прогнозирование
  • Если вы выбираете stateful=True с самого начала:
    • , это обязательно означает ручное обучение l oop (например, train_on_batch);
    • это обязательно означает, что вам понадобится model.reset_states() всякий раз, когда вы собираетесь представить пакет, последовательности которого не являются продолжениями последнего пакета (каждый пакет, если ваши серии содержат целые последовательности).
    • не нужно создавать новую модель для ручного прогнозирования, но ручной прогноз остается прежним
2 голосов
/ 30 января 2020

Я думаю, что вы идете в правильном направлении, чтобы увеличить временные шаги в каждый день, вам нужно будет добавить пэд в свои данные, этот пример может помочь вам: https://github.com/keras-team/keras/blob/master/examples/imdb_lstm.py#L46.

Однако я бы также попробовал другие подходы, например, зафиксировать количество временных шагов, например, 3 дня, 4, 5 ... И затем, оценивая свой поезд, вы можете выбрать, сколько временных шагов лучшее для вашей модели.

Возможно, ваш первоначальный подход к увеличению количества дней будет лучше, но в этом типе проблемы найти лучшее количество временных шагов в LSTM очень важно.

...