tensorflow - Stateful LSTM Tensorflow Invalid Input_h Shape Error

标签 tensorflow keras neural-network lstm 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)

当我运行上述代码时,在第一个 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

但是,如果我将 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()

尽管如此,对于非常大的数据(100 万行),由于 batch_size 为 1,因此模型训练需要很长时间。

所以,我想知道,如何训练批量大小大于 1(例如 64)的有状态 LSTM,而不会出现无效的 input_h 形状错误?

感谢您的回答。

最佳答案

解决方法是确保批处理大小永远不会在批处理之间发生变化。它们的大小必须相同。

方法一

一种方法是使用将您的数据集完美划分为大小相等的批处理的批处理大小。例如,如果数据的总大小为 1500 个示例,则使用 50 或 100 的批量大小或 1500 的其他适当除数。

batch_size = len(data)/proper_divisor

方法二

另一种方法是忽略任何小于指定大小的批处理,这可以使用 TensorFlow Dataset API 并将 drop_remainder 设置为 是的

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)

当使用上述数据集 API 时,您还需要指定多少轮训练计为一个 epoch(本质上是多少批处理计为 1 个 epoch)。 tf.data.Dataset 实例(来自 tf.data.Dataset.from_tensor_slices 的结果)不知道它正在流式传输到模型的数据的大小,因此必须使用 steps_per_epoch 手动指定什么构成一个 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)

您也可以包含验证集,如下所示(不显示其他代码):


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)

警告:这意味着模型永远不会看到一些数据点。为了解决这个问题,您可以在每轮训练中打乱数据集,以便每个 epoch 留下的数据点发生变化,让每个人都有机会被模型看到。

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)

为什么会出现错误

有状态的 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 会将其 reshape 为 (15, 10, 2)。

关于tensorflow - Stateful LSTM Tensorflow Invalid Input_h Shape Error,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64159777/

相关文章:

Tensorflow:get_tensor_by_name 与 get_operation_by_name 的区别?

deep-learning - 如何在 keras 中对矩阵的每一行应用不同的密集层

python - 将每个批处理或纪元的验证准确性打印到控制台(Keras)

machine-learning - 为什么caffe训练阶段会有准确率输出?

python - CancelledError : [_Derived_]RecvAsync is cancelled. 在 google colab 上运行

Tensorflow 构建错误

python - 网络在形状 N 的网格上训练良好,但在评估任何变化时失败

validation - ImageNet:ILSVRC2012 中的验证类别

neural-network - 与 caffe 相比,pycaffe 的训练有多好?

python - 预期dense_43_input具有形状(3,)但得到形状为(1,)的数组