Нейронная сеть LSTM форма ввода из датафрейма
Я пытаюсь реализовать LSTM с Keras.
Я знаю, что для LSTM в Керасе требуется трехмерный тензор с формой (nb_samples, timesteps, input_dim)
в качестве входа. Тем не менее, я не совсем уверен, как должны выглядеть входные данные в моем случае, так как у меня есть только один образец T
наблюдения для каждого входа, а не для нескольких выборок, т.е. (nb_samples=1, timesteps=T, input_dim=N)
, Лучше ли разбить каждый из моих входов на образцы длины T/M
? T
для меня это около нескольких миллионов наблюдений, так как долго должна быть каждая выборка в этом случае, т.е. как бы я выбрал M
?
Кроме того, я прав, что этот тензор должен выглядеть примерно так:
[[[a_11, a_12, ..., a_1M], [a_21, a_22, ..., a_2M], ..., [a_N1, a_N2, ..., a_NM]],
[[b_11, b_12, ..., b_1M], [b_21, b_22, ..., b_2M], ..., [b_N1, b_N2, ..., b_NM]],
...,
[[x_11, x_12, ..., a_1M], [x_21, x_22, ..., x_2M], ..., [x_N1, x_N2, ..., x_NM]]]
где M и N определены как прежде, а x соответствует последнему образцу, который я получил бы при расщеплении, как обсуждалось выше?
Наконец, дано информационный кадр с пандами с T
наблюдения в каждой колонке, и N
столбцы, по одному на каждый вход, как я могу создать такой вход для подачи в Keras?
2 ответа
Ниже приведен пример, который устанавливает данные временных рядов для обучения LSTM. Вывод модели - это чепуха, поскольку я настроил ее только для демонстрации того, как построить модель.
import pandas as pd
import numpy as np
# Get some time series data
df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/timeseries.csv")
df.head()
Фрейм данных временного ряда:
Date A B C D E F G
0 2008-03-18 24.68 164.93 114.73 26.27 19.21 28.87 63.44
1 2008-03-19 24.18 164.89 114.75 26.22 19.07 27.76 59.98
2 2008-03-20 23.99 164.63 115.04 25.78 19.01 27.04 59.61
3 2008-03-25 24.14 163.92 114.85 27.41 19.61 27.84 59.41
4 2008-03-26 24.44 163.45 114.84 26.86 19.53 28.02 60.09
Вы можете построить входные данные в вектор, а затем использовать панд .cumsum()
Функция для построения последовательности для временного ряда:
# Put your inputs into a single list
df['single_input_vector'] = df[input_cols].apply(tuple, axis=1).apply(list)
# Double-encapsulate list so that you can sum it in the next step and keep time steps as separate elements
df['single_input_vector'] = df.single_input_vector.apply(lambda x: [list(x)])
# Use .cumsum() to include previous row vectors in the current row list of vectors
df['cumulative_input_vectors'] = df.single_input_vector.cumsum()
Выходные данные могут быть настроены аналогичным образом, но это будет отдельный вектор вместо последовательности:
# If your output is multi-dimensional, you need to capture those dimensions in one object
# If your output is a single dimension, this step may be unnecessary
df['output_vector'] = df[output_cols].apply(tuple, axis=1).apply(list)
Входные последовательности должны быть одинаковой длины, чтобы проходить их через модель, поэтому вам нужно добавить их, чтобы получить максимальную длину ваших совокупных векторов:
# Pad your sequences so they are the same length
from keras.preprocessing.sequence import pad_sequences
max_sequence_length = df.cumulative_input_vectors.apply(len).max()
# Save it as a list
padded_sequences = pad_sequences(df.cumulative_input_vectors.tolist(), max_sequence_length).tolist()
df['padded_input_vectors'] = pd.Series(padded_sequences).apply(np.asarray)
Данные обучения могут быть извлечены из кадра данных и помещены в массивы. Обратите внимание, что входные данные, которые выходят из фрейма данных, не будут создавать трехмерный массив. Он создает массив массивов, что не одно и то же.
Вы можете использовать hstack и reshape для создания входного массива 3D.
# Extract your training data
X_train_init = np.asarray(df.padded_input_vectors)
# Use hstack to and reshape to make the inputs a 3d vector
X_train = np.hstack(X_train_init).reshape(len(df),max_sequence_length,len(input_cols))
y_train = np.hstack(np.asarray(df.output_vector)).reshape(len(df),len(output_cols))
Чтобы доказать это:
>>> print(X_train_init.shape)
(11,)
>>> print(X_train.shape)
(11, 11, 6)
>>> print(X_train == X_train_init)
False
Когда у вас есть тренировочные данные, вы можете определить размеры входного и выходного слоев.
# Get your input dimensions
# Input length is the length for one input sequence (i.e. the number of rows for your sample)
# Input dim is the number of dimensions in one input vector (i.e. number of input columns)
input_length = X_train.shape[1]
input_dim = X_train.shape[2]
# Output dimensions is the shape of a single output vector
# In this case it's just 1, but it could be more
output_dim = len(y_train[0])
Построить модель:
from keras.models import Model, Sequential
from keras.layers import LSTM, Dense
# Build the model
model = Sequential()
# I arbitrarily picked the output dimensions as 4
model.add(LSTM(4, input_dim = input_dim, input_length = input_length))
# The max output value is > 1 so relu is used as final activation.
model.add(Dense(output_dim, activation='relu'))
model.compile(loss='mean_squared_error',
optimizer='sgd',
metrics=['accuracy'])
Наконец, вы можете обучить модель и сохранить журнал тренировок как историю:
# Set batch_size to 7 to show that it doesn't have to be a factor or multiple of your sample size
history = model.fit(X_train, y_train,
batch_size=7, nb_epoch=3,
verbose = 1)
Выход:
Epoch 1/3
11/11 [==============================] - 0s - loss: 3498.5756 - acc: 0.0000e+00
Epoch 2/3
11/11 [==============================] - 0s - loss: 3498.5755 - acc: 0.0000e+00
Epoch 3/3
11/11 [==============================] - 0s - loss: 3498.5757 - acc: 0.0000e+00
Вот и все. использование model.predict(X)
где X
тот же формат (кроме количества образцов), что и X_train
для того, чтобы делать прогнозы из модели.
Тензорная форма
Вы правы, что Keras ожидает 3D-тензор для нейронной сети LSTM, но я думаю, что вам не хватает того, что Keras ожидает, что каждое наблюдение может иметь несколько измерений.
Например, в Керасе я использовал векторы слов для представления документов для обработки на естественном языке. Каждое слово в документе представлено n-мерным числовым вектором (так что если n = 2
слово "кот" будет представлено чем-то вроде [0.31, 0.65]
). Для представления одного документа векторы слов выстроены в последовательности (например, "Кошка села". = [[0.12, 0.99], [0.31, 0.65], [0.94, 0.04]]
). Документом будет один образец в Keras LSTM.
Это аналогично вашим наблюдениям временных рядов. Документ подобен временному ряду, а слово - как отдельное наблюдение в вашем временном ряду, но в вашем случае просто представление вашего наблюдения просто n = 1
размеры.
Из-за этого, я думаю, что ваш тензор должен быть что-то вроде [[[a1], [a2], ... , [aT]], [[b1], [b2], ..., [bT]], ..., [[x1], [x2], ..., [xT]]]
, где x
соответствует nb_samples
, timesteps = T
, а также input_dim = 1
потому что каждое из ваших наблюдений - только одно число.
Размер партии
Размер пакета должен быть установлен так, чтобы максимизировать пропускную способность без превышения объема памяти на вашем компьютере, согласно этой публикации с перекрестной проверкой. Насколько я знаю, ваши входные данные не должны быть кратными размеру пакета, ни при обучении модели, ни при ее прогнозировании.
Примеры
Если вы ищете пример кода, на Keras Github есть несколько примеров использования LSTM и других типов сетей с последовательным вводом.