为什么用于预测的 Keras LSTM 批量大小必须与拟合批量大小相同?
Why does Keras LSTM batch size used for prediction have to be the same as fitting batch size?
当我使用 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
后,我就可以对 fitting/training 和预测使用不同的批量大小。这是什么原因?
不幸的是,你想做的事用 Keras 是不可能的......我也在这个问题上挣扎了很多时间,唯一的方法是潜入兔子洞并直接与 Tensorflow 一起工作来做 LSTM 滚动预测。
首先,要明确术语,batch_size
通常表示一起训练的序列数,num_steps
表示一起训练的时间步数。当您指的是 batch_size=1
和 "just predicting the next value" 时,我认为您的意思是用 num_steps=1
.
进行预测
否则,应该可以使用 batch_size=50
进行训练和预测,这意味着您正在训练 50 个序列并在每个时间步长进行 50 次预测,每个序列一个(意思是 training/prediction num_steps=1
).
但是,我认为你的意思是你想使用状态 LSTM 与 num_steps=50
一起训练并用 num_steps=1
进行预测。从理论上讲,这是有道理的并且应该是可能的,并且使用 Tensorflow 是可能的,而不是 Keras。
问题:Keras 需要有状态 RNN 的显式批量大小。您必须指定 batch_input_shape(batch_size、num_steps、功能)。
原因: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. This might or might not work at all for your problem as the gradient for back propagation will be computed on only one time step. See: 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 and blog post http://karpathy.github.io/2015/05/21/rnn-effectiveness/。请注意,一张图仍然只能使用指定的一张图 batch_size
,但您可以在 Tensorflow 中设置多个共享权重的模型图。
遗憾的是,您希望的是不可能的,因为您在定义模型时指定了 batch_size...
但是,我找到了解决此问题的简单方法:创建 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')
请注意,您只想保存和加载权重,而不是整个模型(包括架构、优化器等...)。这样你就可以获得权重,但你可以一次输入一批......
有关 keras save/load 模型的更多信息:
https://keras.io/getting-started/faq/#how-can-i-save-a-keras-model
请注意,您需要安装 h5py 才能使用 "save weights"。
另一个简单的解决方法是:
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)
我发现下面的内容很有帮助(并且与上面的内容完全一致)。 "Solution 3: Copy Weights" 部分对我有用:
How to use Different Batch Sizes when Training and Predicting with LSTMs, by 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')
我也有同样的问题并解决了。
另一种方式,你可以保存你的权重,当你测试你的结果时,你可以使用相同的架构重新加载你的模型并设置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")
它会很好用。 希望对你有所帮助。
这个问题的最佳解决方案是"Copy Weights"。如果您想使用不同批次大小的 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/
如果您无法访问创建模型的代码,或者如果您只是不想让您的prediction/validation代码取决于您的模型创建和训练代码还有另一种方法:
您可以像这样从已加载模型配置的修改版本创建新模型:
loaded_model = tf.keras.models.load_model('model_file.h5')
config = loaded_model.get_config()
old_batch_input_shape = config['layers'][0]['config']['batch_input_shape']
config['layers'][0]['config']['batch_input_shape'] = (new_batch_size, old_batch_input_shape[1])
new_model = loaded_model.__class__.from_config(config)
new_model.set_weights(loaded_model.get_weights())
这对我来说效果很好,因为我有几个不同的模型,它们具有全状态 RNN 层,在图形网络中协同工作,但使用不同的网络分别进行训练,从而导致不同的批量大小。它允许我试验模型结构和训练批次,而无需更改验证脚本中的任何内容。
当我使用 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
后,我就可以对 fitting/training 和预测使用不同的批量大小。这是什么原因?
不幸的是,你想做的事用 Keras 是不可能的......我也在这个问题上挣扎了很多时间,唯一的方法是潜入兔子洞并直接与 Tensorflow 一起工作来做 LSTM 滚动预测。
首先,要明确术语,batch_size
通常表示一起训练的序列数,num_steps
表示一起训练的时间步数。当您指的是 batch_size=1
和 "just predicting the next value" 时,我认为您的意思是用 num_steps=1
.
否则,应该可以使用 batch_size=50
进行训练和预测,这意味着您正在训练 50 个序列并在每个时间步长进行 50 次预测,每个序列一个(意思是 training/prediction num_steps=1
).
但是,我认为你的意思是你想使用状态 LSTM 与 num_steps=50
一起训练并用 num_steps=1
进行预测。从理论上讲,这是有道理的并且应该是可能的,并且使用 Tensorflow 是可能的,而不是 Keras。
问题:Keras 需要有状态 RNN 的显式批量大小。您必须指定 batch_input_shape(batch_size、num_steps、功能)。
原因: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. This might or might not work at all for your problem as the gradient for back propagation will be computed on only one time step. See: 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 and blog post http://karpathy.github.io/2015/05/21/rnn-effectiveness/。请注意,一张图仍然只能使用指定的一张图 batch_size
,但您可以在 Tensorflow 中设置多个共享权重的模型图。
遗憾的是,您希望的是不可能的,因为您在定义模型时指定了 batch_size... 但是,我找到了解决此问题的简单方法:创建 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')
请注意,您只想保存和加载权重,而不是整个模型(包括架构、优化器等...)。这样你就可以获得权重,但你可以一次输入一批...... 有关 keras save/load 模型的更多信息: https://keras.io/getting-started/faq/#how-can-i-save-a-keras-model
请注意,您需要安装 h5py 才能使用 "save weights"。
另一个简单的解决方法是:
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)
我发现下面的内容很有帮助(并且与上面的内容完全一致)。 "Solution 3: Copy Weights" 部分对我有用:
How to use Different Batch Sizes when Training and Predicting with LSTMs, by 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')
我也有同样的问题并解决了。
另一种方式,你可以保存你的权重,当你测试你的结果时,你可以使用相同的架构重新加载你的模型并设置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")
它会很好用。 希望对你有所帮助。
这个问题的最佳解决方案是"Copy Weights"。如果您想使用不同批次大小的 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/
如果您无法访问创建模型的代码,或者如果您只是不想让您的prediction/validation代码取决于您的模型创建和训练代码还有另一种方法:
您可以像这样从已加载模型配置的修改版本创建新模型:
loaded_model = tf.keras.models.load_model('model_file.h5')
config = loaded_model.get_config()
old_batch_input_shape = config['layers'][0]['config']['batch_input_shape']
config['layers'][0]['config']['batch_input_shape'] = (new_batch_size, old_batch_input_shape[1])
new_model = loaded_model.__class__.from_config(config)
new_model.set_weights(loaded_model.get_weights())
这对我来说效果很好,因为我有几个不同的模型,它们具有全状态 RNN 层,在图形网络中协同工作,但使用不同的网络分别进行训练,从而导致不同的批量大小。它允许我试验模型结构和训练批次,而无需更改验证脚本中的任何内容。