Глубокое обучение
Одномерное прогнозирование временных рядов 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
Хорошего дня!