J'essaie de concilier ma compréhension des LSTM et souligné ici dans ce post par Christopher Olah mis en œuvre à Keras. Je suis le blog écrit par Jason Brownlee pour le tutoriel Keras. Ce qui me trouble le plus, c'est
- Le remodelage de la série de données en
[samples, time steps, features]
et, - Les LSTM avec état
Concentrons-nous sur les deux questions ci-dessus en référence au code collé ci-dessous:
# reshape into X=t and Y=t+1
look_back = 3
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
# reshape input to be [samples, time steps, features]
trainX = numpy.reshape(trainX, (trainX.shape[0], look_back, 1))
testX = numpy.reshape(testX, (testX.shape[0], look_back, 1))
########################
# The IMPORTANT BIT
##########################
# create and fit the LSTM network
batch_size = 1
model = Sequential()
model.add(LSTM(4, batch_input_shape=(batch_size, look_back, 1), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
for i in range(100):
model.fit(trainX, trainY, nb_epoch=1, batch_size=batch_size, verbose=2, shuffle=False)
model.reset_states()
Remarque: create_dataset prend une séquence de longueur N et retourne un N-look_back
tableau dont chaque élément est une look_back
séquence de longueur.
Qu'est-ce que les pas de temps et les fonctionnalités?
Comme on peut le voir TrainX est un tableau 3-D avec Time_steps et Feature étant respectivement les deux dernières dimensions (3 et 1 dans ce code particulier). En ce qui concerne l'image ci-dessous, cela signifie-t-il que nous envisageons le many to one
cas où le nombre de cases roses est de 3? Ou cela signifie-t-il littéralement que la longueur de la chaîne est de 3 (c'est-à-dire seulement 3 cases vertes considérées).
L'argument des caractéristiques devient-il pertinent lorsque nous considérons des séries multivariées? Par exemple, modéliser simultanément deux valeurs financières?
LSTM avec état
Les LSTM avec état signifient-ils que nous sauvegardons les valeurs de la mémoire cellulaire entre les cycles de lots? Si tel est le cas, en batch_size
est un, et la mémoire est réinitialisée entre les cycles d'entraînement donc quel était le point de dire qu'elle était avec état. Je suppose que cela est lié au fait que les données de formation ne sont pas mélangées, mais je ne sais pas comment.
Des pensées? Référence image: http://karpathy.github.io/2015/05/21/rnn-effectiveness/
Modifier 1:
Un peu confus au sujet du commentaire de @ van à propos de l'égalité des cases rouges et vertes. Donc, juste pour confirmer, les appels d'API suivants correspondent-ils aux diagrammes déroulés? Notant particulièrement le deuxième diagramme (a batch_size
été choisi arbitrairement.):
Modifier 2:
Pour les personnes qui ont suivi le cours d'apprentissage en profondeur d'Udacity et qui sont toujours confus à propos de l'argument time_step, consultez la discussion suivante: https://discussions.udacity.com/t/rnn-lstm-use-implementation/163169
Mettre à jour:
Il s'est avéré que model.add(TimeDistributed(Dense(vocab_len)))
c'était ce que je cherchais. Voici un exemple: https://github.com/sachinruk/ShakespeareBot
Update2:
J'ai résumé la plupart de ma compréhension des LSTM ici: https://www.youtube.com/watch?v=ywinX5wgdEU
la source
Réponses:
Tout d'abord, vous choisissez d'excellents tutoriels ( 1 , 2 ) pour commencer.
Time-steps==3
Signification du pas de temps : dans X.shape (Description de la forme des données) signifie qu'il y a trois cases roses. Étant donné que dans Keras, chaque étape nécessite une entrée, le nombre de cases vertes doit donc généralement être égal au nombre de cases rouges. Sauf si vous piratez la structure.plusieurs à plusieurs vs plusieurs à un : en keras, il y a un
return_sequences
paramètre lors de votre initialisationLSTM
ouGRU
ouSimpleRNN
. Quandreturn_sequences
estFalse
(par défaut), alors il est plusieurs pour un comme indiqué dans l'image. Sa forme de retour est(batch_size, hidden_unit_length)
, qui représente le dernier état. Quandreturn_sequences
c'estTrue
, alors c'est plusieurs à plusieurs . Sa forme de retour est(batch_size, time_step, hidden_unit_length)
L'argument des fonctionnalités devient-il pertinent ? L'argument des fonctionnalités signifie "Quelle est la taille de votre boîte rouge" ou quelle est la dimension d'entrée à chaque étape. Si vous souhaitez prévoir, par exemple, 8 types d'informations sur le marché, vous pouvez générer vos données avec
feature==8
.Avec état : vous pouvez rechercher le code source . Lors de l'initialisation de l'état, si
stateful==True
, alors l'état de la dernière formation sera utilisé comme état initial, sinon il générera un nouvel état. Je ne me suis passtateful
encore allumé. Cependant, je ne suis pas d'accord avec le fait que lebatch_size
ne peut être que 1 lorsquestateful==True
.Actuellement, vous générez vos données avec les données collectées. Imaginez que vos informations boursières arrivent sous forme de flux, plutôt que d'attendre une journée pour collecter toutes les informations séquentielles, vous souhaitez générer des données d'entrée en ligne tout en vous entraînant / prédisant avec le réseau. Si vous avez 400 actions partageant un même réseau, vous pouvez définir
batch_size==400
.la source
stateful: Boolean (default False). If True, the last state for each sample at index i in a batch will be used as initial state for the sample of index i in the following batch.
lookback = 1
?stateful=True
: La taille du lot peut être tout ce que vous aimez, mais vous devez vous y tenir. Si vous construisez votre modèle avec une taille de lot de 5, puis tousfit()
,predict()
et les méthodes connexes aurez besoin d' un lot de 5. Notez toutefois que cet état ne sera pas sauvé avecmodel.save()
, ce qui pourrait sembler indésirable. Cependant, vous pouvez ajouter manuellement l'état au fichier hdf5, si vous en avez besoin. Mais en fait, cela vous permet de modifier la taille du lot en enregistrant et en rechargeant simplement un modèle.En complément de la réponse acceptée, cette réponse montre les comportements des kéros et comment réaliser chaque image.
Comportement général de Keras
Le traitement interne des keras standard est toujours un à plusieurs comme dans l'image suivante (où j'ai utilisé
features=2
, pression et température, juste à titre d'exemple):Dans cette image, j'ai augmenté le nombre d'étapes à 5, pour éviter toute confusion avec les autres dimensions.
Pour cet exemple:
Notre tableau d'entrée devrait alors avoir la forme suivante
(N,5,2)
:Entrées pour fenêtres coulissantes
Souvent, les couches LSTM sont censées traiter l'intégralité des séquences. La division des fenêtres n'est peut-être pas la meilleure idée. La couche a des états internes sur l'évolution d'une séquence à mesure qu'elle avance. Windows élimine la possibilité d'apprendre de longues séquences, limitant toutes les séquences à la taille de la fenêtre.
Dans les fenêtres, chaque fenêtre fait partie d'une longue séquence d'origine, mais selon Keras, elles seront vues chacune comme une séquence indépendante:
Notez que dans ce cas, vous n'avez initialement qu'une seule séquence, mais vous la divisez en plusieurs séquences pour créer des fenêtres.
Le concept de "qu'est-ce qu'une séquence" est abstrait. Les parties importantes sont:
Atteindre chaque cas avec des "couches simples"
Atteindre la norme plusieurs à plusieurs:
Vous pouvez réaliser plusieurs à plusieurs avec une simple couche LSTM, en utilisant
return_sequences=True
:Atteindre plusieurs à un:
En utilisant exactement la même couche, les keras effectueront exactement le même prétraitement interne, mais lorsque vous utilisez
return_sequences=False
(ou ignorez simplement cet argument), les keras ignoreront automatiquement les étapes précédentes à la dernière:Atteindre un à plusieurs
Maintenant, cela n'est pas pris en charge par les couches keras LSTM seules. Vous devrez créer votre propre stratégie pour multiplier les étapes. Il existe deux bonnes approches:
stateful=True
pour prendre de façon récurrente la sortie d'une étape et la servir d'entrée de l'étape suivante (besoinsoutput_features == input_features
)Un à plusieurs avec vecteur de répétition
Afin de s'adapter au comportement standard des keras, nous avons besoin d'entrées par étapes, donc, nous répétons simplement les entrées pour la longueur que nous voulons:
Comprendre stateful = True
Vient maintenant l'un des usages possibles de
stateful=True
(en plus d'éviter de charger des données qui ne peuvent pas contenir la mémoire de votre ordinateur à la fois)Stateful nous permet de saisir des "parties" des séquences par étapes. La différence est:
stateful=False
, le deuxième lot contient de nouvelles séquences entières, indépendantes du premier lotstateful=True
, le deuxième lot continue le premier lot, étendant les mêmes séquences.C'est comme diviser les séquences dans les fenêtres aussi, avec ces deux différences principales:
stateful=True
verra ces fenêtres connectées comme une seule longue séquenceDans
stateful=True
, chaque nouveau lot sera interprété comme poursuivant le lot précédent (jusqu'à ce que vous appeliezmodel.reset_states()
).Exemple d'entrées, le lot 1 contient les étapes 1 et 2, le lot 2 contient les étapes 3 à 5:
Remarquez l'alignement des réservoirs des lots 1 et 2! C'est pourquoi nous avons besoin
shuffle=False
(à moins que nous n'utilisions qu'une seule séquence, bien sûr).Vous pouvez avoir un nombre illimité de lots, indéfiniment. (Pour avoir des longueurs variables dans chaque lot, utilisez
input_shape=(None,features)
.Un à plusieurs avec stateful = True
Pour notre cas ici, nous n'utiliserons qu'une seule étape par lot, car nous voulons obtenir une étape de sortie et en faire une entrée.
Veuillez noter que le comportement dans l'image n'est pas "provoqué par"
stateful=True
. Nous forcerons ce comportement dans une boucle manuelle ci-dessous. Dans cet exemple,stateful=True
c'est ce qui nous «permet» d'arrêter la séquence, de manipuler ce que nous voulons et de continuer d'où nous nous sommes arrêtés.Honnêtement, l'approche répétée est probablement un meilleur choix pour ce cas. Mais puisque nous examinons
stateful=True
, c'est un bon exemple. La meilleure façon de l'utiliser est le prochain cas "plusieurs à plusieurs".Couche:
Maintenant, nous allons avoir besoin d'une boucle manuelle pour les prédictions:
Plusieurs à plusieurs avec stateful = True
Maintenant, ici, nous obtenons une très belle application: étant donné une séquence d'entrée, essayez de prédire ses futures étapes inconnues.
Nous utilisons la même méthode que dans le "un à plusieurs" ci-dessus, à la différence que:
Couche (comme ci-dessus):
Formation:
Nous allons former notre modèle pour prédire la prochaine étape des séquences:
Prédire:
La première étape de notre prévision consiste à "ajuster les états". C'est pourquoi nous allons à nouveau prédire la séquence entière, même si nous en connaissons déjà cette partie:
Nous passons maintenant à la boucle comme dans le cas un à plusieurs. Mais ne réinitialisez pas les états ici! . Nous voulons que le modèle sache à quelle étape de la séquence il se trouve (et il sait qu'il est à la première nouvelle étape en raison de la prédiction que nous venons de faire ci-dessus)
Cette approche a été utilisée dans ces réponses et dossier:
Réalisation de configurations complexes
Dans tous les exemples ci-dessus, j'ai montré le comportement de "une couche".
Vous pouvez, bien sûr, empiler plusieurs couches les unes sur les autres, sans nécessairement toutes suivre le même modèle, et créer vos propres modèles.
Un exemple intéressant qui est apparu est le "autoencoder" qui a un "plusieurs à un codeur" suivi d'un décodeur "un à plusieurs":
Encodeur:
Décodeur:
Utilisation de la méthode "répétition";
Encodeur automatique:
Entraînez-vous avec
fit(X,X)
Explications supplémentaires
Si vous voulez des détails sur la façon dont les étapes sont calculées dans les LSTM, ou des détails sur les
stateful=True
cas ci-dessus, vous pouvez en savoir plus dans cette réponse: Doutes concernant `Comprendre les LSTM Keras`la source
my_cell = LSTM(num_output_features_per_timestep, return_state=True)
, suivi d'une boucle dea, _, c = my_cell(output_of_previous_time_step, initial_states=[a, c])
Lorsque vous avez return_sequences dans votre dernière couche de RNN, vous ne pouvez pas utiliser une simple couche dense à la place, utilisez TimeDistributed.
Voici un exemple de code qui pourrait aider les autres.
words = keras.layers.Input (batch_shape = (None, self.maxSequenceLength), name = "input")
la source