来自数据框的神经网络 LSTM 输入形状

Neural Network LSTM input shape from dataframe

我正在尝试实施 LSTM with Keras

我知道 Keras 中的 LSTM 需要一个形状为 (nb_samples, timesteps, input_dim) 的 3D 张量作为输入。但是,我不完全确定在我的情况下输入应该是什么样子,因为每个输入只有一个 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 对应于我从上面讨论的拆分中获得的最后一个样本?

最后,给定一个 pandas 数据框,每列有 T 个观察值,N 列,每个输入一个,我如何创建这样的输入以提供给 Keras ?

张量形状

你说得对,Keras 期待 LSTM 神经网络的 3D 张量,但我认为你缺少的部分是 Keras 期待 每个观察可以有多个维度.

例如,在 Keras 中,我使用词向量来表示用于自然语言处理的文档。文档中的每个单词都由一个 n 维数值向量表示(因此,如果 n = 2 单词 'cat' 将由类似 [0.31, 0.65] 的内容表示)。为了表示单个文档,单词向量按顺序排列(例如 'The cat sat.' = [[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_samplestimesteps = Tinput_dim = 1,因为你的每一个观察结果只有一个数字。

批量大小

根据此 Cross Validated post,应将批处理大小设置为在不超过计算机内存容量的情况下最大化吞吐量。据我所知,您的输入不需要是批量大小的倍数,在训练模型和根据模型进行预测时也是如此。

例子

如果您正在寻找示例代码,Keras Github 上有许多使用 LSTM 和其他已排序输入的网络类型的示例。

下面是一个设置时间序列数据来训练 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

您可以将输入构建到向量中,然后使用 pandas .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)

可以从数据框中提取训练数据并将其放入 numpy 数组中。 请注意,来自数据框的输入数据不会构成 3D 数组。它做一个数组的数组,这不是一回事。

您可以使用 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),其中 XX_train 的格式相同(样本数除外),以便根据模型进行预测。