【问题标题】:Why is a CNN slower to train than a fully connected MLP in Keras?为什么 CNN 的训练速度比 Keras 中的全连接 MLP 慢?
【发布时间】:2017-08-24 13:27:48
【问题描述】:

我查看了来自 Keras 的以下示例:

MNIST 中的 MLP:https://github.com/fchollet/keras/blob/master/examples/mnist_mlp.py

MNIST 中的 CNN:https://github.com/fchollet/keras/blob/master/examples/mnist_cnn.py

我都在 CPU 上的 Theano 中运行。在 MLP 中,我的平均时间约为 每个 epoch 16 秒,总共有 669,706 个参数:

Layer (type)                 Output Shape              Param #   
=================================================================
dense_33 (Dense)             (None, 512)               401920    
_________________________________________________________________
dropout_16 (Dropout)         (None, 512)               0         
_________________________________________________________________
dense_34 (Dense)             (None, 512)               262656    
_________________________________________________________________
dropout_17 (Dropout)         (None, 512)               0         
_________________________________________________________________
dense_35 (Dense)             (None, 10)                5130      
=================================================================
Total params: 669,706.0
Trainable params: 669,706.0
Non-trainable params: 0.0

在 CNN 中,我从原始代码中消除了最后一个隐藏层。我还将优化器更改为 rmsprop 以使两种情况具有可比性,留下以下架构:

Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_36 (Conv2D)           (None, 26, 26, 32)        320       
_________________________________________________________________
conv2d_37 (Conv2D)           (None, 24, 24, 64)        18496     
_________________________________________________________________
max_pooling2d_17 (MaxPooling (None, 12, 12, 64)        0         
_________________________________________________________________
dropout_22 (Dropout)         (None, 12, 12, 64)        0         
_________________________________________________________________
flatten_17 (Flatten)         (None, 9216)              0         
_________________________________________________________________
dense_40 (Dense)             (None, 10)                92170     
=================================================================
Total params: 110,986.0
Trainable params: 110,986.0
Non-trainable params: 0.0

然而,这里的平均时间大约是 每个 epoch 340 秒! 尽管参数少了六倍!

为了对此进行更多检查,我将每层的过滤器数量减少到 4 个,留下以下架构:

Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_38 (Conv2D)           (None, 26, 26, 4)         40        
_________________________________________________________________
conv2d_39 (Conv2D)           (None, 24, 24, 4)         148       
_________________________________________________________________
max_pooling2d_18 (MaxPooling (None, 12, 12, 4)         0         
_________________________________________________________________
dropout_23 (Dropout)         (None, 12, 12, 4)         0         
_________________________________________________________________
flatten_18 (Flatten)         (None, 576)               0         
_________________________________________________________________
dense_41 (Dense)             (None, 10)                5770      
=================================================================
Total params: 5,958.0
Trainable params: 5,958.0
Non-trainable params: 0.0

现在时间是 每个 epoch 28 秒,尽管大约有 6000 个参数!!

这是为什么?直观地说,优化应该只取决于变量的数量和梯度的计算(由于相同的批量大小应该是相似的)。

对此有所了解? 谢谢

【问题讨论】:

  • 你的直觉是错误的。查看您必须进行的计算次数。在密集层中,每个变量在一次乘法中使用一次(此处仅考虑前向传递),它将权重与输入相乘,仅此而已。另一方面,使用卷积,您的内核乘以输出值的次数,这意味着对于您的第一层,一个内核乘以 26*26 次,并且您有 32 个(如果每个都有 10 个变量)我没看错)。所以这里需要的计算能力不等于变量的个数。
  • 谢谢@nassim,我明白了。然而,按照最后一个网络中的逻辑,前两个卷积层将执行 26*26*4+26*26*4=5408 次计算,将其添加到密集层计算中会产生大约 12000 次计算。这个数字甚至比不上第一个网络的 670000 次计算,那么为什么每个 epoch 的最后一个网络时间与第一个网络如此相似呢?
  • 1) 您忘记了内核乘法不仅是“一次计算”,它还是元素矩阵乘法。因此,如果您的内核中有 10 个元素 --> 26*26*4*10。 2)我不是该领域的专家,但我认为做所有这些内核乘法比一个大矩阵乘法更昂贵...... idk它是如何在内部发生的,但我看到更多的I / O活动发生在你的计算上单元。 Dense真的很高效,在gpu/cpu上加载两个矩阵,计算,就是这样。
  • @nassim 你说得对,我忘记了内核的大小。然而,这提供了 60000 次计算,比 MLP 网络少 10 倍以上。我猜它是作为具有共享权重的稀疏矩阵实现的,因此能够像在 MLP 中一样加载到 gpu 中以进行前向传递。毕竟 CNN 的特点是稀疏连接和共享权重,除了避免过度拟合之外,这不正是为了让相同数量的神经元的训练更有效率吗?

标签: neural-network theano keras conv-neural-network


【解决方案1】:

我假设所有卷积操作的内核大小为 (3x3),输入二维数组通道大小为 3。

对于conv2d_36,您将拥有:

  • 3 * 32 = 所有通道的操作次数
  • 26 * 26 = 每个通道的卷积操作数
  • 3 * 3 = 每个卷积的乘法次数

所以,排除所有的求和(bias + conv internal),

  • 对于conv2d_36,您将有3 * 32 * 26 * 26 * 3 * 3 =~ 585k 乘法运算
  • 对于conv2d_37,类似32 * 64 * 24 * 24 * 3 * 3 =~ 10.6M 乘法运算
  • 对于dense_40,因为没有卷积,它将等于9216 * 10 = 92k 乘法运算。

当我们将所有这些加起来时,对于带有 CNN 的第二个模型,有 ~11.3M 单次乘法运算。

另一方面,如果我们将其展平并应用 MLP,

  • 对于dense_33层,会有28 * 28 * 3 * 512 = 1.2M乘法运算
  • 对于dense_34层,会有512 * 512 = 262k乘法运算
  • 对于dense_35层,会有512 * 10 = 5k乘法运算

当我们总结所有这些时,对于带有 MLP 的第一个模型,有 ~1.5M 单次乘法运算。

因此,仅 CNN 模型的乘法就比 MLP 模型高约 7.5 倍。考虑到层内的开销,其他操作成本,如求和和内存复制/访问操作,CNN 模型像你提到的那样慢似乎是完全合理的。

【讨论】:

    【解决方案2】:

    卷积操作比密集层复杂得多。 卷积是将图像的每个元素添加到其本地邻居的过程,由内核加权。 每个卷积本质上都是一个多重嵌套循环。这意味着密集层需要的时间是卷积层的一小部分。 Wikipedia 有一个卷积运算的启发性例子。

    【讨论】:

    • 感谢您的回答。然而,卷积可以实现为具有稀疏连接和权重共享的层。在这种情况下,前向传递的操作与密集情况下的操作基本相同(只是矩阵乘法)。对于反向传播,也许复杂性会因权重共享而有所不同,但是……这么多?为什么?我认为 CNN 的全部目的是通过利用空间相关性来减少参数和操作的数量,以减少过度拟合,同时提高效率。
    猜你喜欢
    • 2019-08-05
    • 1970-01-01
    • 2017-05-11
    • 1970-01-01
    • 2020-10-21
    • 2020-02-01
    • 2018-08-14
    • 2019-07-05
    • 1970-01-01
    相关资源
    最近更新 更多