资讯详情

资讯详情

PaddleOCR模型训练实战:从微调数据准备到部署上线

上篇我们聊完PaddleOCR的安装和官方模型直接跑通识别这篇接着把怎么训练自己的模型这层窗户纸捅破。标题挂着AI6-PaddleOCR模型训练2其实就是想写当你真拿一批自己的图片去微调PaddleOCR时会遇到什么、要准备什么、哪些参数能改、哪些坑别踩。PaddleOCR这套框架发展到现在官方预训练模型已经能扛住绝大多数印刷体场景但真到自己的业务数据上——比如特殊字体、扭曲文本、生僻字、票据印章——还是得走一遍自己的模型训练流程。这篇就按我实际跑项目的顺序把从数据准备到部署上线的完整链路拆开讲。先说清楚一个认知你不需要从零训练一个OCR模型。所谓训练自己的模型绝大多数情况下是拿官方预训练模型做微调。PaddleOCR之所以能省那么多算力靠的就是预训练模型打底这也是为什么网上搜resnet预训练模型、各种backbone权重时一定要分清它是主干网络权重还是完整训练好的检测/识别模型。1. 什么场景下官方模型真的不够用1.1 官方模型为什么会在你的数据上失灵PP-OCR系列的识别模型在通用印刷体中文、英文、数字上已经做得非常成熟但它的训练数据分布和你业务数据的分布大概率不是一回事。我遇到过三类典型场景第一类是字符集外。官方模型的字典是常见简体中文字符、英文字母、数字但你的场景里有生僻字、特殊符号、计量单位比如㎥、²模型在推理时只能给一个相似字或者乱码。第二类是字体和排版偏移。比如古籍里的繁体竖排、手写体、艺术字、带干扰线的验证码通用模型识别率会直线下降。第三类是检测环节出错。PaddleOCR是先检测文本框再识别内容如果你的版面是表格、印章、倾斜透视文本检测框画不准后面识别再强也白搭。这时候你去调推理参数、换后处理阈值天花板就在那最实际的路径就是自己训练。训练的目标不是超越官方模型而是让模型拟合你的数据分布。1.2 训练的本质是微调不是从零造轮子第一次接触模型训练的人最容易产生我要从零写网络、从零训权重的误解。实际上PaddleOCR的训练脚本里pretrained_model这个参数就是干这个的把官方在超大数据集上训练好的权重作为初始值只在你自己的数据上继续迭代。这跟学骑车先有个大人扶着是一个道理你只需要调整平衡不需要重新发明轮子。所以在动手之前先想清楚两件事你要解决的是检测问题还是识别问题还是两者都要重新训检测模型负责文本在哪识别模型负责文本是啥。很多项目只需要重新训识别模型检测直接用官方的。你的数据量和标注质量能不能支撑微调识别模型最低也得有几千张有效标注否则你训出来的模型只会过拟合到你那几十张图上。想明白这两点再往下走。2. 训练前的数据准备格式、标注、字典2.1 千万别把检测和识别任务的标注搞混PaddleOCR中检测任务和识别任务的数据格式完全不同这是新手第一道坎。识别模型REC的训练数据格式非常朴素每行就是图片路径 标签文本标签文本是你要让模型识别出来的字符串注意中间用制表符\t分隔图片路径和标签之间不能有空格。如果标签里本身带空格比如英文句子就要用制表符来分隔路径和标签标签内的空格保留。检测模型DET则要复杂得多它需要标注文本框的四个角点图片路径 [{points: [[x1, y1], [x2, y2], [x3, y3], [x4, y4]], transcription: GT文本, ignore: false}, ...]这里的points是四边形四个顶点顺序要按顺时针或逆时针保持一致不要求矩形框多边形也能处理。transcription是对应的文本内容检测训练时它会参与损失计算ignore标记为true的框算作应忽略区域。我见过有人把识别模型的数据喂给检测模型训练直接报shape错一看就是没搞清楚这个区别。建议动手前先分别跑一遍官方给的快速开始示例确认两种数据格式各自长什么样。2.2 标注工具与字符字典推荐直接用PaddleOCR自带的PPOCRLabel工具做标注它和检测/识别的数据格式天然兼容你标完导出就是上面那个JSON格式。手动改JSON效率极低而且容易格式错误。识别模型训练前还需要一个dict.txt字符字典它的每一行代表一个字符顺序就是模型输出层softmax的索引顺序。这里有几个常见的坑字典里不能有重复字符否则两个索引对应同一个字符训练目标就乱了。字典里必须包含blank符号吗识别模型的CTC解码里blank字符是内置的不需要在dict里手动加但PaddleOCR的配置里会用character_dict_path指向一个纯字符列表。中英文混排场景尤其要注意全角、半角字符都算不同字符比如和A不是一个东西。空格要不要进字典如果你有英文句子空格必须进字典否则推理时所有空格都会被去掉。生成字典最稳妥的方式是遍历所有训练标注文本把所有出现过的字符去重后按频率排序写进dict.txt。频率排序的好处是可以把高频字符排在前面对模型收敛有一定的正面影响。2.3 多少数据才够用官方模型微调的最低数据量识别模型我建议每个字符至少出现10次以上总体样本五六千张起步比较稳。检测模型对数据量的要求更高因为目标框的形状变化太丰富一万张是及格线五万张才能谈效果。如果你的数据远低于这个量级先别急着砸时间和算力优先做两件事加数据增强。PaddleOCR训练配置里自带RecAug、RandAugment等增强策略可以轻微旋转、缩放、颜色扰动、噪声叠加。增强不要做得太过比如旋转超过30度印刷体文本识别就基本没人能看懂了。从网上找公开的开源OCR数据集补充进来混合训练。这样虽然增加了点噪声但能显著缓解过拟合。3. 环境与平台本地GPU与在线训练怎么选3.1 本地环境搭建里最容易被忽略的版本问题如果你有NVIDIA显卡优先装GPU版PaddlePaddle。PaddleOCR官方文档对CUDA版本有明确要求但很多人在这一步翻车原因就一个字版本漂移。这里敲黑板划重点paddlepaddle-gpu、CUDA、cuDNN、GPU驱动的版本必须对齐。比如你装paddlepaddle-gpu2.5.x对应CUDA 11.7如果机器上只有CUDA 11.2或者驱动太老训练时就会出现无法定位cuDNN库或者直接报Out of memory但显存明明是够的。建议严格照官方安装表格装别凭感觉选最新版本。装好Paddle之后PaddleOCR本身用pip安装即可但训练需要把源码仓库克隆到本地因为训练脚本、配置文件、工具脚本都在仓库里。很多人只pip了paddleocr包就去找train.py结果半天找不到——paddleocr是个推理库训练源码要另外拿一份。3.2 免费GPU在线平台的实操体验没有本地GPU的同学也别灰心现在有几个免费的GPU训练平台可以白嫖比如AI Studio、Kaggle Notebooks。但在线训练有几个具体问题要注意会话断开。在线平台的GPU实例不是永久的长时间没有操作会自动回收训练到一半断掉是家常便饭。所以训练一定要配eval和save_model的周期策略每几百个迭代存一次checkpoint断了也能从最近断点接着跑。数据上传。几十GB的数据在Notebook环境里上传很痛苦。建议做好数据集后先打包成压缩文件传上去再在代码里解压别一个文件一个文件拖。路径不要写死。在线平台的挂载路径和你本地一定不一样配置文件里的Global.train_data_dir、Global.epoch_num这些路径参数到了平台必须改。我自己比较推荐的做法是代码和配置先在本地调通用CPU跑个几十步验证数据管道再整个项目目录上传在线平台用GPU跑正式训练。先在本地用少量数据跑通流程能省掉大量在平台上调试的时间——在线平台调试一次就要排队等GPU很烦。3.3 本地和在线选哪个维度本地GPU在线GPU平台硬件成本一次性投入高免费额度够用调试便利性随时改随时跑排队等待、会话易断隐私安全数据不出门数据要上传第三方长时间训练稳定有会话时长限制如果你的数据涉及敏感信息比如票据、医疗报告即便在线平台有隐私承诺我仍然建议本地训练。数据安全这条线永远不要指望平台的自律。4. 配置文件里的每个参数到底干什么的4.1 认识PaddleOCR的config体系yaml文件就是你的训练蓝图PaddleOCR训练不是靠命令行传几百个参数而是靠一个yaml配置文件把所有东西都管起来。打开configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml你会看到五大块Global、Architecture、Loss、Optimizer、Metric、Dataset。其中Dataset又分Train和Eval两个子配置。对于首次训练核心关注这几个参数Global.epoch_num训练轮数。识别模型一般80到150轮就能收敛不是越多越好跑太久反而过拟合。Global.pretrained_model预训练权重路径。这里填官方发布的识别模型训练权重ch_PP-OCRv3_rec_train之类的它会作为初始权重加载。如果你不填就是从零训练代价是训练时间成倍增加、效果还差。Global.use_gpu是否用GPU。没GPU的机器记得设成false。Optimizer.lr学习率。这是所有参数里最敏感的微调阶段一般设0.0005到0.001比从零训练低一个量级因为预训练权重已经在好位置附近了学习率太大会把权重踢出好区域。Optimizer.batch_size.per_device每张卡上的批大小。受显存限制识别模型一般16到64检测模型一般8到16。Dataset.Train.data_dir和label_file_list你的训练图片目录和标注文件路径。Dataset.Train.transforms数据增强。新手建议先用RecAug默认配置不要上来就自定义。4.2 识别模型和检测模型的关键差异识别模型是看图识字输入是已经裁剪好的文本行图像输出是字符串检测模型是找字在哪输入是整张图输出是一堆多边形框。两者在配置上的差异主要体现在网络结构识别模型用MobileNetV3或PP-LCNet做backbone加CTC解码器检测模型用DB或DB结构。你搜到的resnet预训练模型通常指这两种结构里的backbone预训练权重替换Architecture.backbone相关配置即可但整体微调时直接用官方整个模型的权重就包含了backbone的部分不需要单独处理resnet权重。输入尺寸识别模型输出的是文本行宽度可以动态变化所以rec_img_shape一般是[3, 48, 320]这样高固定宽可变的检测模型输入则是[3, 736, 1280]这类固定整图尺寸。loss识别模型用CTCLoss检测模型用DBLoss。自己改配置的时候别改串了。4.3 训练命令与一个能跑的baseline环境就绪、数据就绪后训练命令极简cd PaddleOCR # 识别模型训练 python tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml # 如果想在默认配置上覆盖某些参数用 -o 追加 python tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml \ -o Global.epoch_num100 \ Optimizer.batch_size.per_device32 \ Global.pretrained_model./pretrain_models/PP-OCRv3_train首次训练我建议先用-o把epoch_num压到10把batch_size压到4在CPU上跑几十步目的是验证数据管道通畅能正常读图、正常算loss、正常存checkpoint。这一步跑通再上GPU全量训练能帮你省半天时间。5. 报nan、显存爆掉、loss僵死训练现场的真实问题5.1 训练过程怎么读日志训练一旦开始终端会滚动输出训练日志核心看这几列loss总损失训练初期应该在2到5之间波动然后逐步下降。如果loss从几千上万开始说明学习率大了或者数据有异常。lr当前学习率会随scheduler变化。acc识别模型的字符准确率最终希望到0.9以上打印字符级别但注意这只是训练集上的评估集要单独看。日志里的loss在训练初期轻微浮动是正常的不用焦虑。但如果你发现loss从第一轮开始就在上升那不是预热大概率是配置出问题了。5.2 模型训练报nan的完整排查思路模型训练报nan这个搜索词常年高居热榜因为太常见了。我总结一套排查链路按顺序看先查学习率。学习率过大是nan的第一原因尤其是从头训练没加载预训练的时候。微调一般0.0005不会炸如果你设了0.01还带动量炸的概率非常高。先把学习率降到0.0001试一次。查数据里有没有异常值。图片损坏、全黑图、标注文件里多了不可见字符都会让loss失稳。用脚本遍历图片和标注把打不开的图、空标签样本挑出来删掉。查梯度裁剪。配置里有grad_clip相关选项把它设上比如max_norm5能防止梯度爆炸导致的nan。这招治标不治本但它能让你先排除梯度问题。关混合精度。如果你开启了AMP混合精度在某些低端GPU上会因为fp16精度溢出导致nan。把Global.amp相关配置关掉再试。查预训练权重是否匹配。加载了错误的预训练权重比如用检测模型权重初始化识别模型前向传播会直接崩掉loss输出nan。检查配置里的通道数和类别数是否一致。我印象最深的一次nan折腾了三个小时最后发现是标注文件里的标签有个\u3000全角空格模型把它当成一个不存在的字符索引直接炸掉。所以数据清洗比调参更重要这句话我想加重显示。5.3 显存不够和data loader崩溃显存不够OOM就两点降batch_size、降输入图片尺寸。识别模型把batch_size从64降到16是很正常的不要觉得丢人跑得稳比跑得快重要。data loader崩溃常见现象是训练刚开始就报一堆worker错误。在Windows上尤其常见因为PaddleOCR默认的dataloader会拉起多个子进程Windows进程模型和Linux不一样容易挂。临时方案是把dataloader_num设成0强制在主线进程里读数据性能会打折扣但至少能跑起来长期方案是换到Linux环境训练这确实是最省心的路线。6. 从checkpoint到部署评估、导出与C落地6.1 评估指标怎么判断模型能不能用训练过程中脚本会定期做评估输出metric结果。识别模型主要看acc字符准确率和norm_edit_dis归一化编辑距离检测模型看precision、recall和hmeanF1。光看这些还不够拿到checkpoint后我会写一个几十行的推理脚本挑二三十张最难的真实图跑一遍肉眼看输出结果。训练日志上的acc高不等于业务上能用尤其在样本类别不均衡时模型可能只学会了高频字符。此时你该做的是按字符统计识别错误找出错误最集中的是哪些字符。回到数据把这类字符的样本补足重新微调一轮。这是OCR效果调优最朴素也最有效的手段我在几个项目里都是这么把准确率从85%拉到97%的。6.2 导出inference模型训练得到的checkpointbest_accuracy.pdparams默认是PaddlePaddle的动态图格式推理前要先转成inference模型静态图这样部署时才不需要加载训练时那些冗余配置。# 识别模型导出示例 python tools/export_model.py \ -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml \ -o Global.pretrained_model./output/best_accuracy \ Global.save_inference_dir./inference/rec_model导出后inference目录下有inference.pdmodel和inference.pdiparams两个文件这才是部署真正用的东西。用tools/infer/predict_rec.py验证一下导出的inference模型和训练时的预测结果一致再拿去部署很多部署问题其实都出在导出环节的config没对齐。6.3 PaddleOCR C部署思路与边缘设备扩展说到部署网上关于paddleocr c的搜索量一直很大因为项目上线时Python推理往往不够快尤其是CPU环境。C部署其实没有那么神秘原理就是加载上面导出的inference模型用Paddle Inference的C API做前向推理。PaddleOCR官方仓库的deploy目录下有现成C代码编译依赖OpenCV和Paddle Inference库。关键点在于编译时要选对WITH_GPU选项CPU版就不要开启GPU选项。预处理逻辑resize、归一化要和训练配置完全一致否则识别率掉一截。后处理包括文本框还原、CTC解码在C里要自己实现官方示例代码可以救急但复杂场景还是要读源码改。如果你部署的目标是边缘设备比如搜索词里出现的K210这一类那就要另说。K210的内存和算力非常有限跑完整的PaddleOCR不现实通常是在服务器上跑PaddleOCR得到文本行图再把裁剪后的文字图片扔给边缘设备上的轻量模型做识别。这种架构已经不属于PaddleOCR训练的范畴了但架构设计时要提前考虑别等训练完了再发现部署不上去。最后再分享一条我这几年攒下的经验模型训练的成败八成在数据两成在参数。网上能找到各种花里胡哨的调参技巧但当你真正把一个项目的准确率从不能用调到能用回头看往往是因为把标注错误改掉了、把缺失的字符样本补齐了。PaddleOCR给了你一套非常成熟的训练框架你要做的不是去挑战这套框架而是把你的业务数据理解清楚。如果你正准备训自己的第一个OCR模型先把数据格式跑通、把预训练模型路径配好用一次10轮的小训练验证全流程再考虑调参优化——这个顺序走完你已经超过一半的人了。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →