Red neuronal LSTM forma de entrada desde dataframe


Estoy tratando de implementar un LSTM con Keras.

Sé que los LSTM en Keras requieren un tensor 3D con shape (nb_samples, timesteps, input_dim) como entrada. Sin embargo, no estoy completamente seguro de cómo debería ser la entrada en mi caso, ya que solo tengo una muestra de T observaciones para cada entrada, no varias muestras, es decir, (nb_samples=1, timesteps=T, input_dim=N). Es mejor dividir cada una de mis entradas en muestras de longitud T/M? T es alrededor de unos pocos millones de observaciones para mí, así que cuánto tiempo debe cada muestra en ese caso ser, es decir, ¿cómo elegiría M?

También, estoy en lo cierto en que este tensor debería verse algo así como: {[12]]}

[[[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]]]

Donde M y N definidos como antes y x corresponden a la última muestra que habría obtenido de la división como se discutió anteriormente?

Finalmente, dado un dataframe de pandas con T observaciones en cada columna, y N columnas, una para cada entrada, ¿cómo puedo crear tal entrada para alimentar a Keras?

Author: blue-phoenox, 2016-09-24

2 answers

A continuación se muestra un ejemplo que configura datos de series temporales para entrenar un LSTM. La salida del modelo es una tontería, ya que solo la configuré para demostrar cómo construir el modelo.

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()

Dataframe de la serie temporal:

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

Puede construir entradas put en un vector y luego usar la función pandas .cumsum() para construir la secuencia para la serie temporal:

# 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()

La salida se puede configurar de manera similar, pero será un solo vector en lugar de una secuencia:

# 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)

La entrada las secuencias tienen que tener la misma longitud para ejecutarlas a través del modelo, por lo que necesita rellenarlas para que sean la longitud máxima de sus vectores acumulativos:

# 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)

Los datos de entrenamiento se pueden extraer del dataframe y poner en matrices numpy. Tenga en cuenta que los datos de entrada que salen del dataframe no formarán una matriz 3D. Hace una matriz de matrices, que no es lo mismo.

Puede usar hstack y reshape para construir una matriz de entrada 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))

Para probar it:

>>> print(X_train_init.shape)
(11,)
>>> print(X_train.shape)
(11, 11, 6)
>>> print(X_train == X_train_init)
False

Una vez que tenga datos de entrenamiento, puede definir las dimensiones de la capa de entrada y las capas de salida.

# 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])

Construir el modelo:

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'])

Finalmente puede entrenar el modelo y guardar el registro de entrenamiento como historial:

# 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)

Salida:

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 

Eso es todo. Utilice model.predict(X) donde X es el mismo formato (distinto del número de muestras) que X_train para hacer predicciones a partir del modelo.

 29
Author: Andrew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-12 18:25:12

Forma del tensor

Tienes razón en que Keras espera un tensor 3D para una red neuronal LSTM, pero creo que lo que te falta es que Keras espera que cada observación pueda tener múltiples dimensiones.

Por ejemplo, en Keras he usado vectores de palabras para representar documentos para el procesamiento del lenguaje natural. Cada palabra en el documento está representada por un vector numérico n-dimensional (así que si n = 2 la palabra ' cat ' estaría representada por algo así como [0.31, 0.65]). Para representar un solo documento, los vectores de palabras se alinean en secuencia (por ejemplo, ' The cat sat.' = [[0.12, 0.99], [0.31, 0.65], [0.94, 0.04]]). Un documento sería una sola muestra en un LSTM de Keras.

Esto es análogo a sus observaciones de series temporales. Un documento es como una serie temporal, y una palabra es como una sola observación en su serie temporal, pero en su caso es solo que la representación de su observación es simplemente n = 1 dimensiones.

Debido a eso, creo que su tensor debe ser algo así como [[[a1], [a2], ... , [aT]], [[b1], [b2], ..., [bT]], ..., [[x1], [x2], ..., [xT]]], donde x corresponde a nb_samples, timesteps = T, y input_dim = 1, porque cada una de sus observaciones es solo un número.

Tamaño del lote

El tamaño del lote debe configurarse para maximizar el rendimiento sin exceder la capacidad de memoria de su máquina, según este Post cruzado validado. Por lo que sé, su entrada no necesita ser un múltiplo del tamaño de su lote, ni al entrenar el modelo y hacer predicciones desde se.

Ejemplos

Si está buscando código de ejemplo, en el Keras Github hay una serie de ejemplos que usan LSTM y otros tipos de red que tienen entrada secuenciada.

 5
Author: Andrew,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-13 12:44:13