ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

卷积神经网络CNN核心原理与训练实战:从全连接到卷积的架构跃迁

卷积神经网络CNN核心原理与训练实战:从全连接到卷积的架构跃迁

先说一个我自己复习时反复确认过很多次的结论:卷积神经网络(CNN)真正厉害的地方,不是它有多少层、用了多少参数,而是它在一开始就从架构层面绕开了全连接网络在图像任务上的两大死穴——参数爆炸和空间结构丢失。2017年CS231n第五讲花了大量篇幅把这件事拆开揉碎地讲,我当时没有完全听进去,后来自己复现了几个经典结构,才彻底想明白。这篇内容就是我对这一讲笔记的完整整理,把卷积层、池化层、全连接层、激活函数、训练技巧串起来讲,适合正在学深度视觉、准备复现模型、或者刚被各种卷积术语绕晕的同学。

先说好,这不是课程视频的逐句翻译,而是我自己消化之后重新组织的版本。重点放在“为什么这么做”和“动手时要注意什么”上,公式会有,但每个公式我都会想办法解释到你能自己推出来。

1. 从全连接层到卷积层:为什么非改不可

1.1 一张图片被全连接层“拉直”之后丢掉了什么

假设输入是一张224×224的RGB图片,数据形状是224×224×3。传统全连接层的做法很直接:把整个三维数组展平成一维向量,长度是224×224×3=150528,然后接入一个拥有若干神经元的隐层。听起来没什么大不了,但如果你让这个隐层有512个神经元,权重矩阵的规模就是150528×512,约7700万个参数,这还只是一层。

更关键的问题不是参数量,而是结构。图像是三维的,像素之间存在天然的空间邻域关系:相邻像素往往颜色相近、纹理连续,猫的眼睛总是出现在脸的局部区域。展平成一维向量之后,这种邻域关系被彻底打乱,网络看到的只是“一长串数字”,每个位置之间的关系完全失去了空间含义。你等于把一张照片撕成碎片,再硬塞给一个只会数顺序的模型。

课程里反复强调一个类比:对图像识别来说,位置相近的像素比距离远的像素关系大得多,这是最基本的先验。全连接层没有利用这个先验,他默认所有输入特征是全连接的、地位对等的,这在图像任务上是一种巨大的浪费。

1.2 参数共享和局部连接是怎么救场的

卷积层就是针对这两个问题设计的。

第一是局部连接。每个卷积核不再连接整张输入图,而是只连接到输入的一个局部区域,这个区域的大小就是卷积核的尺寸,比如3×3或5×5。这和人的视觉系统很像,看东西的时候也是一小块一小块地看,局部纹理先被检测出来,再由后面更深的层组合成更大的语义概念。

第二是参数共享。同一个卷积核会游走整张输入图,也就是说,在左上角检测“横向边缘”的那组权重,也会被用在右下角。为什么合理?因为图像中同一个特征可能出现在任意位置,一只猫在图片左上角和右下角,本质上都是“猫”,对应的边缘纹理并没有变。既然特征本身一样,检测特征的那组参数也没必要区分位置。这一下子把参数量从几千万压到几百。

你可以拿全连接和卷积做个对比,直观感受一下差距:

结构处理224×224×3图像的典型参数量是否保留空间关系
全连接层,隐层512节点约7700万否,展平成一维
卷积层,6个3×3卷积核6×(3×3×3+1)=168是,按局部窗口扫描

168对7700万,差了约46万倍。课程里常说的“卷积让深度学习在视觉上变得可行”,说的就是这个差距。参数少了,过拟合风险随之降低,训练需要的样本量和计算资源也友好很多。

1.3 平移等变性:换个位置,特征依然能被抓住

参数共享还带来一个隐藏的好处:卷积天然具备平移等变性。意思是输入图像里的一个目标平移一段距离,卷积层输出的特征图也会跟着平移,但特征本身仍然会被检测出来。这对图像任务太重要了,因为我们不愿意模型因为猫从左边挪到右边就从“猫”变成“未知物体”。

