原文: https://machinelearningmastery.com/use-different-batch-sizes-training-predicting-python-keras/
Keras 使用快速符号数学库作为后端,例如 TensorFlow 和 Theano。
使用这些库的缺点是,无论您是在训练网络还是做出预测,数据的形状和大小都必须预先定义并保持不变。
在序列预测问题上,可能需要在训练网络时使用大批量大小,并且在做出预测时使用批量大小为 1 以便预测序列中的下一步骤。
在本教程中,您将了解如何解决此问题,甚至在训练和预测期间使用不同的批量大小。
完成本教程后,您将了解:
- 如何设计简单的序列预测问题并开发 LSTM 来学习它。
- 如何改变在线和基于批量的学习和预测的 LSTM 配置。
- 如何改变用于训练的批量大小与用于预测的批量大小。
让我们开始吧。
如何使用不同的批量大小进行 Python 的训练和预测与 Keras 照片由 steveandtwyla ,保留一些权利。
本教程分为 6 个部分,如下所示:
- 批量大小
- 序列预测问题描述
- LSTM 模型和变化的批量大小
- 解决方案 1:在线学习(批量大小= 1)
- 解决方案 2:批量预测(批量大小= N)
- 解决方案 3:复制权重
假设 Python 2 或 3 环境已安装并正常工作。
这包括 SciPy 与 NumPy 和 Pandas。必须使用 TensorFlow 或 Keras 后端安装 Keras 2.0 或更高版本。
有关设置 Python 环境的帮助,请参阅帖子:
使用 Keras 的一个好处是它建立在象征性数学库之上,如 TensorFlow 和 Theano,可实现快速高效的计算。大型神经网络需要这样做。
使用这些高效库的一个缺点是您必须预先定义数据的范围。具体来说,批量大小。
批量大小限制在可以执行权重更新之前要显示给网络的样本数。当使用拟合模型做出预测时,会施加同样的限制。
具体而言,在拟合模型时使用的批量大小控制着您一次必须进行多少次预测。
当您希望一次进行与训练期间使用的批量大小相同的数字预测时,这通常不是问题。
当您希望进行的预测少于批量大小时,这确实会成为一个问题。例如,您可以获得批量较大的最佳结果,但需要在时间序列或序列问题等方面对一次观察做出预测。
这就是为什么在将网络拟合到训练数据时可能需要具有与在对测试数据或新输入数据做出预测时不同的批量大小的原因。
在本教程中,我们将探索解决此问题的不同方法。
我们将使用简单的序列预测问题作为上下文来演示在训练和预测之间改变批量大小的解决方案。
序列预测问题为不同的批量大小提供了一个很好的案例,因为您可能希望批量大小等于训练期间的训练数据集大小(批量学习),并且在对一步输出做出预测时批量大小为 1。
序列预测问题涉及学习预测以下 10 步序列中的下一步:
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
我们可以在 Python 中创建这个序列,如下所示:
length = 10
sequence = [i/float(length) for i in range(length)]
print(sequence)
运行该示例打印我们的序列:
[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
我们必须将序列转换为监督学习问题。这意味着当 0.0 显示为输入模式时,网络必须学会将下一步预测为 0.1。
我们可以使用 Pandas shift() 函数在 Python 中执行此操作,如下所示:
from pandas import concat
from pandas import DataFrame
# create sequence
length = 10
sequence = [i/float(length) for i in range(length)]
# create X/y pairs
df = DataFrame(sequence)
df = concat([df, df.shift(1)], axis=1)
df.dropna(inplace=True)
print(df)
运行该示例显示所有输入和输出对。
1 0.1 0.0
2 0.2 0.1
3 0.3 0.2
4 0.4 0.3
5 0.5 0.4
6 0.6 0.5
7 0.7 0.6
8 0.8 0.7
9 0.9 0.8
我们将使用称为长短期记忆网络的循环神经网络来学习序列。因此,我们必须将输入模式从 2D 数组(1 列 9 行)转换为由[_ 行,时间步长,列 _]组成的 3D 数组,其中时间步长为 1,因为我们只有一个时间步长观察每一行。
我们可以使用 NumPy 函数 reshape() 执行此操作,如下所示:
from pandas import concat
from pandas import DataFrame
# create sequence
length = 10
sequence = [i/float(length) for i in range(length)]
# create X/y pairs
df = DataFrame(sequence)
df = concat([df, df.shift(1)], axis=1)
df.dropna(inplace=True)
# convert to LSTM friendly format
values = df.values
X, y = values[:, 0], values[:, 1]
X = X.reshape(len(X), 1, 1)
print(X.shape, y.shape)
运行该示例创建X
和y
数组,准备与 LSTM 一起使用并打印其形状。
(9, 1, 1) (9,)
在本节中,我们将针对该问题设计 LSTM 网络。
训练批量大小将覆盖整个训练数据集(批量学习),并且将一次一个地做出预测(一步预测)。我们将证明虽然模型能够解决问题,但一步预测会导致错误。
我们将使用适合 1000 个时期的 LSTM 网络。
权重将在每个训练时期结束时更新(批量学习),这意味着批量大小将等于训练观察的数量(9)。
对于这些实验,我们将需要对 LSTM 的内部状态何时更新进行细粒度控制。通常 LSTM 状态在 Keras 的每个批次结束时被清除,但是我们可以通过使 LSTM 有状态并且调用 model.reset_state() 来手动管理该状态来控制它。这将在后面的章节中提到。
网络有一个输入,一个隐藏层有 10 个单元,一个输出层有 1 个单元。默认的 tanh 激活函数用于 LSTM 单元,而线性激活函数用于输出层。
使用有效的 ADAM 优化算法将均方误差优化函数用于该回归问题。
以下示例配置并创建网络。
# 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')
我们将网络适合每个时期的所有示例,并在每个时期结束时手动重置网络状态。
# 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()
最后,我们将一次预测序列中的每个步骤。
这需要批量大小为 1,这与用于适合网络的批量大小 9 不同,并且在运行示例时将导致错误。
# online forecast
for i in range(len(X)):
testX, testy = X[i], y[i]
testX = testX.reshape(1, 1, 1)
yhat = model.predict(testX, batch_size=1)
print('>Expected=%.1f, Predicted=%.1f' % (testy, yhat))
下面是完整的代码示例。
from pandas import DataFrame
from pandas import concat
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
# create sequence
length = 10
sequence = [i/float(length) for i in range(length)]
# create X/y pairs
df = DataFrame(sequence)
df = concat([df, df.shift(1)], axis=1)
df.dropna(inplace=True)
# convert to LSTM friendly format
values = df.values
X, y = values[:, 0], values[:, 1]
X = X.reshape(len(X), 1, 1)
# 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')
# 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()
# online forecast
for i in range(len(X)):
testX, testy = X[i], y[i]
testX = testX.reshape(1, 1, 1)
yhat = model.predict(testX, batch_size=1)
print('>Expected=%.1f, Predicted=%.1f' % (testy, yhat))
运行该示例可以很好地匹配模型,并在做出预测时导致错误。
报告的错误如下:
ValueError: Cannot feed value of shape (1, 1, 1) for Tensor 'lstm_1_input:0', which has shape '(9, 1, 1)'
该问题的一个解决方案是使用在线学习来拟合模型。
这是批量大小设置为值 1 并且在每个训练示例之后更新网络权重的位置。
这可以具有更快学习的效果,但也会增加学习过程的不稳定性,因为权重随着每批次而变化很大。
尽管如此,这将使我们能够对问题进行一步预测。唯一需要做的更改是将n_batch
设置为 1,如下所示:
n_batch = 1
完整的代码清单如下。
from pandas import DataFrame
from pandas import concat
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
# create sequence
length = 10
sequence = [i/float(length) for i in range(length)]
# create X/y pairs
df = DataFrame(sequence)
df = concat([df, df.shift(1)], axis=1)
df.dropna(inplace=True)
# convert to LSTM friendly format
values = df.values
X, y = values[:, 0], values[:, 1]
X = X.reshape(len(X), 1, 1)
# configure network
n_batch = 1
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')
# 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()
# online forecast
for i in range(len(X)):
testX, testy = X[i], y[i]
testX = testX.reshape(1, 1, 1)
yhat = model.predict(testX, batch_size=1)
print('>Expected=%.1f, Predicted=%.1f' % (testy, yhat))
运行该示例将打印 9 个预期结果和正确的预测。
>Expected=0.0, Predicted=0.0
>Expected=0.1, Predicted=0.1
>Expected=0.2, Predicted=0.2
>Expected=0.3, Predicted=0.3
>Expected=0.4, Predicted=0.4
>Expected=0.5, Predicted=0.5
>Expected=0.6, Predicted=0.6
>Expected=0.7, Predicted=0.7
>Expected=0.8, Predicted=0.8
另一种解决方案是批量生产所有预测。
这意味着我们在模型使用方式上可能非常有限。
我们必须立即使用所有预测,或者只保留第一个预测并丢弃其余的预测。
我们可以通过预测批量大小等于训练批量大小来调整批量预测的示例,然后枚举预测批次,如下所示:
# batch forecast
yhat = model.predict(X, batch_size=n_batch)
for i in range(len(y)):
print('>Expected=%.1f, Predicted=%.1f' % (y[i], yhat[i]))
下面列出了完整的示例。
from pandas import DataFrame
from pandas import concat
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
# create sequence
length = 10
sequence = [i/float(length) for i in range(length)]
# create X/y pairs
df = DataFrame(sequence)
df = concat([df, df.shift(1)], axis=1)
df.dropna(inplace=True)
# convert to LSTM friendly format
values = df.values
X, y = values[:, 0], values[:, 1]
X = X.reshape(len(X), 1, 1)
# 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')
# 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()
# batch forecast
yhat = model.predict(X, batch_size=n_batch)
for i in range(len(y)):
print('>Expected=%.1f, Predicted=%.1f' % (y[i], yhat[i]))
运行该示例将打印预期和正确的预测值。
>Expected=0.0, Predicted=0.0
>Expected=0.1, Predicted=0.1
>Expected=0.2, Predicted=0.2
>Expected=0.3, Predicted=0.3
>Expected=0.4, Predicted=0.4
>Expected=0.5, Predicted=0.5
>Expected=0.6, Predicted=0.6
>Expected=0.7, Predicted=0.7
>Expected=0.8, Predicted=0.8
更好的解决方案是使用不同的批量大小进行训练和预测。
执行此操作的方法是从拟合网络复制权重,并使用预先训练的权重创建新网络。
我们可以使用 Keras API 中的 get_weights() 和 set_weights() 函数轻松完成此操作,如下所示:
# 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)
这将创建一个以批量大小为 1 编译的新模型。然后,我们可以使用此新模型进行一步预测:
# online forecast
for i in range(len(X)):
testX, testy = X[i], y[i]
testX = testX.reshape(1, 1, 1)
yhat = new_model.predict(testX, batch_size=n_batch)
print('>Expected=%.1f, Predicted=%.1f' % (testy, yhat))
The complete example is listed below.
from pandas import DataFrame
from pandas import concat
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
# create sequence
length = 10
sequence = [i/float(length) for i in range(length)]
# create X/y pairs
df = DataFrame(sequence)
df = concat([df, df.shift(1)], axis=1)
df.dropna(inplace=True)
# convert to LSTM friendly format
values = df.values
X, y = values[:, 0], values[:, 1]
X = X.reshape(len(X), 1, 1)
# configure network
n_batch = 3
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')
# 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')
# online forecast
for i in range(len(X)):
testX, testy = X[i], y[i]
testX = testX.reshape(1, 1, 1)
yhat = new_model.predict(testX, batch_size=n_batch)
print('>Expected=%.1f, Predicted=%.1f' % (testy, yhat))
运行该示例将打印预期的值,并再次正确预测值。
>Expected=0.0, Predicted=0.0
>Expected=0.1, Predicted=0.1
>Expected=0.2, Predicted=0.2
>Expected=0.3, Predicted=0.3
>Expected=0.4, Predicted=0.4
>Expected=0.5, Predicted=0.5
>Expected=0.6, Predicted=0.6
>Expected=0.7, Predicted=0.7
>Expected=0.8, Predicted=0.8
在本教程中,您了解了如何通过相同的网络来改变用于训练和预测的批量大小的需求。
具体来说,你学到了:
- 如何设计简单的序列预测问题并开发 LSTM 来学习它。
- 如何改变在线和基于批量的学习和预测的 LSTM 配置。
- 如何改变用于训练的批量大小与用于预测的批量大小。
您对批量大小有任何疑问吗? 在下面的评论中提出您的问题,我会尽力回答。