En complément de la réponse acceptée, cette réponse montre les comportements de keras et comment réaliser chaque image.
Comportement général de Keras
Le traitement interne standard de keras est toujours un many to many comme dans l'image suivante (où j'ai utilisé features=2
la pression et la température, à 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 :
- Nous avons des réservoirs d'huile N
- Nous avons passé 5 heures à prendre des mesures à l'heure (pas de temps)
- Nous avons mesuré deux caractéristiques :
Notre tableau d'entrée devrait alors avoir la forme suivante (N,5,2)
:
[ Step1 Step2 Step3 Step4 Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
....
Tank N: [[Pn1,Tn1], [Pn2,Tn2], [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
]
Entrées pour les fenêtres coulissantes
Souvent, les couches LSTM sont censées traiter les séquences entières. Diviser les fenêtres n'est peut-être pas la meilleure idée. La couche a des états internes sur la façon dont une séquence évolue au fur et à mesure qu'elle avance. Les fenêtres éliminent la possibilité d'apprendre de longues séquences, en limitant toutes les séquences à la taille de la fenêtre.
Dans Windows, chaque fenêtre fait partie d'une longue séquence originale, mais avec Keras, elles seront considérées chacune comme une séquence indépendante :
[ Step1 Step2 Step3 Step4 Step5
Window A: [[P1,T1], [P2,T2], [P3,T3], [P4,T4], [P5,T5]],
Window B: [[P2,T2], [P3,T3], [P4,T4], [P5,T5], [P6,T6]],
Window C: [[P3,T3], [P4,T4], [P5,T5], [P6,T6], [P7,T7]],
....
]
Remarquez que dans ce cas, vous n'avez initialement qu'une seule séquence, mais vous la divisez en plusieurs séquences pour créer Windows.
Le concept de "ce qu'est une séquence" est abstrait. Les parties importantes sont :
- vous pouvez avoir des lots avec de nombreuses séquences individuelles
- Ce qui fait que les séquences sont des séquences, c'est qu'elles évoluent par étapes (généralement des étapes de temps).
Réaliser chaque cas avec des "couches uniques".
Atteindre la norme beaucoup à beaucoup :
Vous pouvez obtenir un grand nombre d'entre eux avec une simple couche LSTM, en utilisant les éléments suivants return_sequences=True
:
outputs = LSTM(units, return_sequences=True)(inputs)
#output_shape -> (batch_size, steps, units)
Réaliser le "many to one" :
En utilisant exactement la même couche, keras effectuera exactement le même prétraitement interne, mais lorsque vous utilisez return_sequences=False
(ou ignorez simplement cet argument), keras ignorera automatiquement les étapes antérieures à la dernière :
outputs = LSTM(units)(inputs)
#output_shape -> (batch_size, units) --> steps were discarded, only the last was returned
Réaliser le one to many
Or, ceci n'est pas pris en charge par les seules couches LSTM de Keras. Vous devrez créer votre propre stratégie pour multiplier les étapes. Il existe deux bonnes approches :
- Créer une entrée constante à plusieurs étapes en répétant un tenseur
- Utilisez un
stateful=True
pour prendre de manière récurrente la sortie d'une étape et l'utiliser comme entrée de l'étape suivante (besoin de output_features == input_features
)
Un à plusieurs avec vecteur de répétition
Afin de s'adapter au comportement standard de Keras, nous avons besoin d'entrées par étapes, donc, nous répétons simplement les entrées pour la longueur que nous voulons :
outputs = RepeatVector(steps)(inputs) #where inputs is (batch,features)
outputs = LSTM(units,return_sequences=True)(outputs)
#output_shape -> (batch_size, steps, units)
Comprendre stateful = True
Voici maintenant l'une des utilisations possibles de stateful=True
(en plus d'éviter de charger des données qui ne peuvent pas occuper la mémoire de votre ordinateur en une seule fois)
Stateful nous permet de saisir des "parties" des séquences par étapes. La différence est la suivante :
- Sur
stateful=False
le deuxième lot contient des séquences entièrement nouvelles, indépendantes du premier lot.
- Sur
stateful=True
le deuxième lot poursuit le premier lot, en prolongeant les mêmes séquences.
C'est comme diviser les séquences dans Windows aussi, avec ces deux différences principales :
- ces fenêtres ne se superposent pas !
-
stateful=True
verra ces fenêtres connectées comme une seule longue séquence.
Sur stateful=True
chaque nouveau lot sera interprété comme la continuation du lot précédent (jusqu'à ce que vous appeliez model.reset_states()
).
- La séquence 1 du lot 2 continuera la séquence 1 du lot 1.
- La séquence 2 du lot 2 continuera la séquence 2 du lot 1.
- La séquence n du lot 2 poursuivra la séquence n du lot 1.
Exemple d'entrées, le lot 1 contient les étapes 1 et 2, le lot 2 contient les étapes 3 à 5 :
BATCH 1 BATCH 2
[ Step1 Step2 | [ Step3 Step4 Step5
Tank A: [[Pa1,Ta1], [Pa2,Ta2], | [Pa3,Ta3], [Pa4,Ta4], [Pa5,Ta5]],
Tank B: [[Pb1,Tb1], [Pb2,Tb2], | [Pb3,Tb3], [Pb4,Tb4], [Pb5,Tb5]],
.... |
Tank N: [[Pn1,Tn1], [Pn2,Tn2], | [Pn3,Tn3], [Pn4,Tn4], [Pn5,Tn5]],
] ]
Remarquez l'alignement des réservoirs dans le lot 1 et le lot 2 ! C'est pourquoi nous avons besoin shuffle=False
(à moins que l'on n'utilise qu'une seule séquence, bien sûr).
Vous pouvez avoir un nombre quelconque 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 allons utiliser seulement 1 étape par lot, parce que nous voulons obtenir une étape de sortie et la faire devenir une entrée.
Veuillez noter que le comportement dans l'image n'est pas "causé par" stateful=True
. Nous allons forcer ce comportement dans une boucle manuelle ci-dessous. Dans cet exemple, stateful=True
est ce qui nous "permet" d'arrêter la séquence, de manipuler ce que nous voulons, et de reprendre là où nous nous sommes arrêtés.
Honnêtement, l'approche de la répétition est probablement un meilleur choix pour ce cas. Mais puisque nous cherchons à stateful=True
Il s'agit d'un bon exemple. La meilleure façon de l'utiliser est le cas suivant "many to many".
Couche :
outputs = LSTM(units=features,
stateful=True,
return_sequences=True, #just to keep a nice output shape even with length 1
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length
#output_shape -> (batch_size, steps, units)
Maintenant, nous allons avoir besoin d'une boucle manuelle pour les prédictions :
input_data = someDataWithShape((batch, 1, features))
#important, we're starting new sequences, not continuing old ones:
model.reset_states()
output_sequence = []
last_step = input_data
for i in steps_to_predict:
new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step
#end of the sequences
model.reset_states()
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, avec la différence que :
- nous utiliserons la séquence elle-même comme donnée cible, avec une longueur d'avance.
- nous connaissons une partie de la séquence (nous rejetons donc cette partie des résultats).
Couche (comme ci-dessus) :
outputs = LSTM(units=features,
stateful=True,
return_sequences=True,
input_shape=(None,features))(inputs)
#units = features because we want to use the outputs as inputs
#None because we want variable length
#output_shape -> (batch_size, steps, units)
Formation :
Nous allons entraîner notre modèle à prédire l'étape suivante des séquences :
totalSequences = someSequencesShaped((batch, steps, features))
#batch size is usually 1 in these cases (often you have only one Tank in the example)
X = totalSequences[:,:-1] #the entire known sequence, except the last step
Y = totalSequences[:,1:] #one step ahead of X
#loop for resetting states at the start/end of the sequences:
for epoch in range(epochs):
model.reset_states()
model.train_on_batch(X,Y)
Prédire :
La première étape de notre prédiction consiste à "ajuster les états". C'est pourquoi nous allons à nouveau prédire la séquence entière, même si nous connaissons déjà cette partie de la séquence :
model.reset_states() #starting a new sequence
predicted = model.predict(totalSequences)
firstNewStep = predicted[:,-1:] #the last step of the predictions is the first future step
Maintenant, nous passons à la boucle comme dans le cas d'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 se trouve à la première nouvelle étape grâce à la prédiction que nous venons de faire ci-dessus).
output_sequence = [firstNewStep]
last_step = firstNewStep
for i in steps_to_predict:
new_step = model.predict(last_step)
output_sequence.append(new_step)
last_step = new_step
#end of the sequences
model.reset_states()
Cette approche a été utilisée dans ces réponses et ce dossier :
Réaliser des configurations complexes
Dans tous les exemples ci-dessus, j'ai montré le comportement d'une "seule couche".
Vous pouvez, bien sûr, empiler de nombreuses couches les unes sur les autres, sans nécessairement suivre le même modèle, et créer vos propres modèles.
Un exemple intéressant qui a fait son apparition est celui de l'"autoencodeur" qui comporte un "codeur de plusieurs à un" suivi d'un décodeur de "un à plusieurs" :
Encodeur :
inputs = Input((steps,features))
#a few many to many layers:
outputs = LSTM(hidden1,return_sequences=True)(inputs)
outputs = LSTM(hidden2,return_sequences=True)(outputs)
#many to one layer:
outputs = LSTM(hidden3)(outputs)
encoder = Model(inputs,outputs)
Décodeur :
En utilisant la méthode de "répétition" ;
inputs = Input((hidden3,))
#repeat to make one to many:
outputs = RepeatVector(steps)(inputs)
#a few many to many layers:
outputs = LSTM(hidden4,return_sequences=True)(outputs)
#last layer
outputs = LSTM(features,return_sequences=True)(outputs)
decoder = Model(inputs,outputs)
Auto-codeur :
inputs = Input((steps,features))
outputs = encoder(inputs)
outputs = decoder(outputs)
autoencoder = Model(inputs,outputs)
S'entraîner avec fit(X,X)
Explications supplémentaires
Si vous souhaitez obtenir des détails sur la façon dont les étapes sont calculées dans les LSTM, ou des détails sur la méthode de calcul de l'indice d'efficacité de l'énergie. stateful=True
ci-dessus, vous pouvez en savoir plus dans cette réponse : Doutes concernant "Comprendre les LSTM de Keras".
10 votes
La première photo devrait être (batch_size, 5, 1) ; la deuxième photo devrait être (batch_size, 4, 3) (s'il n'y a pas de séquences suivantes). Et pourquoi la sortie est toujours "X" ? Devrait-il être "Y" ?
1 votes
Ici, je suppose que X_1, X_2 ... X_6 est un seul nombre. Et trois nombres (X_1, X_2, X_3) forment un vecteur de forme (3,). Un seul nombre (X_1) forme un vecteur de forme (1,).
2 votes
@Van, votre hypothèse est correcte. C'est intéressant, donc en fait le modèle n'apprend pas de modèle au-delà du nombre de pas de temps. Donc si j'ai une série temporelle d'une longueur de 1000, et que je peux visuellement voir un modèle tous les 100 jours, je devrais faire en sorte que le paramètre time_steps soit au moins de 100. Cette observation est-elle correcte ?
4 votes
Oui. Et si vous pouvez collecter 3 caractéristiques pertinentes par jour, alors vous pouvez définir la taille des caractéristiques à 3 comme vous l'avez fait dans la deuxième photo. Dans cette circonstance, la forme d'entrée sera (batch_size, 100, 3).
1 votes
Et pour répondre à votre première question, c'est parce que je prenais une seule série temporelle. Par exemple, les prix des actions, donc X et Y sont de la même série.
1 votes
Il y a aussi cet article de blog plus récent, qui présente une introduction aux LSTM : blog.echen.me/2017/05/30/exploration-lstms
1 votes
Pourquoi la dimensionnalité LSTM de l'espace de sortie (32) diffère-t-elle du nombre de caractéristiques (dans les images, 1 et 3) ?
0 votes
@sachinruk : Est-ce que je comprends bien que le
1
surbatch_input_shape=(batch_size, look_back, 1)
esnum_features
? Et 4 est le nombre de cellules LSTM ?