【问题标题】:Keras 2D input to 2D outputKeras 2D 输入到 2D 输出
【发布时间】:2019-03-11 21:42:53
【问题描述】:

首先,我已阅读 thisthis 与我的名字相似的问题,但仍然没有答案。

我想建立一个用于序列预测的前馈网络。 (我意识到 RNN 更适合这项任务,但我有我的理由)。序列的长度为 128,每个元素是一个包含 2 个条目的向量,因此每个批次的形状应为 (batch_size, 128, 2),目标是序列中的下一步,因此目标张量的形状应为 (batch_size, 1, 2)

网络架构是这样的:

    model = Sequential()
    model.add(Dense(50, batch_input_shape=(None, 128, 2), kernel_initializer="he_normal" ,activation="relu"))
    model.add(Dense(20, kernel_initializer="he_normal", activation="relu"))
    model.add(Dense(5, kernel_initializer="he_normal", activation="relu"))
    model.add(Dense(2))

但尝试训练时出现以下错误:

ValueError: Error when checking target: expected dense_4 to have shape (128, 2) but got array with shape (1, 2)

我尝试过以下变体:

model.add(Dense(50, input_shape=(128, 2), kernel_initializer="he_normal" ,activation="relu"))

但得到同样的错误。

【问题讨论】:

  • 我不知道这个任务,但是有几种方法可以安排前馈 nns,以 (128,2) 作为输入和 (1,2) 作为输出。也许你可以解释一下为什么你认为它是一个 128 的序列,一次有 2 个向量,而不是一个 2 的序列,一次有 128 个向量?
  • 因为这些是时间序列,每个步骤有 128 个步骤(每个步骤一个 2 入口向量),我想保留时间关系
  • 您似乎正在寻找TimeDistributed 包装器,但您却让我感到困惑。如果时间有 128 步,每次有 2 个向量,向量的维数是多少?在您的网络中,您希望将时间维度合并为 1 个步骤?这两个项目是相互组成的吗?还是需要分开存放?
  • @Mehdi 感谢您提到 TimeDistributed,我对这个包装器并不熟悉。也许我的措辞有问题,我的意思是每个序列的形状都是 [[x1_1, x1_2], [x2_1, x1_2], [x2_1, x1_2], ...124 steps..., [x128_1, x128_2]]。 x_1 和 x_2 是独立的。
  • @Mehdi @H.Rappeport 只是一个旁注:正如我在回答中提到的那样,由于Dense layer is applied on the last axisTimeDistributed(Dense(...))Dense(...) 之间没有区别。

标签: python machine-learning keras time-series forecasting


【解决方案1】:

如果您查看model.summary() 输出,您会发现问题所在:

Layer (type)                 Output Shape              Param #   
=================================================================
dense_13 (Dense)             (None, 128, 50)           150       
_________________________________________________________________
dense_14 (Dense)             (None, 128, 20)           1020      
_________________________________________________________________
dense_15 (Dense)             (None, 128, 5)            105       
_________________________________________________________________
dense_16 (Dense)             (None, 128, 2)            12        
=================================================================
Total params: 1,287
Trainable params: 1,287
Non-trainable params: 0
_________________________________________________________________

如您所见,模型的输出是(None, 128,2),而不是您预期的(None, 1, 2)(或(None, 2))。因此,您可能知道也可能不知道 Dense layer is applied on the last axis of its input array,因此,正如您在上面看到的,时间轴和维度会一直保留到最后。

如何解决这个问题?您提到您不想使用 RNN 层,因此您有两个选择:您需要在模型中的某处使用 Flatten 层,或者您也可以使用一些 Conv1D + Pooling1D 层,甚至是 GlobalPooling 层。例如(这些只是为了演示,你可以做不同的):

使用Flatten

model = models.Sequential()
model.add(Dense(50, batch_input_shape=(None, 128, 2), kernel_initializer="he_normal" ,activation="relu"))
model.add(Dense(20, kernel_initializer="he_normal", activation="relu"))
model.add(Dense(5, kernel_initializer="he_normal", activation="relu"))
model.add(Flatten())
model.add(Dense(2))

model.summary()

模型总结:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_17 (Dense)             (None, 128, 50)           150       
_________________________________________________________________
dense_18 (Dense)             (None, 128, 20)           1020      
_________________________________________________________________
dense_19 (Dense)             (None, 128, 5)            105       
_________________________________________________________________
flatten_1 (Flatten)          (None, 640)               0         
_________________________________________________________________
dense_20 (Dense)             (None, 2)                 1282      
=================================================================
Total params: 2,557
Trainable params: 2,557
Non-trainable params: 0
_________________________________________________________________

使用GlobalAveragePooling1D

model = models.Sequential()
model.add(Dense(50, batch_input_shape=(None, 128, 2), kernel_initializer="he_normal" ,activation="relu"))
model.add(Dense(20, kernel_initializer="he_normal", activation="relu"))
model.add(GlobalAveragePooling1D())
model.add(Dense(5, kernel_initializer="he_normal", activation="relu"))
model.add(Dense(2))

model.summary()

​模型总结:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_21 (Dense)             (None, 128, 50)           150       
_________________________________________________________________
dense_22 (Dense)             (None, 128, 20)           1020      
_________________________________________________________________
global_average_pooling1d_2 ( (None, 20)                0         
_________________________________________________________________
dense_23 (Dense)             (None, 5)                 105       
_________________________________________________________________
dense_24 (Dense)             (None, 2)                 12        
=================================================================
Total params: 1,287
Trainable params: 1,287
Non-trainable params: 0
_________________________________________________________________

请注意,在上述两种情况下,您都需要将标签(即目标)数组重塑为 (n_samples, 2)(或者您可能希望在最后使用 Reshape 层)。

【讨论】:

  • 谢谢。后续问题(可能值得或不值得提出单独的问题):展平层的位置有什么影响?放在第一层还是最后一层之前会有什么不同吗?
  • @H.Rappeport 当然可以。它改变了连接。正如我在回答中提到的,Dense 层应用于最后一个轴,并且权重是共享的(即应用相同的权重)。为了澄清这一点,请查看上面模型摘要中的第二个 Dense 层。您会看到它有 1020 个参数:每个单元有 50 个参数 (50 * 20 = 1000),这些参数连接到前一层中的每一行(即 50 个元素),加上每个单元的一个偏置参数 (20)。现在在该层之前放置一个 Flatten 层:参数数量为 128*50*20+20。完全不同!
猜你喜欢
  • 1970-01-01
  • 2017-06-28
  • 1970-01-01
  • 2020-07-22
  • 2019-07-23
  • 2019-01-20
  • 1970-01-01
  • 2017-08-22
  • 1970-01-01
相关资源
最近更新 更多