【人工智能学习之PaddleOCR训练教程】

具体的训练教程:

准备数据集

OCR数据集

(以下文字转载官方文档ocr_datasets)

这里整理了OCR中常用的公开数据集,持续更新中,欢迎各位小伙伴贡献数据集~

1. 文本检测

1.1 PaddleOCR 文字检测数据格式

PaddleOCR 中的文本检测算法支持的标注文件格式如下,中间用"\t"分隔:

" 图像文件名                    json.dumps编码的图像标注信息"
ch4_test_images/img_61.jpg    [{"transcription": "MASA", "points": [[310, 104], [416, 141], [418, 216], [312, 179]]}, {...}]

json.dumps编码前的图像标注信息是包含多个字典的list,字典中的 points 表示文本框的四个点的坐标(x, y),从左上角的点开始顺时针排列。
transcription 表示当前文本框的文字,当其内容为“###”时,表示该文本框无效,在训练时会跳过。

如果您想在我们未提供的数据集上训练,可以按照上述形式构建标注文件。

1.2 公开数据集

数据集名称 图片下载地址 PaddleOCR 标注下载地址
ICDAR 2015 https://rrc.cvc.uab.es/?ch=4&com=downloads train / test
ctw1500 https://paddleocr.bj.bcebos.com/dataset/ctw1500.zip 图片下载地址中已包含
total text https://paddleocr.bj.bcebos.com/dataset/total_text.tar 图片下载地址中已包含
td tr https://paddleocr.bj.bcebos.com/dataset/TD_TR.tar 图片下载地址中已包含
1.2.1 ICDAR 2015

ICDAR 2015 数据集包含1000张训练图像和500张测试图像。ICDAR 2015 数据集可以从上表中链接下载,首次下载需注册。
注册完成登陆后,下载下图中红色框标出的部分,其中, Training Set Images下载的内容保存在icdar_c4_train_imgs文件夹下,Test Set Images 下载的内容保存早ch4_test_images文件夹下

将下载到的数据集解压到工作目录下,假设解压在 PaddleOCR/train_data/下。然后从上表中下载转换好的标注文件。

PaddleOCR 也提供了数据格式转换脚本,可以将官网 label 转换支持的数据格式。 数据转换工具在 ppocr/utils/gen_label.py, 这里以训练集为例:

# 将官网下载的标签文件转换为 train_icdar2015_label.txt
python gen_label.py --mode="det" --root_path="/path/to/icdar_c4_train_imgs/"  \
                    --input_path="/path/to/ch4_training_localization_transcription_gt" \
                    --output_label="/path/to/train_icdar2015_label.txt"

解压数据集和下载标注文件后,PaddleOCR/train_data/ 有两个文件夹和两个文件,按照如下方式组织icdar2015数据集:

扫描二维码关注公众号,回复: 17495016 查看本文章
/PaddleOCR/train_data/icdar2015/text_localization/
  └─ icdar_c4_train_imgs/         icdar 2015 数据集的训练数据
  └─ ch4_test_images/             icdar 2015 数据集的测试数据
  └─ train_icdar2015_label.txt    icdar 2015 数据集的训练标注
  └─ test_icdar2015_label.txt     icdar 2015 数据集的测试标注

2. 文本识别

2.1 PaddleOCR 文字识别数据格式

PaddleOCR 中的文字识别算法支持两种数据格式:

  • lmdb 用于训练以lmdb格式存储的数据集,使用 lmdb_dataset.py 进行读取;
  • 通用数据 用于训练以文本文件存储的数据集,使用 simple_dataset.py进行读取。

下面以通用数据集为例, 介绍如何准备数据集:

  • 训练集

建议将训练图片放入同一个文件夹,并用一个txt文件(rec_gt_train.txt)记录图片路径和标签,txt文件里的内容如下:

注意: txt文件中默认请将图片路径和图片标签用 \t 分割,如用其他方式分割将造成训练报错。

" 图像文件名                 图像标注信息 "

train_data/rec/train/word_001.jpg   简单可依赖
train_data/rec/train/word_002.jpg   用科技让复杂的世界更简单
...

最终训练集应有如下文件结构:

|-train_data
  |-rec
    |- rec_gt_train.txt
    |- train
        |- word_001.png
        |- word_002.jpg
        |- word_003.jpg
        | ...

除上述单张图像为一行格式之外,PaddleOCR也支持对离线增广后的数据进行训练,为了防止相同样本在同一个batch中被多次采样,我们可以将相同标签对应的图片路径写在一行中,以列表的形式给出,在训练中,PaddleOCR会随机选择列表中的一张图片进行训练。对应地,标注文件的格式如下。

["11.jpg", "12.jpg"]   简单可依赖
["21.jpg", "22.jpg", "23.jpg"]   用科技让复杂的世界更简单
3.jpg   ocr

上述示例标注文件中,"11.jpg"和"12.jpg"的标签相同,都是简单可依赖,在训练的时候,对于该行标注,会随机选择其中的一张图片进行训练。

  • 验证集

同训练集类似,验证集也需要提供一个包含所有图片的文件夹(test)和一个rec_gt_test.txt,验证集的结构如下所示:

|-train_data
  |-rec
    |- rec_gt_test.txt
    |- test
        |- word_001.jpg
        |- word_002.jpg
        |- word_003.jpg
        | ...

2.2 公开数据集

数据集名称 图片下载地址 PaddleOCR 标注下载地址
en benchmark(MJ, SJ, IIIT, SVT, IC03, IC13, IC15, SVTP, and CUTE.) DTRB LMDB格式,可直接用lmdb_dataset.py加载
ICDAR 2015 http://rrc.cvc.uab.es/?ch=4&com=downloads train/ test
多语言数据集 百度网盘 提取码:frgi
google drive
图片下载地址中已包含
2.1 ICDAR 2015

ICDAR 2015 数据集可以在上表中链接下载,用于快速验证。也可以从上表中下载 en benchmark 所需的lmdb格式数据集。

下载完图片后从上表中下载转换好的标注文件。

PaddleOCR 也提供了数据格式转换脚本,可以将ICDAR官网 label 转换为PaddleOCR支持的数据格式。 数据转换工具在 ppocr/utils/gen_label.py, 这里以训练集为例:

# 将官网下载的标签文件转换为 rec_gt_label.txt
python gen_label.py --mode="rec" --input_path="{path/of/origin/label}" --output_label="rec_gt_label.txt"

数据样式格式如下,(a)为原始图片,(b)为每张图片对应的 Ground Truth 文本文件:

3. 数据存放路径

PaddleOCR训练数据的默认存储路径是 PaddleOCR/train_data,如果您的磁盘上已有数据集,只需创建软链接至数据集目录:

# linux and mac os
ln -sf <path/to/dataset> <path/to/paddle_ocr>/train_data/dataset
# windows
mklink /d <path/to/paddle_ocr>/train_data/dataset <path/to/dataset>

文字检测

(以下文字转载官方文档detection)

本节以icdar2015数据集为例,介绍PaddleOCR中检测模型训练、评估、测试的使用方式。

1. 准备数据和模型

1.1 准备数据集

准备数据集可参考 ocr_datasets。

1.2 下载预训练模型

首先下载模型backbone的pretrain model,PaddleOCR的检测模型目前支持两种backbone,分别是MobileNetV3、ResNet_vd系列,
您可以根据需求使用PaddleClas中的模型更换backbone,
对应的backbone预训练模型可以从PaddleClas repo 主页中找到下载链接

cd PaddleOCR/
# 根据backbone的不同选择下载对应的预训练模型
# 下载MobileNetV3的预训练模型
wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/pretrained/MobileNetV3_large_x0_5_pretrained.pdparams
# 或,下载ResNet18_vd的预训练模型
wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/pretrained/ResNet18_vd_pretrained.pdparams
# 或,下载ResNet50_vd的预训练模型
wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/pretrained/ResNet50_vd_ssld_pretrained.pdparams

2. 开始训练

2.1 启动训练

如果您安装的是cpu版本,请将配置文件中的 use_gpu 字段修改为false

# 单机单卡训练 mv3_db 模型
python3 tools/train.py -c configs/det/det_mv3_db.yml \
     -o Global.pretrained_model=./pretrain_models/MobileNetV3_large_x0_5_pretrained

# 单机多卡训练,通过 --gpus 参数设置使用的GPU ID
python3 -m paddle.distributed.launch --gpus '0,1,2,3' tools/train.py -c configs/det/det_mv3_db.yml \
     -o Global.pretrained_model=./pretrain_models/MobileNetV3_large_x0_5_pretrained

上述指令中,通过-c 选择训练使用configs/det/det_mv3_db.yml配置文件。
有关配置文件的详细解释,请参考链接

您也可以通过-o参数在不需要修改yml文件的情况下,改变训练的参数,比如,调整训练的学习率为0.0001

