一、卷积神经网络(CNN)基础回顾
各位同学好,今天咱们来聊聊CNN的基础。说实话,这部分内容很多教程都讲,但真正理解透的人不多。我当年刚入行时也踩过不少坑,今天就把这些经验分享给大家。
1.1 卷积操作:到底在干什么?
卷积操作,说白了就是用一个小的窗口(卷积核)在输入图像上滑动,每次做点乘求和。嗯,就这么简单。
举个例子,假设我们有一个5×5的输入图像,用一个3×3的卷积核去扫它:
输入图像 (5×5): 卷积核 (3×3):
[1 1 1 0 0] [1 0 1]
[0 1 1 1 0] [0 1 0]
[0 0 1 1 1] [1 0 1]
[0 0 1 1 0]
[0 1 1 0 0]
第一次卷积计算:
1×1 + 1×0 + 1×1 + 0×0 + 1×1 + 1×0 + 0×1 + 0×0 + 1×1 = 4
我在项目中遇到过一个问题:很多人以为卷积核越大越好。其实不然,3×3的卷积核堆叠两层,感受野相当于5×5,但参数量更少,非线性更强。这是个很实用的技巧。
关键点:卷积操作的核心是参数共享和局部连接。同一个卷积核在整个图像上滑动,大大减少了参数量。
1.2 池化:为什么要丢掉信息?
池化操作,我习惯叫它"下采样"。它的目的很明确:降低特征图尺寸,减少计算量,同时保留主要特征。
常见的池化方式有两种:
- 最大池化(Max Pooling):取窗口内的最大值。我一般用它来保留纹理特征。
- 平均池化(Average Pooling):取窗口内的平均值。适合保留背景信息。
举个例子,2×2的最大池化:
输入特征图 (4×4): 输出特征图 (2×2):
[1 3 2 4] [3 4]
[5 6 7 8] → [7 8]
[9 1 2 3]
[4 5 6 7]
我的经验:池化窗口大小一般选2×2,步长也设为2。太大容易丢失细节,太小又起不到降维作用。
1.3 感受野:网络能看到多大范围?
感受野这个概念,说白了就是特征图上每个像素对应原始图像上的区域大小。你想想看,浅层网络的感受野小,只能看到局部纹理;深层网络的感受野大,能看到全局结构。
计算公式其实很简单:
RF_l = RF_{l-1} + (kernel_size - 1) × stride_{l-1}
其中RF_l是第l层的感受野大小。
举个例子,一个3层3×3卷积(步长均为1)的网络:
- 第1层:感受野 = 3×3
- 第2层:感受野 = 5×5
- 第3层:感受野 = 7×7
我曾经犯过一个错误:在移动端部署时,用了太大的卷积核导致感受野过大,结果模型对局部细节不敏感。后来改用小卷积核堆叠,效果反而更好。
注意:空洞卷积可以扩大感受野而不增加参数量,但使用不当会导致网格效应。我建议在需要大感受野的场景下,优先考虑堆叠小卷积核。
1.4 CNN在移动端的局限性
好了,前面讲了CNN的基础,现在说说为什么它在移动端会遇到瓶颈。我做了这么多年移动端部署,总结下来主要有三个问题:
| 问题 | 具体表现 | 影响 |
|---|---|---|
| 计算量大 | 标准卷积需要大量乘加运算 | 手机CPU/GPU扛不住 |
| 参数量多 | 全连接层动辄上百万参数 | 模型文件太大,下载慢 |
| 内存占用高 | 中间特征图占用大量显存 | 低端手机直接闪退 |
举个例子,一个标准的VGG-16模型,参数量约1.38亿,模型文件超过500MB。你想想看,哪个用户愿意下载一个500MB的App?
更麻烦的是,CNN的全局建模能力有限。虽然可以通过堆叠层数扩大感受野,但本质上还是局部操作。对于需要全局上下文的任务(比如语义分割),CNN就显得力不从心了。
核心矛盾:CNN擅长局部特征提取,但缺乏全局建模能力。而移动端又要求模型轻量高效。这就是为什么我们需要MobileViT这样的混合架构。
嗯,说到这里,大家应该对CNN的基础和局限性有了清晰的认识。下一节我们会深入探讨自注意力机制,看看它是如何解决这些问题的。