AI-深度学习

嵌入式视觉模型进阶 23:OCR 识别:序列模型与 CTC

展开合集目录
  1. 嵌入式视觉模型进阶 01:怎样读懂一个实际模型
  2. 嵌入式视觉模型进阶 02:卷积进阶:分组、深度、逐点与空洞卷积
  3. 嵌入式视觉模型进阶 03:MobileNet:深度可分离卷积与倒残差
  4. 嵌入式视觉模型进阶 04:通道注意力与 MobileNetV3
  5. 嵌入式视觉模型进阶 05:ShuffleNet:通道拆分与重排
  6. 嵌入式视觉模型进阶 06:结构重参数化:训练分支怎样合为一个卷积
  7. 嵌入式视觉模型进阶 07:Backbone、Neck、Head 与多尺度特征
  8. 嵌入式视觉模型进阶 08:FPN 与 PAN:怎样融合不同尺度的信息
  9. 嵌入式视觉模型进阶 09:检测头:分类、位置与置信度
  10. 嵌入式视觉模型进阶 10:检测训练:标签分配与损失计算
  11. 嵌入式视觉模型进阶 11:完整 YOLOv8 推理:从图片到原图目标框
  12. 嵌入式视觉模型进阶 12:训练自己的检测器与错误分析
  13. 嵌入式视觉模型进阶 13:检测器导出对照与其他结构路线
  14. 嵌入式视觉模型进阶 14:跟踪基础:运动预测、匹配与轨迹生命周期
  15. 嵌入式视觉模型进阶 15:ByteTrack 思路:用低分框恢复已有轨迹
  16. 嵌入式视觉模型进阶 16:外观特征与 ReID:怎样比较两个目标
  17. 嵌入式视觉模型进阶 17:目标跟随:从轨迹到云台控制接口
  18. 嵌入式视觉模型进阶 18:视频系统:队列、时间戳与异步流水线
  19. 嵌入式视觉模型进阶 19:人脸处理流程:检测、关键点与对齐
  20. 嵌入式视觉模型进阶 20:特征识别:人脸向量、相似度与阈值
  21. 嵌入式视觉模型进阶 21:人体关键点与姿态估计
  22. 嵌入式视觉模型进阶 22:OCR 检测:从文字区域到矫正图片
  23. 嵌入式视觉模型进阶 23:OCR 识别:序列模型与 CTC
  24. 嵌入式视觉模型进阶 24:完整 OCR 流程与识别错误分析
  25. 嵌入式视觉模型进阶 25:轻量语义分割与实例分割
  26. 嵌入式视觉模型进阶 26:工业异常检测:缺陷样本少时怎么办
  27. 嵌入式视觉模型进阶 27:深度估计与图像恢复:两个专题入口
  28. 嵌入式视觉模型进阶 28:面向 NPU 的计算图与算子兼容
  29. 嵌入式视觉模型进阶 29:量化、蒸馏与剪枝的实际取舍
  30. 嵌入式视觉模型进阶 30:综合项目:检测、跟踪与云台跟随验收
嵌入式视觉模型进阶 23:OCR 识别:序列模型与 CTC的封面

第 23 / 30 课。 前置:上一课。本篇的运行范围以实验说明和验证记录为准,构造样例不代表真实任务精度或板端性能。

一张长图片怎样变成序列

卷积输出 [N,C,H,W],可以沿高度聚合后把宽度 W 作为时间轴,得到 [N,T,C]。这要求保留沿文字方向的位置关系,不能把全部空间平均成一个向量再期待识别任意长文本。

RNN 用递归状态传递历史,LSTM 使用门控与细胞状态,GRU 使用较紧凑的门控结构。双向网络同时看左右上下文,适合整行离线识别,但不能直接作为不看未来的流式模型。本课用双向 GRU 实现最小可运行结构。

CTC 解决的是对齐未知

标注只给字符串,没有给每个时间步对应哪个字符。CTC 对合法对齐路径求和,引入 blank 并允许字符重复占据多个时间步。它不是一种循环网络,也不要求一定搭配 RNN。

贪心解码顺序是先合并连续重复,再移除 blank。例如 A,A,blank,A,B,B 得到 AAB;若先移除 blank 再合并,会错误变成 AB。字符表、blank 索引与空格是否在词表中必须与权重一致。

运行与长度检查

脚本使用 [2,1,16,32] 构造输入,CNN 将时间长度变为 16,输出 [T,N,4] 的 log probabilities;目标是 AB 与 AA。连续重复目标需要 blank 隔开,因此最小时间长度还与重复字符数相关。

设置 zero_infinity 并不能代替长度检查;它可能把无效样本损失置零,掩盖标签错误。本课保留默认错误暴露并检查损失、梯度有限。

练习

把贪心序列中的 blank 删除,解释为什么结果变化。把输入宽度缩得过小,观察 AA 的对齐是否仍可行。参考结论:时间轴必须容纳标签及必要的重复分隔,宽度缩放策略直接影响可识别长度。

本实验只执行一个训练步,随机权重没有文字识别能力;完整流程还需要词表、数据、训练与独立评估。

配套实验与运行记录

实验:OCR 识别:序列模型与 CTC

查看完整代码:main.py
"""把图像宽度变为时间轴,运行小型 CNN-GRU-CTC 训练步并验证解码顺序。"""

import torch
from torch import nn


def greedy(ids, alphabet):
    result = []
    previous = None
    for index in ids:
        if index != previous and index != 0:
            result.append(alphabet[index])
        previous = index
    return "".join(result)


class CRNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.cnn = nn.Sequential(
            nn.Conv2d(1, 8, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2)
        )
        self.rnn = nn.GRU(8, 12, batch_first=True, bidirectional=True)
        self.head = nn.Linear(24, 4)

    def forward(self, x):
        features = self.cnn(x).mean(2).transpose(1, 2)
        sequence, _ = self.rnn(features)
        return self.head(sequence).log_softmax(-1).transpose(0, 1)


def main():
    torch.manual_seed(7)
    torch.set_num_threads(2)
    net = CRNN()
    output = net(torch.rand(2, 1, 16, 32))
    targets = torch.tensor([1, 2, 1, 1])
    loss = nn.CTCLoss(blank=0)(
        output, targets, torch.tensor([16, 16]), torch.tensor([2, 2])
    )
    optimizer = torch.optim.Adam(net.parameters(), lr=0.001)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    assert torch.isfinite(loss) and all(
        p.grad is not None and torch.isfinite(p.grad).all() for p in net.parameters()
    )
    result = greedy([1, 1, 0, 1, 2, 2], ["", "A", "B", "C"])
    assert result == "AAB"
    print("output TNC", list(output.shape), "loss", loss.item(), "greedy", result)


if __name__ == "__main__":
    main()
下载代码

在项目根目录执行;下载包解压后,在解压目录执行 python3 main.py。

cd 'content/posts/AI-深度学习/嵌入式视觉模型进阶/23-OCR 识别/code' && python3 main.py

在本篇代码目录执行 python3 main.py。依赖安装、可选入口见包内 README.md;实际运行结果见 verification.md。下载包包含本课使用的辅助模块与样例。

参考与进一步阅读

原始论文或官方文档用于核对结构、接口和适用范围。本篇代码是围绕教学目标编写的最小实验;除明确注明的完整入口外,不视为对应论文模型的完整复现。


完整进阶目录 · 入门系列 · 上一篇 · 下一篇