【问题标题】:Why does reshaping my data completely change the behaviour of a fully connected neural network in Keras?为什么重塑我的数据会完全改变 Keras 中全连接神经网络的行为?
【发布时间】:2020-07-20 19:45:51
【问题描述】:

我希望能对此有所了解。我正在使用简单的神经网络在 Keras 中解决回归问题。我有训练和测试数据,训练数据由 33230 个样本和 20020 个特征组成(对于这个数据量来说,这是一大堆特征,但这是另一回事——这些特征只是各种测量值)。测试集是具有相同数量特征的 8308 个样本。我的数据位于 pandas 数据框中,我将其转换为看起来符合预期的 numpy 数组:

X_train = np.array(X_train_df)
X_train.shape

(33230, 20020)

X_test = np.array(X_test_df)
X_test.shape

(8308, 20020)

如果我将它传递给以下全连接模型,它会非常快速地训练,并在测试集上产生糟糕的结果:

型号:

model = Sequential()
model.add(Dense(300, activation="relu", input_shape=(20020,)))
model.add(Dense(300, activation="relu"))
model.add(Dense(100, activation="relu"))
model.add(Dense(1, activation='linear'))
model.compile(optimizer='adam', loss='mse',  metrics=['mean_absolute_error'])

适合:

model.fit(x=X_train, y=y_train, validation_data=(X_test,  y_test), batch_size=128, shuffle=True, epochs=100)

5 个 epoch 后的结果(此后基本没有变化,训练损失下降,验证损失增加):

Train on 33230 samples, validate on 8308 samples
Epoch 1/100
33230/33230 [==============================] - 11s 322us/sample - loss: 217.6460 - mean_absolute_error: 9.6896 - val_loss: 92.2517 - val_mean_absolute_error: 7.6400
Epoch 2/100
33230/33230 [==============================] - 10s 308us/sample - loss: 70.0501 - mean_absolute_error: 7.0170 - val_loss: 90.1813 - val_mean_absolute_error: 7.5721
Epoch 3/100
33230/33230 [==============================] - 10s 309us/sample - loss: 62.5253 - mean_absolute_error: 6.6401 - val_loss: 104.1333 - val_mean_absolute_error: 8.0131
Epoch 4/100
33230/33230 [==============================] - 11s 335us/sample - loss: 55.6250 - mean_absolute_error: 6.2346 - val_loss: 142.8665 - val_mean_absolute_error: 9.3112
Epoch 5/100
33230/33230 [==============================] - 10s 311us/sample - loss: 51.7378 - mean_absolute_error: 5.9570 - val_loss: 208.8995 - val_mean_absolute_error: 11.4158

但是,如果我重塑数据:

X_test = X_test.reshape(8308, 20020, 1)
X_train = X_train.reshape(33230, 20020, 1)

然后在第一层之后使用带有 Flatten() 的相同模型:

model = Sequential()
model.add(Dense(300, activation="relu", input_shape=(20020,1)))
model.add(Flatten())
model.add(Dense(300, activation="relu"))
model.add(Dense(100, activation="relu"))
model.add(Dense(1, activation='linear'))
model.compile(optimizer='adam', loss='mse',  metrics=['mean_absolute_error'])

然后我的结果看起来很不一样,而且好多了:

Train on 33230 samples, validate on 8308 samples
Epoch 1/100
33230/33230 [==============================] - 1117s 34ms/sample - loss: 112.4860 - mean_absolute_error: 7.5939 - val_loss: 59.3871 - val_mean_absolute_error: 6.2453
Epoch 2/100
33230/33230 [==============================] - 1112s 33ms/sample - loss: 4.7877 - mean_absolute_error: 1.6323 - val_loss: 23.8041 - val_mean_absolute_error: 3.8226
Epoch 3/100
33230/33230 [==============================] - 1116s 34ms/sample - loss: 2.3945 - mean_absolute_error: 1.1755 - val_loss: 14.9597 - val_mean_absolute_error: 2.8702
Epoch 4/100
33230/33230 [==============================] - 1113s 33ms/sample - loss: 1.5722 - mean_absolute_error: 0.9616 - val_loss: 15.0566 - val_mean_absolute_error: 2.9075
Epoch 5/100
33230/33230 [==============================] - 1117s 34ms/sample - loss: 1.4161 - mean_absolute_error: 0.9179 - val_loss: 11.5235 - val_mean_absolute_error: 2.4781

它也需要 1000 倍的时间,但在测试集上表现良好。我不明白为什么会这样。有人可以解释一下吗?我猜我错过了一些非常基本的东西,但我不知道是什么。

