3、CNN基础回顾:卷积层原理、池化层作用、全连接层、激活函数(ReLU/Sigmoid)、经典网络结构(AlexNet/VGG/ResNet)
好,咱们进入第三章。说实话,很多做AI芯片部署的朋友,一上来就盯着算子优化、内存搬运这些细节,结果模型跑起来效果不对,回头一查,原来是基础概念理解有偏差。我个人习惯是,不管多忙,每隔一段时间都要把CNN的这些基础构件拿出来重新捋一遍。你想想看,地基不稳,楼盖得再高也白搭。
3.1 卷积层原理:不仅仅是“滑窗”
卷积层是CNN的核心,这个大家都知道。但它的本质到底是什么?我理解,它其实是在做特征提取。用一个小的卷积核(比如3x3),在输入图像上滑动,每次做一次点积运算。这个点积的结果,就代表了该位置与卷积核的“相似度”。
举个例子,一个垂直边缘检测的卷积核,它在图像上滑动时,遇到垂直边缘就会输出较大的值。多个卷积核堆叠在一起,就能提取出不同的特征,比如纹理、角点、颜色变化等等。
这里有个关键参数:步长(Stride)和填充(Padding)。步长决定了卷积核每次移动的像素数,步长越大,输出特征图越小。填充则是在输入图像周围补0,目的是控制输出特征图的大小,或者保留边缘信息。
Output = (Input - Kernel + 2 * Padding) / Stride + 1
我在项目中遇到过一个问题:部署一个轻量级模型时,发现推理速度比预期慢很多。排查了半天,发现是卷积层的padding设置不当,导致特征图尺寸计算错误,内存访问模式变得非常低效。嗯,这里要注意,padding的“same”模式并不总是最优的,尤其是在硬件部署时,它可能会引入额外的边界处理开销。
3.2 池化层作用:降维与不变性
池化层,说白了就是“下采样”。它的作用很明确:降低特征图的尺寸,从而减少参数量和计算量,同时也能防止过拟合。
最常见的两种池化方式:
- 最大池化(Max Pooling):取窗口内的最大值。我个人习惯用它,因为它能保留最显著的特征,比如边缘、纹理等。
- 平均池化(Average Pooling):取窗口内的平均值。它更平滑,适合在网络的最后阶段使用,比如全局平均池化。
池化层还有一个重要的特性:平移不变性。什么意思呢?就是图像稍微平移几个像素,池化后的结果基本不变。这个特性对于分类任务来说非常有用,因为我们要识别的是“有没有猫”,而不是“猫在图像的哪个位置”。
3.3 全连接层:分类器的“最后一公里”
全连接层(FC层)通常放在网络的最后几层,它的作用是把前面提取到的“高级特征”映射到样本标记空间。说白了,就是做分类或者回归。
全连接层的参数量非常大,因为它每个神经元都和上一层的所有神经元相连。举个例子,一个输入为4096维、输出为1000维的全连接层,参数量就是4096 * 1000 = 409.6万个参数。这往往是模型体积的主要来源。
在部署时,我建议你优先考虑用全局平均池化(GAP)替代全连接层。GAP没有可训练参数,而且能大大减少模型体积。ResNet就是这么干的,效果非常好。
3.4 激活函数:ReLU vs Sigmoid
激活函数的作用是引入非线性。如果没有激活函数,神经网络就退化成线性模型,表达能力会大打折扣。
咱们重点看两个:
| 激活函数 | 公式 | 优点 | 缺点 |
|---|---|---|---|
| ReLU | f(x) = max(0, x) | 计算简单,缓解梯度消失,稀疏激活 | 神经元“死亡”(负半轴梯度为0) |
| Sigmoid | f(x) = 1 / (1 + e^{-x}) | 输出在0~1之间,适合二分类 | 容易梯度消失,计算开销大 |
我个人习惯,隐藏层首选ReLU。为什么?因为它计算简单,而且能有效缓解梯度消失问题。你想想看,Sigmoid在两端梯度几乎为0,网络深了根本训不动。而ReLU在正半轴梯度恒为1,梯度可以顺畅地反向传播。
不过ReLU也有个坑:神经元死亡。如果某个神经元的输入一直为负,那么它的输出就一直是0,梯度也为0,这个神经元就“死”了,再也无法更新。我在项目中遇到过这种情况,后来用Leaky ReLU或者PReLU解决了。
3.5 经典网络结构:AlexNet / VGG / ResNet
这些网络结构是CNN发展史上的里程碑。了解它们,能帮你理解CNN的设计思路演变。
3.5.1 AlexNet:深度学习的“开山之作”
AlexNet在2012年ImageNet竞赛中一战成名。它的核心贡献是:
- 使用ReLU激活函数,解决了Sigmoid的梯度消失问题。
- 使用Dropout,防止过拟合。
- 使用数据增强,扩大训练集。
- 使用GPU并行训练,大大缩短了训练时间。
AlexNet的结构是:5个卷积层 + 3个全连接层。卷积核大小从11x11逐渐减小到3x3。我记得第一次跑AlexNet时,觉得它好大,参数有6000多万个。现在看来,它其实挺小的。
3.5.2 VGG:更深的网络,更小的卷积核
VGG的核心思想是:用多个小卷积核(3x3)堆叠,替代大卷积核(5x5、7x7)。这样做的好处是:
- 减少参数量:两个3x3卷积的参数量是18,而一个5x5卷积是25。
- 增加非线性:两个卷积层之间有两个ReLU,非线性更强。
- 感受野不变:两个3x3卷积的感受野等于一个5x5卷积。
VGG的结构非常规整:卷积层全部用3x3,池化层全部用2x2。这种“模块化”的设计思想,对后来的网络影响很大。我个人很喜欢VGG,因为它简单、清晰,非常适合做特征提取的骨干网络。
3.5.3 ResNet:残差学习,让网络“深”下去
ResNet解决了网络退化问题。什么是网络退化?就是网络层数增加,但准确率反而下降。这不是过拟合,而是优化困难。
ResNet的核心是残差块(Residual Block):
输出 = F(x) + x
其中F(x)是卷积+激活函数,x是输入。这个“跳跃连接”(Skip Connection)让梯度可以直接从后面传到前面,解决了深层网络的梯度消失问题。
ResNet的另一个贡献是瓶颈结构(Bottleneck):先用1x1卷积降维,再用3x3卷积提取特征,最后用1x1卷积升维。这样可以大大减少参数量和计算量。
好了,CNN的基础知识就回顾到这里。这些内容虽然基础,但非常重要。你想想看,如果你连卷积核的尺寸、步长、填充都搞不清楚,怎么去优化推理性能?下一章,我们会进入FFT预处理的核心内容,敬请期待。