python3 tools/train.py -c configs/det/det_mv3_db.yml -o Optimizer.base_lr=0.0001

2.2 断点训练

如果训练程序中断,如果希望加载训练中断的模型从而恢复训练,可以通过指定Global.checkpoints指定要加载的模型路径:

python3 tools/train.py -c configs/det/det_mv3_db.yml -o Global.checkpoints=./your/trained/model

注意Global.checkpoints的优先级高于Global.pretrained_model的优先级,即同时指定两个参数时,优先加载Global.checkpoints指定的模型,如果Global.checkpoints指定的模型路径有误,会加载Global.pretrained_model指定的模型。

2.3 更换Backbone 训练

PaddleOCR将网络划分为四部分,分别在ppocr/modeling下。 进入网络的数据将按照顺序(transforms->backbones->
necks->heads)依次通过这四个部分。

├── architectures # 网络的组网代码
├── transforms    # 网络的图像变换模块
├── backbones     # 网络的特征提取模块
├── necks         # 网络的特征增强模块
└── heads         # 网络的输出模块

如果要更换的Backbone 在PaddleOCR中有对应实现,直接修改配置yml文件中Backbone部分的参数即可。

如果要使用新的Backbone,更换backbones的例子如下:

  1. ppocr/modeling/backbones 文件夹下新建文件,如my_backbone.py。
  2. 在 my_backbone.py 文件内添加相关代码,示例代码如下:
import paddle
import paddle.nn as nn
import paddle.nn.functional as F


class MyBackbone(nn.Layer):
    def __init__(self, *args, **kwargs):
        super(MyBackbone, self).__init__()
        # your init code
        self.conv = nn.xxxx

    def forward(self, inputs):
        # your network forward
        y = self.conv(inputs)
        return y
  1. ppocr/modeling/backbones/_init_.py文件内导入添加的MyBackbone模块,然后修改配置文件中Backbone进行配置即可使用,格式如下:
Backbone:
name: MyBackbone
args1: args1

注意:如果要更换网络的其他模块,可以参考文档

2.4 混合精度训练

如果您想进一步加快训练速度,可以使用自动混合精度训练, 以单机单卡为例,命令如下:

python3 tools/train.py -c configs/det/det_mv3_db.yml \
     -o Global.pretrained_model=./pretrain_models/MobileNetV3_large_x0_5_pretrained \
     Global.use_amp=True Global.scale_loss=1024.0 Global.use_dynamic_loss_scaling=True

注意
文本检测模型使用AMP时可能遇到训练不收敛问题,可以参考discussions中的临时解决方案进行使用。

2.5 分布式训练

多机多卡训练时,通过 --ips 参数设置使用的机器IP地址,通过 --gpus 参数设置使用的GPU ID:

python3 -m paddle.distributed.launch --ips="xx.xx.xx.xx,xx.xx.xx.xx" --gpus '0,1,2,3' tools/train.py -c configs/det/det_mv3_db.yml \
     -o Global.pretrained_model=./pretrain_models/MobileNetV3_large_x0_5_pretrained

注意: (1)采用多机多卡训练时,需要替换上面命令中的ips值为您机器的地址,机器之间需要能够相互ping通;(2)训练时需要在多个机器上分别启动命令。查看机器ip地址的命令为ifconfig;(3)更多关于分布式训练的性能优势等信息,请参考:分布式训练教程

2.6 知识蒸馏训练

PaddleOCR支持了基于知识蒸馏的检测模型训练过程,更多内容可以参考知识蒸馏说明文档

注意: 知识蒸馏训练目前只支持PP-OCR使用的DBCRNN算法。

2.7 其他训练环境

  • Windows GPU/CPU
    在Windows平台上与Linux平台略有不同:
    Windows平台只支持单卡的训练与预测,指定GPU进行训练set CUDA_VISIBLE_DEVICES=0
    在Windows平台,DataLoader只支持单进程模式,因此需要设置 num_workers 为0;

  • macOS
    不支持GPU模式,需要在配置文件中设置use_gpu为False,其余训练评估预测命令与Linux GPU完全相同。

  • Linux DCU
    DCU设备上运行需要设置环境变量 export HIP_VISIBLE_DEVICES=0,1,2,3,其余训练评估预测命令与Linux GPU完全相同。

2.8 模型微调

实际使用过程中,建议加载官方提供的预训练模型,在自己的数据集中进行微调,关于检测模型的微调方法,请参考:模型微调教程

3. 模型评估与预测

3.1 指标评估

PaddleOCR计算三个OCR检测相关的指标,分别是:Precision、Recall、Hmean(F-Score)。

训练中模型参数默认保存在Global.save_model_dir目录下。在评估指标时,需要设置Global.checkpoints指向保存的参数文件。

python3 tools/eval.py -c configs/det/det_mv3_db.yml  -o Global.checkpoints="{path/to/weights}/best_accuracy"

3.2 测试检测效果

测试单张图像的检测效果:

python3 tools/infer_det.py -c configs/det/det_mv3_db.yml -o Global.infer_img="./doc/imgs_en/img_10.jpg" Global.pretrained_model="./output/det_db/best_accuracy"

测试DB模型时,调整后处理阈值:

python3 tools/infer_det.py -c configs/det/det_mv3_db.yml -o Global.infer_img="./doc/imgs_en/img_10.jpg" Global.pretrained_model="./output/det_db/best_accuracy"  PostProcess.box_thresh=0.6 PostProcess.unclip_ratio=2.0
  • 注:box_threshunclip_ratio是DB后处理参数,其他检测模型不支持。

测试文件夹下所有图像的检测效果:

python3 tools/infer_det.py -c configs/det/det_mv3_db.yml -o Global.infer_img="./doc/imgs_en/" Global.pretrained_model="./output/det_db/best_accuracy"

4. 模型导出与预测

inference 模型(paddle.jit.save保存的模型)
一般是模型训练,把模型结构和模型参数保存在文件中的固化模型,多用于预测部署场景。
训练过程中保存的模型是checkpoints模型,保存的只有模型的参数,多用于恢复训练等。
与checkpoints模型相比,inference 模型会额外保存模型的结构信息,在预测部署、加速推理上性能优越,灵活方便,适合于实际系统集成。

检测模型转inference 模型方式:

# 加载配置文件`det_mv3_db.yml`,从`output/det_db`目录下加载`best_accuracy`模型,inference模型保存在`./output/det_db_inference`目录下
python3 tools/export_model.py -c configs/det/det_mv3_db.yml -o Global.pretrained_model="./output/det_db/best_accuracy" Global.save_inference_dir="./output/det_db_inference/"

DB检测模型inference 模型预测:

python3 tools/infer/predict_det.py --det_algorithm="DB" --det_model_dir="./output/det_db_inference/" --image_dir="./doc/imgs/" --use_gpu=True

如果是其他检测,比如EAST模型,det_algorithm参数需要修改为EAST,默认为DB算法:

python3 tools/infer/predict_det.py --det_algorithm="EAST" --det_model_dir="./output/det_db_inference/" --image_dir="./doc/imgs/" --use_gpu=True

更多关于推理超参数的配置与解释,请参考:模型推理超参数解释教程

5. FAQ

Q1: 训练模型转inference 模型之后预测效果不一致?

A:此类问题出现较多,问题多是trained model预测时候的预处理、后处理参数和inference model预测的时候的预处理、后处理参数不一致导致的。以det_mv3_db.yml配置文件训练的模型为例,训练模型、inference模型预测结果不一致问题解决方式如下:

Q1: 训练EAST模型提示找不到lanms库?

A:执行pip3 install lanms-nova 即可。

文字识别

(以下文字转载官方文档recognition)

本文提供了PaddleOCR文本识别任务的全流程指南,包括数据准备、模型训练、调优、评估、预测,各个阶段的详细说明:

1. 数据准备

1.1. 准备数据集

PaddleOCR 支持两种数据格式:

  • lmdb 用于训练以lmdb格式存储的数据集(LMDBDataSet);
  • 通用数据 用于训练以文本文件存储的数据集(SimpleDataSet);

训练数据的默认存储路径是 PaddleOCR/train_data,如果您的磁盘上已有数据集,只需创建软链接至数据集目录:

# linux and mac os
ln -sf <path/to/dataset> <path/to/paddle_ocr>/train_data/dataset
# windows
mklink /d <path/to/paddle_ocr>/train_data/dataset <path/to/dataset>

1.2. 自定义数据集

下面以通用数据集为例, 介绍如何准备数据集:

  • 训练集

建议将训练图片放入同一个文件夹,并用一个txt文件(rec_gt_train.txt)记录图片路径和标签,txt文件里的内容如下:

注意: txt文件中默认请将图片路径和图片标签用 \t 分割,如用其他方式分割将造成训练报错。

" 图像文件名                 图像标注信息 "

