J'essaye d'implémenter un LSTM avec Keras .
Je sais que les LSTM de Keras nécessitent un tenseur 3D de forme (nb_samples, timesteps, input_dim)
en entrée. Cependant, je ne sais pas exactement à quoi devrait ressembler l'entrée dans mon cas, car je n'ai qu'un échantillon d'observations T
pour chaque entrée, pas plusieurs échantillons, c'est-à-dire (nb_samples=1, timesteps=T, input_dim=N)
. Est-il préférable de diviser chacune de mes entrées en échantillons de longueur T/M
? T
représente environ quelques millions d'observations pour moi, alors quelle devrait être la durée de chaque échantillon dans ce cas, c'est-à-dire comment choisir 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 précédemment et x correspond au dernier échantillon que j'aurais obtenu en divisant comme discuté ci-dessus?
Enfin, étant donné un pandas dataframe avec T
observations dans chaque colonne et N
colonnes, une pour chaque entrée, comment puis-je créer une telle entrée pour alimenter à Keras?
Vous trouverez ci-dessous un exemple de configuration de données de séries chronologiques pour former un LSTM. La sortie du modèle est absurde, car je ne l'ai configurée que 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()
Cadre de données des séries chronologiques:
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 créer des entrées put dans un vecteur, puis utiliser la fonction pandas .cumsum()
pour créer la séquence de la série chronologique:
# 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 ce sera un seul vecteur 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 dans le modèle, vous devez donc les remplir pour qu'elles correspondent à la longueur maximale de vos vecteurs cumulatifs:
# 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 d'entraînement peuvent être extraites de la trame de données et placées dans des tableaux numpy. Notez que les données d'entrée qui sortent de la trame de données ne feront pas un tableau 3D. Cela fait un tableau de tableaux, ce qui n'est pas la même chose.
Vous pouvez utiliser hstack et remodeler pour créer un tableau d'entrée 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 des données d'entraînement, 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])
Construisez 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 en tant qu'historique:
# 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)
Production:
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 tout. Utilisez model.predict(X)
où 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.
Forme du tenseur
Vous avez raison de dire que Keras 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, à Keras, j'ai utilisé des vecteurs Word pour représenter des documents pour le traitement du langage naturel. Chaque mot du document est représenté par un vecteur numérique à n dimensions (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 Word sont alignés en séquence (par exemple, 'Le chat était assis.' = [[0.12, 0.99], [0.31, 0.65], [0.94, 0.04]]
). Un document serait un échantillon unique dans un Keras LSTM.
Ceci est analogue à vos observations de séries chronologiques. Un document est comme une série chronologique et un mot est comme une seule observation dans votre série chronologique, mais dans votre cas, c'est simplement que la représentation de votre observation est juste n = 1
dimensions.
Pour cette raison, 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
, car chacune de vos observations n'est qu'un seul chiffre.
Taille du lot
La taille du lot doit être définie pour maximiser le débit sans dépasser la capacité de mémoire de votre machine, par ceci Post validé croisé . Pour autant que je sache, votre saisie n'a pas besoin d'être un multiple de la taille de votre lot, ni lors de la formation du modèle et de la création de prévisions à 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éseaux qui ont une entrée séquencée.