不过我后来想明白一件事:只有卷积层给的是“等变”,而不是“不变”。真正让你对平移不敏感的是后面的池化层,它把局部区域内的响应做聚合,才给了分类器一定的“无论出现在哪都能认出来”的宽容度。所以看这章的时候,最好把卷积和池化当成一对搭档来理解,单独拎出来看任何一个都解释不了完整的网络行为。

2. 卷积层的输出尺寸、超参数与感受野:亲手算一次就忘不掉

2.1 卷积核到底在算什么

一个卷积核本质上是一个小的权重张量。以输入RGB三通道图为例,一个3×3卷积核的形状是3×3×3:空间大小3×3,通道数必须与输入一致。这个卷积核覆盖在输入的某个位置上,和覆盖区域内的27个数值做逐元素乘法,再求和,加上一个偏置,得到输出特征图上的一个数。

这个数代表什么?直观理解就是“这个局部区域与卷积核的匹配程度”。如果卷积核学到的是“横向渐变边缘”,那么它在图像边缘区域就会输出较大的响应,在平滑区域输出接近0。多个卷积核并存时,每个核相当于一个特征检测器,有多少个卷积核就有多少个输出特征图,也就是输出通道数。课程把输出通道数叫深度,这个叫法容易和网络层数混淆,我在笔记里习惯叫“特征图数量”。

2.2 三个超参数决定输出有多大多密

卷积层有三个核心超参数:深度(卷积核个数)、步长(stride)和零填充(zero-padding)。

步长决定了卷积核每次滑动几步。步长为1时,卷积核挨个移动;步长为2时,输出特征图尺寸直接减半左右。填充则是在输入边缘补一圈0,目的有两个:一是防止卷积把特征图越卷越小,信息快速缩水;二是让边缘像素也有机会被卷积核中心覆盖到,毕竟边缘元素在无填充时参与的卷积次数会比中间元素少,信息地位不对等。

输出尺寸公式在课程里写得很清楚:输出边长 = (N - F + 2P) / S + 1。其中N是输入边长,F是卷积核空间尺寸,P是填充量,S是步长。我在纸上算了三年才真正理解这个公式每个项的意图:N - F 是“卷积核中心还能走多远”,加上2P是因为填充让输入边长变长,除以S是看按步长能取几个位置,最后加1是因为初始位置也要算一次。我自己写了个小函数,每次搭网络都过一遍:

def conv_out_size(N, F, S, P=0): return (N - F + 2 * P) // S + 1 # 输入32x32,5x5卷积核,步长1,无填充 print(conv_out_size(32, 5, 1, 0)) # 28 # 输入32x32,5x5卷积核,步长1,填充2 print(conv_out_size(32, 5, 1, 2)) # 32 # 输入7x7,3x3卷积核,步长2,无填充 print(conv_out_size(7, 3, 2, 0)) # 3

搭网络时最怕的就是这里算错。常见配置是卷积核3×3、步长1、填充1,输出尺寸保持不变;或者卷积核5×5、步长1、填充2,输出尺寸也保持不变。这样在设计串联结构时,你可以清晰控制哪些层改变空间尺寸,哪些层只做特征变换。

2.3 感受野与堆叠小卷积核的哲学

感受野是另一个绕不开的概念,意思是输出特征图上一个像素点对应回输入图像上的多大区域。这个理解到后面看网络结构会非常有用,因为你很快就发现,现代网络很少用大的卷积核了。

原因很简单:堆叠两个3×3卷积核,换算成感受野是一个5×5,因为第一个3×3让特征图每个点看到输入3×3区域,再接一个3×3时,看到的是上一层3×3区域对应的输入区域,合起来是5×5范围。但参数量呢?两个3×3卷积的参数量是2×9=18(按单通道看),而一个5×5卷积是25。参数更少,感受野却一样大,而且中间多了一次ReLU激活,给网络增加了非线性表达能力。课程里明确指出,这就是后来很多经典结构偏好使用小卷积核堆叠的根本原因。

1×1卷积也值得单独说。它不改变空间尺寸,但会改变通道数,相当于在每个像素位置上对通道做一次线性组合,可以用很低的成本控制特征图厚度。课程里把1×1卷积看成“跨通道的池化”或者说“通道层面的重组合”,在GoogLeNet这类结构里被大量用来降维,先把通道压下来再做大卷积核计算。

