一篇面向所有对深度学习好奇的朋友的技术分享。本文将以 OCR(光学字符识别)系统为例,拆解其中的 CNN 识别模块是如何被"训练"出来的------它怎样从 140 万张字形样本中自动学会"看"懂笔画、组合出特征、最终输出汉字概率。文中网络参数(Filter 数量、尺寸等)均为便于理解的示例,实际应用中可灵活调整。

一、OCR 系统的"分工":CNN 只负责"认字",不负责"找字"
一套完整的 OCR 系统通常分为两大阶段:
┌─────────────────────────────────────────────────────────────┐
│ 第一阶段:预处理(找字 + 切字) │
│ ───────────────────────────────────────────────────────── │
│ 灰度聚类 → 生成 Mask → 连通域分析 → 裁剪归一化 │
│ (把整张大图切成一个个 32×32 的单字小图) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 第二阶段:CNN(认字) │
│ ───────────────────────────────────────────────────────── │
│ 输入:32×32 单字灰度图 │
│ 输出:这是"中"字的概率 92%,"申"字的概率 4%...... │
│ (靠 140 万张样本训练出来的"认字大脑") │
└─────────────────────────────────────────────────────────────┘
CNN 在 OCR 中的角色非常明确:它不管字在图片的哪个位置、怎么切出来的,它只接过一张已经框好的单字小图,输出"这个字是什么"的概率分布。
接下来,我们就走进这个"认字大脑"的内部,看看它是怎么被训练出来的。
二、训练之前:CNN 什么都不会
在训练开始前,CNN 里面的所有 Filter(那些 3×3 的小窗口)里面填的都是随机数。它就像一个刚出生的小孩,看着一张"中"字的图片,完全不知道这是什么。
它的"学习"过程,本质上是通过反向传播算法,不断调整每个 Filter 里的数字,让它在看到"中"字时输出高概率,看到"申"字时输出低概率。
三、输入:对 CNN 来说,一张字就是一张数字表格
一张 32×32 的灰度单字图,在 CNN 眼里是一个 32×32 的矩阵,每个格子是 0~255 的整数:
列0 列1 列2 列3 列4
行0: 255 255 255 255 255 ← 255 = 白色(背景)
行1: 255 255 0 255 255 ← 0 = 黑色(笔画)
行2: 255 255 0 255 255
行3: 255 255 0 255 255
行4: 255 255 255 255 255
CNN 的所有操作,都是在这张数字表格上进行的。
四、卷积:用"小窗口"扫描,收集笔画证据
4.1 Filter 是什么?
CNN 的核心组件叫 Filter (滤波器/卷积核),是一个 3×3 的小窗口,里面填着可学习的数字。
比如一个竖线检测器在训练初期是随机数,训练后会变成类似这样:
Filter (训练后的竖线检测器):
[-1, 2, -1]
[-1, 2, -1]
[-1, 2, -1]
注意 :这些数字不是人设计的,是 CNN 从 140 万张样本中自动学出来的。
4.2 卷积 = 滑动窗口做"点积"
Filter 从左上角开始,一步一步向右、向下滑动 ,每到一个位置就做逐元素相乘再相加:
output[i, j] = Σ_m Σ_n input[i+m, j+n] × filter[m, n]
举个例子:
输入区域(3×3,中间一竖是黑色笔画):
255 0 255
255 0 255
255 0 255
Filter(竖线检测器):
-1 2 -1
-1 2 -1
-1 2 -1
计算结果的绝对值很大,说明 Filter 在这里检测到了竖线。
4.3 Feature Map:一张"热力图"
Filter 滑过整张图后,生成一张 Feature Map(特征图):
- 值很大的位置 → 该特征出现的地方
- 值接近 0 的位置 → 这里没有该特征
第一层通常有几十个 Filter,就会输出几十张 Feature Map,分别检测竖线、横线、斜线、左边缘、右边缘等。
五、池化:把图缩小,让网络"不那么较真"
卷积之后接 MaxPool 2×2:
输入: [120, 80] MaxPool → [150]
[150, 90]
保留 2×2 区域里的最大值,其余扔掉。作用:
- 减少计算量:图缩小一半,后续计算量降为 1/4
- 平移不变性:字稍微歪一点、偏移几个像素,池化后特征仍然保留
- 抗噪:小范围噪声被过滤
六、层次化特征:越深层,越抽象
CNN 的精髓在于逐层组合特征,就像人类认字一样:
| 层级 | 输入 | 学到的特征 | 类比人类认字 |
|---|---|---|---|
| Conv1 | 原始像素 32×32 | 低级特征:竖线、横线、斜线、点 | 先看笔画 |
| Pool1 | 特征图 | 尺寸缩小,保留最强响应 | 忽略细节 |
| Conv2 | 缩小后的特征图 | 中级特征:十字交叉、口字框、偏旁 | 再看结构 |
| Pool2 | 特征图 | 再次缩小 | 进一步抽象 |
| Flatten | 多维特征图 | 拉成一条证据向量 | 整理线索 |
| FC + Softmax | 证据向量 | 输出各类别概率 | 做出判断 |
具体例子:识别"中"字
- Conv1:检测到"有竖线""有横线""有外框"
- Conv2:组合出"有十字交叉""有口字框"
- FC 层:综合证据 → "十字交叉 + 口字框 = 很可能是『中』字"
- Softmax:输出概率 → 中: 0.92, 申: 0.04, 田: 0.02......
七、CNN 是怎么"学会"的?------ 训练过程揭秘
7.1 训练数据:140 万张"字卡"
要训练 CNN 认字,需要准备大量带标签的单字图片:
| 图片内容 | 标签 |
|---|---|
| 各种字体的"中"字 | "中" |
| 各种字体的"国"字 | "国" |
| 各种字体的"A" | "A" |
| ...... | ...... |
这些样本会经过数据增强:随机旋转、缩放、加噪、模糊等,让 CNN 见过各种"变形"的字,提高泛化能力。
7.2 前向传播:猜一次
把一张"中"字图片输入 CNN,它随机初始化的大脑会胡乱猜:
第一次猜测:中: 0.15, 申: 0.20, 田: 0.30, 甲: 0.35...
显然错得很离谱。
7.3 计算损失:错得有多离谱
用 交叉熵损失函数(Cross-Entropy Loss)衡量预测与真实标签的差距:
Loss = -log(预测为"中"的概率)
如果预测"中"的概率只有 0.15,Loss 就很大;如果预测 0.92,Loss 就很小。
7.4 反向传播:调整 Filter 里的数字
这是训练的核心。通过链式法则,把 Loss 的"责任"逐层往前推:
- 输出层错了 → 调整 FC 层的权重
- FC 层的误差 → 继续往前传,调整 Flatten 之前的参数
- Conv2 层的误差 → 调整第二层的 Filter 数值
- Conv1 层的误差 → 调整第一层的 Filter 数值
梯度下降公式:
新参数 = 旧参数 - 学习率 × (Loss 对参数的梯度)
每一次调整,都让 CNN 在下一次看到"中"字时,输出"中"的概率稍微高一点点。
7.5 重复 140 万次
把 140 万张样本轮流喂给 CNN,反复进行:
前向传播 → 算 Loss → 反向传播 → 更新参数
经过成千上万轮(Epoch)训练后,Filter 里的随机数逐渐被"雕刻"成有意义的模式:
- 某个 Filter 变成了竖线检测器
- 某个 Filter 变成了横线检测器
- 某个 Filter 变成了十字交叉检测器
- ......
最终,CNN 从"什么都不会"变成了"训练正确率 99.7%"的认字专家。
八、CNN 的两大核心机制
8.1 局部连接:只看"邻居"
判断"这里有没有竖线"只需要看周围 3×3 的像素,不需要看整张图。每个 Filter 只有 9 个参数,相比全连接网络的"每个神经元连所有像素",参数量减少了几十倍。
8.2 权重共享:一把尺子量到底
同一个 Filter 在整张图上滑动扫描,所有位置共用同一组权重。无论竖线出现在左上角还是右下角,同一个检测器都能抓到。
九、常见误区澄清
Q:CNN 的 Filter 数量、尺寸、层数是固定的吗?
A:不是。 这些都是超参数,可根据任务灵活调整:
| 参数 | 本文示例 | 实际常见范围 |
|---|---|---|
| Filter 数量 | 32, 64 | 16 ~ 512 |
| Filter 尺寸 | 3×3 | 1×1, 3×3, 5×5, 7×7 |
| 网络深度 | 4 层 | 2 ~ 50+ 层 |
| 输入尺寸 | 32×32 | 28×28, 64×64, 224×224 |
本文用 32 个 Filter、3×3 等数字仅为方便讲解原理。实际搭建时,这些数字完全可以根据数据量、计算资源和精度需求来调整。
十、总结
┌─────────────────────────────────────────────────────────────┐
│ OCR 系统完整流程 │
│ ───────────────────────────────────────────────────────── │
│ 整张大图 → 预处理(找字、切字)→ 32×32 单字图 │
│ ↓ │
│ CNN "认字大脑"(经 140 万样本训练) │
│ • Conv1:学到竖线、横线等笔画检测器 │
│ • Pool1:缩小图,获得平移不变性 │
│ • Conv2:学到十字交叉、口字框等组合特征 │
│ • Pool2 + Flatten:整理所有证据 │
│ • FC + Softmax:综合判断,输出概率 │
│ ↓ │
│ 输出:"中"字概率 92%,"申"字概率 4%...... │
└─────────────────────────────────────────────────────────────┘
核心思想 :OCR 里的 CNN 不是天生会认字,而是从海量样本中通过反向传播一点点"雕刻"出 Filter 的权重。它逐层提取"有没有竖线 → 有没有十字 → 像不像中字"的证据链,最终在输出层做概率投票。训练正确率 99.7% 的背后,是 140 万张字卡、成千上万轮迭代、以及无数个梯度下降步骤的积累。
最后,有任何问题,欢迎一起交流探讨!