2. 图像分类基础回顾

做模型压缩和部署优化,说白了你得先懂“原版”长什么样。我见过不少同学一上来就搞剪枝、量化,结果模型精度崩了都不知道问题出在哪——因为对基础网络结构理解不够深。这一章咱们就把卷积神经网络的核心概念和两个经典分类模型(ResNet、MobileNet)掰开揉碎讲清楚。

卷积神经网络的核心概念

先聊聊几个我几乎每天都会打交道的概念。嗯,这些是基本功,但也是坑最多的地方。

卷积层:特征提取的主力

卷积操作本质上就是一个滑动窗口。输入图像和卷积核做点积,输出一张特征图。我刚开始学的时候总觉得这玩意儿很玄乎,后来自己手写了一次前向传播才算真正理解。

关键参数:

  • 卷积核大小:常用 3×3、5×5、7×7。3×3 是性价比之王,两个 3×3 堆叠等效于一个 5×5 的感受野,但参数量更少。
  • 步长:控制滑动步幅。步长=2 时特征图尺寸减半。
  • 填充:保持边界信息。我习惯用 same padding 保持尺寸不变。

举个例子,输入 224×224×3 的图像,用 64 个 3×3 卷积核,步长=1,填充=1,输出就是 224×224×64 的特征图。参数量是多少?(3×3×3+1)×64 = 1792 个参数。你看,其实不多。

池化层:降维与抗过拟合

池化层的作用很直接——缩小特征图尺寸,减少计算量。我常用的有两种:

池化类型 操作 特点 我的经验
最大池化 取窗口内最大值 保留纹理特征,平移不变性强 分类任务首选,效果稳定
平均池化 取窗口内平均值 保留背景信息,更平滑 全连接层前用全局平均池化,参数量骤降

我曾经在一个项目里把最大池化换成平均池化,结果 Top-1 精度掉了 2 个点。后来发现是因为任务对纹理细节敏感,最大池化更适合。所以别小看这个选择。

激活函数:非线性能力的来源

没有激活函数,再深的网络也只是线性变换的堆叠。我常用的就三个:

  • ReLU:f(x)=max(0,x)。简单粗暴,梯度不饱和,训练快。但有个问题——神经元“死亡”,即输入为负时梯度为 0,参数再也不更新了。
  • Leaky ReLU:f(x)=max(αx,x),α 通常取 0.01。解决了死亡问题,我部署时经常用这个。
  • Softmax:多分类输出层标配。把 logits 转成概率分布,所有输出和为 1。

避坑指南:我曾经在 MobileNet 部署到边缘设备时,发现推理速度比预期慢很多。排查了半天,原来是激活函数用了 Swish(包含 sigmoid 计算),在 CPU 上开销太大。换成 ReLU 后速度提升了 30%。部署时一定要考虑目标硬件的算子支持情况。

全连接层与分类头

全连接层把特征图展平成一维向量,然后做分类。但参数量巨大——一个 2048 维的特征向量接 1000 类分类器,就是 2048×1000 ≈ 2M 参数。我一般建议用全局平均池化替代展平操作,能大幅减少参数量。

经典分类模型架构解析

接下来看两个我工作中用得最多的模型。一个追求精度(ResNet),一个追求效率(MobileNet)。

ResNet:残差学习的里程碑

ResNet 解决了深层网络退化问题。说白了就是网络越深,精度反而下降——不是过拟合,是优化困难。ResNet 的核心思想是引入残差连接(skip connection)。

残差块公式:输出 = F(x) + x

其中 F(x) 是卷积堆叠的映射,x 是输入。梯度可以直接通过恒等路径回传,解决了梯度消失问题。

我常用的 ResNet 变体有:

