第 03 篇 · 第一部分 · 模型到底是个什么东西
卷积神经网络:机器为什么能"看懂"图片
在机器眼里,一张图不是什么画面,只是几万个排成格子的数字。卷积做的事,简单说就是拿一个放大镜在这些数字上一格一格地滑过去。然而正是这样一个朴素动作,让参数量从一亿五千万降到了十个。这篇就把卷积、权重共享、感受野、池化这几块讲清楚,再梳理一遍 CNN 这一路的演化,以及它为什么到今天仍广泛部署在手机端。
一、图像对计算机来说只是一组数字
你看到的是一张猫的照片:毛茸茸的耳朵,圆眼睛,胡须。计算机看到的是一张表格——每个像素是 0 到 255 之间的一个整数,越大越亮。彩色图有三条通道,红绿蓝各一层。
拿一张常见的 224×224 彩色图来算:224 乘 224 再乘 3,等于150528 个数字。这就是模型真正的输入,整整齐齐地排列着十五万个整数。黑白的 28×28 小图(老牌手写数字数据集 MNIST 的尺寸)就少些,784 个。
关键在于,这些数字不是随机分布的。相邻的像素之间有强关联:一片天空里挨着的点颜色差不多,猫耳朵的轮廓在哪,旁边几个像素就顺着它走。这种"局部聚集"的性质,是后面所有方法能成立的前提。谁能利用这层结构,谁就占据优势。
二、全连接层的问题:参数量爆炸
假如不加区分,把输入直接铺平,接一个普通的全连接层——就是上一篇讲的那种"每个输入连到每个神经元"。设这一层有一千个神经元。
那么连接数是多少?十五万个输入,每个都要连到这一千个神经元上,光这一层就是 150528 × 1000 ≈ 1.5 亿个权重。而这仅仅是网络的第一层,后面还密密麻麻排着好几层。参数量会像滚雪球一样失控。
更不理想的是,全连接层把图像当成一个没有形状的长列表,完全无视了像素之间的空间关系。把整张图向右移动一个像素,输入向量的各个分量就整体错位,前面耗费训练得到的权重立刻对不上号。同一只猫出现在画面左上角还是右下角,对全连接层来说就是两份毫不相干的输入,各学一套参数——问题就出在这里。
三、卷积核:一个会滑动的放大镜
卷积的思路换个方向来:与其让每个神经元看全图,不如让它只看一小块,然后把同一块"模具"在整张图上滑一遍。
这个模具叫卷积核,通常很小,3×3 最常用,也就是九个权重。把它盖在图像的某个 3×3 区域上,对应的九个像素各自乘上核里那九个数,全部加起来,得到一个输出值。然后整块向右移动一格,再来一次;移动到行末,换行往下,继续。整个过程就像握着放大镜,一格一格在纸上扫过去,看清每一处局部的样子,一路扫下去,就得到一张新的小表格。
不同的核,能挑出不同的花纹。有的核专抓竖直的边缘——例如左侧亮、右侧暗的区域,它的响应最强;有的专抓横边;有的认出一个角。这些花纹听着琐碎,但它们是构成万物的砖块:轮廓拼成形状,形状拼成物体。卷积网络早期的层,学到的往往就是这类边边角角。
四、局部连接与权重共享:一次性省掉七个数量级
这套滑动方式同时解决了两个大问题。
第一个叫局部连接。每个输出只看得到输入的 3×3 那一小块,不涉及远处的像素。这符合直觉:判断某处是不是一条边,只看附近九个点就够了,没必要考虑整张图。
第二个更关键,叫权重共享。核在滑动过程中,那九个权重从头到尾不换——同一套参数,在整个画面上反复使用。这才是真正省参数的地方。
具体算一下:一个 3×3 的核,加上一个偏置,总共十个参数。对比刚才那一亿五千万,差不多降了七个数量级。这个思路在道理上也站得住:猫在左上角是猫耳朵,挪到右下角还是猫耳朵,没有必要用两套参数分别学习,一套就足够。这叫平移不变性:不管目标出现在画面哪个位置,同一套卷积核都能识别出同样的局部特征。节省参数与符合直觉,这次达成了一致。
五、感受野:叠了几层之后能看到什么
3×3 的核只看九个点,视野未免太窄。可只要往上叠,视野就能一层层打开。
第二层的某个输出,是拿着 3×3 的核在第一层的输出上滑出来的。而第一层每个位置,本来就代表了原图上 3×3 的一块。这么一叠,第二层的一个点就间接看到了原图上 5×5 的区域。再叠一层,变成 7×7。每加一层 3×3,最顶上的神经元"看得到"的范围就往外扩两格——这个能看到多大原图区域的尺寸,叫感受野。
仅靠增大核尺寸来扩大视野,速度太慢。于是中间还插入了下采样(比如池化,或者带步长的卷积),把特征图的尺寸一步步缩小。这会加速感受野的增长:假设每层做一次下采样、特征图尺寸减半,叠加三层之后,一个神经元大约能覆盖原图上十几个像素,继续向上叠加快得就能达到上百个像素。有了这条通道,到了网络深处,一个神经元看到的差不多就是原图上的一整只猫、一整个车轮——它才终于有能力判断"这是什么"。
六、池化:有时候模糊一点反而更好
池化是卷积之后常跟着做的一个操作,思路很直接。最常见的是最大池化:把特征图切成 2×2 的小块,每块只留最大的那个数,其余的舍弃,尺寸直接减半。
为什么要这么做?想想缩略图。把一张大图压成小图,细节自然变模糊了,但主体轮廓还在。池化做的就是类似的事——保留最显著的特征,模糊掉不重要的细节。舍弃的那些数,本来也大多接近 0,删去的影响不大。
好处有两个方面。第一方面是节省开销:特征图小了一半,后面每一层的计算量随之下降。第二方面是抗位移:图像里一个小特征稍微移动几格,只要还在同一个池化窗口里,取出来的最大值还是它,输出保持不变。模型对位置的容忍度变高了,不容易因为细微位移就判断错误。当然,池化也不是没有代价,位置信息会被削弱,这在需要精确定位的任务(比如分割)里就比较棘手,因此后来有些设计直接放弃池化、改用带步长的卷积。
七、经典结构演进:LeNet → AlexNet → VGG → ResNet → MobileNet
把这些零件组装起来,就是卷积神经网络。它的演化史,也是一部"更深、更强、更省"的编年史。
- LeNet-5(1998):这一结构的开山之作,为识别手写数字而生,只有七层、约六万个参数,能识别邮编和支票上的数字。受限于数据和算力,当时未能广泛流行。
- AlexNet(2012):真正的引爆点。它在 ImageNet 那场一千类的图像竞赛上,把错误率从前一年的 26% 左右压到 15% 出头,靠的是 ReLU 激活、Dropout、以及用 GPU 训练。八层、约六千万参数。从这年起,"深度学习"成了热词。
- VGG(2014):把结构整理得规整,通篇只用 3×3 小核,靠堆叠层数换取性能,16 层或 19 层。VGG16 约 1.38 亿参数,效果稳定,但体积很大,仅权重就有五百多兆字节。
- ResNet(2015):解决"越深越差"这一问题的。给每层加一条跳跃连接(残差连接),让信息能绕道直通,深层网络才得以顺利训练。ResNet-152 把 ImageNet 的 top-5 错误率压到约 3.57%,比人还准;而 ResNet-50 只要约 2500 万参数,成了此后多年的骨干主力。
- MobileNet(2017):为手机端量身定做的。核心是深度可分离卷积,把普通卷积拆成两步完成,参数量和计算量都大幅下降,第一代约 420 万参数,能装入移动设备实时运行。
这一路看下来,脉络很清楚:浅层认边角,深层认整体;越往上感受野越大、抽象程度越高;而工程上的较量,一直是怎样在精度和成本之间取得平衡。
八、小模型的处境:端侧为什么到今天还在用 CNN
手机、摄像头、车机这些端侧设备,约束和服务器完全不是一回事:算力有限,内存有限,功耗更是硬性约束。模型运行得快重要,运行得省电同样重要。
CNN 在这类场景有天然优势。它结构规整,卷积、池化这些算子已被各类硬件充分支持——手机芯片里的 NPU、各种推理引擎,都对卷积提供了优先加速。同样一个模型,卷积的硬件支持度通常比许多较新的算子要好得多。再加上它自带"局部性"和"平移不变"的归纳偏置,在小数据上也能取得不错的效果,不像某些新架构那样依赖大量数据。
后来 Vision Transformer 一类的架构也进入了这一领域,在超大数据的加持下精度确实能超过 CNN。可它依赖数据和算力,往端侧迁移时需要先经历量化、剪枝等几个步骤,门槛不低。所以到今天,手机里那个默默承担美颜、扫码、人脸识别的网络,多半还是某个环节上的卷积网络。它不算新颖,但可靠、便宜、运行稳定——在端侧,这就是实实在在的优势。
参考资料
- Yann LeCun, Léon Bottou, Yoshua Bengio, Patrick Haffner, Gradient-Based Learning Applied to Document Recognition, 1998. yann.lecun.com/exdb/publis/pdf/lecun-01a.pdf(LeNet 的原始论文)
- Alex Krizhevsky, Ilya Sutskever, Geoffrey E. Hinton, ImageNet Classification with Deep Convolutional Neural Networks, NeurIPS 2012. papers.nips.cc(AlexNet,深度学习引爆点)
- Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun, Deep Residual Learning for Image Recognition, 2015. arXiv:1512.03385(ResNet 与残差连接)
- Andrew G. Howard 等, MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications, 2017. arXiv:1704.04861(端侧轻量卷积网络)
- Stanford CS231n, Convolutional Neural Networks 课程笔记. cs231n.github.io/convolutional-networks(卷积、池化、感受野的图解)