【问题讨论】:

    标签: python tensorflow keras neural-network


    【解决方案1】:

    一个很好的问题。首先,您必须了解网络的实际工作方式。 Dense 层是一个完全连接的层,因此每个神经元都会与前一层的神经元有连接。现在,您提到的网络性能比1000x 慢一点与您的训练数据无关,而是与您的网络有关。您的第二个网络太大了,我无法将它放入我的 RAM 中,也无法放入 Google Colab 中。因此,出于演示目的,我认为您的训练数据是(500, 100) 形状。

    对于您发布的采用上述形状的第一个网络,您的模型网络如下所示:

    model = Sequential()
    model.add(Dense(300, activation="relu", input_shape=(100,)))
    model.add(Dense(300, activation="relu"))
    model.add(Dense(100, activation="relu"))
    model.add(Dense(1, activation='linear'))
    model.compile(optimizer='adam', loss='mse',  metrics=['mean_absolute_error'])
    
    
    Model: "sequential_1"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    dense_2 (Dense)              (None, 300)               30300     
    _________________________________________________________________
    dense_3 (Dense)              (None, 300)               90300     
    _________________________________________________________________
    dense_4 (Dense)              (None, 100)               30100     
    _________________________________________________________________
    dense_5 (Dense)              (None, 1)                 101       
    =================================================================
    Total params: 150,801
    Trainable params: 150,801
    Non-trainable params: 0
    _________________________________________________________________
    

    记下 Total 参数,它是 150,801。 现在,如果我们以您的第二个例子为例。

    model1 = Sequential()
    model1.add(Dense(300, activation="relu", input_shape=(100,1)))
    model1.add(Flatten())
    model1.add(Dense(300, activation="relu"))
    model1.add(Dense(100, activation="relu"))
    model1.add(Dense(1, activation='linear'))
    model1.compile(optimizer='adam', loss='mse',  metrics=['mean_absolute_error'])
    
    Model: "sequential_4"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    dense_14 (Dense)             (None, 100, 300)          600       
    _________________________________________________________________
    flatten_2 (Flatten)          (None, 30000)             0         
    _________________________________________________________________
    dense_15 (Dense)             (None, 300)               9000300   
    _________________________________________________________________
    dense_16 (Dense)             (None, 100)               30100     
    _________________________________________________________________
    dense_17 (Dense)             (None, 1)                 101       
    =================================================================
    Total params: 9,031,101
    Trainable params: 9,031,101
    Non-trainable params: 0
    _________________________________________________________________
    

    您的总参数增加到9,031,101。当您使用长度为20020 的实际数据时,您可以成像。你的模型像任何东西一样增加,我什至无法在我的 RAM 中安装那个模型。

    总而言之,与第一个模型相比,您的第二个模型具有大量参数。这可能是训练慢而性能更好的原因吗?更多的参数使学习更好。如果不实际查看您的数据,就无法说出是什么让它变得更好。但是更多的参数有助于提高性能。

    注意:如果您删除Flatten 层,您的网络参数将减少,这是示例。

    model1 = Sequential()
    model1.add(Dense(300, activation="relu", input_shape=(100,1)))
    model1.add(Dense(300, activation="relu"))
    model1.add(Dense(100, activation="relu"))
    model1.add(Dense(1, activation='linear'))
    model1.compile(optimizer='adam', loss='mse',  metrics=['mean_absolute_error'])
    
    Model: "sequential_5"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    dense_18 (Dense)             (None, 100, 300)          600       
    _________________________________________________________________
    dense_19 (Dense)             (None, 100, 300)          90300     
    _________________________________________________________________
    dense_20 (Dense)             (None, 100, 100)          30100     
    _________________________________________________________________
    dense_21 (Dense)             (None, 100, 1)            101       
    =================================================================
    Total params: 121,101
    Trainable params: 121,101
    Non-trainable params: 0
    _________________________________________________________________
    

    我希望我的回答能帮助您了解什么是 hapening 以及两种模型之间的区别。

    更新:2007 年 7 月 20 日 对于您的评论,我认为最好更新答案以更清晰。您的问题是 -- 参数的数量与网络的形状有何关系?

    说实话,我不太清楚你的意思。我仍然会尝试回答。添加的层数或神经元越多,网络和可训练参数的数量就会增加。

    所以你的实际问题是为什么层Flatten 会增加你的参数。为此,您需要了解如何计算参数。

    model.add(Dense(300, activation="relu", input_shape=(100,)))
    

    考虑到这是您的第一层,参数数量将是 units *(input_size + 1)30300。现在当你添加Flatten层时,这实际上并不会自己增加你的参数,而是Flatten层的输出输入到下一层。所以考虑下面的例子。

    _________________________________________________________________
    flatten_2 (Flatten)          (None, 30000)             0         
    _________________________________________________________________
    dense_15 (Dense)             (None, 300)               9000300   
    _________________________________________________________________
    

    这里可以看到Flatten层的输出大小为30000。现在考虑上面的公式,您可以看到300 *(30000 + 1) 将产生9000300 参数,这本身就是一笔巨大的交易。更多数量的参数可以帮助学习更多特征,并可能有助于获得更好的结果。但这始终取决于数据,您必须对其进行试验。

    我希望以上解释可以消除您的疑虑。

    【讨论】:

    • 感谢您的回答!不过,我会有一个后续问题:参数的数量与网络的形状有何关系?例如,我可以通过向其中一个隐藏层添加任意数量的神经元(例如,300000 个神经元而不是 300 个)来增加第一个非扁平化和非重构示例中的参数数量,使其与第二个相似,但在这种情况下,测试用例的行为相同,即。从第一个纪元开始增加损失。第一层之后的展平如何改变网络行为?
    • 如果上面介绍的解决方案对您有用,我会鼓励您投票,以便其他人可以从中受益。谢谢。
    猜你喜欢
    • 2017-06-14
    • 1970-01-01
    • 2019-05-22
    • 2015-11-11
    • 2020-09-05
    • 2019-04-12
    • 1970-01-01
    • 2022-11-18
    • 2020-06-02
    相关资源
    最近更新 更多