train_data/rec/train/word_001.jpg   简单可依赖
train_data/rec/train/word_002.jpg   用科技让复杂的世界更简单
...

最终训练集应有如下文件结构:

|-train_data
  |-rec
    |- rec_gt_train.txt
    |- train
        |- word_001.png
        |- word_002.jpg
        |- word_003.jpg
        | ...

除上述单张图像为一行格式之外,PaddleOCR也支持对离线增广后的数据进行训练,为了防止相同样本在同一个batch中被多次采样,我们可以将相同标签对应的图片路径写在一行中,以列表的形式给出,在训练中,PaddleOCR会随机选择列表中的一张图片进行训练。对应地,标注文件的格式如下。

["11.jpg", "12.jpg"]   简单可依赖
["21.jpg", "22.jpg", "23.jpg"]   用科技让复杂的世界更简单
3.jpg   ocr

上述示例标注文件中,"11.jpg"和"12.jpg"的标签相同,都是简单可依赖,在训练的时候,对于该行标注,会随机选择其中的一张图片进行训练。

  • 验证集

同训练集类似,验证集也需要提供一个包含所有图片的文件夹(test)和一个rec_gt_test.txt,验证集的结构如下所示:

|-train_data
  |-rec
    |- rec_gt_test.txt
    |- test
        |- word_001.jpg
        |- word_002.jpg
        |- word_003.jpg
        | ...

1.3. 数据下载

  • ICDAR2015

若您本地没有数据集,可以在官网下载 ICDAR2015 数据,用于快速验证。也可以参考DTRB ,下载 benchmark 所需的lmdb格式数据集。

如果你使用的是icdar2015的公开数据集,PaddleOCR 提供了一份用于训练 ICDAR2015 数据集的标签文件,通过以下方式下载:

# 训练集标签
wget -P ./train_data/ic15_data  https://paddleocr.bj.bcebos.com/dataset/rec_gt_train.txt
# 测试集标签
wget -P ./train_data/ic15_data  https://paddleocr.bj.bcebos.com/dataset/rec_gt_test.txt

PaddleOCR 也提供了数据格式转换脚本,可以将ICDAR官网 label 转换为PaddleOCR支持的数据格式。 数据转换工具在 ppocr/utils/gen_label.py, 这里以训练集为例:

# 将官网下载的标签文件转换为 rec_gt_label.txt
python gen_label.py --mode="rec" --input_path="{path/of/origin/label}" --output_label="rec_gt_label.txt"

数据样式格式如下,(a)为原始图片,(b)为每张图片对应的 Ground Truth 文本文件

  • 多语言数据集

多语言模型的训练数据集均为100w的合成数据,使用了开源合成工具 text_renderer ,少量的字体可以通过下面两种方式下载。

1.4. 字典

最后需要提供一个字典({word_dict_name}.txt),使模型在训练时,可以将所有出现的字符映射为字典的索引。

因此字典需要包含所有希望被正确识别的字符,{word_dict_name}.txt需要写成如下格式,并以 utf-8 编码格式保存:

l
d
a
d
r
n

word_dict.txt 每行有一个单字,将字符与数字索引映射在一起,“and” 将被映射成 [2 5 1]

  • 内置字典

PaddleOCR内置了一部分字典,可以按需使用。

ppocr/utils/ppocr_keys_v1.txt 是一个包含6623个字符的中文字典

ppocr/utils/ic15_dict.txt 是一个包含36个字符的英文字典

ppocr/utils/dict/french_dict.txt 是一个包含118个字符的法文字典

ppocr/utils/dict/japan_dict.txt 是一个包含4399个字符的日文字典

ppocr/utils/dict/korean_dict.txt 是一个包含3636个字符的韩文字典

ppocr/utils/dict/german_dict.txt 是一个包含131个字符的德文字典

ppocr/utils/en_dict.txt 是一个包含96个字符的英文字典

目前的多语言模型仍处在demo阶段,会持续优化模型并补充语种,非常欢迎您为我们提供其他语言的字典和字体
如您愿意可将字典文件提交至 dict,我们会在Repo中感谢您。

  • 自定义字典

如需自定义dic文件,请在 configs/rec/PP-OCRv4/en_PP-OCRv4_rec.yml 中添加 character_dict_path 字段, 指向您的字典路径。

1.5. 添加空格类别

如果希望支持识别"空格"类别, 请将yml文件中的 use_space_char 字段设置为 True

1.6. 数据增强

PaddleOCR提供了多种数据增强方式,默认配置文件中已经添加了数据增广。

默认的扰动方式有:颜色空间转换(cvtColor)、模糊(blur)、抖动(jitter)、噪声(Gasuss noise)、随机切割(random crop)、透视(perspective)、颜色反转(reverse)、TIA数据增广。

训练过程中每种扰动方式以40%的概率被选择,具体代码实现请参考:rec_img_aug.py

由于OpenCV的兼容性问题,扰动操作暂时只支持Linux

2. 开始训练

PaddleOCR提供了训练脚本、评估脚本和预测脚本,本节将以 PP-OCRv4 英文识别模型为例:

2.1. 启动训练

首先下载pretrain model,您可以下载训练好的模型在 icdar2015 数据上进行finetune

cd PaddleOCR/
# 下载英文PP-OCRv4的预训练模型
wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/PP-OCRv4/english/en_PP-OCRv4_rec_train.tar
# 解压模型参数
cd pretrain_models
tar -xf en_PP-OCRv4_rec_train.tar && rm -rf en_PP-OCRv4_rec_train.tar

开始训练:

如果您安装的是cpu版本,请将配置文件中的 use_gpu 字段修改为false

# GPU训练 支持单卡,多卡训练
# 训练icdar15英文数据 训练日志会自动保存为 "{save_model_dir}" 下的train.log

#单卡训练(训练周期长,不建议)
python3 tools/train.py -c configs/rec/PP-OCRv4/en_PP-OCRv4_rec.yml -o Global.pretrained_model=./pretrain_models/en_PP-OCRv4_rec_train/best_accuracy

#多卡训练,通过--gpus参数指定卡号
python3 -m paddle.distributed.launch --gpus '0,1,2,3'  tools/train.py -c configs/rec/PP-OCRv4/en_PP-OCRv4_rec.yml -o Global.pretrained_model=./pretrain_models/en_PP-OCRv4_rec_train/best_accuracy

正常启动训练后,会看到以下log输出:

[2024/06/16 11:28:26] ppocr INFO: epoch: [1/50], global_step: 10, lr: 0.000007, acc: 0.343750, norm_edit_dis: 0.752802, CTCLoss: 13.178495, NRTRLoss: 1.398275, loss: 14.568232, avg_reader_cost: 0.28627 s, avg_batch_cost: 1.04250 s, avg_samples: 67.2, ips: 64.46042 samples/s, eta: 0:57:09, max_mem_reserved: 12078 MB, max_mem_allocated: 11935 MB
[2024/06/16 11:28:30] ppocr INFO: epoch: [1/50], global_step: 20, lr: 0.000014, acc: 0.361979, norm_edit_dis: 0.764480, CTCLoss: 12.389563, NRTRLoss: 1.389737, loss: 13.795437, avg_reader_cost: 0.00035 s, avg_batch_cost: 0.47960 s, avg_samples: 65.6, ips: 136.78172 samples/s, eta: 0:41:36, max_mem_reserved: 12078 MB, max_mem_allocated: 11949 MB
[2024/06/16 11:28:35] ppocr INFO: epoch: [1/50], global_step: 30, lr: 0.000030, acc: 0.390625, norm_edit_dis: 0.788205, CTCLoss: 10.617269, NRTRLoss: 1.334532, loss: 11.975240, avg_reader_cost: 0.00035 s, avg_batch_cost: 0.48364 s, avg_samples: 78.4, ips: 162.10323 samples/s, eta: 0:36:26, max_mem_reserved: 12078 MB, max_mem_allocated: 11976 MB
[2024/06/16 11:28:40] ppocr INFO: epoch: [1/50], global_step: 40, lr: 0.000045, acc: 0.393229, norm_edit_dis: 0.785400, CTCLoss: 10.627735, NRTRLoss: 1.330406, loss: 11.949156, avg_reader_cost: 0.00036 s, avg_batch_cost: 0.48152 s, avg_samples: 73.6, ips: 152.84850 samples/s, eta: 0:33:47, max_mem_reserved: 12078 MB, max_mem_allocated: 11976 MB
[2024/06/16 11:28:45] ppocr INFO: epoch: [1/50], global_step: 50, lr: 0.000060, acc: 0.401042, norm_edit_dis: 0.804457, CTCLoss: 8.343242, NRTRLoss: 1.220365, loss: 9.561325, avg_reader_cost: 0.00035 s, avg_batch_cost: 0.48413 s, avg_samples: 67.2, ips: 138.80508 samples/s, eta: 0:32:11, max_mem_reserved: 12078 MB, max_mem_allocated: 11976 MB
[2024/06/16 11:28:50] ppocr INFO: epoch: [1/50], global_step: 60, lr: 0.000075, acc: 0.468750, norm_edit_dis: 0.833311, CTCLoss: 7.356572, NRTRLoss: 1.191381, loss: 8.570213, avg_reader_cost: 0.00028 s, avg_batch_cost: 0.47786 s, avg_samples: 68.8, ips: 143.97404 samples/s, eta: 0:31:02, max_mem_reserved: 12078 MB, max_mem_allocated: 11990 MB
[2024/06/16 11:28:53] ppocr INFO: epoch: [1/50], global_step: 66, lr: 0.000084, acc: 0.489583, norm_edit_dis: 0.841231, CTCLoss: 7.246758, NRTRLoss: 1.181412, loss: 8.424673, avg_reader_cost: 0.00018 s, avg_batch_cost: 0.28659 s, avg_samples: 36.8, ips: 128.40797 samples/s, eta: 0:30:30, max_mem_reserved: 12078 MB, max_mem_allocated: 11990 MB

