- 教程
- 人工智能
- 机器学习
- 深度学习
【免费下载链接】AI-For-Beginners
12 Weeks, 24 Lessons, AI for All!
导读
本文基于 AI-For-Beginners 课程第 07 课(lessons/4-ComputerVision/07-ConvNets/README.md),系统讲解卷积神经网络(CNN)的三大核心思想——卷积滤波器提取模式、自动学习滤波器参数、特征层级化提取,并完整展开金字塔架构(Pyramid Architecture)、VGG-16 等经典网络设计。通过本课,你将掌握卷积层与池化层的实现细节(nn.Conv2d/keras.layers.Conv2D的关键参数),并能在 MNIST 与 CIFAR-10 数据集上亲手搭建、训练 CNN,理解其相对全连接网络的精度与泛化优势。
为什么 MNIST 分类还不够:从"固定位置"到"任意位置"
此前课程已经证明,即使单层感知机也能以可接受的精度识别 MNIST 手写数字。但 MNIST 数据集非常特殊——所有数字都被居中放置在图像内部,这让任务大大简化。
真实世界的计算机视觉任务则完全不同:我们希望在图片任意位置都能识别目标物体。与通用分类相比,计算机视觉的关键差异在于:当我们寻找图像中的某个对象时,实际上是在扫描图像、寻找某些特定的"模式(patterns)"及其组合。例如,要在一张图中找猫,我们可能先寻找构成胡须的水平线条,而一定组合的胡须可以让我们确定这就是一张猫的图片。模式的相对位置与存在性重要,而模式在图像中的精确位置并不重要——这正是 CNN 与传统全连接网络在思想上最本质的差异。
卷积滤波器:小窗口扫描图像提取模式
滤波器的数学直觉
要提取模式,我们使用卷积滤波器(convolutional filters)。图像以 2D 矩阵(灰度)或 3D 张量(含颜色深度通道)表示。应用一个滤波器意味着:取一个相对较小的滤波器核(filter kernel)矩阵,对原图像中的每个像素,与其邻域像素计算加权平均。可以把它想象成一个在整幅图像上滑动的窗口,按照滤波器核矩阵中的权重对所有像素做加权平均。
以两个经典的 3×3 边缘滤波器为例——垂直边缘滤波器核为:
$$ \begin{pmatrix} -1 & 0 & 1 \ -1 & 0 & 1 \ -1 & 0 & 1 \end{pmatrix} $$
水平边缘滤波器核为:
$$ \begin{pmatrix} -1 & -1 & -1 \ 0 & 0 & 0 \ 1 & 1 & 1 \end{pmatrix} $$
将其应用于 MNIST 数字时:垂直边缘滤波器在图像存在垂直边缘的位置产生高响应值(高亮),而水平边缘会被平均掉;水平边缘滤波器则正好相反。这两个滤波器由此可以用于"寻找"边缘。除了手工设计边缘滤波器,我们还可以设计不同滤波器去查找各种低层级模式(如 Leung-Malik 滤波器组)。
|
图片作者:Dmitry Soshnikov
(Leung-Malik 滤波器组图片见 translated_images/cs/lmfilters.ea9e4868a82cf74c.webp)
从手工设计到自动学习:CNN 的核心思想
虽然我们可以手工设计滤波器来提取特定模式,但更自然的做法是把网络设计成能够自动学习这些模式。这正是 CNN 背后最主要的思想之一。更完整地讲,CNN 的工作原理建立在三条重要原则上:
- 卷积滤波器可以提取模式;
- 网络可以被设计成自动训练学习滤波器参数;
- 同一套方法可以用于在高层级特征中寻找模式,而不只作用于原始图像。因此 CNN 的特征提取是在一个特征层级上工作的:从低层级的像素组合,到更高层级的图像部件组合。
图片来自 Hislop-Lynch 等人关于计算机视觉行人轨迹预测的研究
动手实验:在笔记本中验证"可训练滤波器"
课程提供了两个配套 notebook 供动手实践,读者应逐步运行以理解卷积网络如何实现可训练滤波器:
- 卷积神经网络 - PyTorch
- 卷积神经网络 - TensorFlow
PyTorch 实现:单卷积层网络
在 ConvNetsPyTorch.ipynb 中,卷积层通过nn.Conv2d定义,需要指定三个关键参数:
| 参数 | 含义 | 本课示例取值 |
|---|---|---|
in_channels | 输入通道数 | 灰度图为 1 |
out_channels | 使用的滤波器数量 | 9 个滤波器,给网络充分机会探索哪种滤波器最适合 |
kernel_size | 滑动窗口(卷积核)尺寸 | 通常使用 3×3 或 5×5 |
最简单的 CNN 只包含一个卷积层。输入 28×28 的图像,应用 9 个 5×5 滤波器后,得到 9×24×24 的张量(空间尺寸变小,是因为在 28 个像素上,长度为 5 的滑动窗口只能放下 24 个位置)。随后把 9×24×24 张量展平为长度 5184 的向量,再接一个输出 10 个类别的线性层,层间使用relu激活函数。完整模型定义如下:
class OneConv(nn.Module): def __init__(self): super(OneConv, self).__init__() self.conv = nn.Conv2d(in_channels=1,out_channels=9,kernel_size=(5,5)) self.flatten = nn.Flatten() self.fc = nn.Linear(5184,10) def forward(self, x): x = nn.functional.relu(self.conv(x)) x = self.flatten(x) x = nn.functional.log_softmax(self.fc(x),dim=1) return x用torchinfo.summary查看结构:Conv2d输出[1, 9, 24, 24](234 个参数)、Flatten输出[1, 5184]、Linear输出[1, 10](51850 个参数),总计约5.2 万可训练参数,而此前课中全连接多层网络约有 8 万参数。训练 5 个 epoch 后训练精度约 0.988、验证精度约 0.976——参数更少、精度更高、收敛更快,因为卷积网络在更小数据集上也能有更好的泛化表现。可视化训练后的 9 个卷积核权重可以看到:有些滤波器看起来能识别斜向笔画,另一些则看起来比较随机,这正是"自动学习"得到的特征。
训练与验证的循环由辅助模块 pytorchcv.py 提供:load_mnist()加载 MNIST 数据,train()用 Adam 优化器与nn.NLLLoss完成多轮训练,plot_convolution()则可直接可视化任意手工滤波器对 MNIST 数字的卷积响应。
TensorFlow/Keras 实现
ConvNetsTF.ipynb 用 KerasSequentialAPI 给出等价结构:
model = keras.models.Sequential([ keras.layers.Conv2D(filters=9, kernel_size=(5,5), input_shape=(28,28,1),activation='relu'), keras.layers.Flatten(), keras.layers.Dense(10) ])注意:实际应用中卷积层通常作用在彩色图像上,因此Conv2D期望输入形状为W×H×C(宽 × 高 × 通道数),灰度图像同样用该形状、令C=1。
金字塔架构:空间维度递减、滤波器数量递增
用于图像处理的大多数 CNN 都遵循所谓的金字塔架构(pyramid architecture):
- 第一层卷积作用于原始图像,通常只有相对较少的滤波器(8–16 个),对应各种像素组合,如水平/垂直线条或笔画;
- 下一层开始降低网络的空间维度,同时增加滤波器数量,对应简单特征更多可能的组合;
- 越靠近最终分类器,图像空间维度越小、滤波器数量越多。
从源码结构看,这种"空间缩小、通道增宽"的设计有两个直接收益:一是大幅压缩后续全连接层的输入维度,使可训练参数显著减少(有助于防止小数据集上的过拟合);二是让网络从低层到高层逐级组合出越来越抽象的特征。
池化层:降维的关键算子
降维由池化层(pooling layers)完成,卷积 notebook 中明确介绍了两种方式:
- 平均池化(Average Pooling):取滑动窗口(例如 2×2 像素)内数值的平均值;
- 最大池化(Max Pooling):用窗口内最大值替换窗口——其思想是检测滑动窗口内是否存在某种模式,而非精确位置。
典型 CNN 由多个卷积层组成,中间穿插池化层以递减图像尺寸;同时不断增加滤波器数量,因为模式越复杂,需要寻找的有趣组合就越多。
PyTorch 多层 CNN 示例(见 ConvNetsPyTorch.ipynb):
class MultiLayerCNN(nn.Module): def __init__(self): super(MultiLayerCNN, self).__init__() self.conv1 = nn.Conv2d(1, 10, 5) self.pool = nn.MaxPool2d(2, 2) self.conv2 = nn.Conv2d(10, 20, 5) self.fc = nn.Linear(320,10) def forward(self, x): x = self.pool(nn.functional.relu(self.conv1(x))) x = self.pool(nn.functional.relu(self.conv2(x))) x = x.view(-1, 320) x = nn.functional.log_softmax(self.fc(x),dim=1) return x该模型结构为Conv2d(1→10)→MaxPool2d(24×24→12×12)→Conv2d(10→20)(→8×8)→MaxPool2d(→4×4)→Linear(320→10),总参数仅约8490 个,训练 5 个 epoch 验证精度约 0.98。实现中有三个值得注意的细节:
- 展平直接在
forward中用view完成(展平层无可训练权重,无需单独建层); - 池化层也没有可训练参数,因此模型只需一个池化层实例即可复用;
- 参数数量比单卷积层模型(5.2 万)更少,比全连接网络(约 8 万)更是大幅下降,正面印证了金字塔架构对抗过拟合的价值。
对应 Keras 版本:
model = keras.models.Sequential([ keras.layers.Conv2D(filters=10, kernel_size=(5,5), input_shape=(28,28,1),activation='relu'), keras.layers.MaxPooling2D(), keras.layers.Conv2D(filters=20, kernel_size=(5,5), activation='relu'), keras.layers.MaxPooling2D(), keras.layers.Flatten(), keras.layers.Dense(10) ])实例:VGG-16 的金字塔结构
以 2014 年在 ImageNet top-5 分类中达到92.7% 准确率的VGG-16为例,它可以清晰地看到金字塔架构:网络是"卷积层-池化层"的序列组合,从原始图像出发逐层减少空间分辨率、放大滤波器通道数。
图片来自 ResearchGate 上的 VGG 模型结构示意图
更复杂的真实任务:从 MNIST 到 CIFAR-10(LeNet)
训练 notebook 中继续把注意力投向真实图像数据集 CIFAR-10:它包含 6 万张 32×32 的图像,分为 10 个类别。经典的LeNet(由 Yann LeCun 提出)架构遵循相同原则,主要区别是输入为 3 个彩色通道而非 1 个。此外还做了一处简化:不再使用log_softmax作为输出激活,而是直接返回最后一个全连接层的输出,此时可直接使用CrossEntropyLoss作为损失函数。
class LeNet(nn.Module): def __init__(self): super(LeNet, self).__init__() self.conv1 = nn.Conv2d(3, 6, 5) self.pool = nn.MaxPool2d(2) self.conv2 = nn.Conv2d(6, 16, 5) self.conv3 = nn.Conv2d(16,120,5) self.flat = nn.Flatten() self.fc1 = nn.Linear(120,64) self.fc2 = nn.Linear(64,10) def forward(self, x): x = self.pool(nn.functional.relu(self.conv1(x))) x = self.pool(nn.functional.relu(self.conv2(x))) x = nn.functional.relu(self.conv3(x)) x = self.flat(x) x = nn.functional.relu(self.fc1(x)) x = self.fc2(x) return xLeNet 的参数量约 5.9 万,训练 3 个 epoch 即可超过 50% 验证精度(盲猜仅为 10%)。这个精度在如此短的训练时间内已经是不错的成果——CIFAR-10 比 MNIST 困难得多。注意:若要充分训练该网络,需要相当可观的训练时间,最好在 GPU 上进行。
拓展阅读:最知名的 CNN 架构
继续深入学习最知名的 CNN 架构,可阅读 CNN_Architectures.md,其中介绍了四种里程碑式设计:
- VGG-16:典型金字塔架构,是"卷积-池化层序列"的代表。
- ResNet(2015,微软研究院):核心是残差块(residual blocks)——通过恒等直通(identity pass-through)让每一层去预测前一层结果与残差块输出之间的差值(故称 residual)。这类块更容易训练,可以堆叠数百层(常见变体为 ResNet-52、ResNet-101、ResNet-152)。也可以把网络理解为能根据数据集自动调节复杂度:训练初期权重较小,大部分信号走恒等直通层;随训练推进、权重变大,网络参数的作用增强,网络逐步获得足够表达力来正确分类。
- Google Inception:把思想再推进一步,把每一层构建为多条不同路径的组合。其中1×1 卷积的作用值得强调:卷积滤波器同样作用于多个深度通道(最初是 RGB 颜色,后续层则是不同滤波器的通道),1×1 卷积就是用不同的可训练权重混合这些输入通道,也可以视为在通道维度上做降采样(池化)。
- MobileNet:体积精简、适合移动设备的模型族,适合资源受限且可牺牲少量精度的场景。核心是深度可分离卷积(depthwise separable convolution):把卷积滤波器分解为空间卷积与深度通道上的 1×1 卷积的组合,从而大幅减少参数,网络更小、也更易用少量数据训练。
课后挑战与作业:宠物面部品种分类
作为收尾练习,lab/README.md 给出了完整的实战作业:使用Oxford-IIIT Pet Dataset(包含 37 个猫狗品种的图像)训练 CNN 完成品种分类。数据集按文件名组织(如Abyssinian_1.jpg、Bengal_2.jpg),notebook 中包含把图片整理到按品种区分子目录的代码。下载数据集:
wget https://thor.robots.ox.ac.uk/~vgg/data/pets/images.tar.gz tar xfz images.tar.gz然后从 PetFaces.ipynb 开始实验。这个任务的图像比 MNIST 更复杂、维度更高、类别更多(超过 10 类),是有一定难度的从零开始的图像分类问题;建议同时度量top-k 精度,因为有些类别即使在人类看来也极易混淆。配套的 PyTorch 辅助模块 pytorchcv.py 与 TensorFlow 辅助模块 tfcv.py 都内置了猫狗/宠物数据集的加载、损坏图片清理与训练循环。
小结
本课掌握了计算机视觉神经网络的核心概念——卷积网络:卷积滤波器提取模式、网络自动学习滤波器、特征层级化提取,以及贯穿其中的金字塔架构。现实世界中驱动图像分类、目标检测乃至图像生成网络的架构,本质上都基于 CNN,只是层数更多、并附加了一些额外的训练技巧。建议读者完整运行两个 notebook,尝试 notebook 底部关于如何获得更高精度的提示,在实践中验证"复杂架构用更少数据学到通用模式"这一结论。
- 教程
- 人工智能
- 机器学习
- 深度学习
【免费下载链接】AI-For-Beginners
12 Weeks, 24 Lessons, AI for All!
相关推荐
AI-For-Beginners 卷积神经网络(CNN)实战指南:从卷积核原理到 LeNet 与经典架构
AI For Beginners 卷积神经网络(CNN)实战指南:从卷积核原理到 LeNet 与经典架构 导读 卷积神经网络(Convolutional Neu
教程人工智能机器学习深度学习AI for Beginners 课程:卷积神经网络(CNN)实战指南——从边缘滤波器到金字塔架构
AI for Beginners 课程:卷积神经网络(CNN)实战指南——从边缘滤波器到金字塔架构 本指南是 AI for Beginners 课程第 07 课
教程人工智能机器学习深度学习卷积神经网络(CNN)原理与实战全解:组成层、卷积核、池化与 NetVLAD
卷积神经网络(CNN)原理与实战全解:组成层、卷积核、池化与 NetVLAD 卷积神经网络(Convolutional Neural Network,CNN)是
深度学习机器学习计算机视觉NLP教程知识库
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考