glo*_*ian 3 neural-network lstm keras tensorflow lstm-stateful
我正在使用 TensorFlow 在时间序列回归问题上试验有状态 LSTM。我很抱歉无法共享数据集。下面是我的代码。
train_feature = train_feature.reshape((train_feature.shape[0], 1, train_feature.shape[1]))
val_feature = val_feature.reshape((val_feature.shape[0], 1, val_feature.shape[1]))
batch_size = 64
model = tf.keras.Sequential()
model.add(tf.keras.layers.LSTM(50, batch_input_shape=(batch_size, train_feature.shape[1], train_feature.shape[2]), stateful=True))
model.add(tf.keras.layers.Dense(1))
model.compile(optimizer='adam',
loss='mse',
metrics=[tf.keras.metrics.RootMeanSquaredError()])
model.fit(train_feature, train_label,
epochs=10,
batch_size=batch_size)
Run Code Online (Sandbox Code Playgroud)
当我运行上面的代码时,在第一个 epoch 结束后,我会得到如下错误。
InvalidArgumentError: [_Derived_] Invalid input_h shape: [1,64,50] [1,49,50]
[[{{node CudnnRNN}}]]
[[sequential_1/lstm_1/StatefulPartitionedCall]] [Op:__inference_train_function_1152847]
Function call stack:
train_function -> train_function -> train_function
Run Code Online (Sandbox Code Playgroud)
但是,如果我将batch_size更改为 1,并将模型训练的代码更改为以下代码,则模型将成功训练。
total_epochs = 10
for i in range(total_epochs):
model.fit(train_feature, train_label,
epochs=1,
validation_data=(val_feature, val_label),
batch_size=batch_size,
shuffle=False)
model.reset_states()
Run Code Online (Sandbox Code Playgroud)
尽管如此,对于非常大的数据(100 万行),由于batch_size 为1,模型训练将花费很长时间。
所以,我想知道,如何训练批量大小大于 1(例如 64)的有状态 LSTM,而不会出现无效的 input_h 形状错误?
感谢您的回答。
解决方法是确保批次大小在批次之间永远不会改变。它们的大小必须相同。
一种方法是使用批量大小,将您的数据集完美地划分为大小相等的批次。例如,如果数据的总大小为 1500 个示例,则使用 50 或 100 或其他适当除数 1500 的批量大小。
batch_size = len(data)/proper_divisor
Run Code Online (Sandbox Code Playgroud)
另一种方法是忽略任何批次小于规定尺寸,这样就可以使用TensorFlow数据集API和设置来完成drop_remainder对True。
batch_size = 64
train_data = tf.data.Dataset.from_tensor_slices((train_feature, train_label))
train_data = train_data.repeat().batch(batch_size, drop_remainder=True)
steps_per_epoch = len(train_feature) // batch_size
model.fit(train_data,
epochs=10, steps_per_epoch = steps_per_epoch)
Run Code Online (Sandbox Code Playgroud)
使用上述 Dataset API 时,您还需要指定将多少轮训练计为一个 epoch(本质上是将多少批次计为 1 个 epoch)。一个tf.data.Dataset实例(从结果tf.data.Dataset.from_tensor_slices)不知道数据的大小,它的流媒体的模式,所以什么是为一个时代必须与手动指定steps_per_epoch。
您的新代码将如下所示:
train_feature = train_feature.reshape((train_feature.shape[0], 1, train_feature.shape[1]))
val_feature = val_feature.reshape((val_feature.shape[0], 1, val_feature.shape[1]))
batch_size = 64
train_data = tf.data.Dataset.from_tensor_slices((train_feature, train_label))
train_data = train_data.repeat().batch(batch_size, drop_remainder=True)
model = tf.keras.Sequential()
model.add(tf.keras.layers.LSTM(50, batch_input_shape=(batch_size, train_feature.shape[1], train_feature.shape[2]), stateful=True))
model.add(tf.keras.layers.Dense(1))
model.compile(optimizer='adam',
loss='mse',
metrics=[tf.keras.metrics.RootMeanSquaredError()])
steps_per_epoch = len(train_feature) // batch_size
model.fit(train_data,
epochs=10, steps_per_epoch = steps_per_epoch)
Run Code Online (Sandbox Code Playgroud)
您还可以包含验证集,如下所示(不显示其他代码):
batch_size = 64
val_data = tf.data.Dataset.from_tensor_slices((val_feature, val_label))
val_data = val_data.repeat().batch(batch_size, drop_remainder=True)
validation_steps = len(val_feature) // batch_size
model.fit(train_data, epochs=10,
steps_per_epoch=steps_per_epoch,
validation_steps=validation_steps)
Run Code Online (Sandbox Code Playgroud)
警告:这意味着模型永远不会看到一些数据点。为了解决这个问题,你可以在每一轮训练中对数据集进行洗牌,这样每个时期留下的数据点都会发生变化,让每个人都有机会被模型看到。
buffer_size = 1000 # the bigger the slower but more effective shuffling.
train_data = tf.data.Dataset.from_tensor_slices((train_feature, train_label))
train_data = train_data.shuffle(buffer_size=buffer_size, reshuffle_each_iteration=True)
train_data = train_data.repeat().batch(batch_size, drop_remainder=True)
Run Code Online (Sandbox Code Playgroud)
有状态 RNN 及其变体(LSTM、GRU 等)需要固定的批大小。原因很简单,因为有状态是通过时间实现截断反向传播的一种方式,通过将一个批次的最终隐藏状态作为下一个批次的初始隐藏状态传递。第一批的最终隐藏状态必须与下一批的初始隐藏状态具有完全相同的形状,这要求批次大小在各批次之间保持相同。
当您将批次大小设置为 64 时,model.fit将使用 epoch 结束时的剩余数据作为批次,而这可能不会有多达 64 个数据点。因此,您会收到这样的错误,因为批大小与有状态 LSTM 所期望的不同。您没有批量大小为 1 的问题,因为在一个时期结束时的任何剩余数据将始终包含 1 个数据点,因此没有错误。更一般地说,1 总是任何整数的除数。因此,如果您选择了数据大小的任何其他除数,则不会出现错误。
在您发布的错误消息中,最后一批的大小似乎是 49 而不是 64。 附带说明:形状看起来与输入不同的原因是,在幕后,keras 与 time_major 中的张量一起工作(即第一个轴用于顺序步骤)。当您传递一个表示 (batch_size, steps_per_sequence, num_features) 的形状为 (10, 15, 2) 的张量时,keras 在后台将其重塑为 (15, 10, 2)。
| 归档时间: |
|
| 查看次数: |
787 次 |
| 最近记录: |