【问题标题】:Tensorflow/Keras: Output shape mismatch in training data and predicted dataTensorflow/Keras:训练数据和预测数据中的输出形状不匹配
【发布时间】:2020-09-12 19:42:56
【问题描述】:

我在 tensorflow/keras 中定义了一个 LSTM 模型,如下所示。我只包括与问题有关的相关细节。

t_steps = 60
n_features = 3

def LSTMModel():
  input = Input(shape=(t_steps, n_features))
  l1 = BatchNormalization()(input)
  l2 = LSTM(160,return_sequences=True)(l1)
  l3 = LSTM(80,return_sequences=True)(l2)
  l4 = LSTM(10,return_sequences=True)(l3)
  l5 = Dense(1, activation = 'relu')(l4)
  model = Model(inputs = input, outputs = l5)
  model.compile(loss="mean_squared_error", optimizer='adam')
  return model

# shape of X_train_seq is (275268, 60, 3)
# shape of Y_train_seq is (275268,)

model = LSTMModel()
model.fit(X_train_seq, Y_train_seq, epochs=n_epochs,
  batch_size=batch_size,verbose=1,initial_epoch=init_epoch)

然后,当我在形状为 (30355, 60, 3) 的 X_test_seq 上使用此模型进行预测时,我得到形状为 (30355, 60, 1) 的 Y_test_seq_pred,而我期望预测形状为 (30355,)。发生这种情况是因为我上面代码中的 l4 行应该是

l4 = LSTM(10,return_sequences=False)(l3)

我的问题是,使用原始代码,为什么 Tensorflow/Keras 在训练期间没有给出错误或产生任何类型的警告,因为传递给 fit() 方法的 Y_train_seq 的形状是 (275268,) 并且在训练期间,它必须在优化期间为每个批次在内部预测形状为 (batch_size, 60, 1) 的 Y,并将其与来自 Y_train_seq 的形状切片 (batch_size,) 进行比较。为什么 Y 中的这种尺寸不匹配仍然让代码继续,只是让我在训练结束时发现它? 我确信这背后一定有一些原因,我想知道发生了什么。 谢谢!!

【问题讨论】:

  • 我在 google colab 上创建了一个示例代码,怀疑这可能与 tf/keras 版本有关。使用 colab 上的默认版本(Keras 2.3.1,tf 2.2.0)它确实给我一个关于尺寸不匹配的错误。然后进行交叉检查,我安装了 Keras 2.2.4(这是我的机器所拥有的)并且代码执行良好,没有任何错误。为了完成 A-B-A 测试,我在 google colab 上重新安装了 Keras 2.3.1,希望它会给我一个错误,但它仍然执行得很好,没有说明任何尺寸。这让我很困惑。

标签: python tensorflow machine-learning keras lstm


【解决方案1】:

这是由于 Numpy 广播所调用的,它描述了 Numpy 如何处理具有不同形状的数组。

让我们首先定义两个张量 A 和 B 具有以下形状的张量,

dim(A) = (32, 60, 1)
dim(B) = (32,)

例如,如果您尝试在 A 和 B,在这种情况下 Tensorflow 表示 B 维度的方式,例如用无关替换维度。 p>

dim(B) = (do_not_care, do_not_care, 32)

所以在迭代时,从一个包含 32 个元素(值)的数组中减去标量值 x,因此输出是一个包含 32 个不同值的列矩阵。

dim(output) = (32, 60, 32),这是有效但意外的行为。

这样的操作可以递归实现,我们从第一维度(轴)开始迭代更高维度的张量到第二张量的已知维度,然后我们可以将所需的操作应用于生成的 chunked 张量,如果它们的形状匹配,即广播成功。


减法广播的实现可以如下进行。

def supstract(a, b): # a and b are numpy.array()

  # check if shape valid
  if a.squeeze().ndim == b.squeeze().ndim:
    if b.squeeze().shape[-1] == b.squeeze().shape[-1]:
      print(a - b, '\n')
      return
    else:
      raise ValueError(f'could not Broadcasting, {a.shape} != {b.shape}')

  elif a.ndim > b.ndim:
    for sub_a in a:
      supstract(sub_a, b) # recursive call
  else:
    for sub_b in b:
      supstract(a, sub_b) # recursive call

我已经使用下面的例子来检查实现,所以我可能遗漏了一些条件(不同的情况处理)。

a = np.random.randint(1, 4, (2, 2, 6, 1))
b = np.random.randint(1, 4, (4, )) 

在您的情况下,Tensorflow 需要 Y 来计算损失函数,您使用的是 MSE,它只是一个标量值,使用 Keras 后端计算如下。

from tensorflow.keras import backend as K

def mean_squared_error(y_true, y_pred):
  return K.mean((y_pred - y_true) ** 2) # broadcasting (y_pred - y_true)

更新

|1 2 3| + |7 8 9|
|4 5 6|

|1 2 3| + 7 = |8  9  10|
|4 5 6|       |11 12 13|

基于描述broadcasting 的Tensorflow 文档。 Numpy(广播)处理上述任何操作,但数学上你不能应用它们中的任何一个。如果您想对任何广播操作发出警告,您可能会收到 吨 警告。

【讨论】:

  • 嗨@m-zayan 谢谢。即使 python 广播让 if 发生,问题是为什么没有任何警告。这对我来说不是一个真正的问题,因为我有一个正确的代码,但只是好奇。
  • 嗨 Makarand,问题是,广播是一个有效的操作,所以有时收到警告是不合理的,至少对于 Numpy 和 Tensorflow 如何处理数组而言,广播对于许多操作来说意义重大,因为它解决了一个很多问题并避免出现错误和大量警告。特别是对于 tensorflow 获得 N 维张量的警告,没有太大帮助(numpy 和 tensorflow 喜欢有一个通用的解决方案),您可以在构建模型时轻松处理异常和预处理你的数据集。
  • Makarand,我已经更新了答案,希望对您有所帮助
  • 嗨 m-zayan:请参阅我添加到原始问题的评论。虽然广播是一种合理的操作,但在 ML 应用中,如果模型给出的输出与提供给它的目标不同,就会出现问题。
猜你喜欢
  • 1970-01-01
  • 2017-05-29
  • 2019-05-05
  • 2018-02-19
  • 1970-01-01
  • 2018-06-01
  • 2019-03-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多