从像素到汉字:OCR 模型是如何依靠 CNN “学会“识字的?

一篇面向所有对深度学习好奇的朋友的技术分享。本文将以 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. 减少计算量:图缩小一半,后续计算量降为 1/4
  2. 平移不变性:字稍微歪一点、偏移几个像素,池化后特征仍然保留
  3. 抗噪:小范围噪声被过滤

六、层次化特征:越深层,越抽象

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 的"责任"逐层往前推:

  1. 输出层错了 → 调整 FC 层的权重
  2. FC 层的误差 → 继续往前传,调整 Flatten 之前的参数
  3. Conv2 层的误差 → 调整第二层的 Filter 数值
  4. 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 万张字卡、成千上万轮迭代、以及无数个梯度下降步骤的积累。


最后,有任何问题,欢迎一起交流探讨!

相关推荐
努力搬砖的咸鱼1 小时前
意图理解:让Agent从需求描述自动生成Pytest测试策略
人工智能·python·ai·单元测试·pytest·agent
ZJU_统一阿萨姆1 小时前
【推理优化进阶】性能实验科学:工作负载、统计显著性与尾延迟归因
开发语言·人工智能·语言模型·系统架构·vllm
weixin_509138341 小时前
【无标题】
人工智能·agi·智能体·认知动力学·智能体认知
IT_陈寒1 小时前
Java Stream并行处理让我数据库崩了两次
前端·人工智能·后端
2601_956319881 小时前
2026年下半年,量化学习要把交易认知和技术实现接起来
人工智能·python
jay神1 小时前
深度学习为什么需要反向传播
人工智能·深度学习·yolo·目标检测·cnn·毕业设计
zhuyingxiao1 小时前
ChatGPT、Claude Code、Codex 能直接控制泵阀吗?AI Agent 液路监测的正确架构
人工智能·chatgpt·架构
数字孪生视频孪生1 小时前
异构架构赋能三维实时重构 核工危化跨境追踪一屏统揽
大数据·人工智能·重构·空间计算
小唔w1 小时前
学习资料备份:我目前用的三款工具
人工智能