本节摘要:图像识别的难点不在"认出"而在"认准"——光照、视角、遮挡、形变让同一个物体在像素层面千变万化。本节用可复现的小实验说明规则方法与手工特征为何相继触顶,并解释"让特征从数据里学出来"为什么是卷积网络登场的先决条件。它是全册流水线的起点:先看清进料的混乱,才理解后面每一道工序存在的理由。
1990 年代的邮政系统有过一个体面的愿望:让机器自动分拣手写信封。规则很快写出来了——数字"1"是一条竖线,"0"是一个圈。可信封一上手就穿帮:有人把"1"写得带钩,有人把"7"写得像"1",钢笔字洇开、复印件发虚、邮票盖歪压住了数字。每补一条规则,就冒出更多例外。工程师最终承认:识别难,不是因为规则不够多,而是因为像素世界里"同一个东西"变化太大,规则永远追不完。
这个反例值得每个入门者亲眼看一遍。下面的小实验用最朴素的"像素距离"做识别:谁离模板近就是谁。结果会颠覆直觉。
import numpy as np # 造一张 8×8 的斜线图案,模拟一个手写字符的笔画 img = np.zeros((8, 8)) img[2, 2] = img[3, 3] = img[4, 4] = img[5, 5] = 1.0 # 同一个字向右挪一格:人眼看来毫无区别 shifted = np.roll(img, shift=1, axis=1) # 另一个完全不同的图案:一横(与斜线在中间共享一个像素) other = np.zeros((8, 8)) other[3, 2:6] = 1.0 def l2(a, b): return float(np.sqrt(((a - b) ** 2).sum())) print("同一个字挪一格的像素距离:", round(l2(img, shifted), 2)) print("两个不同图案的像素距离: ", round(l2(img, other), 2))
运行结果值得抄在笔记本上:同一个字挪一格,像素距离 2.83;换成一个完全不同的图案,距离反而只有 2.45。像素空间里,"位置变化"造成的差异比"换了字"还大。任何直接在像素上比距离、套规则的方案,都会先被平移这种最无害的变化击倒——这就是图像识别的敌人清单里的第一位,后面还排着光照、旋转、尺度、遮挡与背景干扰。
阅读完本节,你应当能够:
规则方法的隐含假设是:物体的类别与像素值之间存在可以直接写出的对应关系。这个假设在打印体、固定机位、纯色背景的实验室条件下勉强成立,一进真实世界就碎裂。原因可以归结为一条:类内变化远大于类间差异。同一只猫在正午与黄昏的像素差,可能比猫与狗在标准照中的像素差更大。
用一行伪代码概括这类方案:如果图像里有圆形且下方有两条竖线,就输出"人脸"。它的问题不是写不出,而是写不完——圆形可以是脸、是轮子、是满月;两条竖线可以是鼻子、是树干、是门缝。规则之间还会打架,维护成本随规则数超线性增长。业内把这类系统的宿命叫"规则沼泽":越挣扎陷得越深。
研究者很快换了思路:别在像素上较劲,先把图像变换到一组对光照、平移不那么敏感的描述子上,再在描述子上做分类。SIFT 在局部关键点上统计梯度方向直方图,对旋转与尺度有一定容忍;HOG 把图像切成小块,统计每块的梯度分布,特别适合捕捉人体与字符的轮廓。这些手工特征加上 SVM 之类的浅分类器,在 2000 年代撑起了大半个人工视觉系统。
它们确实比裸像素强得多,但用法是"流水线式"的:检测器在图上滑窗,每个窗口提一遍特征,分类器逐窗判决。开销可以算出来,这也正是它跑不快的根源。
# 滑动窗口的账:一张 224×224 的图,找 64×64 的目标 W = H = 224 # 输入边长 win = 64 # 窗口边长 stride = 16 # 步长 scales = 5 # 图像金字塔层数(应对远近大小) per_axis = (H - win) // stride + 1 # 每行可放的位置数 per_scale = per_axis * per_axis # 单尺度窗口总数 hog_dim = 49 * 36 # 64×64 图的 HOG 维度:49 个块,每块 36 维 print("单尺度窗口数:", per_scale) # 121 print("五个尺度总窗口数:", per_scale * scales) # 605 print("每窗口特征维数:", hog_dim) # 1764 print("每图特征总量级:", per_scale * scales * hog_dim) # 约 106 万
每个窗口 1764 维特征、整图 605 个窗口,一帧就要处理上百万维的量级;视频流下更是成倍放大。更要命的是天花板:HOG 数梯度方向,它就永远看不见"梯度直方图没编码的语义";SIFT 数关键点,纹理弱的物体它就没辙。特征是人定的,识别的上限就被人锁死了。 研究者不是没想过自动组合特征,但在深度网络成熟之前,没人能让"特征学习"这件事可优化、可规模化。
转折点的想法朴素得惊人:既然特征难设计,就把它变成参数,让优化算法从数据里学。问题只剩一个——什么样的网络结构能让"学特征"这件事高效?答案是卷积神经网络:它的局部连接限制了每个神经元只看一小块区域,权值共享让同一套检测模式在整个图像上复用。这两条设计在下一节展开,这里只需记住分工:手工特征时代,人负责"看什么";学习时代,人只负责"怎么学",看什么交给梯度下降。
2012 年 ImageNet 竞赛上,卷积网络把冠军错误率一下子拉到比第二名低十个百分点以上,靠的不是更多规则、更精的特征,而是数据与算力喂出来的端到端学习。从那以后,图像识别的技术栈整体迁到了"数据进、特征出、分类头上"的新流水线上。
| 方案 | 特征来源 | 对平移与光照 | 维护方式 | 上限 |
|---|---|---|---|---|
| 规则系统 | 人写条件分支 | 极差,规则互相打架 | 加规则,规则沼泽 | 实验室条件 |
| 手工特征 + 浅分类器 | 人设计描述子 | 中等,看特征设计 | 换描述子、调核 | 特征设计者的想象力 |
| 卷积网络 | 从数据端到端学习 | 好,逐层抽象消化变化 | 加数据、调结构 | 数据与算力的边界 |
⚠️ 常见误判:把"深度学习赢了"归因于模型更聪明。真实因果是——特征学习把"设计特征"的人力成本换成了"标注数据 + 算力"的成本,而后者在 2010 年代恰好开始规模化。没有这个前提,再好的结构也无人问津。
下一节走进入线检查区的第二站:卷积网络究竟靠哪两条设计原则,把"学特征"变成了划算的买卖。