keras 中的 Flatten() 和 GlobalAveragePooling2D() 有啥区别

Posted

技术标签:

【中文标题】keras 中的 Flatten() 和 GlobalAveragePooling2D() 有啥区别【英文标题】:what is the difference between Flatten() and GlobalAveragePooling2D() in keraskeras 中的 Flatten() 和 GlobalAveragePooling2D() 有什么区别 【发布时间】:2018-08-24 00:28:14 【问题描述】:

我想将 ConvLSTM 和 Conv2D 的输出传递到 Keras 中的 Dense Layer,使用全局平均池化和 flatten 有什么区别 两者都适用于我的情况。

model.add(ConvLSTM2D(filters=256,kernel_size=(3,3)))
model.add(Flatten())
# or model.add(GlobalAveragePooling2D())
model.add(Dense(256,activation='relu'))

【问题讨论】:

【参考方案1】:

两者似乎都有效并不意味着它们的作用相同。

Flatten 将采用任何形状的张量并将其转换为一维张量(加上样本维度),但将所有值保留在张量中。例如,张量 (samples, 10, 20, 1) 将被展平为 (samples, 10 * 20 * 1)。

GlobalAveragePooling2D 做了一些不同的事情。它在空间维度上应用平均池化,直到每个空间维度为一,而其他维度保持不变。在这种情况下,值不会保留,因为它们是平均的。例如,张量 (samples, 10, 20, 1) 将输出为 (samples, 1, 1, 1),假设第 2 和第 3 维是空间的(通道在后)。

【讨论】:

@NicolasGervais 实际上不,它更复杂,我的答案基于 2018 年的 Keras,您的答案基于 tf.keras(我猜是 2020 年),它们的行为不同。这不会使我的答案错。 @NicolasGervais 如果您在 2.0 版左右使用 keras,您会看到它实际输出 (n, 1, 1, c)。他们在以后的版本中对其进行了更改。 @NicolasGervais 没有错也没有过时,我一直在这里说 keras 和 tf.keras 实际上是具有不同行为的不同库。 @NicolasGervais 那又怎样?人们仍在使用它。在 tf.keras 的案例中已经有了答案,你的答案没有添加任何新内容。 @NicolasGervais 另请注意,这个问题被标记为 [keras],并且从标签描述中:如果您使用的是 tensorflow 的内置 keras,请使用 [tf.keras] 标签【参考方案2】:

扁平化很简单,它只是通过重新排列元素将多维对象转换为一维对象。

虽然 GlobalAveragePooling 是一种用于更好地表示矢量的方法。它可以是 1D/2D/3D。它使用一个解析器窗口,该窗口在对象上移动并通过平均数据(GlobalAveragePooling)或选取最大值(GlobalMaxPooling)来汇集数据。基本上需要填充来考虑极端情况。

两者都用于以更简单的方式考虑排序的影响。

【讨论】:

【参考方案3】:

如果你更有信心,你可以自己测试 Flatten 和 GlobalPooling 之间的区别,并与 numpy 进行比较

我们使用一批具有这种形状(batch_dim, height, width, n_channel)的图像作为输入进行演示

import numpy as np
from tensorflow.keras.layers import *

batch_dim, H, W, n_channels = 32, 5, 5, 3
X = np.random.uniform(0,1, (batch_dim,H,W,n_channels)).astype('float32')

Flatten 接受至少 3D 的输入张量。它使用这种格式(batch_dim, all the rest) 对 2D 输入进行整形。在我们的 4D 案例中,它以 (batch_dim, H*W*n_channels) 的格式进行重塑。

np_flatten = X.reshape(batch_dim, -1) # (batch_dim, H*W*n_channels)
tf_flatten = Flatten()(X).numpy() # (batch_dim, H*W*n_channels)

(tf_flatten == np_flatten).all() # True

GlobalAveragePooling2D 接受 4D 张量作为输入。它对所有通道的高度和宽度维度进行平均。得到的维度是 2D (batch_dim, n_channels)GlobalMaxPooling2D 做同样的事情,但使用最大操作。

np_GlobalAvgPool2D = X.mean(axis=(1,2)) # (batch_dim, n_channels)
tf_GlobalAvgPool2D = GlobalAveragePooling2D()(X).numpy() # (batch_dim, n_channels)

(tf_GlobalAvgPool2D == np_GlobalAvgPool2D).all() # True

【讨论】:

【参考方案4】:

Flatten 层的作用

经过卷积运算,tf.keras.layers.Flatten 会将张量重塑为(n_samples, height*width*channels),例如将(16, 28, 28, 3) 转换为(16, 2352)。让我们试试吧:

import tensorflow as tf

x = tf.random.uniform(shape=(100, 28, 28, 3), minval=0, maxval=256, dtype=tf.int32)

flat = tf.keras.layers.Flatten()

flat(x).shape
TensorShape([100, 2352])

GlobalAveragePooling 层的作用

在卷积操作之后,tf.keras.layers.GlobalAveragePooling 层确实是根据最后一个轴对所有值进行平均。这意味着生成的形状将是(n_samples, last_axis)。例如,如果你的最后一个卷积层有 64 个过滤器,它将把 (16, 7, 7, 64) 变成 (16, 64)。让我们在一些卷积操作之后进行测试:

import tensorflow as tf

x = tf.cast(
    tf.random.uniform(shape=(16, 28, 28, 3), minval=0, maxval=256, dtype=tf.int32),
    tf.float32)


gap = tf.keras.layers.GlobalAveragePooling2D()

for i in range(5):
    conv = tf.keras.layers.Conv2D(64, 3)
    x = conv(x)
    print(x.shape)

print(gap(x).shape)
(16, 24, 24, 64)
(16, 22, 22, 64)
(16, 20, 20, 64)
(16, 18, 18, 64)
(16, 16, 16, 64)

(16, 64)

你应该使用哪个?

Flatten 层将始终具有至少与GlobalAveragePooling2D 层一样多的参数。如果展平前的最终张量形状仍然很大,例如(16, 240, 240, 128),则使用Flatten 将产生大量参数:240*240*128 = 7,372,800。这个巨大的数字将乘以下一个密集层中的单元数!那时,GlobalAveragePooling2D 在大多数情况下可能是首选。如果你使用MaxPooling2DConv2D 如此之多以至于你在展平之前的张量形状就像(16, 1, 1, 128),它不会有什么不同。如果你过度拟合,你可能想试试GlobalAveragePooling2D

【讨论】:

以上是关于keras 中的 Flatten() 和 GlobalAveragePooling2D() 有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

了解 Flatten 在 Keras 中的作用并确定何时使用它 [关闭]

使用 Theano 后端的 Keras Flatten() 层行为不一致

Keras 的功能类似于 Torch 中的视图

keras---cnn---rnn---lstm

从Keras Layer获得权重

使用Keras Functional API微调模型