log 中自动打印如下信息:

字段 含义
epoch 当前迭代轮次
iter 当前迭代次数
lr 当前学习率
loss 当前损失函数
acc 当前batch的准确率
norm_edit_dis 当前 batch 的编辑距离
reader_cost 当前 batch 数据处理耗时
batch_cost 当前 batch 总耗时
samples 当前 batch 内的样本数
ips 每秒处理图片的数量

PaddleOCR支持训练和评估交替进行, 可以在 configs/rec/PP-OCRv4/en_PP-OCRv4_rec.yml 中修改 eval_batch_step 设置评估频率,默认每500个iter评估一次。评估过程中默认将最佳acc模型,保存为 output/en_PP-OCRv4_rec/best_accuracy

如果验证集很大,测试将会比较耗时,建议减少评估次数,或训练完再进行评估。

提示: 可通过 -c 参数选择 configs/rec/ 路径下的多种模型配置进行训练,PaddleOCR支持的识别算法可以参考前沿算法列表

训练中文数据,推荐使用ch_PP-OCRv4_rec_distillation.yml,如您希望尝试其他算法在中文数据集上的效果,请参考下列说明修改配置文件:

ch_PP-OCRv4_rec_distillation.yml 为例:

Global:
  ...
  # 添加自定义字典,如修改字典请将路径指向新字典
  character_dict_path: ppocr/utils/ppocr_keys_v1.txt
  ...
  # 识别空格
  use_space_char: True


Optimizer:
  ...
  # 添加学习率衰减策略
  lr:
    name: Cosine
    learning_rate: 0.0005
  ...

...

Train:
  dataset:
    # 数据集格式,支持LMDBDataSet以及SimpleDataSet
    name: SimpleDataSet
    # 数据集路径
    data_dir: ./train_data/
    # 训练集标签文件
    label_file_list: ["./train_data/train_list.txt"]
    transforms:
      ...
      - RecResizeImg:
          # 修改 image_shape 以适应长文本
          image_shape: [3, 48, 320]
      ...
  loader:
    ...
    # 单卡训练的batch_size
    batch_size_per_card: 256
    ...

Eval:
  dataset:
    # 数据集格式,支持LMDBDataSet以及SimpleDataSet
    name: SimpleDataSet
    # 数据集路径
    data_dir: ./train_data
    # 验证集标签文件
    label_file_list: ["./train_data/val_list.txt"]
    transforms:
      ...
      - RecResizeImg:
          # 修改 image_shape 以适应长文本
          image_shape: [3, 48, 320]
      ...
  loader:
    # 单卡验证的batch_size
    batch_size_per_card: 256
    ...

注意,预测/评估时的配置文件请务必与训练一致。

2.2. 断点训练

如果训练程序中断,如果希望加载训练中断的模型从而恢复训练,可以通过指定Global.checkpoints指定要加载的模型路径:

python3 tools/train.py -c configs/rec/PP-OCRv4/en_PP-OCRv4_rec.yml -o Global.checkpoints=./your/trained/model

注意Global.checkpoints的优先级高于Global.pretrained_model的优先级,即同时指定两个参数时,优先加载Global.checkpoints指定的模型,如果Global.checkpoints指定的模型路径有误,会加载Global.pretrained_model指定的模型。

2.3. 更换Backbone 训练

PaddleOCR将网络划分为四部分,分别在ppocr/modeling下。 进入网络的数据将按照顺序(transforms->backbones->necks->heads)依次通过这四个部分。

├── architectures # 网络的组网代码
├── transforms    # 网络的图像变换模块
├── backbones     # 网络的特征提取模块
├── necks         # 网络的特征增强模块
└── heads         # 网络的输出模块

如果要更换的Backbone 在PaddleOCR中有对应实现,直接修改配置yml文件中Backbone部分的参数即可。

如果要使用新的Backbone,更换backbones的例子如下:

  1. ppocr/modeling/backbones 文件夹下新建文件,如my_backbone.py。
  2. 在 my_backbone.py 文件内添加相关代码,示例代码如下:
import paddle
import paddle.nn as nn
import paddle.nn.functional as F


class MyBackbone(nn.Layer):
    def __init__(self, *args, **kwargs):
        super(MyBackbone, self).__init__()
        # your init code
        self.conv = nn.xxxx

    def forward(self, inputs):
        # your network forward
        y = self.conv(inputs)
        return y
  1. ppocr/modeling/backbones/_init_.py文件内导入添加的MyBackbone模块,然后修改配置文件中Backbone进行配置即可使用,格式如下:
Backbone:
name: MyBackbone
args1: args1

注意:如果要更换网络的其他模块,可以参考文档

2.4. 混合精度训练

如果您想进一步加快训练速度,可以使用自动混合精度训练, 以单机单卡为例,命令如下:

python3 tools/train.py -c configs/rec/PP-OCRv4/en_PP-OCRv4_rec.yml \
     -o Global.pretrained_model=./pretrain_models/en_PP-OCRv4_rec_train/best_accuracy \
     Global.use_amp=True Global.scale_loss=1024.0 Global.use_dynamic_loss_scaling=True

2.5. 分布式训练

多机多卡训练时,通过 --ips 参数设置使用的机器IP地址,通过 --gpus 参数设置使用的GPU ID:

python3 -m paddle.distributed.launch --ips="xx.xx.xx.xx,xx.xx.xx.xx" --gpus '0,1,2,3' tools/train.py -c configs/rec/PP-OCRv4/en_PP-OCRv4_rec.yml \
     -o Global.pretrained_model=./pretrain_models/en_PP-OCRv4_rec_train/best_accuracy

注意: (1)采用多机多卡训练时,需要替换上面命令中的ips值为您机器的地址,机器之间需要能够相互ping通;(2)训练时需要在多个机器上分别启动命令。查看机器ip地址的命令为ifconfig;(3)更多关于分布式训练的性能优势等信息,请参考:分布式训练教程

2.6. 知识蒸馏训练

PaddleOCR支持了基于知识蒸馏的文本识别模型训练过程,更多内容可以参考知识蒸馏说明文档

2.7. 多语言模型训练

PaddleOCR目前已支持80种(除中文外)语种识别,configs/rec/multi_languages 路径下提供了一个多语言的配置文件模版: rec_multi_language_lite_train.yml

按语系划分,目前PaddleOCR支持的语种有:

配置文件 算法名称 backbone trans seq pred language
rec_chinese_cht_lite_train.yml CRNN Mobilenet_v3 small 0.5 None BiLSTM ctc 中文繁体
rec_en_lite_train.yml CRNN Mobilenet_v3 small 0.5 None BiLSTM ctc 英语(区分大小写)
rec_french_lite_train.yml CRNN Mobilenet_v3 small 0.5 None BiLSTM ctc 法语
rec_ger_lite_train.yml CRNN Mobilenet_v3 small 0.5 None BiLSTM ctc 德语
rec_japan_lite_train.yml CRNN Mobilenet_v3 small 0.5 None BiLSTM ctc 日语
rec_korean_lite_train.yml CRNN Mobilenet_v3 small 0.5 None BiLSTM ctc 韩语
rec_latin_lite_train.yml CRNN Mobilenet_v3 small 0.5 None BiLSTM ctc 拉丁字母
rec_arabic_lite_train.yml CRNN Mobilenet_v3 small 0.5 None BiLSTM ctc 阿拉伯字母
rec_cyrillic_lite_train.yml CRNN Mobilenet_v3 small 0.5 None BiLSTM ctc 斯拉夫字母
rec_devanagari_lite_train.yml CRNN Mobilenet_v3 small 0.5 None BiLSTM ctc 梵文字母

更多支持语种请参考: 多语言模型

如您希望在现有模型效果的基础上调优,请参考下列说明修改配置文件:

rec_french_lite_train 为例:

