代表性卷积神经网络#
学习目标与记号#
准确解释 LeNet-5、AlexNet、VGG-16 与 U-Net 的结构特点及其设计动机;
根据公式和张量维度分析 MobileNet 与 YOLO v1,并识别常见实现错误;
解释 ResNet 所针对的退化问题、梯度破碎现象与残差连接,并用
Python完成实现核验。
本节沿用统一记号:普通小写字母表示标量,粗体小写字母表示向量,粗体大写字母表示矩阵或高阶张量;层编号写作上标 \([l]\),样本或时间编号写作下标;转置写作 \(\trans\)。第 \(l\) 层特征图的通道数、高和宽分别记为 \(d_C^{[l]}\)、\(d_H^{[l]}\) 和 \(d_W^{[l]}\)。除非另有说明,程序中的一批图像按照“样本数、通道数、高、宽”的顺序存放,维度写作 \(m\times d_C^{[l]}\times d_H^{[l]}\times d_W^{[l]}\)。正文与练习中的程序都应同时检查数值结果和数组维度。本节练习的参考答案见 代表性 CNN 架构答案。
比较网络前,可先复习 卷积层与输出尺寸、池化层、Dropout 和 Batch Normalization。
下面几类网络体现了 CNN 设计思想的演进:LeNet 验证了卷积与下采样的组合,AlexNet 展示了大规模数据和 GPU 训练的作用,VGG 强调规则统一的重复模块,U-Net 用编码器—解码器和同尺度跳跃连接兼顾整体信息与空间细节,MobileNet 关注计算效率,YOLO 在一次计算中同时完成目标分类与位置预测,ResNet 则用残差连接改善深层网络的优化。历史架构中的某些组件已不再常用,但其设计动机仍值得理解。
LeNet-5#
LeNet-5 是面向手写字符识别的早期 CNN。经典结构接收 \(32\times32\) 灰度图像,主要尺寸变化如下:
C1:6 个 \(5\times5\) 卷积核,得到 \(6\times28\times28\);
S2:\(2\times2\) 下采样,得到 \(6\times14\times14\);
C3:16 个 \(5\times5\) 卷积输出,得到 \(16\times10\times10\);
S4:再次下采样,得到 \(16\times5\times5\);
C5:120 个 \(5\times5\) 核,得到 \(120\times1\times1\);
F6 与输出层:映射到 84 维,再完成 10 类预测。
图 16 LeNet-5 的网络结构#
LeNet-5 的隐藏层使用 tanh 函数,原始下采样层采用带有可学习缩放与偏置的平均池化,而不是现代代码中常见的最大池化。它把“卷积提取局部特征、池化缩小空间尺寸、全连接层完成分类”组织成清晰的层次结构,证明了卷积网络能够直接处理真实视觉任务。本章代码保留主要尺寸结构,改用 ReLU、最大池化和线性输出配合交叉熵,因而应称为“LeNet 风格网络”,不能把每一处实现细节都归于原始架构。
AlexNet#
AlexNet 把更大规模 CNN、GPU 计算与大规模图像数据结合起来,并在 ILSVRC 2012 图像分类竞赛中取得了突出成绩。它使用 ReLU 函数加快优化,以重叠最大池化逐步下采样,并在全连接层使用 Dropout;随机裁剪、翻转和颜色扰动等数据增强也有助于改善模型在新图像上的表现。原模型还使用局部响应归一化(LRN),但该组件后来很少作为默认选择。
图 17 LeNet-5 与 AlexNet 的结构对比#
AlexNet 当时因显存和计算限制把部分通道分布到两个 GPU。今天常见的单设备实现会合并这些分组,因此参数连接方式可能与 Krizhevsky 等(2012) 的原论文略有差异。课件中的结构尺寸链从 \(227\times227\) 输入开始;一些资料则把输入概括为约 \(224\times224\),这通常与裁剪方式、首层填充和边界处理约定有关。逐层计算时必须写明所采用的输入尺寸、填充和步幅,不能混用两套设置。重新实现和运行该模型时,还应明确采用的是“历史原版”还是“适配后的教学版本”。
VGG#
VGG 的核心是规则、可重复的卷积块:多个 \(3\times3\)、步幅 1、填充 1 的卷积保持 \(d_H^{[l]}\) 和 \(d_W^{[l]}\) 不变,随后用 \(2\times2\)、步幅 2 的最大池化把两个空间维度减半。VGG-16 包含 13 个卷积层和 3 个全连接层;“16”按含参数层计数。随着空间尺寸逐步缩小,通道数通常从 64 增加到 128、256 和 512,使网络能够在较低分辨率上表示更丰富的特征。
图 18 VGG 块与 VGG 网络#
当步幅和空洞率均为 1 时,堆叠两个 \(3\times3\) 卷积具有与一个 \(5\times5\) 卷积相同大小的理论感受野,而且可以在两层之间加入一次非线性变换。VGG 的模块化设计便于理解和迁移,但全连接层参数量和整体计算成本很高,不能仅凭结构规整就认为它适合资源受限部署。
U-Net#
Ronneberger 等(2015) 最初为生物医学图像分割提出 U-Net。普通图像分类网络通常把整幅图像压缩为一个类别结果;图像分割则要判断每个像素属于哪个类别,因此既要理解较大范围内的物体结构,又要保留边界和位置等细节。U-Net 使用一条逐步缩小特征图的 编码器路径 和一条逐步恢复特征图大小的 解码器路径。把这两条路径画在左右两侧后,整体形状近似字母“U”,网络由此得名。
图 19 编码器与解码器构成近似字母“U”的路径,同尺度跳跃连接横跨左右两侧#
U-Net 的主要组成部分如下。
编码器。 每个阶段先用卷积提取特征,再通过池化或带步幅的卷积减小特征图的高和宽。随着空间分辨率降低,通道数通常增加;较深位置的一个特征能够综合更大范围的输入信息,因此更适合判断目标的整体结构和上下文。
瓶颈层。 编码器与解码器之间分辨率最低的部分称为瓶颈层。这里的特征保留较强的整体信息,但精确位置和边界细节已经减少。
解码器。 每个阶段先通过插值、转置卷积等方法提高空间分辨率,再用卷积逐步恢复位置和边界信息。这里的“解码”是把低分辨率特征转换为空间输出,并不是把压缩文件还原。
同尺度跳跃连接。 解码器恢复到某个分辨率时,接收编码器在相同分辨率保存的特征。这里的“同尺度”是指两组特征的高和宽相同,并不要求通道数相同。经典 U-Net 将两组特征沿通道方向拼接,再用卷积进行融合;拼接后的通道数会暂时增加。较深特征提供整体语义,较浅特征补充边缘、纹理和精确位置,因此输出能够同时利用两类信息。
输出映射。 在分割任务中,最后常用 \(1\times1\) 卷积把通道数变为类别数,使每个空间位置都得到一组类别结果。现代实现通常利用填充让输出与输入具有相同的高和宽;若卷积、下采样或上采样导致尺寸不完全一致,则必须通过裁剪、填充或插值使需要拼接的两组特征对齐。上图采用保持空间大小的填充,以便清楚展示对称的尺寸变化;原始 U-Net 使用无填充卷积,并会裁剪编码器特征,因此其具体尺寸并不完全对称。
例 5.1:从缩小图像到恢复像素位置
假设输入为 \(1\times128\times128\) 的灰度图像。编码器可依次产生空间大小为 \(128\times128\)、\(64\times64\) 和 \(32\times32\) 的特征,瓶颈层利用低分辨率特征判断目标的大致形状;解码器再按 \(32\times32\)、\(64\times64\) 和 \(128\times128\) 的顺序恢复分辨率。在恢复到 \(64\times64\) 时,它会接收编码器先前保存的 \(64\times64\) 特征;恢复到 \(128\times128\) 时也进行相同处理。这样,网络不必仅靠瓶颈层重新猜测像素的精确位置。
U-Net 是一个框架,不是一组固定层数
U-Net 的核心是“逐步下采样—瓶颈层—逐步上采样”以及左右两侧的同尺度跳跃连接,而不是某一组固定的通道数、卷积层数或上采样方法。原始 U-Net 主要用于图像分割;后来的模型保留这一多尺度框架,并根据任务加入残差块、注意力、归一化和条件信息。在扩散模型中,U-Net 通常不输出像素类别,而是接收含噪图像和噪声等级,输出与输入维度对应的噪声或其他反向过程所需的预测量。
MobileNet 与深度可分离卷积#
MobileNet 使用深度可分离卷积降低计算量。它把标准卷积分解为:
深度卷积(depthwise convolution):每个输入通道独立使用一个 \(f\times f\) 核,不进行通道混合;
逐点卷积(pointwise convolution):用 \(1\times1\) 卷积把 \(d_C^{[l-1]}\) 个输入通道线性组合成 \(d_C^{[l]}\) 个输出通道。
若卷积核尺寸为 \(f\times f\),标准卷积的权重数为 \(f^2d_C^{[l-1]}d_C^{[l]}\),上述分解的权重数为
例如,设输入张量为 \(\bX\in\mathbb{R}^{3\times6\times6}\),首先对 3 个输入通道分别使用一个 \(3\times3\) 卷积核,不填充且步幅为 1,再用 5 个 \(1\times1\) 卷积核生成 5 个输出通道。中间结果和最终结果的维度分别为 \(3\times4\times4\) 和 \(5\times4\times4\)。忽略偏置时,权重总数为
如果直接使用标准卷积,则同一例子需要 \(5\times3\times3\times3=135\) 个权重。空间尺寸较大时,乘加次数也有类似比例的下降。不过实际运行时间还取决于内存访问、算子实现和硬件,并不由参数量单独决定。
图 20 深度卷积后接逐点卷积#
下面把这一分解封装为一个 PyTorch 模块。构造函数接收输入通道数、输出通道数和步幅;前向输入 x 应为 NCHW 张量,输出与标准 \(3\times3\)、相同步幅和填充 1 的卷积具有相同的批量大小与空间尺寸规则,但通道数变为 out_channels。代码只定义网络层,不会自行生成样本、执行训练或打印结果。
1 import torch.nn as nn
2
3 class DepthwiseSeparableConv(nn.Module):
4 def __init__(self, in_channels, out_channels, stride=1):
5 super().__init__()
6 self.depthwise = nn.Conv2d(
7 in_channels, in_channels, kernel_size=3,
8 stride=stride, padding=1, groups=in_channels,
9 bias=False,
10 )
11 self.pointwise = nn.Conv2d(
12 in_channels, out_channels, kernel_size=1,
13 bias=False,
14 )
15
16 def forward(self, x):
17 return self.pointwise(self.depthwise(x))
groups=in_channels 使第一个卷积的每个输入通道只连接一个对应卷积核,先提取各通道内部的空间特征;随后 \(1\times1\) 的 pointwise 卷积在每个位置混合所有通道。示例省略偏置,也没有在两步之间加入 Batch Normalization 或激活函数,以突出核心分解。实际 MobileNet 块通常还包含这些组件;同时,参数量和理论乘加次数减少并不保证在所有硬件上获得相同比例的加速。
YOLO:从分类到目标检测#
图像分类为整幅图像输出类别;目标检测还要预测目标位置,并处理数量不定的实例。YOLO(You Only Look Once)把目标分类与位置预测放在一次网络前向传播中完成,避免为每个候选区域重复运行分类器。这里介绍的是 Redmon 等(2016) 提出的 YOLO v1;后续版本的结构和训练方法已有明显变化。
YOLO v1 把输入图像划分为 \(S\times S\) 个互不重叠的网格单元。每个网格单元预测 \(B\) 个边界框,每个边界框包含中心坐标 \((x,y)\)、宽和高 \((w,h)\) 以及置信度 \(c\);其中 \(x,y\) 表示中心相对于所在网格单元的位置,\(w,h\) 表示宽和高相对于整幅图像的比例。该网格单元还共同预测 \(C\) 个条件类别概率。因此,整个输出张量的维度为
如果某个目标的中心落入一个网格单元,就由该网格单元负责这个目标。在该单元的 \(B\) 个候选框中,训练时与真实框交并比最大的候选框预测器负责拟合该目标。YOLO v1 的置信度同时反映“框中存在目标的可能性”和“预测框定位是否准确”,其经典定义为
YOLO v1 的五项代价函数
令 \(\mathbb{1}_{ij}^{\mathrm{obj}}\) 表示第 \(i\) 个网格单元的第 \(j\) 个候选框负责预测目标,\(\mathbb{1}_{ij}^{\mathrm{noobj}}\) 表示该候选框不负责目标;不带帽的量表示真实值,带帽的量表示模型预测。YOLO v1 的代价函数可以写为
五项依次衡量中心位置、宽高、负责目标的候选框置信度、不负责目标的候选框置信度和类别概率误差。课件采用 \(\lambda_{\mathrm{coord}}=5\) 与 \(\lambda_{\mathrm{noobj}}=0.5\),以加强定位误差的作用并减弱大量无目标候选框的影响。对宽和高先开平方,可以降低大框尺寸误差在平方损失中的支配作用。
推断时会得到许多重叠框。交并比(intersection over union,IoU)定义为
推断时,首先用类别得分阈值删除得分过低的候选框。非极大值抑制(NMS)再按得分排序,保留当前得分最高的框,并抑制与它的 IoU 超过给定阈值的同类低分框,之后对剩余候选框重复这一过程。类别得分阈值和 NMS 的 IoU 阈值作用不同,都应在验证集上选择:前者决定哪些低分框可以进入后续处理,后者决定两个重叠框是否被视为对同一目标的重复预测。
ResNet#
He 等(2016) 观察到,当普通网络不断加深时,训练误差可能反而上升。例如,56 层普通网络在 CIFAR-10 上的训练误差高于 20 层普通网络。更深的网络在表示能力上至少可以包含较浅网络,但实际训练却没有找到同样好的参数,因此这种现象称为“退化”。
退化不是过拟合
过拟合通常表现为训练误差很低而测试误差较高;退化则表现为更深模型连训练误差都更高。因此,退化首先说明深层网络更难优化,不能简单解释为模型在训练样本上拟合得太好。
设残差块输入为 \(\ba^{[l]}\)。课件所示的两层残差分支先计算
其中 \(\bz^{[l+2]}\) 是残差分支给出的修正量,\(\ba^{[l]}\) 通过直连(shortcut)路径直接送到相加处。维度一致时,直连分支是恒等映射,不引入新的参数;残差分支只需学习在原有表示上应补充什么修正。
当 \(\bz^{[l+2]}\) 与 \(\ba^{[l]}\) 的维度不一致时,可以在直连分支使用投影矩阵 \(\bW_s^{[l+2]}\):
其中卷积网络通常用带有适当步幅的 \(1\times1\) 卷积实现 \(\bW_s^{[l+2]}\),使直连分支与残差分支具有相同的 \(d_C^{[l+2]}\)、\(d_H^{[l+2]}\) 和 \(d_W^{[l+2]}\)。
图 21 ResNet 的残差模块与网络结构#
梯度破碎
Prince(2024) 用相近输入点处梯度的相关程度解释另一个困难:浅层网络对两个相近输入得到的梯度通常仍较相似;网络加深后,这种相似性可能迅速衰减,梯度会随输入发生剧烈变化。这种现象称为“梯度破碎(shattered gradients)”。直连路径提供了不必依次通过全部残差变换的传播通道,可以减缓梯度相关性随深度的衰减,但不能保证梯度始终稳定。
直连路径的位置
直连分支应跨过残差分支中的线性或卷积变换,并在残差分支的最后一个线性变换之后参与相加。直连分支本身不应额外经过会截断负值的 ReLU 函数;否则,直连分支只能传递非负值,会限制它保留原有信息和提供修正的能力。经典的后激活残差块在两条分支相加后再使用 ReLU 函数。
残差连接显著改善了深层网络的优化,但不能保证任意深度、任意训练设置都能成功,也不能笼统地归结为“彻底解决梯度消失和梯度爆炸”。Batch Normalization 可以缓解很深网络中的梯度尺度问题,合理初始化、学习率和优化器仍然重要;即使同时使用残差连接和 Batch Normalization,也仍需检查激活值与梯度是否保持在合理范围内。
Shiny 交互演示:理论感受野与残差连接
交互页面可以逐层计算卷积网络的理论感受野及相邻输出中心在输入上的间距,还可以比较残差分支与恒等或投影直连分支的输出。理论感受野只表示输入中可能影响某个输出的区域;随机参数下的残差结果也只用于核对两条分支如何相加。
核心推导与实现核验#
核心关系
其中 \(\mathcal{F}\!\left(\ba^{[l]};\btheta\right)\) 表示残差分支以 \(\ba^{[l]}\) 为输入时计算得到的修正量,\(\btheta\) 表示该分支中所有可训练参数的集合。对于前文的两层残差分支,\(\btheta\) 包括 \(\bW^{[l+1]}\)、\(\bb^{[l+1]}\)、\(\bW^{[l+2]}\) 和 \(\bb^{[l+2]}\),并且 \(\mathcal{F}\!\left(\ba^{[l]};\btheta\right)=\bz^{[l+2]}\)。这个映射只表示残差分支的计算,不包括恒等直连分支,也不包括两条分支相加后使用的输出激活函数。\(\widetilde{\ba}^{[l+2]}\) 表示使用输出激活函数之前的相加结果。对 \(\ba^{[l]}\) 求导可得
推导路径。 残差分支学习相对于输入的修正量;求导后,输入梯度同时包含残差分支的导数项和直连分支产生的恒等项。若使用投影直连分支,恒等项相应改为投影矩阵的导数。
关键条件
维度相同时,恒等直连分支不增加参数,并提供导数中的恒等项;但连续多个残差块的总导数仍包含多个矩阵的乘积,因此直连路径只能改善传播条件,不能保证梯度绝不消失或爆炸。
数据规模
残差分支和直连分支只有在样本数 \(m\)、通道数 \(d_C^{[l+2]}\)、高 \(d_H^{[l+2]}\) 和宽 \(d_W^{[l+2]}\) 全部一致时才能逐项相加。需要下采样或改变通道数时,可在直连分支使用带有适当步幅的 \(1\times1\) 卷积,使两条分支的输出维度一致。
常见误区
只按发表年代或参数量判断架构优劣会忽略训练方法、输入分辨率、运行时间和硬件;残差分支与直连分支相加时也不能依赖广播机制自动补齐维度。
动手检查
用一批随机生成的输入记录逐层 \(m\times d_C^{[l]}\times d_H^{[l]}\times d_W^{[l]}\) 维度、参数量以及一次后向传播得到的梯度;残差块还要检查两条分支维度相同,并验证残差分支输出为 0 时的恒等映射。
数值稳定性与规模
训练损失直接接收输出层的线性运算结果;BatchNorm 统计量保持足够精度。混合精度下使用损失缩放,并对每层输出、梯度和学习率做有限性检查。
本节小结#
代表性架构围绕参数效率、可优化性和硬件代价取舍。
U-Net 用多尺度编码器—解码器汇总整体信息,并通过同尺度跳跃连接帮助恢复空间细节。
残差分支与直连分支相加前必须明确匹配维度。
架构比较必须控制训练配方与计算预算。
综合练习#
程序题应固定随机种子、写出维度断言并报告运行环境;比较题还应固定数据划分、随机种子集合和训练预算。全部参考答案见 代表性 CNN 架构答案。
残差梯度推导。 对激活函数之前的相加结果 \(\widetilde{\ba}^{[l+2]}=\mathcal F(\ba^{[l]};\btheta)+\ba^{[l]}\),推导 \(\partial\widetilde{\ba}^{[l+2]}/\partial\ba^{[l]}\) 和损失对 \(\ba^{[l]}\) 的梯度,说明恒等直连分支产生的直接项;再解释该项为什么不能保证深层网络的梯度绝不消失或爆炸。
深度可分离卷积计算。 输入通道数为 32、输出通道数为 64、核大小为 \(3\times3\),忽略偏置。计算标准卷积与“逐通道卷积 + \(1\times1\) 逐点卷积”的参数量及比值;对同一输出空间尺寸说明乘加量比值为何相同。
小卷积核堆叠。 假设输入与输出通道数均为 64,忽略偏置。计算一个 \(5\times5\) 卷积和两个串联 \(3\times3\) 卷积的参数量;说明两者感受野为何相同,以及串联结构额外加入非线性的意义。
残差维度计算。 输入为 \(m\times64\times32\times32\),残差分支首个 \(3\times3\) 卷积使用步幅 2 并输出 128 通道。写出残差分支输出维度,说明直连分支为什么需要 \(1\times1\)、步幅 2 的投影,并计算该投影忽略偏置时的参数量。
经典模块实现。 分别实现 VGG 风格双卷积块、MobileNet 深度可分离卷积块和 ResNet 基本残差块;每个模块应自动检查输入输出通道和空间尺寸,并提供参数量与中间激活大小统计。
性质与库对照。 把自编模块与框架层复制为相同权重并比较输出;将残差分支参数置零,验证无投影块在激活函数之前退化为恒等映射;核对深度可分离卷积的
groups、参数量和输出维度。代表网络比较。 在同一图像分类数据上比较小型 VGG、MobileNet 和 ResNet,并在可行范围内匹配参数预算。固定数据划分、随机种子集合、训练预算和增强;报告任务性能、训练时间、固定批量预测时间、参数量、乘加量及峰值内存。
直连路径与梯度破碎。 比较同深度、同通道配置的普通卷积网络与 ResNet。除逐层梯度范数外,再选择若干彼此接近的输入,计算其输入梯度之间的相关程度,观察这种相关程度是否随网络深度衰减。固定数据划分、随机种子集合、初始化和训练预算;报告任务性能、达到指定验证指标所需时间、固定批量预测时间、参数量及峰值内存,并分析直连路径可能带来的影响。
卷积形式比较。 在同一骨干网络中把标准卷积替换为深度可分离卷积,并分别进行两次比较:一次保持原宽度,另一次调整宽度使两种模型的参数量接近。每次比较都使用相同的数据划分、随机种子和训练预算;报告任务性能、训练时间、固定批量预测时间、参数量、乘加量及峰值内存,并分析卷积形式可能带来的影响。