我试图了解 Flatten
函数在 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),我为什么需要进一步将其展平?
如果您阅读 Dense
的 Keras 文档条目,您将看到此调用:
Dense(16, input_shape=(5,3))
将产生一个具有 3 个输入和 16 个输出的 Dense
网络,这些网络将独立应用于 5 个步骤中的每一个。因此,如果 D(x)
将 3 维向量转换为 16 维向量,您将从层得到的输出将是一系列向量:[D(x[0,:]), D(x[1,:]),..., D(x[4,:])]
,形状为 (5, 16)
。为了获得您指定的行为,您可以首先将您的输入 Flatten
输入到 15 维向量,然后应用 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')
编辑:有些人难以理解 - 这里有一张解释图片:
https://i.stack.imgur.com/Wk8eV.png
https://i.stack.imgur.com/lmrin.png
短读:
展平张量意味着删除除一个之外的所有维度。这正是 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 中 Flatten 层的作用超级简单:
张量上的展平操作将张量重塑为具有等于张量中包含的元素数量的形状,不包括批量维度。
https://i.stack.imgur.com/IBt6j.jpg
注意:我使用 model.summary()
方法来提供输出形状和参数详细信息。
None
表示任意batch size,但是为什么D16
的输出shape也有None
,这里的3
不就是batch size吗?
我最近遇到了这个问题,它确实帮助我理解了:https://www.cs.ryerson.ca/~aharley/vis/conv/
所以有一个输入,一个 Conv2D、MaxPooling2D 等,Flatten 层位于最后,并准确显示它们是如何形成的,以及它们如何继续定义最终分类 (0-9)。
根据经验,网络中的第一层应该与数据的形状相同。例如,我们的数据是 28x28 的图像,28 层的 28 个神经元是不可行的,因此将 28,28 扁平化为 784x1 更有意义。我们不是自己编写所有代码来处理它,而是在开始时添加 Flatten() 层,稍后当数组加载到模型中时,它们会自动为我们展平。
Flatten 明确说明了如何序列化多维张量(通常是输入张量)。这允许(展平的)输入张量和第一个隐藏层之间的映射。如果第一个隐藏层是“密集”的(序列化)输入张量的每个元素将与隐藏数组的每个元素连接。如果不使用 Flatten,输入张量映射到第一个隐藏层的方式将是模棱两可的。
当您必须处理图像数据集等多维输入时,Keras flatten 类非常重要。 Keras.layers.flatten
函数将多维输入张量扁平化为一维,因此您可以对输入层进行建模并构建神经网络模型,然后将这些数据有效地传递到模型的每个神经元中。
您可以使用时尚 MNIST 数据集轻松理解这一点。该数据集中的图像为 28 * 28 像素。因此,如果您在 python 中打印第一张图像,您可以看到一个多维数组,我们确实无法将其输入到我们的深度神经网络的输入层。
print(train_images[0])
为了解决这个问题,我们可以在将图像数据输入神经网络时将其展平。我们可以通过将这个多维张量转换为一维数组来做到这一点。在这个扁平化的数组中,现在我们有 784 个元素 (28 * 28)。然后我们可以创建具有 784 个神经元的输入层来处理传入数据的每个元素。
我们可以通过使用一行代码来完成这一切,有点……
keras.layers.flatten(input_shape=(28,28))
如果您需要了解其实际工作原理、训练模型并评估其准确性,您可以在 neural net lab 阅读完整教程。
xTrain = xTrain.reshape(xTrain.shape[0], -1)
xTest = xTest.reshape(xTest.shape[0], -1)
在这里,我想介绍 Flatten 函数的另一种替代方法。这可能有助于了解内部发生的情况。另一种方法增加了三个代码行。而不是使用
#==========================================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 是一个方便的功能,所有这些都是自动完成的。当然,这两种方式都有其特定的用例。 Keras 提供了足够的灵活性来操作您想要创建模型的方式。
不定期副业成功案例分享
Dense(16, input_shape=(5,3)
,来自 16 个集合的每个输出神经元(并且,对于所有 5 个这些神经元集合),是否会连接到所有 (3 x 5 = 15) 个输入神经元?或者第一组16个中的每个神经元只连接到第一组5个输入神经元中的3个神经元,然后第二组16个中的每个神经元只连接到第二组5个输入中的3个神经元神经元等......我很困惑它是什么!input_shape=(5,3)
表示有5个像素,每个像素有3个通道(R,G,B)。但是根据您所说的,每个通道都将单独处理,而我希望所有三个通道都由第一层的所有神经元处理。那么在开始时立即应用Flatten
层会给我想要的吗?Flatten
的小图可能有助于理解。