之前的模型因为是使用rec_r34_vd_none_bilstm_ctc
这个预训练模型,resnet34层,所以比较重,跑起来比较慢,导致识别+检测在部署到现场机器上时差不多要一秒一张。
为了加速,考虑以下几种措施:
- 换轻量级的backbone
- 用paddleslim剪枝(参数精度降低)
- 是否可以尝试使用c++部署
- 是否可以转换成其他框架的模型,使用mlkdnn来进行加速。
1. 换轻量级backbone
1.1 模型说明
第一步:
确定要使用的预训练模型,可使用的ppocr提供的预训练模型列表,点击这里,或者还有PaddleOCR开源的文本识别算法列表,点击这里:
中文识别模型
模型名称 | 模型简介 | 配置文件 | 推理模型大小 | 下载地址 |
ch_ppocr_mobile_slim_v1.1_rec | slim裁剪量化版超轻量模型,支持中英文、数字识别 | rec_chinese_lite_train_v1.1.yml | 1.6M | |
ch_ppocr_mobile_v1.1_rec | 原始超轻量模型,支持中英文、数字识别 | rec_chinese_lite_train_v1.1.yml | 4.6M | |
ch_ppocr_server_v1.1_rec | 通用模型,支持中英文、数字识别 | rec_chinese_common_train_v1.1.yml | 105M |
说明: 训练模型
是基于预训练模型在真实数据与竖排合成文本数据上finetune得到的模型,在真实应用场景中有着更好的表现,预训练模型
则是直接基于全量真实数据与合成数据训练得到,更适合用于在自己的数据集上finetune。
英文识别模型
模型名称 | 模型简介 | 配置文件 | 推理模型大小 | 下载地址 |
en_ppocr_mobile_slim_v1.1_rec | slim裁剪量化版超轻量模型,支持英文、数字识别 | rec_en_lite_train.yml | 0.9M | |
en_ppocr_mobile_v1.1_rec | 原始超轻量模型,支持英文、数字识别 | rec_en_lite_train.yml | 2.0M |
因为我的场景目前是LED七段数字码识别,所以可用的有英文的mobile训练模型en_ppocr_mobile_v1.1_rec
,以及中文的ch_ppocr_mobile_v1.1_rec
好了。
- 下载了
ch_ppocr_mobile_v1.1_rec
,解压后,其中文件有些问题,ch_ppocr_mobile_v1-1_rec_pre.pdparams
,一开始名称是ch_ppocr_mobile_v1.1_rec_pre
,其后缀是.1_rec_pre
,在linux下解压,发现变成了符合格式的三个。- 下载了
en_ppocr_mobile_v1.1_rec
,其中也只有一个文件best_accuracy.pdparams
- 之前下载的文件都是有3个的,所以这个是否可以进行预训练有待考虑。
根据FAQ文档中,点击这里
Q3.1.50: 为什么在checkpoints中load下载的预训练模型会报错?
A: 这里有两个不同的概念:
pretrained_model:指预训练模型,是已经训练完成的模型。这时会load预训练模型的参数,但并不会load学习率、优化器以及训练状态等。如果需要finetune,应该使用pretrained。
checkpoints:指之前训练的中间结果,例如前一次训练到了100个epoch,想接着训练。这时会load尝试所有信息,包括模型的参数,之前的状态等。
这里应该使用pretrained_model而不是checkpoints
1.2 下载模型代码
主要的两个说明文档分别是:
注意2.0和1.1分开,建议使用2.0
cd PaddleOCR/
# 下载CRNN MobileNetV3的预训练模型
wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/rec_mv3_none_bilstm_ctc.tar
# 解压
cd pretrain_models
tar -xf rec_mv3_none_bilstm_ctc.tar && rm -rf rec_mv3_none_bilstm_ctc.tar
# 或者下载英文ppocr的预训练模型 v1.1
wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/20-09-22/mobile/en/en_ppocr_mobile_v1.1_rec_train.tar
# 解压
cd pretrain_models
tar -xf en_ppocr_mobile_v1.1_rec_train.tar && rm -rf en_ppocr_mobile_v1.1_rec_train.tar
# 或者下载中文ppocr的预训练模型 v1.1
wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/20-09-22/mobile/rec/ch_ppocr_mobile_v1.1_rec_pre.tar
# 解压
cd pretrain_models
tar -xf ch_ppocr_mobile_v1.1_rec_pre.tar && rm -rf ch_ppocr_mobile_v1.1_rec_pre.tar
# 下面都是2.0的模型,应该会更符合格式一些。
wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/rec_mv3_none_bilstm_ctc_v2.0_train.tar
wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/dygraph_v2.0/multilingual/en_number_mobile_v2.0_rec_train.tar
wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_rec_pre.tar
cd pretrain_models
tar -xf rec_mv3_none_bilstm_ctc_v2.0_train.tar && rm -rf rec_mv3_none_bilstm_ctc_v2.0_train.tar
tar -xf en_number_mobile_v2.0_rec_train.tar && rm -rf en_number_mobile_v2.0_rec_train.tar
tar -xf ch_ppocr_mobile_v2.0_rec_pre.tar && rm -rf ch_ppocr_mobile_v2.0_rec_pre.tar
1.3 对应配置文件
除了模型之外,还需要有对应的配置文件:
模型 | 对应的配置文件 |
rec_mv3_none_bilstm_ctc_v2.0_train ,12.25MB | configs/rec/rec_icdar15_train.yml |
ch_ppocr_mobile_v2.0_rec_pre | , 5.2MBconfigs/rec/ch_ppocr_v2.0/rec_chinese_lite_train_v2.0.yml |
en_number_mobile_v2.0_rec_train, 2.6MB | configs/rec/multi_language/rec_en_number_lite_train.yml |
1.4 修改配置文件
还是直接使用rec_mv3_none_bilstm_ctc_v2.0_train
来试试,也就12.25MB,算上其他几个文件不到50M的模型,以后有更轻量需求的,再使用ppocr_mobile。
- 注意,LED七段数码管是之前的
train_data2
数据集 - 配置文件最好复制一份再改
重点修改的部分:
save_model_dir: ./output/rec/seven_digital_lite/
pretrained_model: ./pretrain_models/rec_mv3_none_bilstm_ctc_v2.0_train/best_accuracy
character_dict_path: ppocr/utils/dict/digit.txt
distort: True
还有训练集和测试集路径配置
1.5 启动训练
先进入docker
docker start OCR
docker exec -it OCR /bin/bash
如果训练时间不长,可以直接输入训练命令,不然可以考虑使用tmux
tmux new -s train
python3.7 -m paddle.distributed.launch --gpus '0' tools/train.py -c configs/rec/rec_seven_digital_lite.yml
# 记得指定自己环境的GPU
tmux detach
# 或者 ctrl+b 进入tmux的命令模式,然后输入d
tmux attach -t train
然后等待训练结束即可,2点开始,72轮,差不多4w张图,非常奇怪,似乎在2.0里面,并不是从头训练,不会造成1.0那种模型一开始训练准确度为0。训练时一上来准确率就是1???
1.6 转换为推理模型测试
转为推理模型
点击这里,查看文档,转换为推理模型的代码如下:
python3.7 tools/export_model.py -c configs/rec/rec_seven_digital_lite.yml -o Global.pretrained_model=output/rec/seven_digital_lite/best_accuracy Global.load_static_weights=False Global.save_inference_dir=./inference/rec_seven_digital_lite/
测试
测试,暂时不用代码测试了,直接用命令行执行查看结果,文档点击这里
python3.7 tools/infer/predict_rec.py --rec_model_dir="./inference/rec_seven_digital_lite/" --rec_image_shape="3, 32, 100" --rec_char_type="ch" --rec_char_dict_path="./ppocr/utils/dict/digit.txt" --image_dir="./train_data2/test/led1157.png"
结论
效果其实还行,直接把inference下载下来,可以看到,和之前的resnet34骨架的相比,基于resnet的模型文件夹有94MB,基于mobilenet的模型文件夹只有6.51MB,差得真的好多。
1- 后续
由于在读取视频流,截图时,发光字符边缘会发生粘连,导致很容易将0识别成1,8/9/3这三个字符容易混淆。所以考虑进行再次训练,直接将测试集变成训练集,弄成过拟合,因为可以迁移训练的数据非常有限。
修改配置文件如下:
epoch_num: 30
# 减少训练次数,不用72轮
save_model_dir: ./output/rec/seven_digital_lite_twice/
# 修改保存文件位置,相关文件都以twice为后缀
pretrained_model: ./output/rec/seven_digital_lite/best_accuracy
#./pretrain_models/rec_mv3_none_bilstm_ctc_v2.0_train/best_accuracy
# 预训练模型地址修改,改成上面训练好的轻量级模型,也就是迁移训练后再次迁移
Train:
dataset:
name: SimpleDataSet
data_dir: ./train_data2_twice/
label_file_list: ["./train_data2_twice/train.txt"]
# 训练集和测试集数据修改
Eval:
dataset:
name: SimpleDataSet
data_dir: ./train_data2_twice/
label_file_list: ["./train_data2_twice/train.txt"]
另外,在很早之前数据很少的时候,遇到过一个问题,PaddleOCR数字仪表识别——3.paddleocr迁移学习。这里报错图片数量太少,
Exception: The number of the whole data (800) is smaller than the batch_size * devices_num * num_workers (2048)
所以还需要再进行一些修改
loader:
shuffle: True
batch_size_per_card: 128
drop_last: True
num_workers: 4
use_shared_memory: False
# 训练集和测试机的batch-size 都从256改成了128,num_workers都是4,训练从8改成4,测试本来就是4,devices_num 我的虚拟机默认只有1个GPU
上传好数据和配置文件后,开始训练
python3.7 -m paddle.distributed.launch --gpus '0' tools/train.py -c configs/rec/rec_seven_digital_lite_twice.yml
数据量太小了,即便默认打开了distort
数据增强,效果还是很奇怪,将学习率调小试试。
# 从2000改成100
eval_batch_step: [0, 50]
Optimizer:
name: Adam
beta1: 0.9
beta2: 0.999
lr:
learning_rate: 0.000001
# 学习率从0.0005改成0.0001
regularizer:
name: 'L2'
factor: 0
调小之后确实看起来还可以,
但是训练轮数太少了
还是72合适点,不能30,太少,其实准确率还在变,改了epoch之后:
已经0.9987了
快速测试一下
python3.7 tools/infer_rec.py -c configs/rec/rec_seven_digital_lite_twice.yml -o Global.checkpoints=output/rec/seven_digital_lite_twice/best_accuracy Global.infer_img=train_data2_twice/train/0.jpg
结果:result: (‘0.112’, 0.99995196)
差不多了,然后转换为推理模型并下载
# 转换
python3.7 tools/export_model.py -c configs/rec/rec_seven_digital_lite_twice.yml -o Global.pretrained_model=output/rec/seven_digital_lite_twice/best_accuracy Global.load_static_weights=False Global.save_inference_dir=./inference/rec_seven_digital_lite_twice/
提示如下:
效果还是不好,遂将新造的400张数据合到之前的训练数据中,再次训练。
python3.7 tools/train.py -c configs/rec/rec_seven_digital_lite_all.yml 2>&1 | tee train_rec3.log
依然是将模型转换为推理模型,下载进行测试
python3.7 tools/export_model.py -c configs/rec/rec_seven_digital_lite_all.yml -o Global.pretrained_model=output/rec/seven_digital_lite_all/best_accuracy Global.load_static_weights=False Global.save_inference_dir=./inference/seven_digital_lite_all/
2. slim裁剪量化版超轻量模型
主要用到的几个文档是:
# 首先安装PaddleSlim
pip install paddleslim -i https://pypi.tuna.tsinghua.edu.cn/simple
# 对应paddle2.0的是paddleslim2.8
有一定上手门槛,主要是要使用paddlepaddle来敲代码了,不单是之前配置就可以。
3. 转换为C++代码
可以参考的文档有:
- 服务器端C++预测
- 预测示例 (C++) 看看代码,基本就劝退了不太熟悉C++的人了
4. 转换为其他框架的模型
主要参考的文档有:
上面训练所使用的的backbone网络是MobileNetV3,而目前的X2Paddle工具支持的模型列表中,刚好没有这个网络。
2021.6.18 暂时不支持。
5. 进一步调研过程中发现
5.1 关于检测模型
使用python的profile工具检测函数性能耗时,
最大的问题其实是在检测上,查看这个predict_det
函数。
1. 模型转换
在我的场景中,最耗时的其实是检测,和识别没什么关系,即便转换为小模型,识别时间减小了非常多,但是检测耗时依然很多。
2. 更换backbone
FAQ-2.3.20: 如何根据不同的硬件平台选用不同的backbone? 在不同的硬件上,不同的backbone的速度优势不同,可以根据不同平台的速度-精度图来确定backbone,这里可以参考PaddleClas模型速度-精度图。
根据PPOCR的论文,检测和识别网络采取的backbone骨架网络都是:MobileNetV3_large_0.5
,虽然下面的下载列表有这个网络,但是测速里没有这个,也不知道为啥???
3. 调整参数
FAQ-Q3.1.62: 弯曲文本(如略微形变的文档图像)漏检问题 A: db后处理中计算文本框平均得分时,是求rectangle区域的平均分数,容易造成弯曲文本漏检,已新增求polygon区域的平均分数,会更准确,但速度有所降低,可按需选择,在相关pr中可查看可视化对比效果。该功能通过参数 det_db_score_mode进行选择,参数值可选[fast(默认)、slow],fast对应原始的rectangle方式,slow对应polygon方式。感谢用户buptlihang提pr帮助解决该问题🌹。
5.2 转换语言
识别模型自训练后在python下预测验证比C++下好很多,同样输出的识别模型(自训练)和检测模型(官方自带) #2900 结论是C++可以提速,效果和python差不多,但是要保证使用的都是最新的分支。