有状态LSTM Tensorflow无效的Input_h形状错误

我正在通过使用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],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)

当我运行上述代码时,在第一个时期结束后,我将收到如下错误消息。

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,epochs=1,validation_data=(val_feature,val_label),batch_size=batch_size,shuffle=False)

    model.reset_states()

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

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

感谢您的回答。

mengxt001 回答:有状态LSTM Tensorflow无效的Input_h形状错误

解决方法是确保批次之间的批次大小不变。它们的大小都必须相同。

方法1

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

batch_size = len(data)/proper_divisor

方法2

另一种方法是忽略小于指定大小的任何批次,这可以使用TensorFlow Dataset 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)

在使用上述的Dataset API时,您还需要指定将多少轮训练计为一个纪元(实际上是将多少个批次计为1个纪元)。 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],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,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,steps_per_epoch=steps_per_epoch,validation_steps=validation_steps)

注意::这意味着模型永远不会看到一些数据点。为了解决这个问题,您可以在每轮训练中改组数据集,以使每个纪元后面的数据点都发生变化,从而使每个人都有机会被模型看到。

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将在一个纪元末尾使用剩余的数据作为批处理,并且此数据点最多可以包含64个数据点。因此,由于批次大小与有状态LSTM期望的大小不同,您会收到这样的错误。批处理大小为1不会有问题,因为在一个纪元末尾的任何剩余数据将始终恰好包含1个数据点,因此没有错误。更一般而言,1始终是任何整数的除数。因此,如果您选择了数据大小的其他除数,则不会收到错误。

在您发布的错误消息中,似乎最后一批的大小为49,而不是64。旁注:形状看起来与输入不同的原因是,在幕后,keras与张量一起使用。 time_major(即第一个轴用于顺序步骤)。当您传递表示(batch_size,steps_per_sequence,num_features)的形状(10、15、2)的张量时,keras会将其重塑为引擎盖下的(15、10、2)。

本文链接:https://www.f2er.com/1468534.html

大家都在问