Временные ряды - модель LSTM

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

LSTM - это класс рекуррентной нейронной сети. Поэтому, прежде чем мы сможем перейти к LSTM, важно понять нейронные сети и рекуррентные нейронные сети.

Нейронные сети

Искусственная нейронная сеть - это слоистая структура связанных нейронов, вдохновленная биологическими нейронными сетями. Это не один алгоритм, а комбинации различных алгоритмов, которые позволяют нам выполнять сложные операции с данными.

Рекуррентные нейронные сети

Это класс нейронных сетей, предназначенных для работы с временными данными. Нейроны RNN имеют состояние / память ячейки, и ввод обрабатывается в соответствии с этим внутренним состоянием, которое достигается с помощью циклов с в нейронной сети. В RNN есть повторяющиеся модули слоев 'tanh', которые позволяют им сохранять информацию. Однако ненадолго, поэтому нам нужны модели LSTM.

LSTM

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

На приведенном выше рисунке показаны четыре слоя нейронной сети в желтых прямоугольниках, точечные операторы в зеленых кружках, ввод в желтых кружках и состояние ячейки в голубых кружках. Модуль LSTM имеет состояние ячейки и три шлюза, которые предоставляют им возможность выборочно изучать, отменять или сохранять информацию от каждого из модулей. Состояние ячеек в LSTM помогает информации проходить через блоки без изменения, позволяя лишь несколько линейных взаимодействий. Каждое устройство имеет вход, выход и вентиль забывания, который может добавлять или удалять информацию о состоянии ячейки. Шлюз забывания решает, какую информацию из предыдущего состояния ячейки следует забыть, для чего он использует сигмоидальную функцию. Входной вентиль управляет информационным потоком к текущему состоянию ячейки, используя операцию умножения "сигмоида" и "tanh" соответственно по точкам. Наконец, выходной вентиль решает, какую информацию следует передать в следующее скрытое состояние.

Теперь, когда мы разобрались с внутренней работой модели LSTM, приступим к ее реализации. Чтобы понять реализацию LSTM, мы начнем с простого примера - прямой линии. Посмотрим, сможет ли LSTM узнать взаимосвязь прямой и предсказать ее.

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

В [402]:

x = numpy.arange (1,500,1)
y = 0.4 * x + 30
plt.plot(x,y)

Из [402]:

[<matplotlib.lines.Line2D at 0x1eab9d3ee10>]

В [403]:

trainx, testx = x[0:int(0.8*(len(x)))], x[int(0.8*(len(x))):]
trainy, testy = y[0:int(0.8*(len(y)))], y[int(0.8*(len(y))):]
train = numpy.array(list(zip(trainx,trainy)))
test = numpy.array(list(zip(trainx,trainy)))

Теперь, когда данные созданы и разделены на обучающие и тестовые. Давайте преобразуем данные временных рядов в форму данных контролируемого обучения в соответствии со значением периода ретроспективного анализа, который, по сути, представляет собой количество задержек, которые видны для прогнозирования значения в момент времени 't'.

Итак, такой временной ряд -

time variable_x
t1  x1
t2  x2
 :   :
 :   :
T   xT

Когда период ретроспективного анализа равен 1, преобразуется в -

x1   x2
x2   x3
 :    :
 :    :
xT-1 xT

В [404]:

def create_dataset(n_X, look_back):
   dataX, dataY = [], []
   for i in range(len(n_X)-look_back):
      a = n_X[i:(i+look_back), ]
      dataX.append(a)
      dataY.append(n_X[i + look_back, ])
   return numpy.array(dataX), numpy.array(dataY)

В [405]:

look_back = 1
trainx,trainy = create_dataset(train, look_back)
testx,testy = create_dataset(test, look_back)

trainx = numpy.reshape(trainx, (trainx.shape[0], 1, 2))
testx = numpy.reshape(testx, (testx.shape[0], 1, 2))

Теперь обучим нашу модель.

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

В [ ]:

from keras.models import Sequential
from keras.layers import LSTM, Dense

model = Sequential()
model.add(LSTM(256, return_sequences = True, input_shape = (trainx.shape[1], 2)))
model.add(LSTM(128,input_shape = (trainx.shape[1], 2)))
model.add(Dense(2))
model.compile(loss = 'mean_squared_error', optimizer = 'adam')
model.fit(trainx, trainy, epochs = 2000, batch_size = 10, verbose = 2, shuffle = False)
model.save_weights('LSTMBasic1.h5')

В [407]:

model.load_weights('LSTMBasic1.h5')
predict = model.predict(testx)

Теперь посмотрим, как выглядят наши прогнозы.

В [408]:

plt.plot(testx.reshape(398,2)[:,0:1], testx.reshape(398,2)[:,1:2])
plt.plot(predict[:,0:1], predict[:,1:2])

Из [408]:

[<matplotlib.lines.Line2D at 0x1eac792f048>]

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

В [409]:

x = numpy.arange (1,500,1)
y = numpy.sin(x)
plt.plot(x,y)

Из [409]:

[<matplotlib.lines.Line2D at 0x1eac7a0b3c8>]

В [410]:

trainx, testx = x[0:int(0.8*(len(x)))], x[int(0.8*(len(x))):]
trainy, testy = y[0:int(0.8*(len(y)))], y[int(0.8*(len(y))):]
train = numpy.array(list(zip(trainx,trainy)))
test = numpy.array(list(zip(trainx,trainy)))

В [411]:

look_back = 1
trainx,trainy = create_dataset(train, look_back)
testx,testy = create_dataset(test, look_back)
trainx = numpy.reshape(trainx, (trainx.shape[0], 1, 2))
testx = numpy.reshape(testx, (testx.shape[0], 1, 2))

В [ ]:

model = Sequential()
model.add(LSTM(512, return_sequences = True, input_shape = (trainx.shape[1], 2)))
model.add(LSTM(256,input_shape = (trainx.shape[1], 2)))
model.add(Dense(2))
model.compile(loss = 'mean_squared_error', optimizer = 'adam')
model.fit(trainx, trainy, epochs = 2000, batch_size = 10, verbose = 2, shuffle = False)
model.save_weights('LSTMBasic2.h5')

В [413]:

model.load_weights('LSTMBasic2.h5')
predict = model.predict(testx)

В [415]:

plt.plot(trainx.reshape(398,2)[:,0:1], trainx.reshape(398,2)[:,1:2])
plt.plot(predict[:,0:1], predict[:,1:2])

Из [415]:

[<matplotlib.lines.Line2D at 0x1eac7a1f550>]

Теперь вы готовы перейти к любому набору данных.