Plusieurs à un et plusieurs à plusieurs exemples LSTM dans Keras

108

J'essaie de comprendre les LSTM et comment les construire avec Keras. J'ai découvert qu'il y avait principalement les 4 modes pour exécuter un RNN (les 4 bons sur l'image)

entrez la description de l'image ici Source de l'image: Andrej Karpathy

Maintenant, je me demande à quoi ressemblerait un extrait de code minimaliste pour chacun d'eux dans Keras. Donc quelque chose comme

model = Sequential()
model.add(LSTM(128, input_shape=(timesteps, data_dim)))
model.add(Dense(1))

pour chacune des 4 tâches, peut-être avec un peu d'explication.

Luca Thiede
la source

Réponses:

121

Alors:

  1. Un-à-un : vous pouvez utiliser un Densecalque car vous ne traitez pas de séquences:

    model.add(Dense(output_size, input_shape=input_shape))
  2. Un-à-plusieurs : cette option n'est pas prise en charge et le chaînage des modèles n'est pas très facile Keras, donc la version suivante est la plus simple:

    model.add(RepeatVector(number_of_times, input_shape=input_shape))
    model.add(LSTM(output_size, return_sequences=True))
  3. Plusieurs-à-un : en fait, votre extrait de code est (presque) un exemple de cette approche:

    model = Sequential()
    model.add(LSTM(1, input_shape=(timesteps, data_dim)))
  4. Plusieurs à plusieurs : il s'agit de l'extrait de code le plus simple lorsque la longueur de l'entrée et de la sortie correspond au nombre d'étapes récurrentes:

    model = Sequential()
    model.add(LSTM(1, input_shape=(timesteps, data_dim), return_sequences=True))
  5. Plusieurs-à-plusieurs lorsque le nombre d'étapes diffère de la longueur d'entrée / sortie : c'est bizarre dans Keras. Il n'y a pas d'extraits de code faciles à coder.

MODIFIER: Annonce 5

Dans l'une de mes applications récentes, nous avons implémenté quelque chose qui pourrait être similaire à plusieurs-à-plusieurs de la 4ème image. Dans le cas où vous souhaitez avoir un réseau avec l'architecture suivante (lorsqu'une entrée est plus longue que la sortie):

                                        O O O
                                        | | |
                                  O O O O O O
                                  | | | | | | 
                                  O O O O O O

Vous pouvez y parvenir de la manière suivante:

    model = Sequential()
    model.add(LSTM(1, input_shape=(timesteps, data_dim), return_sequences=True))
    model.add(Lambda(lambda x: x[:, -N:, :]

Nest le nombre de dernières étapes que vous souhaitez couvrir (sur l'image N = 3).

À partir de là, arriver à:

                                        O O O
                                        | | |
                                  O O O O O O
                                  | | | 
                                  O O O 

est aussi simple qu'une séquence de remplissage artificiel de longueur Nutilisant par exemple des 0vecteurs, afin de l'ajuster à une taille appropriée.

Marcin Możejko
la source
10
Une clarification: par exemple, pour plusieurs à un, vous utilisez LSTM (1, input_shape = (timesteps, data_dim))) Je pensais que le 1 représente le nombre de cellules LSTM / nœuds cachés, mais apparemment pas Comment coderiez-vous un Many- à un avec disons, 512 nœuds cependant que? (Parce que j'ai lu quelque chose de similaire, je pensais que ce serait fait avec model.add (LSTM (512, input_shape = ...)) model.add (Dense (1)) à quoi cela sert-il?)
Luca Thiede
1
Dans ce cas - votre code - après avoir corrigé une faute de frappe devrait être correct.
Marcin Możejko
Pourquoi utilisons-nous le RepeatVector, et non un vecteur avec la première entrée 1 = 0 et toutes les autres entrées = 0 (selon l'image ci-dessus, il n'y a pas d'entrée du tout dans les états ultérieurs, et pas toujours la même entrée, ce que Repeat Vector ferait dans ma compréhension)
Luca Thiede
1
Si vous réfléchissez bien à cette image - ce n'est qu'une présentation conceptuelle d'une idée de un-à-plusieurs . Toutes ces unités cachées doivent accepter quelque chose comme entrée. Donc - ils peuvent accepter la même entrée ainsi que l'entrée avec la première entrée égale à xet l'autre égale à 0. Mais - d'un autre côté - ils pourraient accepter la même chose xrépétée plusieurs fois aussi. Une approche différente consiste à enchaîner les modèles qui sont difficiles à comprendre Keras. L'option que j'ai fournie est le cas le plus simple d' architecture un-à-plusieurs dans Keras.
Marcin Możejko
Agréable ! Je pense à utiliser LSTM N à N dans une architecture GAN. J'aurai un générateur basé sur LSTM. Je donnerai à ce générateur (tel qu'utilisé dans "Variable latente" en gans) la première moitié de la série temporelle et ce générateur produira la seconde moitié de la série temporelle. Ensuite, je combinerai les deux moitiés (réelle et générée) pour produire la "fausse" entrée pour le gan. Pensez-vous que l'utilisation du point 4 de votre solution fonctionnera? ou, en d'autres termes, est-ce (solution 4) la bonne façon de procéder?
rjpg
6

Bonne réponse de @Marcin Możejko

J'ajouter ce qui suit à NR.5 (plusieurs à plusieurs avec différentes in / out longueur):

A) comme Vanilla LSTM

model = Sequential()
model.add(LSTM(N_BLOCKS, input_shape=(N_INPUTS, N_FEATURES)))
model.add(Dense(N_OUTPUTS))

B) comme encodeur-décodeur LSTM

model.add(LSTM(N_BLOCKS, input_shape=(N_INPUTS, N_FEATURES))  
model.add(RepeatVector(N_OUTPUTS))
model.add(LSTM(N_BLOCKS, return_sequences=True))  
model.add(TimeDistributed(Dense(1)))
model.add(Activation('linear')) 
Gustavz
la source
1
Pourriez-vous s'il vous plaît expliquer les détails de l' B) Encoder-Decoder LSTMarchitecture? J'ai des problèmes pour comprendre les rôles des étapes "RepeatVector" / "TimeDistributed".
Marsellus Wallace