Global:
  ...
  # 添加自定义字典,如修改字典请将路径指向新字典
  character_dict_path: ./ppocr/utils/dict/french_dict.txt
  ...
  # 识别空格
  use_space_char: True

...

Train:
  dataset:
    # 数据集格式,支持LMDBDataSet以及SimpleDataSet
    name: SimpleDataSet
    # 数据集路径
    data_dir: ./train_data/
    # 训练集标签文件
    label_file_list: ["./train_data/french_train.txt"]
    ...

Eval:
  dataset:
    # 数据集格式,支持LMDBDataSet以及SimpleDataSet
    name: SimpleDataSet
    # 数据集路径
    data_dir: ./train_data
    # 验证集标签文件
    label_file_list: ["./train_data/french_val.txt"]
    ...

2.8. 其他训练环境

  • Windows GPU/CPU
    在Windows平台上与Linux平台略有不同:
    Windows平台只支持单卡的训练与预测,指定GPU进行训练set CUDA_VISIBLE_DEVICES=0
    在Windows平台,DataLoader只支持单进程模式,因此需要设置 num_workers 为0;

  • macOS
    不支持GPU模式,需要在配置文件中设置use_gpu为False,其余训练评估预测命令与Linux GPU完全相同。

  • Linux DCU
    DCU设备上运行需要设置环境变量 export HIP_VISIBLE_DEVICES=0,1,2,3,其余训练评估预测命令与Linux GPU完全相同。

2.9 模型微调

实际使用过程中,建议加载官方提供的预训练模型,在自己的数据集中进行微调,关于识别模型的微调方法,请参考:模型微调教程

3. 模型评估与预测

3.1. 指标评估

训练中模型参数默认保存在Global.save_model_dir目录下。在评估指标时,需要设置Global.checkpoints指向保存的参数文件。评估数据集可以通过 configs/rec/PP-OCRv3/en_PP-OCRv3_rec.yml 修改Eval中的 label_file_path 设置。

# GPU 评估, Global.checkpoints 为待测权重
python3 -m paddle.distributed.launch --gpus '0' tools/eval.py -c configs/rec/PP-OCRv4/en_PP-OCRv4_rec.yml -o Global.checkpoints={path/to/weights}/best_accuracy

3.2. 测试识别效果

使用 PaddleOCR 训练好的模型,可以通过以下脚本进行快速预测。

默认预测图片存储在 infer_img 里,通过 -o Global.checkpoints 加载训练好的参数文件:

根据配置文件中设置的 save_model_dirsave_epoch_step 字段,会有以下几种参数被保存下来:

output/rec/
├── best_accuracy.pdopt
├── best_accuracy.pdparams
├── best_accuracy.states
├── config.yml
├── iter_epoch_3.pdopt
├── iter_epoch_3.pdparams
├── iter_epoch_3.states
├── latest.pdopt
├── latest.pdparams
├── latest.states
└── train.log

其中 best_accuracy.* 是评估集上的最优模型;iter_epoch_x.* 是以 save_epoch_step 为间隔保存下来的模型;latest.* 是最后一个epoch的模型。

# 预测英文结果
python3 tools/infer_rec.py -c configs/rec/PP-OCRv4/en_PP-OCRv4_rec.yml -o Global.pretrained_model={path/to/weights}/best_accuracy  Global.infer_img=doc/imgs_words/en/word_1.png

得到输入图像的预测结果:

infer_img: doc/imgs_words/en/word_1.png
        result: ('joint', 0.9998967)

预测使用的配置文件必须与训练一致,如您通过 python3 tools/train.py -c configs/rec/ch_ppocr_v2.0/rec_chinese_lite_train_v2.0.yml 完成了中文模型的训练,
您可以使用如下命令进行中文模型预测。

# 预测中文结果
python3 tools/infer_rec.py -c configs/rec/ch_ppocr_v2.0/rec_chinese_lite_train_v2.0.yml -o Global.pretrained_model={path/to/weights}/best_accuracy Global.infer_img=doc/imgs_words/ch/word_1.jpg

得到输入图像的预测结果:

infer_img: doc/imgs_words/ch/word_1.jpg
        result: ('韩国小馆', 0.997218)

4. 模型导出与预测

inference 模型(paddle.jit.save保存的模型)
一般是模型训练,把模型结构和模型参数保存在文件中的固化模型,多用于预测部署场景。
训练过程中保存的模型是checkpoints模型,保存的只有模型的参数,多用于恢复训练等。
与checkpoints模型相比,inference 模型会额外保存模型的结构信息,在预测部署、加速推理上性能优越,灵活方便,适合于实际系统集成。

识别模型转inference模型与检测的方式相同,如下:

# -c 后面设置训练算法的yml配置文件
# -o 配置可选参数
# Global.pretrained_model 参数设置待转换的训练模型地址,不用添加文件后缀 .pdmodel,.pdopt或.pdparams。
# Global.save_inference_dir参数设置转换的模型将保存的地址。

python3 tools/export_model.py -c configs/rec/PP-OCRv4/en_PP-OCRv4_rec.yml -o Global.pretrained_model=./pretrain_models/en_PP-OCRv4_rec_train/best_accuracy  Global.save_inference_dir=./inference/en_PP-OCRv4_rec/

**注意:**如果您是在自己的数据集上训练的模型,并且调整了中文字符的字典文件,请注意修改配置文件中的character_dict_path为自定义字典文件。

转换成功后,在目录下有三个文件:

inference/en_PP-OCRv4_rec/
    ├── inference.pdiparams         # 识别inference模型的参数文件
    ├── inference.pdiparams.info    # 识别inference模型的参数信息,可忽略
    └── inference.pdmodel           # 识别inference模型的program文件
  • 自定义模型推理

    如果训练时修改了文本的字典,在使用inference模型预测时,需要通过--rec_char_dict_path指定使用的字典路径,更多关于推理超参数的配置与解释,请参考:模型推理超参数解释教程

    python3 tools/infer/predict_rec.py --image_dir="./doc/imgs_words_en/word_336.png" --rec_model_dir="./your inference model" --rec_image_shape="3, 48, 320" --rec_char_dict_path="your text dict path"
    

5. FAQ

Q1: 训练模型转inference 模型之后预测效果不一致?

A:此类问题出现较多,问题多是trained model预测时候的预处理、后处理参数和inference model预测的时候的预处理、后处理参数不一致导致的。可以对比训练使用的配置文件中的预处理、后处理和预测时是否存在差异。

文本方向分类器

(以下文字转载官方文档angle_class)

1. 方法介绍

文本方向分类器主要用于图片非0度的场景下,在这种场景下需要对图片里检测到的文本行进行一个转正的操作。在PaddleOCR系统内,
文字检测之后得到的文本行图片经过仿射变换之后送入识别模型,此时只需要对文字进行一个0和180度的角度分类,因此PaddleOCR内置的
文本方向分类器只支持了0和180度的分类。如果想支持更多角度,可以自己修改算法进行支持。

0和180度数据样本例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2. 数据准备

请按如下步骤设置数据集:

训练数据的默认存储路径是 PaddleOCR/train_data/cls,如果您的磁盘上已有数据集,只需创建软链接至数据集目录:

ln -sf <path/to/dataset> <path/to/paddle_ocr>/train_data/cls/dataset

请参考下文组织您的数据。

  • 训练集

首先建议将训练图片放入同一个文件夹,并用一个txt文件(cls_gt_train.txt)记录图片路径和标签。

注意: 默认请将图片路径和图片标签用 \t 分割,如用其他方式分割将造成训练报错

0和180分别表示图片的角度为0度和180度

" 图像文件名                 图像标注信息 "
train/cls/train/word_001.jpg   0
train/cls/train/word_002.jpg   180

最终训练集应有如下文件结构:

|-train_data
    |-cls
        |- cls_gt_train.txt
        |- train
            |- word_001.png
            |- word_002.jpg
            |- word_003.jpg
            | ...
  • 测试集

同训练集类似,测试集也需要提供一个包含所有图片的文件夹(test)和一个cls_gt_test.txt,测试集的结构如下所示:

|-train_data
    |-cls
        |- cls_gt_test.txt
        |- test
            |- word_001.jpg
            |- word_002.jpg
            |- word_003.jpg
            | ...

3. 启动训练

将准备好的txt文件和图片文件夹路径分别写入配置文件的 Train/Eval.dataset.label_file_listTrain/Eval.dataset.data_dir 字段下,Train/Eval.dataset.data_dir字段下的路径和文件里记载的图片名构成了图片的绝对路径。

PaddleOCR提供了训练脚本、评估脚本和预测脚本。

开始训练:

如果您安装的是cpu版本,请将配置文件中的 use_gpu 字段修改为false