3. 池化层和全连接层:缩小特征图与汇总决策

3.1 池化层不是“必须”,但它的动机很朴素

池化层负责的是特征图的降采样。最常见的是最大池化:用一个2×2窗口以步长2扫过特征图,每个窗口内取最大值,输出宽高直接减半,通道数不变。

为什么需要这一步?首先,卷积层虽然已经控制了参数规模,但特征图本身依然很大,如果一路保持高分辨率,后面的层计算量会一直维持在很高的水平。其次,最大池化给了网络对微小位移的容忍度:物体偏移一两个像素时,池化窗口内的最大值往往变化不大,后续层看到的仍是接近相同的特征。用课程里的说法,池化是在逐步抽象,位置细节慢慢让位于语义内容。

这里特别想说,池化并不改变通道数量。它只在宽和高两个维度上做压缩,通道维度保持不动。常见配置就是2×2窗口加步长2,效果是特征图每个维度减半,相当于对特征图做了空间上的“浓缩”。

3.2 最大池化和平均池化的取舍

讲师在课上对比过两种池化。最大池化取窗口内的最强响应,实际经验里效果更好,因为它保留的是“这个区域里到底有没有某种特征”,而不是被区域内大量低响应值拉低平均。平均池化没那么激进,把窗口内所有值等权汇总,信息更平滑但更容易把微弱特征稀释掉。

不过平均池化有一个用法一直活到了今天:全局平均池化,也就是把整张特征图池化成1×1。它一般出现在网络的末端,用来替代全连接层做最终分类前的特征汇总,好处是参数量几乎为零,并且天然输出一个与类别数一致的特征向量。课程在讲经典网络的时候提到这种设计,我当时没太在意,后来自己动手做小模型时试了一次,才发现这种结尾方式既省参数又不容易过拟合。

3.3 全连接层:把二维特征图变成分类分数

卷积层和池化层把图像逐步抽象成了“长宽更小、通道更多”的特征图,但分类任务最终要输出一个向量,比如10个类别的得分。全连接层做的就是最后这一步:把特征图展平成一维,然后通过一个权重矩阵映射到类别维度上。

全连接层的问题和开头讲的一样:参数量很大。假设最后一个卷积层输出是7×7×512,展平后长度是25088,如果再接一个1024节点的全连接层,权重就是25088×1024,约2570万。这也是为什么很多现代结构要么不用全连接层,要么只保留最后一层。课程里提过一个技巧:全连接层本质上可以被看成一种特殊卷积,当输入特征图空间尺寸为1×1时,全连接就是1×1卷积。理解这个对应关系,对改造网络结构很有帮助,比如你想把某个分类网络改成全卷积的版本,只需要把全连接层替换成对应的1×1卷积。

到这里,一个经典网络的完整骨架就清楚了:输入图像,经过多轮“卷积-激活-池化”,把空间尺寸逐步压低、通道逐步加深,最后展平接全连接层,再接一个Softmax,把得分变成概率。整个流程可以概括成:特征提取在前,分类决策在后。

4. 激活函数与经典网络骨架:从CONV-RELU-POOL到现代变体

4.1 为什么Sigmoid在深度网络里基本被放弃了

2017年课程讲激活函数时,仍然是从Sigmoid讲起的,因为它历史上重要,但随后很快就指出它的致命缺陷:饱和。Sigmoid把输入压到0到1之间,当输入绝对值较大时,曲线变得非常平缓,梯度接近0。多个层连起来的时候,这些接近0的梯度一乘,就会让靠近输入层的参数几乎得不到更新信号,这就是梯度消失。

Tanh比Sigmoid好一点,输出是零中心的,但同样存在饱和区的问题。ReLU就朴素多了,函数是max(0,x),正半轴梯度恒为1,负半轴直接置0。优势很明显:计算只要一次比较,收敛速度比Sigmoid快很多,而且正的梯度能顺利往后传。课程里给出的建议非常直接:默认用ReLU,如果遇到神经元大量死亡,尝试Leaky ReLU或带参数的变体。

