Глубокое обучение

Одномерное прогнозирование временных рядов LSTM

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

Привет, как дела, надеюсь, тоже отлично.

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

Долговременная память (LSTM) — это следующее поколение рекуррентной нейронной сети (RNN), используемой в глубоком обучении благодаря своей оптимизированной архитектуре, позволяющей легко фиксировать закономерности в последовательных данных. . Преимущество этого типа сети заключается в том, что она может обучаться и запоминать длинные последовательности и не полагается на предварительно заданное наблюдение с задержкой окна в качестве входных данных.

В Keras это называется состоянием и включает в себя установку для аргумента «Stateful» значения «True» на уровне LSTM.

Кратко о том, что такое LSTM?

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

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

a.) Входной шлюз: решает, какие значения из ввода обновить состояние памяти.

b.) Forget Gate: определяет, какую информацию выбрасывать из блока.

c.) Шлюз вывода: окончательно определяет, что должно быть на выходе, на основе входных данных и шлюза памяти.

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

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

Давайте начнем!

Во-первых, это этап предварительной обработки данных, на котором мы должны предоставить структуру данных для контролируемого обучения в формате X и Y.

Проще говоря, он определяет силу и значения взаимосвязи (положительное/отрицательное воздействие, а полученные значения называются количественной оценкой воздействия) между одной зависимой переменной (Y) и рядом других независимых переменных X.

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

Теперь, как вы знаете, для обучения с учителем требуются независимые и зависимые переменные X и Y для алгоритма обучения / обучения, поэтому мы сначала преобразуем наши данные в такой формат.

Что мы сделаем, так это сначала возьмем данные о продажах (t) в нашем первом столбце, а затем во втором столбце будут данные о продажах (t+1) за следующий месяц, которые мы будем использовать для прогнозирования. Помните формат независимой и зависимой переменной X & Y, где мы используем Y для прогнозирования данных.

Приведенный ниже код преобразует временные ряды в контролируемое обучение. И да, df.fillna(0,inplace=True) означает замену значения NaN на 0 значений.

#supervised learning function
def timeseries_to_supervised(data, lag=1):
df = DataFrame(data)
columns = [df.shift(i) for i in range(1, lag+1)]
columns.append(df)
df = concat(columns, axis=1)
df.fillna(0, inplace=True)
return df

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

Следующим шагом будет преобразование данных временных рядов в Стационарные. И наши данные «sales_year.csv» не являются постоянными.

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

Стационарные данные легче моделировать, и, скорее всего, это приведет к более точным прогнозам.

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

Мы можем легко удалить тренд, отличив данные с помощью функции diff() от панд, которые представляют собой наблюдения с предыдущего временного шага (t-1), вычтенные из текущего наблюдения (t). Это даст нам ряд различий.

#create a differences series
def difference(dataset, interval=1):
diff = list()
for i in range(interval, len(dataset)):
value = dataset[i] - dataset[i - interval]
diff.append(value)
return Series(diff)
#invert differences value
def inverse_difference(history, yhat, interval=1):
return yhat + history[-interval]

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

LSTM немного чувствительны к широко распространенному масштабу данных. Даже во всех методах глубокого обучения масштабирование диапазона данных от -1 до 1 перед его подгонкой к нашему алгоритму является хорошей практикой, которая помогает алгоритму работать быстрее и эффективнее. И да масштабирование данных не потеряет своего первоначального смысла от данных. Мы также называем это нормализацией с использованием функции класса предварительной обработки MinMaxScaler.

Даже функцией активации по умолчанию для LSTMS является гиперболический тангенс (tanh), который выводит значения от -1 до 1, что является предпочтительным диапазоном для данных временных рядов.

#transform scale
X = series.values
X = X.reshape(len(X), 1)
scaler = MinMaxScaler(feature_range=(-1, 1))
scaler = scaler.fit(X)
scaled_X = scaler.transform(X)

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

invert transform
inverted_X = scaler.inverse_transform(scaled_X)

Пришло время развернуть LSTM.

По умолчанию слой LSTM в Keras поддерживает состояние между данными в одном пакете. Пакет данных — это количество строк фиксированного размера из обучающего набора данных, которое определяет, сколько шаблонов необходимо обработать перед обновлением весов сети. По умолчанию состояние в слое LSTM между пакетами очищается. Поэтому мы должны сделать LSTM с состоянием. Это дает нам детальный контроль над тем, когда состояние слоя LSTM очищается, с помощью функции reset_states().

Сеть LSTM ожидает, что входные данные (X) будут иметь формат [выборки, временные шаги, признаки].

X = X.reshape(X.shape[0], 1, X.shape[1])

Мы будем использовать Sequential API для определения сети. Форма входных данных должна быть указана в слое LSTM с использованием аргумента «batch_input_shape» в виде кортежа, который указывает ожидаемое количество наблюдений для достижения каждой партии, количество временных шагов и количество функций.

А количество нейронов также называют единицами памяти или блоками. Затем у нас есть 1 выходной слой Dense(1). В сети компиляции мы должны указать функцию потерь и алгоритм оптимизации для расчета потерь и веса.

