之前的模型因为是使用rec_r34_vd_none_bilstm_ctc这个预训练模型,resnet34层,所以比较重,跑起来比较慢,导致识别+检测在部署到现场机器上时差不多要一秒一张。

为了加速,考虑以下几种措施:

  1. 换轻量级的backbone
  2. 用paddleslim剪枝(参数精度降低)
  3. 是否可以尝试使用c++部署
  4. 是否可以转换成其他框架的模型,使用mlkdnn来进行加速。

1. 换轻量级backbone

1.1 模型说明

第一步:
确定要使用的预训练模型,可使用的ppocr提供的预训练模型列表,点击这里,或者还有PaddleOCR开源的文本识别算法列表,点击这里

中文识别模型

模型名称

模型简介

配置文件

推理模型大小

下载地址

ch_ppocr_mobile_slim_v1.1_rec

slim裁剪量化版超轻量模型,支持中英文、数字识别

rec_chinese_lite_train_v1.1.yml

1.6M

推理模型 / slim模型

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

推理模型 / slim模型

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好了。

Paddle OCR java使用 paddle ocr 速度_Paddle OCR java使用

  1. 下载了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下解压,发现变成了符合格式的三个。
  2. 下载了en_ppocr_mobile_v1.1_rec,其中也只有一个文件best_accuracy.pdparams
  3. Paddle OCR java使用 paddle ocr 速度_python_02

  4. 之前下载的文件都是有3个的,所以这个是否可以进行预训练有待考虑。

根据FAQ文档中,点击这里

Q3.1.50: 为什么在checkpoints中load下载的预训练模型会报错?

A: 这里有两个不同的概念:
pretrained_model:指预训练模型,是已经训练完成的模型。这时会load预训练模型的参数,但并不会load学习率、优化器以及训练状态等。如果需要finetune,应该使用pretrained。
checkpoints:指之前训练的中间结果,例如前一次训练到了100个epoch,想接着训练。这时会load尝试所有信息,包括模型的参数,之前的状态等。
这里应该使用pretrained_model而不是checkpoints

1.2 下载模型代码

主要的两个说明文档分别是:

  1. OCR模型列表(V1.1,9月22日更新)
  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。

  1. 注意,LED七段数码管是之前的train_data2数据集
  2. 配置文件最好复制一份再改

重点修改的部分:

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

Paddle OCR java使用 paddle ocr 速度_paddle_03


数据量太小了,即便默认打开了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

调小之后确实看起来还可以,

Paddle OCR java使用 paddle ocr 速度_paddle_04


但是训练轮数太少了


还是72合适点,不能30,太少,其实准确率还在变,改了epoch之后:

Paddle OCR java使用 paddle ocr 速度_推理模型_05


已经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

Paddle OCR java使用 paddle ocr 速度_Paddle OCR java使用_06


结果: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/

提示如下:

Paddle OCR java使用 paddle ocr 速度_Paddle OCR java使用_07


效果还是不好,遂将新造的400张数据合到之前的训练数据中,再次训练。

python3.7 tools/train.py -c configs/rec/rec_seven_digital_lite_all.yml 2>&1 | tee train_rec3.log

Paddle OCR java使用 paddle ocr 速度_Paddle OCR java使用_08


依然是将模型转换为推理模型,下载进行测试

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裁剪量化版超轻量模型

主要用到的几个文档是:

  1. PaddleSlim
  2. PaddleLite
  3. PaddleInference
# 首先安装PaddleSlim
pip install paddleslim -i https://pypi.tuna.tsinghua.edu.cn/simple
# 对应paddle2.0的是paddleslim2.8

有一定上手门槛,主要是要使用paddlepaddle来敲代码了,不单是之前配置就可以。

3. 转换为C++代码

可以参考的文档有:

  1. 服务器端C++预测
  2. 预测示例 (C++) 看看代码,基本就劝退了不太熟悉C++的人了

4. 转换为其他框架的模型

主要参考的文档有:

  1. 模型转换工具 X2Paddle

上面训练所使用的的backbone网络是MobileNetV3,而目前的X2Paddle工具支持的模型列表中,刚好没有这个网络。

2021.6.18 暂时不支持。

5. 进一步调研过程中发现

5.1 关于检测模型

使用python的profile工具检测函数性能耗时,

Paddle OCR java使用 paddle ocr 速度_paddle_09


最大的问题其实是在检测上,查看这个predict_det函数。

1. 模型转换

https://github.com/PaddlePaddle/PaddleOCR/issues/1833

Paddle OCR java使用 paddle ocr 速度_paddle_10


在我的场景中,最耗时的其实是检测,和识别没什么关系,即便转换为小模型,识别时间减小了非常多,但是检测耗时依然很多。

Paddle OCR java使用 paddle ocr 速度_推理模型_11


2. 更换backbone

FAQ-2.3.20: 如何根据不同的硬件平台选用不同的backbone? 在不同的硬件上,不同的backbone的速度优势不同,可以根据不同平台的速度-精度图来确定backbone,这里可以参考PaddleClas模型速度-精度图

Paddle OCR java使用 paddle ocr 速度_paddle_12


根据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差不多,但是要保证使用的都是最新的分支。