OCR模型训练失败?cv_resnet18_ocr-detection日志排查指南
1. 为什么训练会失败:先搞懂这个模型在做什么
cv_resnet18_ocr-detection 是一个专为中文场景优化的文字检测模型,不是识别模型,它只负责“找文字在哪”,不负责“认出是什么字”。很多人一上来就卡在训练环节,其实问题往往出在对模型能力边界的误解上。
这个模型用 ResNet-18 作为主干网络,配合 FPN(特征金字塔)结构,专门处理中英文混排、倾斜文本、小字号、低对比度等真实场景下的文字区域定位。它输出的是四边形坐标框,每个框对应图中一块可能含文字的区域。训练失败,90%的情况不是代码有问题,而是数据、环境或预期出了偏差。
你不需要成为深度学习专家,但得明白三件事:
- 它不读字,只画框;
- 它对标注质量极其敏感;
- 它对图片分辨率有隐性要求——太小的图喂进去,连自己都找不到文字在哪。
所以当训练报错时,别急着重装库,先打开日志文件,看第一行报错信息。绝大多数问题,答案就藏在那几行红色文字里。
2. 训练失败的五大高频原因与对应日志特征
2.1 数据路径错误:日志里反复出现 FileNotFoundError
这是新手最常踩的坑。WebUI 界面里填的“训练数据目录”,必须是绝对路径,且路径末尾不能带斜杠。
正确写法:/root/custom_data
❌ 错误写法:custom_data、./custom_data/、/root/custom_data/
典型日志片段:
FileNotFoundError: [Errno 2] No such file or directory: '/root/custom_data//train_list.txt'注意那个双斜杠//—— 这就是你多输了一个/的铁证。
快速验证方法:
ls -l /root/custom_data/train_list.txt如果提示“No such file”,立刻检查:
train_list.txt文件是否存在;- 路径中有没有中文、空格、特殊符号(比如括号、&);
- 文件权限是否为 644(
chmod 644 train_list.txt)。
2.2 标注格式不合规:日志中出现 ValueError: could not convert string to float
ICDAR2015 格式看着简单,实则暗藏玄机。txt 标注文件里每一行必须严格满足:
- 8个数字 + 1段文本,用英文逗号分隔;
- 数字之间不能有空格;
- 文本内容不能含逗号(否则会被截断);
- 坐标必须是整数,不能是小数或科学计数法。
错误示例(会导致解析失败):
10.5,20.3,100.2,20,102,25,12,23,发票号码 100, 200, 300, 400, 500, 600, 700, 800, 商品名称正确写法:
10,20,100,20,102,25,12,23,发票号码 100,200,300,400,500,600,700,800,商品名称日志线索:
ValueError: could not convert string to float: '20.3'或
IndexError: list index out of range这说明某一行字段数不对,少于9个。
自查脚本(复制粘贴运行即可):
awk -F',' '{if (NF != 9) print "行号:" NR ", 字段数:" NF ", 内容:" $0}' /root/custom_data/train_gts/1.txt它会直接告诉你哪一行坏了。
2.3 图片打不开:日志中大量 OSError: image file is truncated
这个问题特别隐蔽——图片明明能用看图软件打开,训练却报错“图片截断”。根本原因是:很多截图、微信转发图、网页保存图,表面是 JPG,实际是“伪 JPG”,头部信息不完整。
日志表现:
OSError: image file is truncated (xx bytes not processed)解决办法不是重命名,而是批量修复:
# 安装工具 apt-get update && apt-get install -y libjpeg-dev libpng-dev libtiff-dev # 批量重写图片(保留原尺寸,修复元数据) for img in /root/custom_data/train_images/*.jpg; do convert "$img" "${img%.jpg}_fixed.jpg" mv "${img%.jpg}_fixed.jpg" "$img" done对 PNG 同理,把.jpg换成.png即可。
2.4 显存爆炸:训练启动几秒后直接 Killed
这不是模型bug,是 Linux 的 OOM Killer(内存溢出杀手)干的。它发现 Python 进程吃光显存,直接强制终止。
日志唯一线索:
Killed就这两个字母,后面什么都没有。
判断依据:
nvidia-smi查看显存使用率,训练启动瞬间飙到 100%;dmesg -T | grep -i "killed process"能看到被杀进程名。
根治方案:
把 Batch Size 从默认 8 降到 4 或 2;
在
start_app.sh启动前加一句限制:export CUDA_VISIBLE_DEVICES=0(如果你有多卡,确保只用一张)
更彻底的办法:在训练配置里开启梯度检查点(gradient checkpointing),但 WebUI 暂未开放该开关,所以优先调小 batch。
2.5 学习率崩盘:loss 变成 nan 或负无穷
日志里出现:
Loss: nan或
Loss: -inf说明数值计算溢出了。ResNet-18 对学习率很敏感,0.007 是针对标准 ICDAR 数据集调优的值。如果你的数据集文字密度极高(比如满屏表格),或者图片分辨率远超 800×800,这个学习率就太大了。
安全做法:
- 首次训练,把学习率设为
0.001; - 观察前 10 个 step 的 loss 曲线,如果连续下降,再逐步加到 0.003;
- 如果 loss 波动剧烈(忽高忽低超过 10 倍),立刻停训,换更小学习率。
3. 日志文件在哪?怎么高效定位问题
WebUI 的训练日志不显示在界面上,全存在磁盘里。别翻界面找,直接去服务器查:
3.1 日志位置与命名规则
所有日志统一存放在:
/root/cv_resnet18_ocr-detection/workdirs/里面按时间戳建子目录,例如:
workdirs/20260105_143022_train_log/ ├── train.log # 主训练日志(重点看这个) ├── config.yaml # 实际生效的训练参数 └── val_result.json # 验证集结果(训练中途也会生成)关键技巧:每次点击“开始训练”,WebUI 都会新建一个时间戳目录。你不需要记住名字,用这条命令直接打开最新日志:
tail -f $(find /root/cv_resnet18_ocr-detection/workdirs/ -name "train.log" | sort | tail -n1)3.2 三步速查法:10 秒锁定故障点
别从头到尾读日志。真正的工程师只看三处:
第一步:看最后 5 行
tail -n5 /root/cv_resnet18_ocr-detection/workdirs/*/train.log 2>/dev/null | grep -E "(ERROR|Exception|Killed|nan|-inf)"如果有报错,基本就在这里。
第二步:看 loss 是否稳定
grep "Loss" /root/cv_resnet18_ocr-detection/workdirs/*/train.log | tail -n20正常训练,loss 应缓慢下降或小幅震荡。如果出现Loss: 999999或Loss: nan,就是数值溢出。
第三步:看数据加载是否成功
grep "Loaded" /root/cv_resnet18_ocr-detection/workdirs/*/train.log | head -n3正常应显示:
Loaded 1242 training samples Loaded 312 validation samples如果数字是 0,说明路径或列表文件彻底没读进去。
4. 从零重建训练环境:比修 Bug 更快的解决方案
有时候,花 20 分钟修一个路径错误,不如花 5 分钟重建干净环境。尤其当你改过代码、装过新库、或多人共用一台服务器时。
4.1 一键清理旧训练痕迹
# 删除所有 workdirs(训练产出物) rm -rf /root/cv_resnet18_ocr-detection/workdirs/* # 清空 outputs(避免干扰) rm -rf /root/cv_resnet18_ocr-detection/outputs/* # 重置 WebUI 状态(清除前端缓存) rm -rf /root/cv_resnet18_ocr-detection/__pycache__4.2 验证最小可运行数据集
别拿自己的业务数据当试验品。用官方提供的 mini-sample 测试:
# 创建测试目录 mkdir -p /root/test_ocr/{train_images,train_gts,test_images,test_gts} # 下载一张测试图(模拟清晰证件照) wget -O /root/test_ocr/train_images/idcard.jpg https://example.com/sample_id.jpg # 手动写一个最简标注(四边形框住姓名栏) echo "120,180,320,180,320,210,120,210,张三丰" > /root/test_ocr/train_gts/idcard.txt # 写训练列表 echo "train_images/idcard.jpg train_gts/idcard.txt" > /root/test_ocr/train_list.txt # 写测试列表(可空) touch /root/test_ocr/test_list.txt然后在 WebUI 中填入/root/test_ocr,Batch Size 设为 1,学习率 0.001,跑 2 个 epoch。如果成功,说明环境没问题,问题一定出在你的原始数据上。
5. 高级排查:当常规方法都失效时
如果以上全试过,训练还是挂,可能是底层依赖冲突。cv_resnet18_ocr-detection 基于 PyTorch 1.12 + OpenCV 4.5,对 CUDA 版本有硬性要求。
5.1 检查 CUDA 兼容性
# 查看驱动支持的最高 CUDA 版本 nvidia-smi # 查看当前 PyTorch 使用的 CUDA 版本 python -c "import torch; print(torch.version.cuda)" # 必须满足:驱动支持版本 ≥ PyTorch 编译版本 # 例如:驱动支持 11.8,PyTorch 是 11.3 → OK;如果是 11.9 → 不兼容5.2 强制重装关键依赖(无痛版)
cd /root/cv_resnet18_ocr-detection # 卸载可能冲突的包 pip uninstall -y torch torchvision torchaudio opencv-python # 用官方推荐版本重装(适配 CUDA 11.3) pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 torchaudio==0.12.1 --extra-index-url https://download.pytorch.org/whl/cu113 # 安装带 CUDA 支持的 OpenCV(不是 pip install opencv-python!) pip install opencv-python-headless==4.5.5.64 # 验证 python -c "import torch; print('CUDA可用:', torch.cuda.is_available()); import cv2; print('OpenCV版本:', cv2.__version__)"6. 总结:训练成功的三个确定性信号
别再凭感觉判断训练是否成功。盯紧这三个信号,比看 loss 曲线还准:
信号一:日志里出现
Validation mAP: 0.xx
mAP(mean Average Precision)大于 0.3,说明模型真的学到了文字定位能力;低于 0.1,基本等于没学。信号二:
workdirs/xxx/visualization/下生成了val_vis_*.jpg
这是验证集图片的检测效果可视化图。打开看看——框是不是大致罩住了文字?哪怕歪一点、大一点,也比完全没框强。信号三:
workdirs/xxx/weights/下有best.pth文件且大小 > 50MB
小于 10MB 的权重文件,大概率是空模型或保存异常。
只要这三个信号齐全,哪怕训练中途断过、loss 跳过,模型也是可用的。把它拖进“单图检测”页,上传一张图试试——能画出框,就是成功。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。