Réseau neuronal LSTM input shape from dataframe

j'essaie d'implémenter un LSTM avec Keras .

je sais que les LSTM en Keras nécessitent un tenseur 3D avec la forme (nb_samples, timesteps, input_dim) comme entrée. Cependant, je ne suis pas tout à fait sûr de la façon dont l'entrée devrait ressembler dans mon cas, car je n'ai qu'un échantillon d'observations T pour chaque entrée, pas plusieurs échantillons, c.-à-d. (nb_samples=1, timesteps=T, input_dim=N) . Est-il préférable de diviser chacune de mes entrées dans les échantillons de longueur T/M ? T est autour de quelques millions d'observations pour moi, alors quelle devrait être la durée de chaque échantillon dans ce cas, c.-à-d., Comment choisirais-je M ?

aussi, ai-je raison en ce que ce tenseur devrait ressembler à quelque chose comme:

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

où M et N définis comme avant et x correspond au dernier échantillon que j'aurais obtenu en divisant comme indiqué ci-dessus?

enfin, compte tenu d'une base de données pandas avec des observations T dans chaque colonne, et N colonnes, une pour chaque entrée, comment puis-je créer une entrée pour nourrir Keras?

24
demandé sur blue-phoenox 2016-09-24 12:21:49

2 réponses

ci-dessous est un exemple qui établit des données de séries chronologiques pour former un LSTM. La sortie du modèle est absurde que je ne le configurer pour montrer comment construire le modèle.

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

le Temps de la série dataframe:

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

vous pouvez construire des entrées put dans un vecteur et ensuite utiliser la fonction pandas .cumsum() pour construire la séquence pour la série temporelle:

# 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 sortie peut être configurée de manière similaire, mais il sera un vecteur unique au lieu d'une séquence:

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

les séquences d'entrée doivent être de la même longueur pour les exécuter à travers le modèle, vous devez donc les padder pour être la longueur maximale de vos vecteurs cumulés:

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

les données de formation peuvent être extraites de la base de données et placées dans des tableaux numpy. notez que les données d'entrée qui sortent du datagramme ne feront pas de tableau 3D. Il fait un tableau de tableaux, ce qui n'est pas la même chose.

vous pouvez utiliser hstack et reshape pour construire un tableau D'entrées 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))

pour le prouver:

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

une fois que vous avez les données de formation, vous pouvez définir les dimensions de votre couche d'entrée et de vos couches de sortie.

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

construire le modèle:

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

enfin, vous pouvez former le modèle et enregistrer le journal de formation comme l'histoire:

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

sortie:

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 

C'est ça. Utilisez model.predict(X)X est le même format (autre que le nombre d'échantillons) que X_train afin de faire des prédictions à partir du modèle.

29
répondu Andrew 2016-10-12 18:25:12

tenseur shape

vous avez raison Keras s'attend à un tenseur 3D pour un réseau neuronal LSTM, mais je pense que la pièce qui vous manque est que Keras s'attend à ce que chaque observation peut avoir plusieurs dimensions .

par exemple, dans Keras j'ai utilisé des vecteurs de mots pour représenter des documents pour le traitement du langage naturel. Chaque mot dans le document est représenté par un n-dimensionnelle numérique vecteur (donc si n = 2 le mot "chat" serait représenté par quelque chose comme [0.31, 0.65] ). Pour représenter un seul document, les vecteurs de mots sont alignés en séquence (par exemple " THE cat sat.'= [[0.12, 0.99], [0.31, 0.65], [0.94, 0.04]] ). Un document serait un échantillon unique dans un LSTM de Keras.

c'est analogue à vos observations de séries chronologiques. Un document est comme une série temporelle, et un mot est comme une observation unique dans votre série temporelle, mais dans votre cas, c'est juste que le la représentation de votre observation n'est que de dimensions n = 1 .

à cause de cela, je pense que votre tenseur devrait être quelque chose comme [[[a1], [a2], ... , [aT]], [[b1], [b2], ..., [bT]], ..., [[x1], [x2], ..., [xT]]] , où x correspond à nb_samples , timesteps = T , et input_dim = 1 , parce que chacune de vos observations est un seul nombre.

Taille du lot

La taille du lot

doit être réglée pour maximiser le débit sans dépasser la capacité de mémoire sur votre machine, par ce poste croisé validé . Pour autant que je sache votre entrée n'a pas besoin d'être un multiple de votre taille de lot, ni lors de la formation du modèle et de faire des prédictions à partir de celui-ci.

exemples

si vous cherchez un exemple de code, sur le Keras Github il y a un certain nombre d'exemples utilisant LSTM et d'autres types de réseau qui ont une entrée séquencée.

5
répondu Andrew 2017-04-13 12:44:13