web-dev-qa-db-fra.com

Pourquoi la taille de lot Keras LSTM utilisée pour la prédiction doit-elle être identique à la taille de lot adaptée?

Lorsque j'utilise un LSTM de Keras pour prévoir des données chronologiques, des erreurs se produisent lorsque j'essaie de former le modèle avec une taille de lot de 50, tout en essayant de prévoir sur le même modèle avec une taille de lot de 1 (c'est-à-dire juste prédire la valeur suivante).

Pourquoi ne puis-je pas former et adapter le modèle à plusieurs lots à la fois, puis utiliser ce modèle pour prévoir autre chose que la même taille de lot. Cela ne semble pas avoir de sens, mais alors je pourrais facilement rater quelque chose à ce sujet.

Edit: c'est le modèle. batch_size est 50, sl est la longueur de la séquence, qui est actuellement fixée à 20.

    model = Sequential()
    model.add(LSTM(1, batch_input_shape=(batch_size, 1, sl), stateful=True))
    model.add(Dense(1))
    model.compile(loss='mean_squared_error', optimizer='adam')
    model.fit(trainX, trainY, epochs=epochs, batch_size=batch_size, verbose=2)

voici la ligne de prédiction sur l'ensemble de formation pour RMSE

    # make predictions
    trainPredict = model.predict(trainX, batch_size=batch_size)

voici la prédiction réelle des pas de temps invisibles

for i in range(test_len):
    print('Prediction %s: ' % str(pred_count))

    next_pred_res = np.reshape(next_pred, (next_pred.shape[1], 1, next_pred.shape[0]))
    # make predictions
    forecastPredict = model.predict(next_pred_res, batch_size=1)
    forecastPredictInv = scaler.inverse_transform(forecastPredict)
    forecasts.append(forecastPredictInv)
    next_pred = next_pred[1:]
    next_pred = np.concatenate([next_pred, forecastPredict])

    pred_count += 1

Ce problème est avec la ligne:

forecastPredict = model.predict(next_pred_res, batch_size=batch_size)

L'erreur lorsque batch_size ici est définie sur 1 est la suivante:

ValueError: Cannot feed value of shape (1, 1, 2) for Tensor 'lstm_1_input:0', which has shape '(10, 1, 2)', qui est la même erreur que celle générée lorsque batch_size est défini ici sur 50, comme les autres tailles de lot.

L'erreur totale est:

    forecastPredict = model.predict(next_pred_res, batch_size=1)
  File "/home/entelechy/tf_keras/lib/python3.5/site-packages/keras/models.py", line 899, in predict
    return self.model.predict(x, batch_size=batch_size, verbose=verbose)
  File "/home/entelechy/tf_keras/lib/python3.5/site-packages/keras/engine/training.py", line 1573, in predict
    batch_size=batch_size, verbose=verbose)
   File "/home/entelechy/tf_keras/lib/python3.5/site-packages/keras/engine/training.py", line 1203, in _predict_loop
    batch_outs = f(ins_batch)
  File "/home/entelechy/tf_keras/lib/python3.5/site-packages/keras/backend/tensorflow_backend.py", line 2103, in __call__
    feed_dict=feed_dict)
  File "/home/entelechy/tf_keras/lib/python3.5/site-packages/tensorflow/python/client/session.py", line 767, in run
    run_metadata_ptr)
  File "/home/entelechy/tf_keras/lib/python3.5/site-packages/tensorflow/python/client/session.py", line 944, in _run
    % (np_val.shape, subfeed_t.name, str(subfeed_t.get_shape())))
ValueError: Cannot feed value of shape (1, 1, 2) for Tensor 'lstm_1_input:0', which has shape '(10, 1, 2)'

Edit: Une fois le modèle défini sur stateful=False, je peux utiliser différentes tailles de lot pour l’ajustement/la formation et la prédiction. Quelle est la raison pour ça?

11
McLeodx

Malheureusement, ce que vous voulez faire est impossible avec Keras ... J'ai également beaucoup de temps à résoudre ce problème et le seul moyen est de plonger dans le terrier du lapin et de travailler avec Tensorflow directement pour effectuer une prédiction en roulis LSTM.

Premièrement, pour être clair sur la terminologie, batch_size signifie généralement le nombre de séquences formées ensemble, et num_steps indique le nombre de pas de temps formés simultanément. Quand vous voulez dire batch_size=1 et "prédire seulement la prochaine valeur", je pense que vous vouliez prédire avec num_steps=1.

Sinon, il devrait être possible de s'entraîner et de prévoir avec batch_size=50, ce qui signifie que vous vous entraînez sur 50 séquences et d'effectuer 50 prédictions à chaque pas de temps, une pour chaque séquence (ce qui signifie entraînement/prédiction num_steps=1).

Cependant, je pense que ce que vous voulez dire, c'est que vous voulez utiliser le LSTM avec état pour vous entraîner avec num_steps=50 et faire une prédiction avec num_steps=1. Théoriquement, cela fait sens et devrait être possible, et c'est possible avec Tensorflow, mais pas avec Keras.

Le problème: Keras nécessite une taille de lot explicite pour RNN avec état. Vous devez spécifier batch_input_shape (batch_size, num_steps, features).

