简介:PaddleOCR 2.6 版本实操教程以一份 docx 文档形式分享,面向需要快速入门 OCR 环境搭建与模型训练的开发者。文档系统梳理了六大关键环节:虚拟环境配置、PPOCRLabel 标签生成、训练/测试数据集划分、YML 配置文件调整、模型训练与验证,以及推理模型导出和串联预测,覆盖从环境准备到最终推理的完整链路。资源仅含 1 个 docx 文件,压缩包大小 78KB,轻量易读,适合按步骤边看边操作。教程不仅给出了每一步的命令和参数,还特别标注了多个容易踩坑的细节,例如导出推理模型时 pretrained_model 参数无法直接传入需写入 YML、batch_size 不能超过图像数量、检测/识别数据集需按对应脚本同步划分等,并说明了 eval 阶段可按 10 步验证一次以保留最优权重的策略。已有 1307 人学习下载,可作为 PaddleOCR 2.6 定制化训练与微调的重要参考资料。
1. 训练完导出模型,加载的还是预训练权重:这个坑最折腾人
做 PaddleOCR 2.6 检测模型微调,最折磨人的不是训练本身,而是当你把整套流程走完——环境配好、标签标完、数据集划分好、yml 改完、训练也跑完——最后执行export_model.py导出推理模型时,发现导出的居然还是没训练过的预训练权重,前面几天的训练等于白跑。我第一次碰到时以为是玄学,反复跑了好几次导出命令,换各种路径写法,最后才定位到是参数没传进去。
这类问题非常典型,PaddleOCR 这套链路太长:环境安装、PPOCRLabel 标注、数据集划分、yml 配置、训练验证、导出预测,每一步都会埋雷,而报错信息又往往不会直接告诉你"权重加载错了"。这篇笔记就是围绕这条链路里最容易翻车的几个节点展开,把现象、根因、解决步骤拆开讲,适合正在用 PP-OCRv3 检测模型微调自己数据集、被各种报错卡住的开发者照方抓药。
2. 装环境就翻车:module 'yml' 找不到、CUDA 装不上、依赖顺序错
2.1 报错 "No module named 'yaml'" 或 "module 'yml' 缺失"
PaddleOCR 的配置体系基于 yml 文件解析,训练、验证、导出全靠它读配置。你新开一个虚拟环境,按 quickstart 装完依赖,第一次跑训练脚本时经常直接抛ModuleNotFoundError: No module named 'yaml',或者更迷惑一点的module 'yml' 缺失——其实指的都是同一个东西:PyYAML 没装上。
pip install PyYAML这条命令本身很简单,但要注意一个细节:paddleocr>=2.6.0.3这个官方包在安装时不一定把 PyYAML 作为强依赖拉进来,尤其是在你已经装了部分依赖、又用-r requirement.txt补装的情况下,很容易漏掉它。装完之后可以用python -c "import yaml; print(yaml.__version__)"快速确认模块可用。以后再遇到类似"缺一个 module"的报错,先别急着搜奇奇怪怪的解决方案,直接看报错模块名,用 pip 补装是最省事的。
2.2 paddlepaddle-gpu 装不上、下载慢、装完还是 CPU 版
GPU 版 PaddlePaddle 是这条链路里最容易出问题的环节。官方源在国内下载速度经常让人崩溃,超时重试几次后 pip 直接失败。常见做法是走百度镜像:
python -m pip install paddlepaddle-gpu -i https://mirror.baidu.com/pypi/simple装完之后别急着往下走,先跑一个验证命令:
python -c "import paddle; paddle.utils.run_check()"这一步非常关键,它能告诉你 PaddlePaddle 是否真的能用 GPU。如果输出里出现PaddlePaddle is installed successfully!但没有 GPU 相关提示,说明你装的可能是 CPU 版,或者 CUDA 环境没对上。我一般还会再加一条python -c "import paddle; print(paddle.device.get_device())"看默认设备。
提示:如果你的机器上 CUDA 版本比较特殊,pip 默认拉取的 GPU 包可能不匹配,这时要按官方版本匹配表指定安装,比如
paddlepaddle-gpu==2.5.x这种带具体版本的写法。
2.3 安装顺序错了:paddleocr 又把 paddlepaddle 拉回 CPU 版
这个坑很隐蔽。很多人图省事,直接pip install paddleocr不指定版本,结果 pip 在解析依赖时发现paddleocr依赖的paddlepaddle还没装,会自动给你装一个 CPU 版 PaddlePaddle,把你辛辛苦苦装好的 GPU 版覆盖掉,或者两个版本共存,运行时直接报版本冲突。
正确的安装顺序应该固定成:先装paddlepaddle-gpu,再装paddleocr>=2.6.0.3和paddleclas>=2.4.3,最后用-r requirement.txt补全剩下依赖。如果已经翻车了,先卸载重来:
pip uninstall paddlepaddle paddlepaddle-gpu -y python -m pip install paddlepaddle-gpu -i https://mirror.baidu.com/pypi/simple pip install "paddleocr>=2.6.0.3" pip install paddleclas>=2.4.3参数说明:-y是跳过确认直接卸载,防止在终端交互卡住;-i指定镜像源,是为了避开默认源下载超时的问题。顺序的意义在于:先让 pip 认为paddlepaddle-gpu已经满足依赖,后面装paddleocr时就不会再尝试拉 CPU 版了。
3. 标注完没法训练:rec_gt.txt 和 Label.txt 的格式、路径与黑匣子
3.1 启动 PPOCRLabel:--lang ch 到底有什么用
标注阶段是整条链路里最费人工的一步。进入 PPOCRLabel 目录后,先装依赖再启动:
cd PPOCRLabel pip install -r requirements.txt python PPOCRLabel.py --lang ch--lang ch这个参数的意义是让标注界面采用中文显示,减少上手成本。启动后先点自动标注,它会用预训练模型把图上已有的文字区域框出来,你再手动修正框的位置和文字内容。很多新手会把自动标注当成完全无人化的过程,实际上自动标注出来的框经常有漏标、错标,尤其在背景复杂或者文字倾斜的图上,必须人工过一遍。这一步偷懒,后面训练出来的模型精度会直接打折。
标注界面里有个细节容易忽略:导出的时候要分别导出"标记结果"和"识别结果",两者会生成不同的文件。如果你只是点了一下保存就关掉窗口,可能发现导出目录里只有检测框数据没有识别文本,或者反过来。
3.2 rec_gt.txt 与 Label.txt:一个管识别,一个管检测
标注完成后,目录下会生成两个关键文件:rec_gt.txt和Label.txt。这两个文件的用途完全不同,很多人在后面配置 yml 时把它们的路径填反了,导致训练能跑但精度奇差。
| 文件 | 用途 | 每行常见内容 | 对应的训练模块 |
|---|---|---|---|
| rec_gt.txt | 识别标签 | 图片路径 + 制表符 + 标注文本内容 | 识别模型 |
| Label.txt | 检测标签 | 图片路径 + 检测框坐标 + 文本 | 检测模型 |
从格式上就能看出来,rec_gt.txt管的是"图上写了什么字",Label.txt管的是"字在哪个位置"。如果你用的是 PP-OCRv3 的蒸馏结构,检测和识别各有自己的标签文件,配置时分别指向对应文件,不能混用。
3.3 标签文件里的路径对不上:训练报 No such file
这是标注阶段最常见的报错。PPOCRLabel 导出标签时,文件里写的图片路径取决于你在哪个目录下做的标注。如果你在PPOCRLabel子目录里标注,导出标签里的路径可能是相对于当前目录的相对路径;训练时你的工作目录切到了项目根目录,两边对不上,训练脚本就会报图片找不到。
排查方法很简单,先看标签文件内容:
head -n 5 rec_gt.txt head -n 5 Label.txt如果发现路径前缀和实际图片目录不一致,常见做法是在生成数据集的脚本里统一修正路径前缀,而不是手动去改每一行。这个修正逻辑会跟数据集划分脚本一起处理,下一章展开讲。记住一个原则:标注阶段只管框和文字,路径问题不要在标注界面里纠结,留到划分数据集时一次性解决。
4. 划分数据集:检测和识别标签为什么对不上、生成的 txt 是空的
4.1 修改 gen_det_train_val_test.py:划分检测数据集
PPOCRLabel 自带的gen_det_train_val_test.py脚本负责把标注好的检测标签划分成训练集、验证集和测试集。运行前需要修改脚本里的参数,常见做法是改三处:数据根目录、划分比例、输出文件名。
# gen_det_train_val_test.py 关键参数 det_label_file = "Label.txt" # 检测标签文件名 img_dir = "./OCR/ALL_1206" # 图片根目录 class_balancing = True # 是否按类别平衡 train_ratio = 0.7 # 训练集比例 val_ratio = 0.15 # 验证集比例 test_ratio = 0.15 # 测试集比例参数说明:det_label_file告诉脚本检测标签文件叫什么名字;img_dir是图片实际存放的目录,脚本会拿着标签里的图片路径去这个目录下确认图片存在;三个 ratio 加起来必须是 1,否则脚本会在划分时丢失一部分样本。
改完参数后运行:
python gen_det_train_val_test.py执行完会生成train.txt、val.txt、test.txt三个文件。这里有个细节值得注意:脚本生成的文件里,图片路径是它根据img_dir重新拼接过的,所以后面配置 yml 时只需要指定train.txt的路径就行,不需要在 yml 里再一次性地写图片根目录。
4.2 gen_rec_follow_det.py:让识别数据集跟随检测划分
识别数据集不能自己独立划分,必须跟着检测的划分走,否则会出现训练检测时用 A 集合、训练识别时用 B 集合的情况,模型推理时两边各干各的,效果对不上。gen_rec_follow_det.py干的就是这件事。
# gen_rec_follow_det.py 关键参数 rec_label_file = "rec_gt.txt" # 识别标签文件名 det_train_file = "train.txt" # 检测训练集合 det_val_file = "val.txt" # 检测验证集合 det_test_file = "test.txt" # 检测测试集合运行:
python gen_rec_follow_det.py它做的事情本质上是拿检测划分出来的三个 txt 去过滤识别标签,只保留图片路径能对得上的行,生成rec_train.txt、rec_test.txt。如果你只看训练集和测试集,验证集可以先不生成,代码里可以自己改,这个脚本本来就是可以按需求调整的。
4.3 划分后 txt 为空、路径多一层少一层
划分脚本跑完,打开生成的 txt 发现是空的,或者行数远少于标注数量,通常原因有两个:一是img_dir配置错误,脚本拿着标签里的图片路径去img_dir下找不到文件,直接跳过;二是标签文件里的图片路径带了子目录,脚本拼接后路径重复,比如./OCR/ALL_1206/OCR/ALL_1206/xxx.jpg这种情况。
解决方式是回到上一步,先head看train.txt的路径格式,对比Label.txt里的原始路径,根据差异调整img_dir的层级。这个阶段多花十分钟检查路径,比训练到一半再回头排查省时间得多。路径问题不要靠肉眼猜,直接用命令看,这是最快的方式。
5. 训练与验证的常见问题:yml 路径、batchsize、导出模型的坑
5.1 yml 配置:pretrained_model 写不对,训练等于白训
PaddleOCR 的训练配置全都集中在 yml 文件里。以configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml为例,把它复制一份改名为ch_PP-OCRv3_det_cml_myself.yml,然后重点修改以下字段:
Global: pretrained_model: "./output/ch_PP-OCR_v3_det_1206/best_accuracy" save_model_dir: "./output/ch_PP-OCR_v3_det_1206" save_inference_dir: "./inference/det_cml_ppocrv3_1206" Train: dataset: name: SimpleDataSet data_dir: label_file_list: ["./train.txt"] loader: batch_size_per_card: 16 Eval: dataset: name: SimpleDataSet data_dir: label_file_list: ["./val.txt"] loader: batch_size_per_card: 16这段配置平时最坑的就是data_dir和label_file_list的配合。检测数据集train.txt里的图片路径已经由划分脚本拼接好了,所以data_dir留空就行,直接指定train.txt路径即可。但识别模块的rec_train.txt生成时不一定把路径补全,图片实际路径如果是./OCR/ALL_1206/crop_img/xxx.jpg,这个前缀就要在 yml 的data_dir里补上。一句话总结:检测数据集路径写在标签文件里,识别数据集的图片根目录写在data_dir里。
5.2 batchsize 超过图片数量:训练一启动就崩
新手最容易犯的错是把 batchsize 设得很大以加快训练,结果训练脚本一启动就报错,提示数据数量不足。PaddleOCR 对 batchsize 的要求是:不能超过训练集或验证集的图片数量。假设val.txt里只有 12 张验证图,batch_size_per_card设成 16,验证阶段必崩。
python -c "count=0; [count:=count+1 for _ in open('val.txt')]; print(count)" # 等效一行统计行数 wc -l val.txt设置 batchsize 前,先wc -l数一下train.txt和val.txt的行数,然后让 batchsize 明显小于这个值。另外,多卡训练时batch_size_per_card是每张卡的批大小,总 batch 是卡数乘以这个值,配置时也要一并算进去。
5.3 eval 的设置:每 10 步验证一次,别让权重堆满硬盘
eval频率的配置是一个容易被忽略的存储问题。如果按 epoch 来保存权重,训练几十个 epoch 后 output 目录里会堆满一整排模型文件,每个几百 MB,硬盘很快被占满。而且每几个 epoch 存一次权重,实际用不上那么多——真正会用到的只有精度最高的那一个。
Global: eval_batch_step: [0, 10]这个配置的意思是每 10 步验证一次,验证时模型会把精度最高的权重自动存为best_accuracy。你不需要手动按 epoch 存权重,训练结束后直接用best_accuracy做导出就行。这样既省了硬盘,也省了事后挑选权重的麻烦。
5.4 导出模型的坑:Global.pretrained_model 传参不生效
这是整条链路里最反直觉的一个 bug,也是这篇笔记的核心。训练完成后,按常规思路执行导出命令,指定用训练好的权重导出推理模型:
python tools/export_model.py \ -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml_myself.yml \ -o Global.pretrained_model="D:/model/PaddleOCR-release-2.6/output/ch_PP-OCR_v3_det_1206/best_accuracy" \ -o Global.save_inference_dir="./inference/det_cml_ppocrv3_1206"执行完你发现模型导出来了,但用推理脚本去预测,效果跟没训练一样。再回头看导出日志,加载的还是 yml 里原来的预训练权重,-o Global.pretrained_model这个参数根本没有传进去。这个 bug 在 2.6 版本里是真实存在的,命令行参数覆盖对pretrained_model不生效。
解决方式很直接:不要用-o传,直接把训练后的权重路径写进 yml 的pretrained_model字段,再执行导出:
# 先修改 ch_PP-OCRv3_det_cml_myself.yml,把 pretrained_model 改成: # ./output/ch_PP-OCR_v3_det_1206/best_accuracy # 然后执行 python tools/export_model.py \ -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml_myself.yml \ -o Global.save_inference_dir="./inference/det_cml_ppocrv3_1206"参数说明:-c指定配置文件,-o只用来覆盖save_inference_dir这类能生效的字段。导出成功后,检测推理模型在./inference/det_cml_ppocrv3_1206目录下,注意蒸馏模型导出后权重在Student子目录里,推理时要指向Student这个路径。同样的道理,识别模型导出后也看Student子目录。
提示:导出后立刻跑一次推理验证,不要等到部署环境再发现模型没更新。推理命令用
predict_system.py,同时指定检测和识别模型目录,模型目录要精确到Student。
5.5 五条高频训练报错:现象、根因、处理
1. 图片找不到:No such file or directory现象:训练脚本启动后很快报错,提示某张图片不存在。 原因:标签文件里的图片路径和实际目录不一致,多半是data_dir没配或者配多了。 解决:先head -n 1 train.txt看路径,再对比图片实际位置,调整data_dir层级,不匹配就重新生成数据集划分文件。
2. 训练一启动就崩:数据量小于 batchsize现象:报错信息里有data相关的异常退出。 原因:val.txt或train.txt行数少于batch_size_per_card。 解决:wc -l数行数,把 batchsize 调小到图片数量以下,或者补标数据。
3. 训练 loss 不降反升现象:前几个 epoch loss 一直在高位震荡,完全没有下降趋势。 原因:pretrained_model路径写错,模型实际是随机初始化,在小数据集上很难训起来。 解决:启动训练后看日志里的加载路径,确认确实加载了预训练权重。加载失败时日志里会出现Not found或直接跳过。
4. eval 精度和 train 差距过大现象:train 的 loss 很低,但 eval 精度上不去。 原因:验证集图片太少,或者验证集的图片和训练集分布差异大,还有一种情况是 eval 时用了错误的模型文件。 解决:检查Eval.datasets的label_file_list是否指向val.txt,以及eval_batch_step是否正常触发。
5. 推理时目录不对,预测结果为空现象:predict_system.py跑完一张结果都没有,输出空白。 原因:det_model_dir或rec_model_dir指向了外层目录,而不是Student子目录。 解决:模型目录精确到./inference/det_cml_ppocrv3_1206/Student,这个路径下的模型才是真正可用于部署的推理模型。
6. 快速定位:一套验证训练、导出、预测是否正常的检查顺序
被这些坑折腾过几轮之后,我总结出一套固定的四步检查法,每次训练完导出前都强制走一遍,半小时内能定位绝大多数问题。
| 检查点 | 命令 | 正常表现 | 异常表现 |
|---|---|---|---|
| 训练真的在学 | 看训练日志的 loss 曲线 | loss 随步数下降 | loss 震荡不降,或卡在一个数值 |
| 最优权重真的生成 | 看output目录的best_accuracy时间戳 | 文件时间是最新训练的 | 文件时间是几天前,说明 eval 没跑 |
| 导出真的更新 | ls -lh ./inference/det_cml_ppocrv3_1206/Student | 模型文件大小和训练 epoch 匹配 | 文件大小和预训练模型一致,说明导出没生效 |
| 推理真的能用 | 跑一张测试图看结果 | 输出框和文本都合理 | 空结果、乱码、位置全错 |
其中第二步最关键,也是这次排错中最后悔没早做的。训练完第一反应应该是去看best_accuracy的修改时间,而不是急着导出。如果时间戳明显是旧的,说明训练过程中 eval 没保存新权重,这时候导出再多也是白费。这个时间戳就是整个训练流程的体检报告。
从那以后,我每次做 PaddleOCR 微调,训练完强制走一遍这个四步检查:先看 loss 是否下降,再看权重时间戳,导出后看模型大小,最后用一张实际图片验证推理结果。任何一步异常都停下来排查,绝不抱着"先导出再看看"的心态。希望帮到你,少走这几步的弯路,能省下大半天的时间。
本文还有配套的精品资源,点击获取