web-dev-qa-db-ja.com

予測に使用されるKeras LSTMバッチサイズは、フィッティングバッチサイズと同じである必要があるのはなぜですか?

Keras LSTMを使用して時系列データを予測する場合、バッチサイズ50を使用してモデルをトレーニングしようとするとエラーが発生し、バッチサイズ1を使用して同じモデルを予測しようとすると(つまり、次の値を予測するだけです)。

モデルを一度に複数のバッチでトレーニングして適合させ、そのモデルを使用して同じバッチサイズ以外のものを予測できないのはなぜですか。それは理にかなっているように見えませんが、その後、私は簡単にこれについて何かを見落としている可能性があります。

編集:これはモデルです。 _batch_size_は50、slはシーケンスの長さで、現在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)
_

これは、RMSEのトレーニングセットを予測するための行です。

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

ここに見えない時間ステップの実際の予測があります

_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
_

この問題は次の行にあります。

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

ここでbatch_sizeが1に設定されている場合のエラーは次のとおりです。

ValueError: Cannot feed value of shape (1, 1, 2) for Tensor 'lstm_1_input:0', which has shape '(10, 1, 2)'これは、_batch_size_が他のバッチサイズと同様に50に設定されている場合にスローされるエラーと同じです。

合計エラーは次のとおりです。

_    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)'
_

編集:モデルを_stateful=False_に設定すると、フィット/トレーニングおよび予測に異なるバッチサイズを使用できます。この理由は何ですか?

14
McLeodx

残念ながら、Kerasではやりたいことは不可能です...私もこの問題に多くの時間を費やしており、唯一の方法はウサギの穴に飛び込み、Lensorローリング予測を行うためにTensorflowと直接連携することです。

まず、用語を明確にするために、batch_sizeは通常一緒にトレーニングされるシーケンスの数を意味し、num_stepsは一緒にトレーニングされるタイムステップの数を意味します。 batch_size=1を意味し、「次の値を予測するだけ」という場合、num_steps=1で予測するつもりだったと思います。

それ以外の場合、batch_size=50を使用してトレーニングと予測を行い、50のシーケンスでトレーニングし、各シーケンスごとにタイムステップごとに50の予測を行うことができます(トレーニング/予測num_steps=1を意味します)。

ただし、ステートフルLSTMを使用してnum_steps=50でトレーニングし、num_steps=1で予測を行いたいということです。理論的には、これは理にかなっており、可能であるべきです。Tensorflowでは可能ですが、Kerasでは不可能です。

問題:Kerasでは、ステートフルRNNに明示的なバッチサイズが必要です。 batch_input_shape(batch_size、num_steps、features)を指定する必要があります。

理由:Kerasは、トレーニング間で値を保持するために、形状(batch_size、num_units)の計算グラフに固定サイズの隠れ状態ベクトルを割り当てる必要がありますバッチ。一方、stateful=Falseの場合、非表示状態ベクトルは各バッチの先頭でゼロで動的に初期化できるため、固定サイズである必要はありません。詳細はこちら: http://philipperemy.github.io/keras-stateful-lstm/

可能性のある回避策num_steps=1でトレーニングおよび予測します。例: https://github.com/keras-team/keras/blob/master/examples/lstm_stateful.py 。これは、逆伝播の勾配が1つのタイムステップでのみ計算されるため、問題に対してまったく機能しない場合があります。参照: https://github.com/fchollet/keras/issues/3669

私の解決策:Tensorflowを使用:Tensorflowでは、batch_size=50, num_steps=100でトレーニングし、batch_size=1, num_steps=1で予測を行うことができます。これは、同じRNN重み行列を共有するトレーニングと予測のために異なるモデルグラフを作成することにより可能です。次の文字の予測については、この例を参照してください: https://github.com/sherjilozair/char-rnn-tensorflow/blob/master/model.py#L11 およびブログ投稿 http: //karpathy.github.io/2015/05/21/rnn-effectiveness/ 。 1つのグラフは、指定されたbatch_sizeでのみ機能しますが、Tensorflowで重みを共有する複数のモデルグラフをセットアップできることに注意してください。

20
Hai-Anh Trinh

残念ながら、モデルを定義するときにbatch_sizeを指定するため、望んでいることは不可能です...しかし、この問題を回避する簡単な方法を見つけました:2つのモデルを作成してください! 1つ目はトレーニングに使用され、2つ目は予測に使用され、重みを共有します。

train_model = Sequential([Input(batch_input_shape=(batch_size,...),
<continue specifying your model>])

predict_model = Sequential([Input(batch_input_shape=(1,...),
<continue specifying exact same model>])

train_model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam())
predict_model.compile(loss='sparse_categorical_crossentropy', optimizer=Adam())

これで、任意のバッチサイズを使用できます。 train_modelを適合させた後、その重みを保存してpredict_modelでロードするだけです:

train_model.save_weights('lstm_model.h5')
predict_model.load_weights('lstm_model.h5')

モデル全体(アーキテクチャ、オプティマイザなどを含む)ではなく、重みのみを保存およびロードすることに注意してください。この方法で重みを取得できますが、一度に1つのバッチを入力できます... kerasの保存/読み込みモデルの詳細: https://keras.io/getting-started/faq/#how-can-i -save-a-keras-model

「ウェイトの保存」を使用するにはh5pyをインストールする必要があることに注意してください。

5
Oren Matar

別の簡単な回避策は次のとおりです。

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

この問題の最良の解決策は「ウェイトのコピー」です。さまざまなバッチサイズのLSTMモデルでトレーニングおよび予測を行う場合は、非常に役立ちます。

たとえば、次のようにバッチサイズ「n」でモデルをトレーニングすると、次のようになります。

# 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')

そして、n = 1。のバッチサイズよりも小さい値を予測したい

できることは、フィットモデルの重みをコピーし、同じアーキテクチャで新しいモデルLSTMモデルを再初期化し、バッチサイズを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)

これで、異なるバッチサイズのLSTMを簡単に予測およびトレーニングできます。

詳細については、以下をお読みください: https://machinelearningmastery.com/use-different-batch-sizes-training-predicting-python-keras/

2
Nomiluks

同じ問題があり解決した

別の方法では、結果をテストするときに、同じアーキテクチャでモデルをリロードしてbatch_size=1 以下のように:

 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")

うまくいくあなたの役に立つことを願っています

0
Toàn Nguyễn

私は以下が役立つことを発見しました(そして上記と完全にインラインで)。 「解決策3:ウェイトをコピーする」セクションは私のために働いた:

LSTMでトレーニングおよび予測する際に異なるバッチサイズを使用する方法、ジェイソンブラウンリー

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