В этой истории мы собираемся сделать прогнозирование временных рядов, используя RNN в наборе данных Quandl в Google Collaboratory.
Quandl (https://www.quandl.com) — набор данных, используемый для финансово-экономического анализа.
Чтобы получить доступ к данным Quandl в коде Python, нам нужно установить пакет Python Quandl:
!pip install quandl
После импорта пакета в код нам нужно установить ключ API, который можно получить на сайте Quandl, создав бесплатную учетную запись.
import quandl quandl.ApiConfig.api_key = 'YOUR_API_KEY'
Мы также будем использовать Keras из пакета TensorFlow. Версия TensorFlow по умолчанию, установленная в Google Colaboratory, — это версия 1.15. Мы можем обновить его до версии 2.0, используя следующий код.
!pip install --upgrade tensorflow import tensorflow as tf from tensorflow import keras Tf.__version__ > '2.0.0'
В этой истории мы будем использовать Quandl API для получения набора данных о ценах на акции Microsoft и попытаемся предсказать высокое значение.
mydata = quandl.get("WIKI/MSFT") mydata.head()
data = mydata['High'].values data.shape > (8076,)
Используя три модели — Simple RNN, Deep RNN и LSTM — мы выполняем одни и те же шаги для каждой:
- Разделение данных
- Определение модели
- Компиляция модели (указание функции потерь, алгоритма оптимизации и показателей)
- Подгонка модели
- Оценка модели
- Делать прогнозы
Использование простой модели RNN
Чтобы применить методы прогнозирования временных рядов, данные необходимо разделить на пакеты:
def split_in_batches(data, n_steps): return data.reshape(-1)[:(data.size // n_steps * n_steps)].reshape(-1,n_steps,1)
Используя наш метод split_in_batches, мы разделили наши данные на партии по 60 (50 шагов обучения/независимая переменная/X и 10 следующих шагов для прогнозирования/зависимая переменная/Y):
n_steps = 50 data = split_in_batches(data, n_steps + 10) data.shape > (134, 60, 1)
На следующем шаге мы должны разделить данные на наборы для обучения, проверки и тестирования. Мы берем 80 процентов в качестве обучающего набора, 10 процентов в качестве проверки, а остальные — в качестве тестового набора.
X_size = data.shape[0] X_train_size = round(X_size * 0.8) X_valid_size = round((X_size - X_train_size)/2) X_test_size = X_size - X_train_size - X_valid_size X_train, y_train = data[:X_train_size, :n_steps], data[:X_train_size, -10:] X_valid, y_valid = data[X_train_size:X_train_size+X_valid_size, :n_steps], data[X_train_size:X_train_size+X_valid_size, -10:] X_test, y_test = data[X_train_size+X_valid_size:, :n_steps], data[X_train_size+X_valid_size:, -10:] print('train:', X_train.shape, y_train.shape) > train: (107, 50, 1) (107, 10, 1) print('valid:', X_valid.shape, y_valid.shape) > valid: (14, 50, 1) (14, 10, 1) print('test:', X_test.shape, y_test.shape) > test: (13, 50, 1) (13, 10, 1)
Затем мы вычисляем базовый прогноз, чтобы оценить производительность нашей модели в конце.
y_pred = np.repeat(X_valid[:,-1], 10, axis=1)[:,:,np.newaxis] np.mean(keras.losses.mean_squared_error(y_valid, y_pred)) > 1.1452930265000008
Мы используем последовательный API Keras для построения простой модели RNN с двумя SimpleRNN и плотным слоем из 10 нейронов в качестве выходных данных.
model_simple_rnn = keras.models.Sequential([ keras.layers.SimpleRNN(20, return_sequences=True, input_shape=[None, 1]), keras.layers.SimpleRNN(20), keras.layers.Dense(10) ])
На этапе компиляции нам нужно указать функцию потерь и оптимизатор. Здесь мы используем «Среднеквадратичную ошибку» в качестве функции потерь и «Адам» в качестве алгоритма оптимизации.
model_simple_rnn.compile(loss='mse', optimizer='adam')
Метод summary
дает текстовое представление модели:
model_simple_rnn.summary() > Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= simple_rnn (SimpleRNN) (None, None, 20) 440 _________________________________________________________________ simple_rnn_1 (SimpleRNN) (None, 20) 820 _________________________________________________________________ dense (Dense) (None, 10) 210 ================================================================= Total params: 1,470 Trainable params: 1,470 Non-trainable params: 0 _________________________________________________________________
Затем мы будем обучать нашу модель по данным поезда. Эпоха — это количество раз, когда наша модель получает данные из всего набора данных. Мы используем %%timeit
для измерения времени обучения. Это одна из магических команд Python, которая используется для измерения времени выполнения команды.
%%timeit model_simple_rnn.fit(X_train, y_train, epochs=200, validation_data=(X_valid, y_valid), verbose=0) > 1 loop, best of 3: 13.3 s per loop
Последним шагом является оценка модели с использованием тестовых данных. Метод evaluate
возвращает значение потерь и значение метрик для модели.
model_simple_rnn.evaluate(X_test, y_test) > 230.00787353515625
Мы можем использовать pyplot
, чтобы нарисовать историю обучения нашей модели.
def plot_training_history(history): plt.plot(history.history['val_loss'], 'r', label='Validation loss') plt.plot(history.history['loss'], 'b', label='Training loss') plt.legend() plot_training_history(model_simple_rnn.history)
Использование модели Deep RNN
Попробуем более сложную модель. В этом разделе вместо того, чтобы пытаться предсказать следующие 10 шагов, основываясь только на последнем шаге (из 50), мы попытаемся предсказать следующие 10 шагов на каждом шаге (из 50). Для этого мы должны определить новый Y.
Y = np.empty((X_size, n_steps, 10)) for step_ahead in range(1, 10 + 1): Y[..., step_ahead - 1] = data[..., step_ahead:step_ahead+n_steps, 0] Y_train = Y[:X_train_size] Y_valid = Y[X_train_size:X_train_size+X_valid_size] Y_test = Y[X_train_size+X_valid_size:]
Мы снова используем последовательный API Keras, чтобы построить модель RNN с двумя SimpleRNN и плотным слоем из 10 нейронов в качестве выходных данных с оболочкой TimeDistributed
, чтобы применить слой ко всем дополнительным слоям, которые мы добавили к Y.
model_deep_rnn = keras.models.Sequential([ keras.layers.SimpleRNN(20, return_sequences=True, input_shape=[None, 1]), keras.layers.SimpleRNN(20, return_sequences=True), keras.layers.TimeDistributed(keras.layers.Dense(10)) ]) model_deep_rnn.summary() > Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= simple_rnn_2 (SimpleRNN) (None, None, 20) 440 _________________________________________________________________ simple_rnn_3 (SimpleRNN) (None, None, 20) 820 _________________________________________________________________ time_distributed (TimeDistri (None, None, 10) 210 ================================================================= Total params: 1,470 Trainable params: 1,470 Non-trainable params: 0
Поскольку мы добавили дополнительные слои к Y, мы не можем просто сравнить потери этой модели с предыдущей. Поэтому мы определяем новую метрику, которая вычисляет только квадрат ошибки для последнего индекса Y.
def last_time_step_mse(Y_true, Y_pred): return keras.metrics.mean_squared_error(Y_true[:, -1], Y_pred[:, -1]) optimizer = keras.optimizers.Adam(lr=0.01) model_deep_rnn.compile(loss="mse", optimizer=optimizer, metrics=[last_time_step_mse])
Затем мы будем обучать нашу модель по данным поезда.
%%timeit model_deep_rnn.fit(X_train, Y_train, epochs=200, validation_data=(X_valid, Y_valid), verbose=0) > 1 loop, best of 3: 14.8 s per loop
И последний шаг — оценка модели с использованием тестовых данных. Метод evaluate
возвращает значение потерь, а также значение пользовательской метрики для модели.
model_deep_rnn.evaluate(X_test, Y_test) > [7.594574928283691, 4.924448]
Как и ожидалось, результат намного лучше, чем у простой модели RNN. Теперь мы можем использовать ранее определенный метод plot_training_hostory
для построения истории обучения нашей новой модели.
plot_training_history(model_deep_rnn.history)
Использование LSTM
Давайте попробуем модель LSTM, чтобы сделать прогноз.
model_lstm = tf.keras.models.Sequential([ tf.keras.layers.LSTM(20, return_sequences=True, input_shape=[None, 1]), tf.keras.layers.LSTM(20, return_sequences=True), tf.keras.layers.TimeDistributed(tf.keras.layers.Dense(10)) ]) model_lstm.compile(loss="mse", optimizer="adam") model_lstm.summary() > Model: "sequential_2" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= lstm (LSTM) (None, None, 20) 1760 _________________________________________________________________ lstm_1 (LSTM) (None, None, 20) 3280 _________________________________________________________________ time_distributed_1 (TimeDist (None, None, 10) 210 ================================================================= Total params: 5,250 Trainable params: 5,250 Non-trainable params: 0 _________________________________________________________________
Затем мы обучим нашу модель LSTM.
%%timeit model_lstm.fit(X_train, Y_train, epochs=200, validation_data=(X_valid, Y_valid),verbose=0) > 1 loop, best of 3: 25.3 s per loop
А затем оцените его, используя тестовые данные.
model_lstm.evaluate(X_test, Y_test) > 162.5330047607422
И, наконец, нарисуйте историю обучения нашей модели LSTM.
plot_training_history(model_lstm.history)