卷积层和池化层是有效的特征提取器。这些层处理输入图像(或其他网格状数据)并生成特征图,这些多维张量表示检测到的模式,例如边缘、纹理或更复杂的形状。例如,在经过几个Conv2D和MaxPooling2D层之后,可能会得到一个形状如 $(height, width, channels)$ 的张量,比如 $(7, 7, 64)$。这个张量保留了空间信息;64个通道中的值对应于降采样后的 $7 \times 7$ 网格中不同位置检测到的特定特征。然而,对于分类等任务,我们通常需要基于提取的全部特征集进行最终预测。标准的(Dense)全连接层期望其输入为一个一维向量,其中每个元素代表一个单一的特征值,不包含任何二维或三维的空间结构。我们的卷积基的输出是一个多维张量,例如 $(7, 7, 64)$,它与Dense层不直接兼容。展平层:连接两端这就是Flatten层的作用。它的任务简单而必要:它接收来自卷积基的多维输出,并将其重塑,或称“展平”,为一个单一的、长的一维向量。它通过逐行、逐通道地展开元素来完成此操作。例如,如果输入张量的形状是 $(height, width, channels)$,Flatten层将生成一个长度为 $height \times width \times channels$ 的向量。使用我们之前 $(7, 7, 64)$ 张量的例子,Flatten层会将其转换为一个包含 $7 \times 7 \times 64 = 3136$ 个元素的向量。digraph G { rankdir=LR; node [shape=box, style=filled, fillcolor="#e9ecef", fontname="sans-serif"]; edge [fontname="sans-serif"]; conv_base [label="卷积/池化层的输出\n(例如,7x7x64张量)"]; flatten_op [label="展平层\n(重塑操作)"]; flat_vector [label="展平后的向量\n(例如,3136个元素)"]; conv_base -> flatten_op; flatten_op -> flat_vector [label="形状:(批量大小, 7*7*64)"]; }示意图显示了展平层将卷积基的多维输出重塑为一维向量的过程。Flatten层本身不学习任何东西;它不包含可训练的权重。它纯粹是一种结构转换,用于连接CNN的特征提取部分(卷积基)到分类或回归部分(头部)。全连接层:从展平特征中学习一旦特征图被展平为向量,我们就可以将这个向量输入到一个或多个标准Dense(全连接)层。这些层的工作方式与您在基础神经网络中遇到的层相同。Dense层中的每个神经元都接收来自前一层中所有神经元(在本例中是展平向量的所有元素)的输入。这些Dense层在CNN架构中的目的是学习卷积基提取的特征组合。卷积层学习局部模式(小图像块中的边缘、纹理),而Dense层则基于哪些特征在何处被激活,学习整个输入图像的全局模式。它们结合这些高层次特征以进行最终预测。通常,CNN在Flatten层之后包含一个或多个Dense层:中间全连接层: 通常使用ReLU激活(relu)来引入非线性,并学习复杂的特征组合。这些层中的单元数量是需要调整的超参数(例如,128、256、512)。输出全连接层: 最后一层生成网络的预测。对于二元分类,它有1个单元,使用sigmoid激活。对于多类分类,它有N个单元(其中N是类别的数量),使用softmax激活。对于回归任务,它有1个或更多单元(取决于目标值的数量),通常使用线性激活(或未指定激活)。Keras中的实现在Keras模型中添加Flatten和Dense层是简单直接的。您只需在最后一个卷积或池化层之后添加它们。以下是它在Sequential模型中的样子:import keras from keras import layers # 假设'model'是一个已经包含Conv2D/MaxPooling2D层的Sequential模型 # 模型输入形状示例:MNIST为(28, 28, 1) model = keras.Sequential( [ keras.Input(shape=(28, 28, 1)), # --- 卷积基 --- layers.Conv2D(32, kernel_size=(3, 3), activation="relu"), layers.MaxPooling2D(pool_size=(2, 2)), layers.Conv2D(64, kernel_size=(3, 3), activation="relu"), layers.MaxPooling2D(pool_size=(2, 2)), # --- 分类器头部 --- layers.Flatten(), # 将3D特征图展平为1D layers.Dropout(0.5), # 可选:用于正则化的Dropout layers.Dense(10, activation="softmax"), # 10个类别的输出层(例如,MNIST数字) ] ) model.summary()在此示例中:卷积基提取特征,产生多维特征图。layers.Flatten()接收最后一个MaxPooling2D层的输出,并将其转换为一维向量。可选择地添加layers.Dropout(0.5)层用于正则化(我们将在第6章介绍这一点)。最终的layers.Dense(10, activation="softmax")层执行分类,输出10个类别中每个类别的概率。用于特征提取的卷积基,以及用于分类的Flatten加Dense层的组合,构成了许多成功CNN的标准架构,这些CNN应用于图像识别和其他方面。关于替代方案的说明: 尽管Flatten后接Dense很常见,但还存在其他方法,如GlobalAveragePooling2D或GlobalMaxPooling2D。这些层也能连接卷积图与最终输出,通常减少参数数量并可能提高泛化能力。它们的工作原理是对每个特征图的空间维度(高度、宽度)取平均值或最大值,从而为每个通道生成一个值,直接创建一个一维向量。我们在此主要介绍Flatten,因为它是一个基本原理,但请留意这些适用于更复杂架构的替代方案。