# GPU训练 支持单卡,多卡训练,通过 '--gpus' 指定卡号。
# 启动训练,下面的命令已经写入train.sh文件中,只需修改文件里的配置文件路径即可
python3 -m paddle.distributed.launch --gpus '0,1,2,3,4,5,6,7'  tools/train.py -c configs/cls/cls_mv3.yml
  • 数据增强

PaddleOCR提供了多种数据增强方式,如果您希望在训练时加入扰动,请在配置文件中取消Train.dataset.transforms下的RecAugRandAugment字段的注释。

默认的扰动方式有:颜色空间转换(cvtColor)、模糊(blur)、抖动(jitter)、噪声(Gasuss noise)、随机切割(random crop)、透视(perspective)、颜色反转(reverse),随机数据增强(RandAugment)。

训练过程中除随机数据增强外每种扰动方式以50%的概率被选择,具体代码实现请参考:
rec_img_aug.py
randaugment.py

由于OpenCV的兼容性问题,扰动操作暂时只支持linux

4. 训练

PaddleOCR支持训练和评估交替进行, 可以在 configs/cls/cls_mv3.yml 中修改 eval_batch_step 设置评估频率,默认每1000个iter评估一次。训练过程中将会保存如下内容:

├── best_accuracy.pdopt # 最佳模型的优化器参数
├── best_accuracy.pdparams # 最佳模型的参数
├── best_accuracy.states # 最佳模型的指标和epoch等信息
├── config.yml # 本次实验的配置文件
├── latest.pdopt # 最新模型的优化器参数
├── latest.pdparams # 最新模型的参数
├── latest.states # 最新模型的指标和epoch等信息
└── train.log # 训练日志

如果验证集很大,测试将会比较耗时,建议减少评估次数,或训练完再进行评估。

注意,预测/评估时的配置文件请务必与训练一致。

5. 评估

评估数据集可以通过修改configs/cls/cls_mv3.yml文件里的Eval.dataset.label_file_list 字段设置。

export CUDA_VISIBLE_DEVICES=0
# GPU 评估, Global.checkpoints 为待测权重
python3 tools/eval.py -c configs/cls/cls_mv3.yml -o Global.checkpoints={path/to/weights}/best_accuracy

6. 预测

  • 训练引擎的预测

使用 PaddleOCR 训练好的模型,可以通过以下脚本进行快速预测。

通过 Global.infer_img 指定预测图片或文件夹路径,通过 Global.checkpoints 指定权重:

# 预测分类结果
python3 tools/infer_cls.py -c configs/cls/cls_mv3.yml -o Global.pretrained_model={path/to/weights}/best_accuracy Global.load_static_weights=false Global.infer_img=doc/imgs_words/ch/word_1.jpg

得到输入图像的预测结果:

infer_img: doc/imgs_words/ch/word_1.jpg
     result: ('0', 0.9998784)

知识蒸馏

(以下文字转载官方文档knowledge_distillation)

1. 简介

1.1 知识蒸馏介绍

近年来,深度神经网络在计算机视觉、自然语言处理等领域被验证是一种极其有效的解决问题的方法。通过构建合适的神经网络,加以训练,最终网络模型的性能指标基本上都会超过传统算法。

在数据量足够大的情况下,通过合理构建网络模型的方式增加其参数量,可以显著改善模型性能,但是这又带来了模型复杂度急剧提升的问题。大模型在实际场景中使用的成本较高。

深度神经网络一般有较多的参数冗余,目前有几种主要的方法对模型进行压缩,减小其参数量。如裁剪、量化、知识蒸馏等,其中知识蒸馏是指使用教师模型(teacher model)去指导学生模型(student model)学习特定任务,保证小模型在参数量不变的情况下,得到比较大的性能提升。

此外,在知识蒸馏任务中,也衍生出了互学习的模型训练方法,论文Deep Mutual Learning中指出,使用两个完全相同的模型在训练的过程中互相监督,可以达到比单个模型训练更好的效果。

1.2 PaddleOCR知识蒸馏简介

无论是大模型蒸馏小模型,还是小模型之间互相学习,更新参数,他们本质上是都是不同模型之间输出或者特征图(feature map)之间的相互监督,区别仅在于 (1) 模型是否需要固定参数。(2) 模型是否需要加载预训练模型。

对于大模型蒸馏小模型的情况,大模型一般需要加载预训练模型并固定参数;对于小模型之间互相蒸馏的情况,小模型一般都不加载预训练模型,参数也都是可学习的状态。

在知识蒸馏任务中,不只有2个模型之间进行蒸馏的情况,多个模型之间互相学习的情况也非常普遍。因此在知识蒸馏代码框架中,也有必要支持该种类别的蒸馏方法。

PaddleOCR中集成了知识蒸馏的算法,具体地,有以下几个主要的特点:

  • 支持任意网络的互相学习,不要求子网络结构完全一致或者具有预训练模型;同时子网络数量也没有任何限制,只需要在配置文件中添加即可。
  • 支持loss函数通过配置文件任意配置,不仅可以使用某种loss,也可以使用多种loss的组合
  • 支持知识蒸馏训练、预测、评估与导出等所有模型相关的环境,方便使用与部署。

通过知识蒸馏,在中英文通用文字识别任务中,不增加任何预测耗时的情况下,可以给模型带来3%以上的精度提升,结合学习率调整策略以及模型结构微调策略,最终提升提升超过5%。

2. 配置文件解析

在知识蒸馏训练的过程中,数据预处理、优化器、学习率、全局的一些属性没有任何变化。模型结构、损失函数、后处理、指标计算等模块的配置文件需要进行微调。

下面以识别与检测的知识蒸馏配置文件为例,对知识蒸馏的训练与配置进行解析。

2.1 识别配置文件解析

配置文件在ch_PP-OCRv3_rec_distillation.yml

2.1.1 模型结构

知识蒸馏任务中,模型结构配置如下所示。

Architecture:
  model_type: &model_type "rec"    # 模型类别,rec、det等,每个子网络的模型类别
  name: DistillationModel          # 结构名称,蒸馏任务中,为DistillationModel,用于构建对应的结构
  algorithm: Distillation          # 算法名称
  Models:                          # 模型,包含子网络的配置信息
    Teacher:                       # 子网络名称,至少需要包含`pretrained`与`freeze_params`信息,其他的参数为子网络的构造参数
      pretrained:                  # 该子网络是否需要加载预训练模型
      freeze_params: false         # 是否需要固定参数
      return_all_feats: true       # 子网络的参数,表示是否需要返回所有的features,如果为False,则只返回最后的输出
      model_type: *model_type      # 模型类别
      algorithm: SVTR              # 子网络的算法名称,该子网络其余参数均为构造参数,与普通的模型训练配置一致
      Transform:
      Backbone:
        name: MobileNetV1Enhance
        scale: 0.5
        last_conv_stride: [1, 2]
        last_pool_type: avg
      Head:
        name: MultiHead
        head_list:
          - CTCHead:
              Neck:
                name: svtr
                dims: 64
                depth: 2
                hidden_dims: 120
                use_guide: True
              Head:
                fc_decay: 0.00001
          - SARHead:
              enc_dim: 512
              max_text_length: *max_text_length
    Student:
      pretrained:
      freeze_params: false
      return_all_feats: true
      model_type: *model_type
      algorithm: SVTR
      Transform:
      Backbone:
        name: MobileNetV1Enhance
        scale: 0.5
        last_conv_stride: [1, 2]
        last_pool_type: avg
      Head:
        name: MultiHead
        head_list:
          - CTCHead:
              Neck:
                name: svtr
                dims: 64
                depth: 2
                hidden_dims: 120
                use_guide: True
              Head:
                fc_decay: 0.00001
          - SARHead:
              enc_dim: 512
              max_text_length: *max_text_length

当然,这里如果希望添加更多的子网络进行训练,也可以按照StudentTeacher的添加方式,在配置文件中添加相应的字段。比如说如果希望有3个模型互相监督,共同训练,那么Architecture可以写为如下格式。

Architecture:
  model_type: &model_type "rec"
  name: DistillationModel
  algorithm: Distillation
  Models:
    Teacher:
      pretrained:
      freeze_params: false
      return_all_feats: true
      model_type: *model_type
      algorithm: SVTR
      Transform:
      Backbone:
        name: MobileNetV1Enhance
        scale: 0.5
        last_conv_stride: [1, 2]
        last_pool_type: avg
      Head:
        name: MultiHead
        head_list:
          - CTCHead:
              Neck:
                name: svtr
                dims: 64
                depth: 2
                hidden_dims: 120
                use_guide: True
              Head:
                fc_decay: 0.00001
          - SARHead:
              enc_dim: 512
              max_text_length: *max_text_length
    Student:
      pretrained:
      freeze_params: false
      return_all_feats: true
      model_type: *model_type
      algorithm: SVTR
      Transform:
      Backbone:
        name: MobileNetV1Enhance
        scale: 0.5
        last_conv_stride: [1, 2]
        last_pool_type: avg
      Head:
        name: MultiHead
        head_list:
          - CTCHead:
              Neck:
                name: svtr
                dims: 64
                depth: 2
                hidden_dims: 120
                use_guide: True
              Head:
                fc_decay: 0.00001
          - SARHead:
              enc_dim: 512
              max_text_length: *max_text_length
    Student2:
      pretrained:
      freeze_params: false
      return_all_feats: true
      model_type: *model_type
      algorithm: SVTR
      Transform:
      Backbone:
        name: MobileNetV1Enhance
        scale: 0.5
        last_conv_stride: [1, 2]
        last_pool_type: avg
      Head:
        name: MultiHead
        head_list:
          - CTCHead:
              Neck:
                name: svtr
                dims: 64
                depth: 2
                hidden_dims: 120
                use_guide: True
              Head:
                fc_decay: 0.00001
          - SARHead:
              enc_dim: 512
              max_text_length: *max_text_length

