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):取窗口内的平均值。它更平滑,适合在网络的最后阶段使用,比如全局平均池化。

池化层还有一个重要的特性:平移不变性。什么意思呢?就是图像稍微平移几个像素,池化后的结果基本不变。这个特性对于分类任务来说非常有用,因为我们要识别的是“有没有猫”,而不是“猫在图像的哪个位置”。

部署小技巧:在AI芯片上,池化层通常可以用卷积层来替代(比如步长为2的卷积),这样可以减少算子种类,提高硬件利用率。我曾经在一个项目中,把所有的最大池化替换成了步长为2的卷积,推理速度提升了约15%。

3.3 全连接层:分类器的“最后一公里”

全连接层(FC层)通常放在网络的最后几层,它的作用是把前面提取到的“高级特征”映射到样本标记空间。说白了,就是做分类或者回归。

全连接层的参数量非常大,因为它每个神经元都和上一层的所有神经元相连。举个例子,一个输入为4096维、输出为1000维的全连接层,参数量就是4096 * 1000 = 409.6万个参数。这往往是模型体积的主要来源。

在部署时,我建议你优先考虑用全局平均池化(GAP)替代全连接层。GAP没有可训练参数,而且能大大减少模型体积。ResNet就是这么干的,效果非常好。

避坑指南:我曾经在部署一个老模型时,发现全连接层的权重矩阵非常大,导致芯片的片上存储(SRAM)放不下。后来我用了权重剪枝量化,才勉强塞进去。所以,如果你的模型要部署到资源受限的设备上,尽量少用全连接层。

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解决了。

部署建议:在AI芯片上,ReLU的实现非常简单,只需要一个比较器。而Sigmoid需要查表或者用多项式近似,计算开销大得多。所以,除非必要,否则不要用Sigmoid

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卷积升维。这样可以大大减少参数量和计算量。

部署经验:ResNet在AI芯片上部署非常友好。因为它的结构规整,而且跳跃连接可以复用特征图,减少内存访问。我曾经在部署ResNet-50时,通过算子融合(把卷积、BN、ReLU融合成一个算子),推理速度提升了30%以上。

好了,CNN的基础知识就回顾到这里。这些内容虽然基础,但非常重要。你想想看,如果你连卷积核的尺寸、步长、填充都搞不清楚,怎么去优化推理性能?下一章,我们会进入FFT预处理的核心内容,敬请期待。