“扁平化”在 Keras 扮演什么角色?

我正试图了解 ABc0在 Keras 所扮演的角色。下面是我的代码,它是一个简单的两层网络。它接收形状(3,2)的二维数据,并输出形状(1,4)的一维数据:

model = Sequential()
model.add(Dense(16, input_shape=(3, 2)))
model.add(Activation('relu'))
model.add(Flatten())
model.add(Dense(4))
model.compile(loss='mean_squared_error', optimizer='SGD')


x = np.array([[[1, 2], [3, 4], [5, 6]]])


y = model.predict(x)


print y.shape

这打印出 y有形状(1,4)。但是,如果我删除 Flatten线,然后它打印出的 y有形状(1,3,4)。

我不明白。根据我对神经网络的理解,model.add(Dense(16, input_shape=(3, 2)))函数创建了一个隐藏的完全连接层,有16个节点。每个节点都连接到每个3x2输入元素。因此,第一层输出的16个节点已经是“平的”。因此,第一层的输出形状应该是(1,16)。然后,第二层将其作为输入,并输出形状(1,4)的数据。

因此,如果第一层的输出已经是“扁平的”和形状(1,16) ,为什么我需要进一步扁平它?

170346 次浏览

如果您阅读了 Dense的 Kera 文档条目,您将看到这个调用:

Dense(16, input_shape=(5,3))

将产生一个 Dense网络,其中3个输入和16个输出将在5个步骤中的每个步骤中独立应用。因此,如果 D(x)将三维矢量转换为16-d 矢量,那么从图层中得到的输出将是一系列矢量: [D(x[0,:]), D(x[1,:]),..., D(x[4,:])]和形状为 (5, 16)的矢量。为了得到你指定的行为,你可以先将 Flatten输入到一个15-d 的矢量中,然后应用 Dense:

model = Sequential()
model.add(Flatten(input_shape=(3, 2)))
model.add(Dense(16))
model.add(Activation('relu'))
model.add(Dense(4))
model.compile(loss='mean_squared_error', optimizer='SGD')

编辑: 正如一些人难以理解的那样——这里你可以看到一个解释图:

enter image description here

简短如下:

平坦张量意味着除去一个尺寸以外的所有尺寸。这正是 Flatten 层所做的。

长文:

如果我们考虑创建的原始模型(带有 Flatten 层) ,我们可以得到以下模型摘要:

Layer (type)                 Output Shape              Param #
=================================================================
D16 (Dense)                  (None, 3, 16)             48
_________________________________________________________________
A (Activation)               (None, 3, 16)             0
_________________________________________________________________
F (Flatten)                  (None, 48)                0
_________________________________________________________________
D4 (Dense)                   (None, 4)                 196
=================================================================
Total params: 244
Trainable params: 244
Non-trainable params: 0

对于这个总结,下一张图片有希望为每个层的输入和输出大小提供更多的信息。

可以读取的 Flatten 层的输出形状是 (None, 48)。这是小费。你应该读 (1, 48)或者 (2, 48)或者... 或者 (16, 48)... 或者 (32, 48)..。

事实上,这个位置上的 None表示任何批量大小。对于要召回的输入,第一维表示批量大小,第二维表示输入特征的数量。

美国商业银行在 Keras 的角色非常简单:

对张量进行平面化操作,可以将张量重塑为等于包含在张量 不包括批量尺寸中的元素数目的形状。

enter image description here


注意: 我使用 model.summary()方法来提供输出形状和参数细节。

enter image description here 这就是 Flatten 将 Matrix 转换为单个数组的工作方式。

Flatten 明确说明了如何序列化多维张量(尤其是输入张量)。这允许在(平坦的)输入张量和第一个隐藏层之间映射。如果第一个隐藏层是“密集的”每个元素的(序列化)输入张量将连接到每个元素的隐藏数组。 如果不使用 Flatten,则将输入张量映射到第一个隐藏层的方式将是不明确的。

我最近碰到了这个,它当然帮助我了解: https://www.cs.ryerson.ca/~aharley/vis/conv/

所以有一个输入,一个 Conv2D,MaxPooling2D 等,扁平层是在最后,并显示它们是如何形成的,以及它们如何定义最终的分类(0-9)。

在这里,我想提出另一个替代扁平函数。这可能有助于了解内部发生了什么。另一种方法增加了三行代码。 而不是利用

#==========================================Build a Model
model = tf.keras.models.Sequential()


model.add(keras.layers.Flatten(input_shape=(28, 28, 3)))#reshapes to (2352)=28x28x3
model.add(layers.experimental.preprocessing.Rescaling(1./255))#normalize
model.add(keras.layers.Dense(128,activation=tf.nn.relu))
model.add(keras.layers.Dense(2,activation=tf.nn.softmax))


model.build()
model.summary()# summary of the model

我们可以利用

    #==========================================Build a Model
tensor = tf.keras.backend.placeholder(dtype=tf.float32, shape=(None, 28, 28, 3))
    

model = tf.keras.models.Sequential()
    

model.add(keras.layers.InputLayer(input_tensor=tensor))
model.add(keras.layers.Reshape([2352]))
model.add(layers.experimental.preprocessing.Rescaling(1./255))#normalize
model.add(keras.layers.Dense(128,activation=tf.nn.relu))
model.add(keras.layers.Dense(2,activation=tf.nn.softmax))
    

model.build()
model.summary()# summary of the model

在第二种情况下,我们首先创建一个张量(使用占位符) 然后创建一个输入层。之后,我们将张量重塑为平面形式。所以基本上,

Create tensor->Create InputLayer->Reshape == Flatten

Flatten 是一个方便的函数,可以自动完成所有这些操作。当然,两种方式都有其特定的用例。Kera 提供了足够的灵活性,可以按照您希望的方式创建模型。

根据经验法则,网络的第一层应该与数据的形状相同。例如,我们的数据是28x28的图像,28层的28个神经元将是不可行的,所以它更有意义的“扁平化”到一个784x1的28,28。我们没有自己编写处理这个问题的所有代码,而是在开始时添加了 Flatten ()层,当数组稍后加载到模型中时,它们将自动为我们变平。

当您必须处理多维输入(如图像数据集)时,Kera 扁平类非常重要。Keras.layers.flatten函数将多维输入张量平坦化为一维,这样就可以对输入层进行建模,建立神经网络模型,然后有效地将这些数据传递到模型的每一个神经元中。

通过时尚的 MNIST 数据集,您可以很容易地理解这一点。该数据集中的图像是28 * 28像素。因此,如果你打印的第一个图像在巨蟒,你可以看到一个多维数组,我们真的不能输入到我们的深层神经网络的输入层。

print(train_images[0])

第一张时尚 MNIST 的照片

为了解决这个问题,我们可以在将图像数据输入神经网络时将其压平。我们可以把这个多维张量变成一维数组。在这个平坦的数组中,我们现在有784个元素(28 * 28)。然后我们可以用784个神经元创建输入层来处理输入数据的每个元素。

我们可以通过使用一行代码来完成这一切,就像..。

keras.layers.flatten(input_shape=(28,28))

扁平化是将数据转换为一维数组,以便将其输入到下一层。我们将卷积层的输出平坦化,创建一个单独的长特征向量。在一些架构中,例如 CNN,如果图像是一维的而不是二维的,那么神经网络能够更好地处理图像。

enter image description here

顾名思义,它只是平化了输入张量。下面给出了一个非常好的视图来理解这一点。 如果有任何疑问,请告诉我。 平面输入张量