用 CRNN + CTC 搞定文字验证码!附 PyTorch 训练 + ONNX 加速部署
📌 非恶意自动化提示:本文及配套工具仅供技术学习交流/非敏感场景的合规自动化测试使用,请遵守《网络安全法》及目标网站的 robots 协议/使用条款。
📂 项目地址:VerificationCodeRecognition
1. 核心背景回顾
文字验证码通常具有字符粘连、倾斜、没有固定分割线的特点,传统的“先分割再分类”方案(比如 YOLO 切割 + 单字符识别)在这类场景下很容易翻车——一旦分割出现偏差,后续识别就会一错到底。
相比之下,CRNN + CTC Loss 是一种无分割、端到端的经典方案,尤其擅长处理序列化的视觉识别任务。三个核心组件分工明确:
- 🧠 CNN(卷积神经网络):把输入图像“拍扁压缩”,提取笔画、纹理等局部视觉特征,生成高度抽象的特征图。
- 🔄 双向 LSTM(循环神经网络):在特征序列上建模字符间的上下文依赖,避免出现类似 “a-q-q-h” 这样不合逻辑的组合。
- 📏 CTC Loss:免去人工标注每个字符的位置,直接根据预测序列和标签序列自动对齐并计算损失,完美解决不定长序列的训练问题。
2. 开发环境快速搭建
基础要求
别用太老的版本,本项目用到了新特性:
- Python: 3.6+
- 深度学习框架: PyTorch 2.0+(建议安装 CUDA 版本,训练速度提升巨大)
- 推理加速: ONNX Runtime(CPU / GPU 均可)
一键安装依赖
3. 数据集准备三步走
验证码识别是一个标准的监督学习任务,数据质量直接决定识别率的上限。
3.1 获取数据
仓库作者提供了一套预设的 4 位纯英文小写字母验证码(例如 aqqh_157845.jpg),可以直接用于练习:
👉 蓝奏云预设数据集
如果你要针对自己的业务场景(如数字 + 大写字母 + 中文混合),则需要自行生成或收集合规的脱敏数据。
3.2 数据存放与命名规范
图片存放路径和命名规则必须保持一致,否则读取逻辑会出错。
- 将所有图片放入根目录下的
data文件夹。 - 文件命名格式为:
真实标签_唯一标识.jpg/png(唯一标识可以是时间戳、序号等,避免重名覆盖)。
正确目录结构示例:
3.3 自定义读取逻辑(可选)
如果你的图片格式、路径或命名方式完全不同,可以修改 tool/dataloader.py 中的 MyDataset 类,适配自己的数据加载流程。
4. 模型训练指南
训练过程中会自动记录:训练集损失(total_loss)、训练集准确率(acc),以及验证集的损失和准确率(若开启了验证)。
4.1 修改核心配置
打开 train.py 开头的 Opt 类,按需调整以下参数:
4.2 启动训练
直接运行即可:
4.3 何时停止训练
不要盲目追求无限迭代,当以下指标趋于稳定时就可以收手了:
- 训练集
acc接近 100%(模型已经充分拟合训练数据) - 验证集
val_acc稳定在 95% 以上(针对纯字母预设数据集),且不再明显波动,避免过拟合
训练好的模型权重会保存在根目录的 expr 文件夹中。
5. 推理与生产级部署
A. 原生 PyTorch 推理(适合开发调试)
适合训练过程中快速验证效果,无需额外格式转换:
耗时参考:纯 CPU 环境约 30-35ms/张,使用 NVIDIA 显卡(如 RTX 2060)约 3-5ms/张。
B. ONNX 加速推理(生产环境首选)
原生 PyTorch 在 CPU 上的推理速度较慢,但导出为 ONNX 格式后,配合 ONNX Runtime 可以获得 3-4 倍 的加速。
1. 导出 ONNX 模型
导出成功后,在 expr 目录下会生成 crnn.onnx 文件。
2. 使用 ONNX 推理
耗时参考:纯 CPU 环境约 7-10ms/张,几乎可以媲美中低端显卡的推理速度。
6. 进阶优化小技巧
6.1 字符字典适配
如果你的验证码包含数字、大写字母、特殊符号甚至中文,一定要第一时间更新 tool/charactes_keys.txt。把可能出现的所有字符按固定顺序写进去,且不能有重复。
6.2 数据增强突破瓶颈
当识别率卡在 90% 左右难以提升时,试试在 tool/dataloader.py 的 MyDataset 类中的 __getitem__ 方法里加入以下增强操作:
- 随机旋转
- 添加高斯噪声或椒盐噪声
- 随机调整对比度、亮度
- 轻微的仿射变换(平移、缩放、倾斜)
6.3 预训练微调省时省力
如果从头开始训练收敛太慢,可以先找一个通用文字识别预训练模型(例如只识别英文的 CRNN 模型),再用你自己的业务数据进行微调,收敛速度会明显加快。
搞定!按照这套流程走下来,你就能拥有一个属于自己的文字验证码识别小工具了。如果在使用中遇到问题,欢迎去项目的 GitHub 仓库提 Issue~