ReLU有个著名的问题叫“死亡ReLU”:如果某个神经元在训练中被负区间压住,它的梯度永远是0,权重再也无法更新,这个神经元就永久退出了。通常原因有两点,一是初始化不合适,二是学习率设置太大。课程里也提到,合理的初始化和学习率能大幅减少这种现象,所以别一见到死亡神经元就急着换激活函数,先把训练配置调对。

4.2 经典层布局:CONV-RELU-[(POOL)]的节奏

普通卷积网络的布局有一个非常清晰的节奏:卷积层负责特征提取,激活函数引入非线性,池化层做空间降维,然后重复。典型的一个阶段是“卷积-ReLU-池化”,或者更细致一点“若干个卷积-ReLU-池化”。为什么卷积和池化的顺序固定成这个样子?因为激活函数必须紧跟卷积,否则多个卷积层叠起来还是线性变换,堆再多层也等效于一个卷积。池化则可以稍微延后,让卷积层先在同一分辨率下充分提取特征,再用池化降低冗余。

课程讲到最后的经典结构演进时,其实讲的都是这个节奏的变化:早期5层网络是“卷积-池化-全连接”的简单拼接;8层的AlexNet把卷积层增加到5层,同时用ReLU和Dropout,让网络第一次在大规模图像数据上取得明显优势;16层风格的VGG网络证明了“小卷积核+深网络”的组合,它完全堆叠3×3卷积,结构极度规整;22层的GoogLeNet则尝试在同一个层上并行使用不同尺寸的卷积核,让网络自己选择合适尺度的特征;而50层以上能训练起来的关键是残差连接,让梯度能绕过一个层直接传到前面。

我自己复习到这一段时,最大的感受是:每一代结构都不是凭空想出来的,都是在解决上一代网络训练或表达的某个具体瓶颈。

经典结构(按课程演进顺序)核心改动参数量量级
早期5层网络卷积+池化+全连接的基本拼接百万级
8层结构加深网络、引入ReLU与随机丢弃约6000万
16层纯卷积结构大量堆叠3×3小卷积核,结构规整约1.38亿
22层多分支结构同层多种尺度卷积并行,组合特征约700万
50层残差结构增加跨层直连,解决深度网络的梯度问题约2560万

4.3 为什么2017年讲的内容到今天仍然适用

虽然这是2017年的课,很多具体结构和数据都已经不是最前沿,但第五讲的核心思想一点没过时:卷积层的局部连接和参数共享、池化层的空间降采样、激活函数的非线性、残差结构对梯度传播的改善,这些仍是今天绝大多数视觉模型的基石。后面的注意力机制、大规模预训练、多模态模型,都是在这些基础构件之上生长出来的。所以我现在看这篇笔记,更多的不是看技术有多新,而是看它如何把若干基本的视觉先验清晰地注入到架构里,这个底层思路是稳定的。

5. 训练卷积神经网络的现实问题:初始化、正则化、数据增强

5.1 输入预处理和权重初始化:两台发动机的预热

课程在训练细节部分很早就强调数据预处理。图像数据最基础的处理是零中心化:对每个像素位置或每个通道减去均值,让输入分布在0附近。这样做的原因是Sigmoid和Tanh这类激活函数在0附近梯度大、不饱和,虽然ReLU对中心化不那么敏感,但中心化仍然能让优化过程更稳定,尤其是配合Batch Normalization时。

权重初始化也是训练成败的隐形关卡。全零初始化不可行,因为所有神经元会同步更新,永远无法分化出不同特征。用小随机数初始化是可接受的基础做法,但更关键是要配合激活函数选择方差尺度:ReLU家族网络更推荐He初始化,它根据输入维度调整权重方差,保证前向传播时信号的方差基本稳定,不会逐层放大或衰减。实测里,初始化错误不会让网络立即报错,而是表现为loss在某个值附近震荡,或者训练很慢不下降,这种问题排查起来比显式报错痛苦得多,所以宁可在一开始就按规则初始化。

5.2 Batch Normalization和Dropout:两个作用完全不同的工具

Batch Normalization,简称BN,在2017年已经非常常用。它的核心操作是让每一层卷积后的特征在通道维度上做一次标准化:减均值再除以标准差,然后用可学习的缩放和平移参数恢复表达能力。效果是网络对初始化敏感度降低,收敛速度明显提升。放到卷积层时,BN的作用位置是在卷积/全连接之后、激活函数之前,这一点我在复现时经常记反,结果效果打了折扣。