模型 层数 参数量 ImageNet Top-1 适用场景
ResNet-18 18 11.7M 69.8% 轻量级分类,快速验证
ResNet-34 34 21.8M 73.3% 中等精度需求
ResNet-50 50 25.6M 76.0% 精度与速度平衡,蒸馏常用
ResNet-101 101 44.5M 77.4% 高精度任务,教师模型首选

我个人习惯用 ResNet-50 作为蒸馏的教师模型。精度够高,参数量适中,训练时间也能接受。ResNet-18 则常作为学生模型的 baseline。

下面这张图展示了 ResNet 的核心结构:

ResNet 残差块结构图 输入 x Conv 3×3, BN, ReLU Conv 3×3, BN + 输出 F(x) + x 恒等映射(skip connection) 💡 残差连接让梯度可以直接回传到浅层,解决了深层网络退化问题。 ResNet-50 有 16 个残差块,每个块包含 3 层卷积(1×1, 3×3, 1×1)。

MobileNet:轻量级部署的利器

MobileNet 是为移动端和嵌入式设备设计的。它的核心创新是深度可分离卷积(Depthwise Separable Convolution)。

传统卷积的计算量是:K_h × K_w × C_in × C_out × H_out × W_out。深度可分离卷积把它拆成两步:

  1. 深度卷积:每个输入通道单独用一个卷积核处理,计算量 K_h × K_w × C_in × H_out × W_out。
  2. 逐点卷积:用 1×1 卷积融合通道信息,计算量 1 × 1 × C_in × C_out × H_out × W_out。

总计算量是两者之和。与传统卷积相比,计算量大约减少到原来的 1/C_out + 1/(K_h × K_w)。用 3×3 卷积核、C_out=64 时,计算量只有原来的 1/8 左右。

我的经验:MobileNetV2 引入了倒残差结构和线性瓶颈层。倒残差是先升维再降维,线性瓶颈层去掉了最后一层的 ReLU,避免信息丢失。我在部署到树莓派时,MobileNetV2 比 ResNet-18 快 3 倍,精度只差 1-2 个点。

MobileNet 系列对比:

版本 核心改进 参数量 ImageNet Top-1 我的推荐场景
MobileNetV1 深度可分离卷积 4.2M 70.6% 极低算力设备
MobileNetV2 倒残差 + 线性瓶颈 3.5M 72.0% 移动端部署首选
MobileNetV3 NAS 搜索 + h-swish 2.5M 75.2% 精度要求较高的轻量场景

下面这张图对比了传统卷积和深度可分离卷积的流程:

传统卷积 vs 深度可分离卷积 传统卷积(标准 3×3) 输入: H×W×C_in 卷积核: C_out × 3×3×C_in 输出: H×W×C_out 计算量: 3×3×C_in×C_out×H×W 深度可分离卷积 步骤1: 深度卷积 每个通道独立卷积,C_in 个 3×3 核 步骤2: 逐点卷积 1×1 卷积融合通道,C_out 个 1×1×C_in 核 输出: H×W×C_out 计算量: 3×3×C_in×H×W + C_in×C_out×H×W 💡 当 C_out=64, 3×3 卷积时,深度可分离卷积计算量约为传统卷积的 1/8。 这是 MobileNet 能在手机上跑分类的核心原因。

从分类模型到蒸馏部署的桥梁

讲完这些基础,我想强调一点:你后面做模型蒸馏时,教师模型和学生模型的选择会直接影响蒸馏效果。我个人习惯:

  • 教师模型:ResNet-50 或 ResNet-101,精度高,知识丰富。
  • 学生模型:MobileNetV2 或 ResNet-18,轻量高效,适合部署。

蒸馏的本质就是让学生模型学习教师模型的“软标签”和中间层特征。理解了卷积层、残差连接、深度可分离卷积这些概念,你才能知道哪些知识值得蒸馏,哪些结构需要调整。

一句话总结:ResNet 用残差连接解决了深度问题,MobileNet 用深度可分离卷积解决了效率问题。这两个模型是蒸馏压缩的绝佳搭档。