model = Sequential()
model.add(LSTM(neurons, batch_input_shape=(batch_size, X.shape[1], X.shape[2]), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')

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

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

Таким образом, мы отключим перемешивание семплов, установив «shuffle» на «False».

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

for i in range(nb_epoch):
model.fit(X, y, epochs=1, batch_size=batch_size, verbose=0, shuffle=False)
model.reset_states()

Для параметра batch_size должно быть установлено значение 1. Даже в функции Predict() модели должно быть установлено значение 1, потому что мы заинтересованы в одношаговых прогнозах на тестовых данных.

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

Если вы новичок в LSTM и все еще не понимаете, как работает LSTM, перейдите по ссылке Иллюстрированное руководство по LSTM и GRU: пошаговое объяснение, чтобы получить четкое объяснение рабочего процесса LSTM.

Теперь давайте сложим все части воедино.

from pandas import DataFrame
from pandas import Series
from pandas import concat
from pandas import read_csv
from pandas import datetime
from sklearn.metrics import mean_squared_error
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from math import sqrt
from matplotlib import pyplot
import numpy
#supervised learning function
def timeseries_to_supervised(data, lag=1):
 df = DataFrame(data)
 columns = [df.shift(i) for i in range(1, lag+1)]
 columns.append(df)
 df = concat(columns, axis=1)
 df.fillna(0, inplace=True)
 return df
 
#create a difference series
def difference(dataset, interval=1):
 diff = list()
 for i in range(interval, len(dataset)):
  value = dataset[i] - dataset[i - interval]
  diff.append(value)
 return Series(diff)
 
#invert difference value
def inverse_difference(history, yhat, interval=1):
 return yhat + history[-interval]
 
#scale train and test data to [-1, 1]
def scale(train, test):
 # fit scaler
 scaler = MinMaxScaler(feature_range=(-1, 1))
 scaler = scaler.fit(train)
 # transform train
 train = train.reshape(train.shape[0], train.shape[1])
 train_scaled = scaler.transform(train)
 # transform test
 test = test.reshape(test.shape[0], test.shape[1])
 test_scaled = scaler.transform(test)
 return scaler, train_scaled, test_scaled
 
#inverse scaling for the forecast value
def invert_scale(scaler, X, value):
 new_row = [x for x in X] + [value]
 array = numpy.array(new_row)
 array = array.reshape(1, len(array))
 inverted = scaler.inverse_transform(array)
 return inverted[0, -1]
 
#fit an LSTM network to training data
def fit_lstm(train, batch_size, nb_epoch, neurons):
 X, y = train[:, 0:-1], train[:, -1]
 X = X.reshape(X.shape[0], 1, X.shape[1])
 model = Sequential()
 model.add(LSTM(neurons, batch_input_shape=(batch_size, X.shape[1], X.shape[2]), stateful=True))
 model.add(Dense(1))
 model.compile(loss='mean_squared_error', optimizer='adam')
 for i in range(nb_epoch):
  model.fit(X, y, epochs=1, batch_size=batch_size, verbose=1, shuffle=False)
  model.reset_states()
 return model
 
#make a one-step forecast
def forecast_lstm(model, batch_size, X):
 X = X.reshape(1, 1, len(X))
 yhat = model.predict(X, batch_size=batch_size)
 return yhat[0,0]
 
#load dataset
series = read_csv('sales_year.csv', header=0, parse_dates=[0], index_col=0, squeeze=True)
 
#transform data to be stationary
raw_values = series.values
diff_values = difference(raw_values, 1)
 
#transform data to be supervised learning
supervised = timeseries_to_supervised(diff_values, 1)
supervised_values = supervised.values
 
#split data into train and test-sets
train, test = supervised_values[0:-12], supervised_values[-12:]
 
#transform the scale of the data
scaler, train_scaled, test_scaled = scale(train, test)
 
#fit the model
lstm_model = fit_lstm(train_scaled, 1, 3000, 4)
#forecast the entire training dataset to build up state for forecasting
train_reshaped = train_scaled[:, 0].reshape(len(train_scaled), 1, 1)
lstm_model.predict(train_reshaped, batch_size=1)
 
#walk-forward validation on the test data
predictions = list()
for i in range(len(test_scaled)):
 #make one-step forecast
 X, y = test_scaled[i, 0:-1], test_scaled[i, -1]
 yhat = forecast_lstm(lstm_model, 1, X)
 #invert scaling
 yhat = invert_scale(scaler, X, yhat)
 #invert differencing
 yhat = inverse_difference(raw_values, yhat, len(test_scaled)+1-i)
 #store forecast
 predictions.append(yhat)
 expected = raw_values[len(train) + i + 1]
 print('Month=%d, Predicted=%f, Expected=%f' % (i+1, yhat, expected))
 
#report performance #raw_values[-12,] refers last 12 months/rows 
rmse = sqrt(mean_squared_error(raw_values[-12:], predictions))
print('Test RMSE: %.3f' % rmse)
#line plot of observed vs predicted
pyplot.plot(raw_values[-12:])
pyplot.plot(predictions)
pyplot.show()

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

Далее мы попробуем многомерный LSTM для временных рядов.

Я надеюсь, что вам понравилось.

Некоторые из моих альтернативных сайтов в Интернете: Facebook, Instagram, Udemy, Blogger, Issuu и другие.

Также доступно на Quora @ https://www.quora.com/profile/Rupak-Bob-Roy

Хорошего дня!