最终该模型训练时,包含3个子网络:Teacher, Student, Student2

蒸馏模型DistillationModel类的具体实现代码可以参考distillation_model.py

最终模型forward输出为一个字典,key为所有的子网络名称,例如这里为StudentTeacher,value为对应子网络的输出,可以为Tensor(只返回该网络的最后一层)和dict(也返回了中间的特征信息)。

在识别任务中,为了添加更多损失函数,保证蒸馏方法的可扩展性,将每个子网络的输出保存为dict,其中包含子模块输出。以该识别模型为例,每个子网络的输出结果均为dict,key包含backbone_out,neck_out, head_outvalue为对应模块的tensor,最终对于上述配置文件,DistillationModel的输出格式如下。

{
    
    
  "Teacher": {
    
    
    "backbone_out": tensor,
    "neck_out": tensor,
    "head_out": tensor,
  },
  "Student": {
    
    
    "backbone_out": tensor,
    "neck_out": tensor,
    "head_out": tensor,
  }
}

2.1.2 损失函数

知识蒸馏任务中,损失函数配置如下所示。

Loss:
  name: CombinedLoss
  loss_config_list:
  - DistillationDMLLoss:                       # 蒸馏的DML损失函数,继承自标准的DMLLoss
      weight: 1.0                              # 权重
      act: "softmax"                           # 激活函数,对输入使用激活函数处理,可以为softmax, sigmoid或者为None,默认为None
      use_log: true                            # 对输入计算log,如果函数已经
      model_name_pairs:                        # 用于计算DML loss的子网络名称对,如果希望计算其他子网络的DML loss,可以在列表下面继续填充
      - ["Student", "Teacher"]
      key: head_out                            # 取子网络输出dict中,该key对应的tensor
      multi_head: True                         # 是否为多头结构
      dis_head: ctc                            # 指定用于计算损失函数的head
      name: dml_ctc                            # 蒸馏loss的前缀名称,避免不同loss之间的命名冲突
  - DistillationDMLLoss:                       # 蒸馏的DML损失函数,继承自标准的DMLLoss
      weight: 0.5                              # 权重
      act: "softmax"                           # 激活函数,对输入使用激活函数处理,可以为softmax, sigmoid或者为None,默认为None
      use_log: true                            # 对输入计算log,如果函数已经
      model_name_pairs:                        # 用于计算DML loss的子网络名称对,如果希望计算其他子网络的DML loss,可以在列表下面继续填充
      - ["Student", "Teacher"]
      key: head_out                            # 取子网络输出dict中,该key对应的tensor
      multi_head: True                         # 是否为多头结构
      dis_head: sar                            # 指定用于计算损失函数的head
      name: dml_sar                            # 蒸馏loss的前缀名称,避免不同loss之间的命名冲突
  - DistillationDistanceLoss:                  # 蒸馏的距离损失函数
      weight: 1.0                              # 权重
      mode: "l2"                               # 距离计算方法,目前支持l1, l2, smooth_l1
      model_name_pairs:                        # 用于计算distance loss的子网络名称对
      - ["Student", "Teacher"]
      key: backbone_out                        # 取子网络输出dict中,该key对应的tensor
  - DistillationCTCLoss:                       # 基于蒸馏的CTC损失函数,继承自标准的CTC loss
      weight: 1.0                              # 损失函数的权重,loss_config_list中,每个损失函数的配置都必须包含该字段
      model_name_list: ["Student", "Teacher"]  # 对于蒸馏模型的预测结果,提取这两个子网络的输出,与gt计算CTC loss
      key: head_out                            # 取子网络输出dict中,该key对应的tensor
  - DistillationSARLoss:                       # 基于蒸馏的SAR损失函数,继承自标准的SARLoss
      weight: 1.0                              # 损失函数的权重,loss_config_list中,每个损失函数的配置都必须包含该字段
      model_name_list: ["Student", "Teacher"]  # 对于蒸馏模型的预测结果,提取这两个子网络的输出,与gt计算CTC loss
      key: head_out                            # 取子网络输出dict中,该key对应的tensor
      multi_head: True                         # 是否为多头结构,为true时,取出其中的SAR分支计算损失函数

上述损失函数中,所有的蒸馏损失函数均继承自标准的损失函数类,主要功能为: 对蒸馏模型的输出进行解析,找到用于计算损失的中间节点(tensor),再使用标准的损失函数类去计算。

以上述配置为例,最终蒸馏训练的损失函数包含下面5个部分。

  • StudentTeacher最终输出(head_out)的CTC分支与gt的CTC loss,权重为1。在这里因为2个子网络都需要更新参数,因此2者都需要计算与g的loss。
  • StudentTeacher最终输出(head_out)的SAR分支与gt的SAR loss,权重为1.0。在这里因为2个子网络都需要更新参数,因此2者都需要计算与g的loss。
  • StudentTeacher最终输出(head_out)的CTC分支之间的DML loss,权重为1。
  • StudentTeacher最终输出(head_out)的SAR分支之间的DML loss,权重为0.5。
  • StudentTeacher的骨干网络输出(backbone_out)之间的l2 loss,权重为1。

关于CombinedLoss更加具体的实现可以参考: combined_loss.py。关于DistillationCTCLoss等蒸馏损失函数更加具体的实现可以参考distillation_loss.py

2.1.3 后处理

知识蒸馏任务中,后处理配置如下所示。

PostProcess:
  name: DistillationCTCLabelDecode       # 蒸馏任务的CTC解码后处理,继承自标准的CTCLabelDecode类
  model_name: ["Student", "Teacher"]     # 对于蒸馏模型的预测结果,提取这两个子网络的输出,进行解码
  key: head_out                          # 取子网络输出dict中,该key对应的tensor
  multi_head: True                       # 多头结构时,会取出其中的CTC分支进行计算

以上述配置为例,最终会同时计算StudentTeahcer 2个子网络的CTC解码输出,返回一个dictkey为用于处理的子网络名称,value为用于处理的子网络列表。

关于DistillationCTCLabelDecode更加具体的实现可以参考: rec_postprocess.py

2.1.4 指标计算

知识蒸馏任务中,指标计算配置如下所示。

Metric:
  name: DistillationMetric         # 蒸馏任务的CTC解码后处理,继承自标准的CTCLabelDecode类
  base_metric_name: RecMetric      # 指标计算的基类,对于模型的输出,会基于该类,计算指标
  main_indicator: acc              # 指标的名称
  key: "Student"                   # 选取该子网络的 main_indicator 作为作为保存保存best model的判断标准
  ignore_space: False              # 评估时是否忽略空格的影响

以上述配置为例,最终会使用Student子网络的acc指标作为保存best model的判断指标,同时,日志中也会打印出所有子网络的acc指标。

关于DistillationMetric更加具体的实现可以参考: distillation_metric.py

2.1.5 蒸馏模型微调

对蒸馏得到的识别蒸馏进行微调有2种方式。

(1)基于知识蒸馏的微调:这种情况比较简单,下载预训练模型,在ch_PP-OCRv3_rec_distillation.yml中配置好预训练模型路径以及自己的数据路径,即可进行模型微调训练。

(2)微调时不使用知识蒸馏:这种情况,需要首先将预训练模型中的学生模型参数提取出来,具体步骤如下。

  • 首先下载预训练模型并解压。
# 下面预训练模型并解压
wget https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar
tar -xf ch_PP-OCRv3_rec_train.tar
  • 然后使用python,对其中的学生模型参数进行提取
import paddle
# 加载预训练模型
all_params = paddle.load("ch_PP-OCRv3_rec_train/best_accuracy.pdparams")
# 查看权重参数的keys
print(all_params.keys())
# 学生模型的权重提取
s_params = {
    
    key[len("Student."):]: all_params[key] for key in all_params if "Student." in key}
# 查看学生模型权重参数的keys
print(s_params.keys())
# 保存
paddle.save(s_params, "ch_PP-OCRv3_rec_train/student.pdparams")