Dropout则是另一个维度的事,它属于正则化,目标是抑制过拟合。做法非常简单粗暴:训练时按概率随机把一部分神经元输出置0,让网络不能过度依赖某几个节点,迫使信息分散到更多连接中。这里最容易翻车的是忘记在验证和测试阶段关闭Dropout,或者把训练用的缩放逻辑搞错。我见过不少人的验证效果比训练差一大截,排查半天发现是验证代码里忘了关Dropout,属于新手区高频失误。

5.3 数据增强:不要钱的训练集扩张

数据增强在图像任务里性价比极高。最简单的几招:随机水平翻转、随机裁剪、小幅颜色抖动、随机旋转和缩放。这些变换不改变图片的语义内容,但让模型看到更多变体,从而学到更鲁棒的特征。课程里明确把它当作一种正则化手段,和Dropout、权值衰减并列。

权值衰减(L2正则化)也值得提一句,它给大权重加惩罚,迫使模型使用分布更平缓的参数。通常系数设在10的负四次方到负五次方这个范围。配上前面的增强和Dropout,三者合起来能让验证准确率提升几个点,是非常划算的组合拳。

5.4 调学习率的过程,比调结构更影响最终结果

课程里反复强调,学习率可能是最需要重点调的超参数。太大容易震荡甚至发散,太小则收敛极其缓慢。常见做法是阶梯式衰减:比如每训练若干轮学习率乘0.1,或者在验证loss不再下降时手动降低学习率。我在复现过程中体会最深的一件事是:与其盯着网络结构改来改去,不如先跑一个少量数据的小实验,把学习率、批大小这些训练参数调到合理范围,再投入全部数据。这个顺序节省下来的时间和算力非常可观。

还有一条被说了无数遍但依然有效的经验:在做大实验之前,先用极少量数据(比如一个batch或几十张图)把网络跑到过拟合。如果连过拟合都做不到,说明代码里有bug;如果能过拟合到接近100%,才说明正向流程是通的。这个“先过拟合验证代码”的思路,是课程和后来各种工程实践都一致认可的起步动作。

6. 复习完这一讲之后,我想留下的几条实操经验

先说最容易卡住新手的“尺寸问题”。每次搭网络前,我建议把每一层的输入输出尺寸、通道数、参数量都手写在一个草稿表里。不要只依赖框架自动计算,因为你真正调试的时候,发现尺寸不匹配会很难受。我自己吃过一次亏:两个分支结构里的卷积padding参数写错,导致特征图尺寸对不上,拼接时直接报错,排查了一个多小时才找到问题。这类问题提前算一遍基本可以规避。

然后是关于“复现经典结构”的路径推荐。如果你正在入门,不建议一上来就啃几十层的复杂结构。先做一个小型卷积网络,跑到CIFAR级别的小数据集上,看清卷积、池化、全连接之间怎么配合;然后照着8层风格的网络复现一遍,体会什么叫“深度增加带来的表达力提升”;最后再去碰残差结构,这时你会真正理解为什么跨层连接能稳住在深层网络的训练。每走一步,都把前面讲的尺寸计算、初始化和正则化流程走一遍,这些基本功才会变成肌肉记忆。

我最后一次完整复习这讲内容时,也顺带整理了一个适合自己的检查清单:数据有没有做零中心化;BN的位置是不是在激活之前;Dropout在验证时有没有关闭;卷积输出尺寸有没有算错;初始化是不是按激活函数选了对应的方案。如果这五项都对,训练一般不会出现“完全学不动”的诡异情况。遇到loss不降时,我第一反应不是改网络结构,而是回头核对这个清单。

最后分享一个观念上的转变。最开始看这类笔记,总会忍不住去记每个经典网络的层数、参数量、准确率,但这些数字过几个月就会模糊。真正留在脑子里的,是卷积为什么比全连接适合图像、感受野是怎么被小卷积核扩大的、网络加深为什么需要残差连接兜底。理解了这些动机之后,再去看任何新模型,都不会觉得是一堆陌生名词的堆砌。这大概是第五讲对我来说最大的价值。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进