卷积神经网络入门:从原理到实践
本文将带你深入理解卷积神经网络(CNN)的原理,以及它为什么在计算机视觉任务上如此成功。我们将通过一个简单的卷积神经网络示例,来对MNIST手写数字进行分类。
一个简单的卷积神经网络示例
在第2章用密集连接网络做MNIST数字分类时,测试精度约为97.8%。下面我们来看一个简单的卷积神经网络实现:
from tensorflow import keras
from tensorflow.keras import layers
# 构建卷积神经网络
inputs = keras.Input(shape=(28, 28, 1))
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(inputs)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = layers.Flatten()(x)
outputs = layers.Dense(10, activation="softmax")(x)
model = keras.Model(inputs=inputs, outputs=outputs)
重要的是,卷积神经网络接收的输入张量形状为(image_height, image_width, image_channels)(不包括批量维度)。本例中,我们处理大小为(28, 28, 1)的输入,这正是MNIST图像的格式。
模型架构分析
让我们看一下这个卷积神经网络的架构:
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 28, 28, 1)] 0
_________________________________________________________________
conv2d (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 13, 13, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 11, 11, 64) 18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64) 0
_________________________________________________________________
conv2d_2 (Conv2D) (None, 3, 3, 128) 73856
_________________________________________________________________
flatten (Flatten) (None, 1152) 0
_________________________________________________________________
dense (Dense) (None, 10) 11530
=================================================================
Total params: 104,202
Trainable params: 104,202
Non-trainable params: 0
_________________________________________________________________
可以看到,每个Conv2D层和MaxPooling2D层的输出都是一个形状为(height, width, channels)的3阶张量。宽度和高度这两个维度的尺寸通常会随着模型加深而减小。通道数对应传入Conv2D层的第一个参数(32、64或128)。
在最后一个Conv2D层之后,我们得到了形状为(3, 3, 128)的输出。为了让这个3阶张量能够传入密集连接分类器,我们先用Flatten层将三维输出展平为一维,然后再添加Dense层。
训练与评估
下面我们在MNIST数字上训练这个卷积神经网络:
from tensorflow.keras.datasets import mnist
# 加载数据
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# 预处理数据
train_images = train_images.reshape((60000, 28, 28, 1))
train_images = train_images.astype("float32") / 255
test_images = test_images.reshape((10000, 28, 28, 1))
test_images = test_images.astype("float32") / 255
# 编译模型
model.compile(optimizer="rmsprop",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"])
# 训练模型
model.fit(train_images, train_labels, epochs=5, batch_size=64)
评估模型性能:
test_loss, test_acc = model.evaluate(test_images, test_labels)
print(f"Test accuracy: {test_acc:.3f}")
结果:Test accuracy: 0.991
与密集连接模型的97.8%测试精度相比,这个简单的卷积神经网络的测试精度达到了99.1%,错误率降低了约60%(相对比例)。这相当不错!
为什么卷积神经网络效果更好?
与密集连接模型相比,卷积神经网络效果更好的原因在于其根本区别:
Dense层从输入特征空间中学到的是全局模式(涉及所有像素的模式)卷积层学到的是局部模式(在输入图像的二维小窗口中发现的模式)
这个重要特性使卷积神经网络具有以下两个有趣的性质:
-
平移不变性:在图片右下角学到某个模式之后,卷积神经网络可以在任何位置识别出这个模式。这使得卷积神经网络在处理图像时可以高效地利用数据,只需要更少的训练样本就可以学到具有泛化能力的数据表示。
-
空间层次结构:第一个卷积层学习较小的局部模式(比如边缘),第二个卷积层学习由第一层特征组成的更大的模式,以此类推。这使得卷积神经网络能够有效地学习越来越复杂、越来越抽象的视觉概念。
卷积运算详解
卷积运算作用于被称为特征图的3阶张量,它有2个空间轴(高度和宽度)和1个深度轴(通道轴)。
-
对于RGB图像,深度轴的维度大小为3(红、绿、蓝颜色通道) -
对于黑白图像(如MNIST),深度为1(灰度值)
卷积运算从输入特征图中提取图块,并对所有这些图块应用相同的变换,生成输出特征图。深度轴的不同通道代表滤波器,每个滤波器对输入数据的某一方面进行编码。
卷积的关键参数:
-
从输入中提取的图块尺寸:通常是3×3或5×5 -
输出特征图的深度:卷积所计算的滤波器的数量
卷积的工作原理:在3维输入特征图上滑动这些3×3或5×5的窗口,在每个位置提取周围特征的3维图块,然后与学到的权重矩阵(卷积核)做张量积,转换成1维向量,最后进行空间重组,形成3维输出特征图。
边界效应和填充
由于边界效应,输出的宽度和高度可能与输入的宽度和高度不同。例如,5×5的特征图中只有9个方块可以作为中心放入3×3的窗口,因此输出特征图尺寸会缩小。
如果希望输出特征图的空间尺寸与输入相同,可以使用填充:在输入特征图的每一边添加适当数量的行和列。对于3×3的窗口,在左右各添加1列,在上下各添加1行。
在Keras中,通过padding参数设置填充:
-
"valid":不填充(只使用有效的窗口位置) -
"same":填充后输出的宽度和高度与输入相同
卷积步幅
步幅是指两个连续窗口之间的距离,默认值为1。使用步进卷积(步幅大于1的卷积)可以对特征图进行下采样。步幅为2意味着对特征图的宽度和高度都做了2倍下采样。
不过在分类模型中,我们通常不使用步幅,而使用最大汇聚运算来对特征图进行下采样。
最大汇聚运算
最大汇聚从输入特征图中提取窗口,并输出每个通道的最大值。它与卷积的区别在于使用硬编码的max张量运算而不是学到的线性变换。
最大汇聚通常使用2×2的窗口和步幅2,目的是对特征图进行2倍下采样。
为什么需要下采样?
-
减少需要处理的特征图的元素个数 -
通过让连续卷积层的观察窗口越来越大,引入空间滤波器的层级结构
为什么选择最大汇聚而不是其他方法?
特征中往往编码了某种模式或概念在特征图的不同位置是否存在,观察不同特征的最大值而不是均值能够给出更多的信息。
总结
通过本文,你应该已经理解了卷积神经网络的基本概念:特征图、卷积和最大汇聚,并且也知道如何构建一个小型卷积神经网络来解决MNIST数字分类等简单问题。卷积神经网络通过其特有的局部连接、权重共享和空间下采样机制,在图像处理任务中表现出色,是现代计算机视觉领域的基石技术。