转化完成之后,使用ch_PP-OCRv3_rec.yml,修改预训练模型的路径(为导出的student.pdparams模型路径)以及自己的数据路径,即可进行模型微调。

2.2 检测配置文件解析

检测模型蒸馏的配置文件在PaddleOCR/configs/det/ch_PP-OCRv3/目录下,包含两个个蒸馏配置文件:

  • ch_PP-OCRv3_det_cml.yml,采用cml蒸馏,采用一个大模型蒸馏两个小模型,且两个小模型互相学习的方法
  • ch_PP-OCRv3_det_dml.yml,采用DML的蒸馏,两个Student模型互蒸馏的方法

2.2.1 模型结构

知识蒸馏任务中,模型结构配置如下所示:

Architecture:
  name: DistillationModel          # 结构名称,蒸馏任务中,为DistillationModel,用于构建对应的结构
  algorithm: Distillation          # 算法名称
  Models:                          # 模型,包含子网络的配置信息
    Student:                       # 子网络名称,至少需要包含`pretrained`与`freeze_params`信息,其他的参数为子网络的构造参数
      freeze_params: false         # 是否需要固定参数
      return_all_feats: false      # 子网络的参数,表示是否需要返回所有的features,如果为False,则只返回最后的输出
      model_type: det
      algorithm: DB
      Backbone:
        name: ResNet
        in_channels: 3
        layers: 50
      Neck:
        name: LKPAN
        out_channels: 256
      Head:
        name: DBHead
        kernel_list: [7,2,2]
        k: 50
    Teacher:                      # 另外一个子网络,这里给的是DML蒸馏示例,
      freeze_params: true
      return_all_feats: false
      model_type: det
      algorithm: DB
      Transform:
      Backbone:
        name: ResNet
        in_channels: 3
        layers: 50
      Neck:
        name: LKPAN
        out_channels: 256
      Head:
        name: DBHead
        kernel_list: [7,2,2]
        k: 50

如果是采用DML,即两个小模型互相学习的方法,上述配置文件里的Teacher网络结构需要设置为Student模型一样的配置,具体参考配置文件ch_PP-OCRv3_det_dml.yml

下面介绍ch_PP-OCRv3_det_cml.yml的配置文件参数:

Architecture:
  name: DistillationModel
  algorithm: Distillation
  model_type: det
  Models:
    Teacher:                         # CML蒸馏的Teacher模型配置
      pretrained: ./pretrain_models/ch_ppocr_server_v2.0_det_train/best_accuracy
      freeze_params: true            # Teacher 不训练
      return_all_feats: false
      model_type: det
      algorithm: DB
      Transform:
      Backbone:
        name: ResNet
        in_channels: 3
        layers: 50
      Neck:
        name: LKPAN
        out_channels: 256
      Head:
        name: DBHead
        kernel_list: [7,2,2]
        k: 50
    Student:                         # CML蒸馏的Student模型配置
      pretrained: ./pretrain_models/MobileNetV3_large_x0_5_pretrained
      freeze_params: false
      return_all_feats: false
      model_type: det
      algorithm: DB
      Backbone:
        name: MobileNetV3
        scale: 0.5
        model_name: large
        disable_se: true
      Neck:
        name: RSEFPN
        out_channels: 96
        shortcut: True
      Head:
        name: DBHead
        k: 50
    Student2:                          # CML蒸馏的Student2模型配置
      pretrained: ./pretrain_models/MobileNetV3_large_x0_5_pretrained
      freeze_params: false
      return_all_feats: false
      model_type: det
      algorithm: DB
      Transform:
      Backbone:
        name: MobileNetV3
        scale: 0.5
        model_name: large
        disable_se: true
      Neck:
        name: RSEFPN
        out_channels: 96
        shortcut: True
      Head:
        name: DBHead
        k: 50

蒸馏模型DistillationModel类的具体实现代码可以参考distillation_model.py

最终模型forward输出为一个字典,key为所有的子网络名称,例如这里为StudentTeacher,value为对应子网络的输出,可以为Tensor(只返回该网络的最后一层)和dict(也返回了中间的特征信息)。

在蒸馏任务中,为了方便添加蒸馏损失函数,每个网络的输出保存为dict,其中包含子模块输出。每个子网络的输出结果均为dict,key包含backbone_out,neck_out, head_outvalue为对应模块的tensor,最终对于上述配置文件,DistillationModel的输出格式如下。

{
    
    
  "Teacher": {
    
    
    "backbone_out": tensor,
    "neck_out": tensor,
    "head_out": tensor,
  },
  "Student": {
    
    
    "backbone_out": tensor,
    "neck_out": tensor,
    "head_out": tensor,
  }
}

2.2.2 损失函数

检测ch_PP-OCRv3_det_cml.yml蒸馏损失函数配置如下所示。

Loss:
  name: CombinedLoss
  loss_config_list:
  - DistillationDilaDBLoss:
      weight: 1.0
      model_name_pairs:
      - ["Student", "Teacher"]
      - ["Student2", "Teacher"]                  # 改动1,计算两个Student和Teacher的损失
      key: maps
      balance_loss: true
      main_loss_type: DiceLoss
      alpha: 5
      beta: 10
      ohem_ratio: 3
  - DistillationDMLLoss:                         # 改动2,增加计算两个Student之间的损失
      model_name_pairs:
      - ["Student", "Student2"]
      maps_name: "thrink_maps"
      weight: 1.0
      # act: None
      key: maps
  - DistillationDBLoss:
      weight: 1.0
      model_name_list: ["Student", "Student2"]   # 改动3,计算两个Student和GT之间的损失
      balance_loss: true
      main_loss_type: DiceLoss
      alpha: 5
      beta: 10
      ohem_ratio: 3

关于DistillationDilaDBLoss更加具体的实现可以参考: distillation_loss.py。关于DistillationDBLoss等蒸馏损失函数更加具体的实现可以参考distillation_loss.py

2.2.3 后处理

知识蒸馏任务中,检测蒸馏后处理配置如下所示。

PostProcess:
  name: DistillationDBPostProcess                  # DB检测蒸馏任务的CTC解码后处理,继承自标准的DBPostProcess类
  model_name: ["Student", "Student2", "Teacher"]   # 对于蒸馏模型的预测结果,提取多个子网络的输出,进行解码,不需要后处理的网络可以不在model_name中设置
  thresh: 0.3
  box_thresh: 0.6
  max_candidates: 1000
  unclip_ratio: 1.5

以上述配置为例,最终会同时计算StudentStudent2Teacher 3个子网络的输出做后处理计算。同时,由于有多个输入,后处理返回的输出也有多个,

关于DistillationDBPostProcess更加具体的实现可以参考: db_postprocess.py

2.2.4 蒸馏指标计算

知识蒸馏任务中,检测蒸馏指标计算配置如下所示。

Metric:
  name: DistillationMetric
  base_metric_name: DetMetric
  main_indicator: hmean
  key: "Student"

由于蒸馏需要包含多个网络,甚至多个Student网络,在计算指标的时候只需要计算一个Student网络的指标即可,key字段设置为Student则表示只计算Student网络的精度。

2.2.5 检测蒸馏模型finetune

PP-OCRv3检测蒸馏有两种方式:

  • 采用ch_PP-OCRv3_det_cml.yml,采用cml蒸馏,同样Teacher模型设置为PaddleOCR提供的模型或者您训练好的大模型
  • 采用ch_PP-OCRv3_det_dml.yml,采用DML的蒸馏,两个Student模型互蒸馏的方法,在PaddleOCR采用的数据集上相比单独训练Student模型有1%-2%的提升。

在具体fine-tune时,需要在网络结构的pretrained参数中设置要加载的预训练模型。

在精度提升方面,cml的精度>dml的精度蒸馏方法的精度。当数据量不足或者Teacher模型精度与Student精度相差不大的时候,这个结论或许会改变。

另外,由于PaddleOCR提供的蒸馏预训练模型包含了多个模型的参数,如果您希望提取Student模型的参数,可以参考如下代码:

# 下载蒸馏训练模型的参数
wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv3_det_distill_train.tar
import paddle
# 加载预训练模型
all_params = paddle.load("ch_PP-OCRv3_det_distill_train/best_accuracy.pdparams")
# 查看权重参数的keys
print(all_params.keys())
# 学生模型的权重提取
s_params = {
    
    key[len("Student."):]: all_params[key] for key in all_params if "Student." in key}
# 查看学生模型权重参数的keys
print(s_params.keys())
# 保存
paddle.save(s_params, "ch_PP-OCRv3_det_distill_train/student.pdparams")

最终Student模型的参数将会保存在ch_PP-OCRv3_det_distill_train/student.pdparams中,用于模型的fine-tune。

猜你喜欢

转载自blog.csdn.net/Jiagym/article/details/142874758