La raison: Keras doit allouer un vecteur d'état caché de taille fixe dans le graphe de calcul de forme (batch_size, num_units) afin de conserver les valeurs entre les lots d'apprentissage. D'autre part, lorsque stateful=False, le vecteur d'état masqué peut être initialisé de manière dynamique avec des zéros au début de chaque lot, de sorte qu'il ne doit pas nécessairement être de taille fixe. Plus de détails ici: http://philipperemy.github.io/keras-stateful-lstm/

Travail possible autour de: Entraînez-vous et prédisez avec num_steps=1. Exemple: https://github.com/keras-team/keras/blob/master/examples/lstm_stateful.py . Cela pourrait ou ne fonctionnerait pas du tout pour votre problème car le gradient pour la propagation en arrière sera calculé sur un seul intervalle de temps. Voir: https://github.com/fchollet/keras/issues/3669

Ma solution: utiliser Tensorflow: dans Tensorflow, vous pouvez vous entraîner avec batch_size=50, num_steps=100, puis faire des prédictions avec batch_size=1, num_steps=1. Cela est possible en créant un graphe modèle différent pour l’entraînement et la prédiction partageant les mêmes matrices de poids RNN. Voir cet exemple pour la prédiction du prochain caractère: https://github.com/sherjilozair/char-rnn-tensorflow/blob/master/model.py#L11 et article de blog http: //karpathy.github .io/2015/05/21/efficacité-rnn/ . Notez qu'un graphique ne peut toujours fonctionner qu'avec un batch_size spécifié, mais vous pouvez configurer plusieurs graphiques de modèle partageant des pondérations dans Tensorflow.

14
Hai-Anh Trinh

Une autre solution de contournement facile est la suivante:

def create_model(batch_size):
    model = Sequential()
    model.add(LSTM(1, batch_input_shape=(batch_size, 1, sl), stateful=True))
    model.add(Dense(1))
    return model

model_train = create_model(batch_size=50)

model_train.compile(loss='mean_squared_error', optimizer='adam')
model_train.fit(trainX, trainY, epochs=epochs, batch_size=batch_size)

model_predict = create_model(batch_size=1)

weights = model_train.get_weights()
model_predict.set_weights(weights)
3
josca

La meilleure solution à ce problème est "Copier les poids". Cela peut être très utile si vous voulez vous entraîner et prévoir avec votre modèle LSTM avec différentes tailles de lots.

Par exemple, une fois que vous avez formé votre modèle à la taille de lot 'n', comme indiqué ci-dessous: 

# configure network
n_batch = len(X)
n_Epoch = 1000
n_neurons = 10
# design network
model = Sequential()
model.add(LSTM(n_neurons, batch_input_shape=(n_batch, X.shape[1], X.shape[2]), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')

Et maintenant, vous voulez prévoir des valeurs inférieures à la taille de votre lot où n = 1.

Ce que vous pouvez faire est de copier les poids de votre modèle d'ajustement et de réinitialiser le nouveau modèle LSTM avec la même architecture et de définir une taille de lot égale à 1.

# re-define the batch size
n_batch = 1
# re-define model
new_model = Sequential()
new_model.add(LSTM(n_neurons, batch_input_shape=(n_batch, X.shape[1], X.shape[2]),       stateful=True))
new_model.add(Dense(1))
# copy weights
old_weights = model.get_weights()
new_model.set_weights(old_weights)

Maintenant, vous pouvez facilement prévoir et former des LSTM avec différentes tailles de lots.

Pour plus d'informations, veuillez consulter: https://machinelearningmastery.com/use-different-batch-sizes-training-predicting-python-keras/

1
Noman Dilawar

J'ai aussi le même problème et résolu .

Vous pouvez également enregistrer vos poids. Lorsque vous testez vos résultats, vous pouvez recharger votre modèle avec la même architecture et définir batch_size=1 comme ci-dessous:

 n_neurons = 10
 # design network
 model = Sequential()
 model.add(LSTM(n_neurons, batch_size=1, batch_input_shape=(n_batch,X.shape[1], X.shape[2]), statefull=True))
 model.add(Dense(1))
 model.compile(loss='mean_squared_error', optimizer='adam')
 model.load_weights("w.h5")

Cela fonctionnera bien . J'espère que cela vous aidera .

0
Toàn Nguyễn

J'ai trouvé ci-dessous utile (et entièrement en ligne avec ci-dessus). La section "Solution 3: Copier des poids" a fonctionné pour moi:

Comment utiliser différentes tailles de lots lors de la formation et de la prévision avec LSTM, par Jason Brownlee

n_neurons = 10
# design network
model = Sequential()
model.add(LSTM(n_neurons, batch_input_shape=(n_batch, X.shape[1], X.shape[2]), stateful=True))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
# fit network
for i in range(n_Epoch):
    model.fit(X, y, epochs=1, batch_size=n_batch, verbose=1, shuffle=False)
    model.reset_states()
# re-define the batch size
n_batch = 1
# re-define model
new_model = Sequential()
new_model.add(LSTM(n_neurons, batch_input_shape=(n_batch, X.shape[1], X.shape[2]), stateful=True))
new_model.add(Dense(1))
# copy weights
old_weights = model.get_weights()
new_model.set_weights(old_weights)
# compile model
new_model.compile(loss='mean_squared_error', optimizer='adam')
0
user2427317