diff --git a/PPOCRLabel/README.md b/PPOCRLabel/README.md index 250d1fc0c989e6db50deffc06d1c9db47ba4c2f0..e67f69e9b3ae0279b65901afae4ae937dfc84610 100644 --- a/PPOCRLabel/README.md +++ b/PPOCRLabel/README.md @@ -8,7 +8,7 @@ PPOCRLabelv2 is a semi-automatic graphic annotation tool suitable for OCR field, | :-------------------------------------------------: | :--------------------------------------------: | | | | | **irregular text annotation** | **key information annotation** | -| | | +| | | ### Recent Update diff --git a/PPOCRLabel/README_ch.md b/PPOCRLabel/README_ch.md index 1901e8f3c184497414723fef9ad69829b79cb218..b3c283b4069a925ba92ed4217c962051d8008c27 100644 --- a/PPOCRLabel/README_ch.md +++ b/PPOCRLabel/README_ch.md @@ -8,7 +8,7 @@ PPOCRLabel是一款适用于OCR领域的半自动化图形标注工具,内置P | :---------------------------------------------------: | :----------------------------------------------: | | | | | **不规则文本标注** | **关键信息标注** | -| | | +| | | #### 近期更新 diff --git a/README.md b/README.md index 87be91f1ea046b05b601385500369da1e5027ebc..afbe77919dd97fca26805906ce08d0747eb4600a 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ PaddleOCR aims to create multilingual, awesome, leading, and practical OCR tools ## Recent updates +- **🔥2022.7 Release [OCR scene application collection](./applications/README_en.md)** + - PaddleOCR scene application covers general, manufacturing, finance, transportation industry of the main OCR vertical applications, including digital tube, LCD screen character, license plate, high-precision SVTR model, etc. **7 vertical models**. - **🔥2022.5.9 Release PaddleOCR [release/2.5](https://github.com/PaddlePaddle/PaddleOCR/tree/release/2.5)** - Release [PP-OCRv3](./doc/doc_en/ppocr_introduction_en.md#pp-ocrv3): With comparable speed, the effect of Chinese scene is further improved by 5% compared with PP-OCRv2, the effect of English scene is improved by 11%, and the average recognition accuracy of 80 language multilingual models is improved by more than 5%. - Release [PPOCRLabelv2](./PPOCRLabel): Add the annotation function for table recognition task, key information extraction task and irregular text image. @@ -37,7 +39,6 @@ PaddleOCR aims to create multilingual, awesome, leading, and practical OCR tools - Release [PP-OCRv2](./doc/doc_en/ppocr_introduction_en.md#pp-ocrv2). The inference speed of PP-OCRv2 is 220% higher than that of PP-OCR server in CPU device. The F-score of PP-OCRv2 is 7% higher than that of PP-OCR mobile. - 2021.8.3 Release PaddleOCR [release/2.2](https://github.com/PaddlePaddle/PaddleOCR/tree/release/2.2) - Release a new structured documents analysis toolkit, i.e., [PP-Structure](./ppstructure/README.md), support layout analysis and table recognition (One-key to export chart images to Excel files). - - [more](./doc/doc_en/update_en.md) @@ -47,14 +48,15 @@ PaddleOCR support a variety of cutting-edge algorithms related to OCR, and devel ![](./doc/features_en.png) -> It is recommended to start with the “quick experience” in the document tutorial +> It is recommended to start with the “quick start” in the document tutorial ## Quick Experience +- One line of code quick use: [Quick Start](./doc/doc_en/quickstart_en.md) - Web online experience for the ultra-lightweight OCR: [Online Experience](https://www.paddlepaddle.org.cn/hub/scene/ocr) - Mobile DEMO experience (based on EasyEdge and Paddle-Lite, supports iOS and Android systems): [Sign in to the website to obtain the QR code for installing the App](https://ai.baidu.com/easyedge/app/openSource?from=paddlelite) -- One line of code quick use: [Quick Start](./doc/doc_en/quickstart_en.md) + @@ -63,14 +65,16 @@ PaddleOCR support a variety of cutting-edge algorithms related to OCR, and devel -## Community +## Community👬 -- **Join us**👬: Scan the QR code below with your Wechat, you can join the official technical discussion group. Looking forward to your participation. +- For international developers, we regard [PaddleOCR Discussions](https://github.com/PaddlePaddle/PaddleOCR/discussions) as our international community platform. All ideas and questions can be discussed here in English. +- For Chinese develops, Scan the QR code below with your Wechat, you can join the official technical discussion group. For richer community content, please refer to [中文README](README_ch.md), looking forward to your participation.
- +
+ ## PP-OCR Series Model List(Update on September 8th) diff --git a/README_ch.md b/README_ch.md index fc2b033888703e4bf6874c6e2a750cf4158f15ed..5bce9749dd8d87187899eb712f0720beb9c8f1d1 100755 --- a/README_ch.md +++ b/README_ch.md @@ -27,17 +27,9 @@ PaddleOCR旨在打造一套丰富、领先、且实用的OCR工具库,助力 ## 近期更新 -- **🔥2022.5.25~26 OCR产业应用两日直播课** +- **🔥2022.7 发布[OCR场景应用集合](./applications)** + - 发布OCR场景应用集合,包含数码管、液晶屏、车牌、高精度SVTR模型等**7个垂类模型**,覆盖通用,制造、金融、交通行业的主要OCR垂类应用。 - - 25日:车牌识别产业应用实战([AI Studio项目链接](https://aistudio.baidu.com/aistudio/projectdetail/3919091?contributionType=1)) - - 26日:一招搞定工业常见数码管、PCB字符识别(AI Studio项目链接:[数码管识别](https://aistudio.baidu.com/aistudio/projectdetail/4049044?contributionType=1),[PCB字符识别](https://aistudio.baidu.com/aistudio/projectdetail/4008973)) - - 扫描下方二维码填写问卷后进入群聊,获取直播链接! -
- -
- - - **🔥2022.5.9 发布PaddleOCR [release/2.5](https://github.com/PaddlePaddle/PaddleOCR/tree/release/2.5)** - 发布[PP-OCRv3](./doc/doc_ch/ppocr_introduction.md#pp-ocrv3),速度可比情况下,中文场景效果相比于PP-OCRv2再提升5%,英文场景提升11%,80语种多语言模型平均识别准确率提升5%以上; - 发布半自动标注工具[PPOCRLabelv2](./PPOCRLabel):新增表格文字图像、图像关键信息抽取任务和不规则文字图像的标注功能; @@ -75,19 +67,19 @@ PaddleOCR旨在打造一套丰富、领先、且实用的OCR工具库,助力 ## 开源社区 - +- **项目合作📑:** 如果您是企业开发者且有明确的OCR垂类应用需求,填写[问卷](https://paddle.wjx.cn/vj/QwF7GKw.aspx)后可免费与官方团队展开不同层次的合作。 - **加入社区👬:** 微信扫描二维码并填写问卷之后,加入交流群领取福利 - **获取PaddleOCR最新发版解说《OCR超强技术详解与产业应用实战》系列直播课回放链接** - **10G重磅OCR学习大礼包:**《动手学OCR》电子书,配套讲解视频和notebook项目;66篇OCR相关顶会前沿论文打包放送,包括CVPR、AAAI、IJCAI、ICCV等;PaddleOCR历次发版直播课视频;OCR社区优秀开发者项目分享视频。 - -- **社区贡献**🏅️:[社区贡献](./doc/doc_ch/thirdparty.md)文档中包含了社区用户**使用PaddleOCR开发的各种工具、应用**以及**为PaddleOCR贡献的功能、优化的文档与代码**等,是官方为社区开发者打造的荣誉墙,也是帮助优质项目宣传的广播站。 +- **社区项目**🏅️:[社区项目](./doc/doc_ch/thirdparty.md)文档中包含了社区用户**使用PaddleOCR开发的各种工具、应用**以及**为PaddleOCR贡献的功能、优化的文档与代码**等,是官方为社区开发者打造的荣誉墙,也是帮助优质项目宣传的广播站。 - **社区常规赛**🎁:社区常规赛是面向OCR开发者的积分赛事,覆盖文档、代码、模型和应用四大类型,以季度为单位评选并发放奖励,赛题详情与报名方法可参考[链接](https://github.com/PaddlePaddle/PaddleOCR/issues/4982)。
- +
+ ## PP-OCR系列模型列表(更新中) @@ -95,14 +87,21 @@ PaddleOCR旨在打造一套丰富、领先、且实用的OCR工具库,助力 | ------------------------------------- | ----------------------- | --------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | 中英文超轻量PP-OCRv3模型(16.2M) | ch_PP-OCRv3_xx | 移动端&服务器端 | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_distill_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar) | | 英文超轻量PP-OCRv3模型(13.4M) | en_PP-OCRv3_xx | 移动端&服务器端 | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_det_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_det_distill_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_rec_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_rec_train.tar) | -| 中英文超轻量PP-OCRv2模型(13.0M) | ch_PP-OCRv2_xx | 移动端&服务器端 | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_distill_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_train.tar) | -| 中英文超轻量PP-OCR mobile模型(9.4M) | ch_ppocr_mobile_v2.0_xx | 移动端&服务器端 | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_det_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_det_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_rec_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_rec_pre.tar) | -| 中英文通用PP-OCR server模型(143.4M) | ch_ppocr_server_v2.0_xx | 服务器端 | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_det_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_det_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_rec_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_rec_pre.tar) | -更多模型下载(包括多语言),可以参考[PP-OCR 系列模型下载](./doc/doc_ch/models_list.md),文档分析相关模型参考[PP-Structure 系列模型下载](./ppstructure/docs/models_list.md) +- 超轻量OCR系列更多模型下载(包括多语言),可以参考[PP-OCR系列模型下载](./doc/doc_ch/models_list.md),文档分析相关模型参考[PP-Structure系列模型下载](./ppstructure/docs/models_list.md) + +### PaddleOCR场景应用模型 +| 行业 | 类别 | 亮点 | 文档说明 | 模型下载 | +| ---- | ------------ | ---------------------------------- | ------------------------------------------------------------ | --------------------------------------------- | +| 制造 | 数码管识别 | 数码管数据合成、漏识别调优 | [光功率计数码管字符识别](./applications/光功率计数码管字符识别/光功率计数码管字符识别.md) | [下载链接](./applications/README.md#模型下载) | +| 金融 | 通用表单识别 | 多模态通用表单结构化提取 | [多模态表单识别](./applications/多模态表单识别.md) | [下载链接](./applications/README.md#模型下载) | +| 交通 | 车牌识别 | 多角度图像处理、轻量模型、端侧部署 | [轻量级车牌识别](./applications/轻量级车牌识别.md) | [下载链接](./applications/README.md#模型下载) | + +- 更多制造、金融、交通行业的主要OCR垂类应用模型(如电表、液晶屏、高精度SVTR模型等),可参考[场景应用模型下载](./applications) + ## 文档教程 - [运行环境准备](./doc/doc_ch/environment.md) diff --git "a/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/PCB\345\255\227\347\254\246\350\257\206\345\210\253.md" "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/PCB\345\255\227\347\254\246\350\257\206\345\210\253.md" new file mode 100644 index 0000000000000000000000000000000000000000..ee13bacffdb65e6300a034531a527fdca4ed29f9 --- /dev/null +++ "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/PCB\345\255\227\347\254\246\350\257\206\345\210\253.md" @@ -0,0 +1,652 @@ +# 基于PP-OCRv3的PCB字符识别 + +- [1. 项目介绍](#1-项目介绍) +- [2. 安装说明](#2-安装说明) +- [3. 数据准备](#3-数据准备) +- [4. 文本检测](#4-文本检测) + - [4.1 预训练模型直接评估](#41-预训练模型直接评估) + - [4.2 预训练模型+验证集padding直接评估](#42-预训练模型验证集padding直接评估) + - [4.3 预训练模型+fine-tune](#43-预训练模型fine-tune) +- [5. 文本识别](#5-文本识别) + - [5.1 预训练模型直接评估](#51-预训练模型直接评估) + - [5.2 三种fine-tune方案](#52-三种fine-tune方案) +- [6. 模型导出](#6-模型导出) +- [7. 端对端评测](#7-端对端评测) +- [8. Jetson部署](#8-Jetson部署) +- [9. 总结](#9-总结) +- [更多资源](#更多资源) + +# 1. 项目介绍 + +印刷电路板(PCB)是电子产品中的核心器件,对于板件质量的测试与监控是生产中必不可少的环节。在一些场景中,通过PCB中信号灯颜色和文字组合可以定位PCB局部模块质量问题,PCB文字识别中存在如下难点: + +- 裁剪出的PCB图片宽高比例较小 +- 文字区域整体面积也较小 +- 包含垂直、水平多种方向文本 + +针对本场景,PaddleOCR基于全新的PP-OCRv3通过合成数据、微调以及其他场景适配方法完成小字符文本识别任务,满足企业上线要求。PCB检测、识别效果如 **图1** 所示: + +
+
图1 PCB检测识别效果
+ +注:欢迎在AIStudio领取免费算力体验线上实训,项目链接: [基于PP-OCRv3实现PCB字符识别](https://aistudio.baidu.com/aistudio/projectdetail/4008973) + +# 2. 安装说明 + + +下载PaddleOCR源码,安装依赖环境。 + + +```python +# 如仍需安装or安装更新,可以执行以下步骤 +git clone https://github.com/PaddlePaddle/PaddleOCR.git +# git clone https://gitee.com/PaddlePaddle/PaddleOCR +``` + + +```python +# 安装依赖包 +pip install -r /home/aistudio/PaddleOCR/requirements.txt +``` + +# 3. 数据准备 + +我们通过图片合成工具生成 **图2** 所示的PCB图片,整图只有高25、宽150左右、文字区域高9、宽45左右,包含垂直和水平2种方向的文本: + +
+
图2 数据集示例
+ +暂时不开源生成的PCB数据集,但是通过更换背景,通过如下代码生成数据即可: + +``` +cd gen_data +python3 gen.py --num_img=10 +``` + +生成图片参数解释: + +``` +num_img:生成图片数量 +font_min_size、font_max_size:字体最大、最小尺寸 +bg_path:文字区域背景存放路径 +det_bg_path:整图背景存放路径 +fonts_path:字体路径 +corpus_path:语料路径 +output_dir:生成图片存储路径 +``` + +这里生成 **100张** 相同尺寸和文本的图片,如 **图3** 所示,方便大家跑通实验。通过如下代码解压数据集: + +
+
图3 案例提供数据集示例
+ + +```python +tar xf ./data/data148165/dataset.tar -C ./ +``` + +在生成数据集的时需要生成检测和识别训练需求的格式: + + +- **文本检测** + +标注文件格式如下,中间用'\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` 表示当前文本框的文字,***当其内容为“###”时,表示该文本框无效,在训练时会跳过。*** + +- **文本识别** + +标注文件的格式如下, txt文件中默认请将图片路径和图片标签用'\t'分割,如用其他方式分割将造成训练报错。 + +``` +" 图像文件名 图像标注信息 " + +train_data/rec/train/word_001.jpg 简单可依赖 +train_data/rec/train/word_002.jpg 用科技让复杂的世界更简单 +... +``` + + +# 4. 文本检测 + +选用飞桨OCR开发套件[PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR)中的PP-OCRv3模型进行文本检测和识别。针对检测模型和识别模型,进行了共计9个方面的升级: + +- PP-OCRv3检测模型对PP-OCRv2中的CML协同互学习文本检测蒸馏策略进行了升级,分别针对教师模型和学生模型进行进一步效果优化。其中,在对教师模型优化时,提出了大感受野的PAN结构LK-PAN和引入了DML蒸馏策略;在对学生模型优化时,提出了残差注意力机制的FPN结构RSE-FPN。 + +- PP-OCRv3的识别模块是基于文本识别算法SVTR优化。SVTR不再采用RNN结构,通过引入Transformers结构更加有效地挖掘文本行图像的上下文信息,从而提升文本识别能力。PP-OCRv3通过轻量级文本识别网络SVTR_LCNet、Attention损失指导CTC损失训练策略、挖掘文字上下文信息的数据增广策略TextConAug、TextRotNet自监督预训练模型、UDML联合互学习策略、UIM无标注数据挖掘方案,6个方面进行模型加速和效果提升。 + +更多细节请参考PP-OCRv3[技术报告](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/PP-OCRv3_introduction.md)。 + + +我们使用 **3种方案** 进行检测模型的训练、评估: +- **PP-OCRv3英文超轻量检测预训练模型直接评估** +- PP-OCRv3英文超轻量检测预训练模型 + **验证集padding**直接评估 +- PP-OCRv3英文超轻量检测预训练模型 + **fine-tune** + +## **4.1 预训练模型直接评估** + +我们首先通过PaddleOCR提供的预训练模型在验证集上进行评估,如果评估指标能满足效果,可以直接使用预训练模型,不再需要训练。 + +使用预训练模型直接评估步骤如下: + +**1)下载预训练模型** + + +PaddleOCR已经提供了PP-OCR系列模型,部分模型展示如下表所示: + +| 模型简介 | 模型名称 | 推荐场景 | 检测模型 | 方向分类器 | 识别模型 | +| ------------------------------------- | ----------------------- | --------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 中英文超轻量PP-OCRv3模型(16.2M) | ch_PP-OCRv3_xx | 移动端&服务器端 | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_distill_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar) | +| 英文超轻量PP-OCRv3模型(13.4M) | en_PP-OCRv3_xx | 移动端&服务器端 | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_det_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_det_distill_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_rec_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_rec_train.tar) | +| 中英文超轻量PP-OCRv2模型(13.0M) | ch_PP-OCRv2_xx | 移动端&服务器端 | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_distill_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_train.tar) | +| 中英文超轻量PP-OCR mobile模型(9.4M) | ch_ppocr_mobile_v2.0_xx | 移动端&服务器端 | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_det_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_det_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_rec_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_rec_pre.tar) | +| 中英文通用PP-OCR server模型(143.4M) | ch_ppocr_server_v2.0_xx | 服务器端 | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_det_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_det_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_cls_train.tar) | [推理模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_rec_infer.tar) / [预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_server_v2.0_rec_pre.tar) | + +更多模型下载(包括多语言),可以参[考PP-OCR系列模型下载](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/models_list.md) + +这里我们使用PP-OCRv3英文超轻量检测模型,下载并解压预训练模型: + + + + +```python +# 如果更换其他模型,更新下载链接和解压指令就可以 +cd /home/aistudio/PaddleOCR +mkdir pretrain_models +cd pretrain_models +# 下载英文预训练模型 +wget https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_det_distill_train.tar +tar xf en_PP-OCRv3_det_distill_train.tar && rm -rf en_PP-OCRv3_det_distill_train.tar +%cd .. +``` + +**模型评估** + + +首先修改配置文件`configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml`中的以下字段: +``` +Eval.dataset.data_dir:指向验证集图片存放目录,'/home/aistudio/dataset' +Eval.dataset.label_file_list:指向验证集标注文件,'/home/aistudio/dataset/det_gt_val.txt' +Eval.dataset.transforms.DetResizeForTest: 尺寸 + limit_side_len: 48 + limit_type: 'min' +``` + +然后在验证集上进行评估,具体代码如下: + + + +```python +cd /home/aistudio/PaddleOCR +python tools/eval.py \ + -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml \ + -o Global.checkpoints="./pretrain_models/en_PP-OCRv3_det_distill_train/best_accuracy" +``` + +## **4.2 预训练模型+验证集padding直接评估** + +考虑到PCB图片比较小,宽度只有25左右、高度只有140-170左右,我们在原图的基础上进行padding,再进行检测评估,padding前后效果对比如 **图4** 所示: + +
+
图4 padding前后对比图
+ +将图片都padding到300*300大小,因为坐标信息发生了变化,我们同时要修改标注文件,在`/home/aistudio/dataset`目录里也提供了padding之后的图片,大家也可以尝试训练和评估: + +同上,我们需要修改配置文件`configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml`中的以下字段: +``` +Eval.dataset.data_dir:指向验证集图片存放目录,'/home/aistudio/dataset' +Eval.dataset.label_file_list:指向验证集标注文件,/home/aistudio/dataset/det_gt_padding_val.txt +Eval.dataset.transforms.DetResizeForTest: 尺寸 + limit_side_len: 1100 + limit_type: 'min' +``` + +如需获取已训练模型,请扫码填写问卷,加入PaddleOCR官方交流群获取全部OCR垂类模型下载链接、《动手学OCR》电子书等全套OCR学习资料🎁 +
+ +
+将下载或训练完成的模型放置在对应目录下即可完成模型评估。 + + +```python +cd /home/aistudio/PaddleOCR +python tools/eval.py \ + -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml \ + -o Global.checkpoints="./pretrain_models/en_PP-OCRv3_det_distill_train/best_accuracy" +``` + +## **4.3 预训练模型+fine-tune** + + +基于预训练模型,在生成的1500图片上进行fine-tune训练和评估,其中train数据1200张,val数据300张,修改配置文件`configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml`中的以下字段: +``` +Global.epoch_num: 这里设置为1,方便快速跑通,实际中根据数据量调整该值 +Global.save_model_dir:模型保存路径 +Global.pretrained_model:指向预训练模型路径,'./pretrain_models/en_PP-OCRv3_det_distill_train/student.pdparams' +Optimizer.lr.learning_rate:调整学习率,本实验设置为0.0005 +Train.dataset.data_dir:指向训练集图片存放目录,'/home/aistudio/dataset' +Train.dataset.label_file_list:指向训练集标注文件,'/home/aistudio/dataset/det_gt_train.txt' +Train.dataset.transforms.EastRandomCropData.size:训练尺寸改为[480,64] +Eval.dataset.data_dir:指向验证集图片存放目录,'/home/aistudio/dataset/' +Eval.dataset.label_file_list:指向验证集标注文件,'/home/aistudio/dataset/det_gt_val.txt' +Eval.dataset.transforms.DetResizeForTest:评估尺寸,添加如下参数 + limit_side_len: 64 + limit_type:'min' +``` +执行下面命令启动训练: + + +```python +cd /home/aistudio/PaddleOCR/ +python tools/train.py \ + -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml +``` + +**模型评估** + + +使用训练好的模型进行评估,更新模型路径`Global.checkpoints`: + + +```python +cd /home/aistudio/PaddleOCR/ +python3 tools/eval.py \ + -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml \ + -o Global.checkpoints="./output/ch_PP-OCR_V3_det/latest" +``` + +使用训练好的模型进行评估,指标如下所示: + + +| 序号 | 方案 | hmean | 效果提升 | 实验分析 | +| -------- | -------- | -------- | -------- | -------- | +| 1 | PP-OCRv3英文超轻量检测预训练模型 | 64.64% | - | 提供的预训练模型具有泛化能力 | +| 2 | PP-OCRv3英文超轻量检测预训练模型 + 验证集padding | 72.13% |+7.5% | padding可以提升尺寸较小图片的检测效果| +| 3 | PP-OCRv3英文超轻量检测预训练模型 + fine-tune | 100% | +27.9% | fine-tune会提升垂类场景效果 | + + +``` +注:上述实验结果均是在1500张图片(1200张训练集,300张测试集)上训练、评估的得到,AIstudio只提供了100张数据,所以指标有所差异属于正常,只要策略有效、规律相同即可。 +``` + +# 5. 文本识别 + +我们分别使用如下4种方案进行训练、评估: + +- **方案1**:**PP-OCRv3中英文超轻量识别预训练模型直接评估** +- **方案2**:PP-OCRv3中英文超轻量检测预训练模型 + **fine-tune** +- **方案3**:PP-OCRv3中英文超轻量检测预训练模型 + fine-tune + **公开通用识别数据集** +- **方案4**:PP-OCRv3中英文超轻量检测预训练模型 + fine-tune + **增加PCB图像数量** + + +## **5.1 预训练模型直接评估** + +同检测模型,我们首先使用PaddleOCR提供的识别预训练模型在PCB验证集上进行评估。 + +使用预训练模型直接评估步骤如下: + +**1)下载预训练模型** + + +我们使用PP-OCRv3中英文超轻量文本识别模型,下载并解压预训练模型: + + +```python +# 如果更换其他模型,更新下载链接和解压指令就可以 +cd /home/aistudio/PaddleOCR/pretrain_models/ +wget https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar +tar xf ch_PP-OCRv3_rec_train.tar && rm -rf ch_PP-OCRv3_rec_train.tar +cd .. +``` + +**模型评估** + + +首先修改配置文件`configs/det/ch_PP-OCRv3/ch_PP-OCRv2_rec_distillation.yml`中的以下字段: + +``` +Metric.ignore_space: True:忽略空格 +Eval.dataset.data_dir:指向验证集图片存放目录,'/home/aistudio/dataset' +Eval.dataset.label_file_list:指向验证集标注文件,'/home/aistudio/dataset/rec_gt_val.txt' +``` + +我们使用下载的预训练模型进行评估: + + +```python +cd /home/aistudio/PaddleOCR +python3 tools/eval.py \ + -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml \ + -o Global.checkpoints=pretrain_models/ch_PP-OCRv3_rec_train/best_accuracy + +``` + +## **5.2 三种fine-tune方案** + +方案2、3、4训练和评估方式是相同的,因此在我们了解每个技术方案之后,再具体看修改哪些参数是相同,哪些是不同的。 + +**方案介绍:** + +1) **方案2**:预训练模型 + **fine-tune** + +- 在预训练模型的基础上进行fine-tune,使用1500张PCB进行训练和评估,其中训练集1200张,验证集300张。 + + +2) **方案3**:预训练模型 + fine-tune + **公开通用识别数据集** + +- 当识别数据比较少的情况,可以考虑添加公开通用识别数据集。在方案2的基础上,添加公开通用识别数据集,如lsvt、rctw等。 + +3)**方案4**:预训练模型 + fine-tune + **增加PCB图像数量** + +- 如果能够获取足够多真实场景,我们可以通过增加数据量提升模型效果。在方案2的基础上,增加PCB的数量到2W张左右。 + + +**参数修改:** + +接着我们看需要修改的参数,以上方案均需要修改配置文件`configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml`的参数,**修改一次即可**: + +``` +Global.pretrained_model:指向预训练模型路径,'pretrain_models/ch_PP-OCRv3_rec_train/best_accuracy' +Optimizer.lr.values:学习率,本实验设置为0.0005 +Train.loader.batch_size_per_card: batch size,默认128,因为数据量小于128,因此我们设置为8,数据量大可以按默认的训练 +Eval.loader.batch_size_per_card: batch size,默认128,设置为4 +Metric.ignore_space: 忽略空格,本实验设置为True +``` + +**更换不同的方案**每次需要修改的参数: +``` +Global.epoch_num: 这里设置为1,方便快速跑通,实际中根据数据量调整该值 +Global.save_model_dir:指向模型保存路径 +Train.dataset.data_dir:指向训练集图片存放目录 +Train.dataset.label_file_list:指向训练集标注文件 +Eval.dataset.data_dir:指向验证集图片存放目录 +Eval.dataset.label_file_list:指向验证集标注文件 +``` + +同时**方案3**修改以下参数 +``` +Eval.dataset.label_file_list:添加公开通用识别数据标注文件 +Eval.dataset.ratio_list:数据和公开通用识别数据每次采样比例,按实际修改即可 +``` +如 **图5** 所示: +
+
图5 添加公开通用识别数据配置文件示例
+ + +我们提取Student模型的参数,在PCB数据集上进行fine-tune,可以参考如下代码: + + +```python +import paddle +# 加载预训练模型 +all_params = paddle.load("./pretrain_models/ch_PP-OCRv3_rec_train/best_accuracy.pdparams") +# 查看权重参数的keys +print(all_params.keys()) +# 学生模型的权重提取 +s_params = {key[len("student_model."):]: all_params[key] for key in all_params if "student_model." in key} +# 查看学生模型权重参数的keys +print(s_params.keys()) +# 保存 +paddle.save(s_params, "./pretrain_models/ch_PP-OCRv3_rec_train/student.pdparams") +``` + +修改参数后,**每个方案**都执行如下命令启动训练: + + + +```python +cd /home/aistudio/PaddleOCR/ +python3 tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml +``` + + +使用训练好的模型进行评估,更新模型路径`Global.checkpoints`: + + +```python +cd /home/aistudio/PaddleOCR/ +python3 tools/eval.py \ + -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml \ + -o Global.checkpoints=./output/rec_ppocr_v3/latest +``` + +所有方案评估指标如下: + +| 序号 | 方案 | acc | 效果提升 | 实验分析 | +| -------- | -------- | -------- | -------- | -------- | +| 1 | PP-OCRv3中英文超轻量识别预训练模型直接评估 | 46.67% | - | 提供的预训练模型具有泛化能力 | +| 2 | PP-OCRv3中英文超轻量识别预训练模型 + fine-tune | 42.02% |-4.6% | 在数据量不足的情况,反而比预训练模型效果低(也可以通过调整超参数再试试)| +| 3 | PP-OCRv3中英文超轻量识别预训练模型 + fine-tune + 公开通用识别数据集 | 77% | +30% | 在数据量不足的情况下,可以考虑补充公开数据训练 | +| 4 | PP-OCRv3中英文超轻量识别预训练模型 + fine-tune + 增加PCB图像数量 | 99.99% | +23% | 如果能获取更多数据量的情况,可以通过增加数据量提升效果 | + +``` +注:上述实验结果均是在1500张图片(1200张训练集,300张测试集)、2W张图片、添加公开通用识别数据集上训练、评估的得到,AIstudio只提供了100张数据,所以指标有所差异属于正常,只要策略有效、规律相同即可。 +``` + +# 6. 模型导出 + +inference 模型(paddle.jit.save保存的模型) 一般是模型训练,把模型结构和模型参数保存在文件中的固化模型,多用于预测部署场景。 训练过程中保存的模型是checkpoints模型,保存的只有模型的参数,多用于恢复训练等。 与checkpoints模型相比,inference 模型会额外保存模型的结构信息,在预测部署、加速推理上性能优越,灵活方便,适合于实际系统集成。 + + +```python +# 导出检测模型 +python3 tools/export_model.py \ + -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml \ + -o Global.pretrained_model="./output/ch_PP-OCR_V3_det/latest" \ + Global.save_inference_dir="./inference_model/ch_PP-OCR_V3_det/" +``` + +因为上述模型只训练了1个epoch,因此我们使用训练最优的模型进行预测,存储在`/home/aistudio/best_models/`目录下,解压即可 + + +```python +cd /home/aistudio/best_models/ +wget https://paddleocr.bj.bcebos.com/fanliku/PCB/det_ppocr_v3_en_infer_PCB.tar +tar xf /home/aistudio/best_models/det_ppocr_v3_en_infer_PCB.tar -C /home/aistudio/PaddleOCR/pretrain_models/ +``` + + +```python +# 检测模型inference模型预测 +cd /home/aistudio/PaddleOCR/ +python3 tools/infer/predict_det.py \ + --image_dir="/home/aistudio/dataset/imgs/0000.jpg" \ + --det_algorithm="DB" \ + --det_model_dir="./pretrain_models/det_ppocr_v3_en_infer_PCB/" \ + --det_limit_side_len=48 \ + --det_limit_type='min' \ + --det_db_unclip_ratio=2.5 \ + --use_gpu=True +``` + +结果存储在`inference_results`目录下,检测如下图所示: +
+
图6 检测结果
+ + +同理,导出识别模型并进行推理。 + +```python +# 导出识别模型 +python3 tools/export_model.py \ + -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml \ + -o Global.pretrained_model="./output/rec_ppocr_v3/latest" \ + Global.save_inference_dir="./inference_model/rec_ppocr_v3/" + +``` + +同检测模型,识别模型也只训练了1个epoch,因此我们使用训练最优的模型进行预测,存储在`/home/aistudio/best_models/`目录下,解压即可 + + +```python +cd /home/aistudio/best_models/ +wget https://paddleocr.bj.bcebos.com/fanliku/PCB/rec_ppocr_v3_ch_infer_PCB.tar +tar xf /home/aistudio/best_models/rec_ppocr_v3_ch_infer_PCB.tar -C /home/aistudio/PaddleOCR/pretrain_models/ +``` + + +```python +# 识别模型inference模型预测 +cd /home/aistudio/PaddleOCR/ +python3 tools/infer/predict_rec.py \ + --image_dir="../test_imgs/0000_rec.jpg" \ + --rec_model_dir="./pretrain_models/rec_ppocr_v3_ch_infer_PCB" \ + --rec_image_shape="3, 48, 320" \ + --use_space_char=False \ + --use_gpu=True +``` + +```python +# 检测+识别模型inference模型预测 +cd /home/aistudio/PaddleOCR/ +python3 tools/infer/predict_system.py \ + --image_dir="../test_imgs/0000.jpg" \ + --det_model_dir="./pretrain_models/det_ppocr_v3_en_infer_PCB" \ + --det_limit_side_len=48 \ + --det_limit_type='min' \ + --det_db_unclip_ratio=2.5 \ + --rec_model_dir="./pretrain_models/rec_ppocr_v3_ch_infer_PCB" \ + --rec_image_shape="3, 48, 320" \ + --draw_img_save_dir=./det_rec_infer/ \ + --use_space_char=False \ + --use_angle_cls=False \ + --use_gpu=True + +``` + +端到端预测结果存储在`det_res_infer`文件夹内,结果如下图所示: +
+
图7 检测+识别结果
+ +# 7. 端对端评测 + +接下来介绍文本检测+文本识别的端对端指标评估方式。主要分为三步: + +1)首先运行`tools/infer/predict_system.py`,将`image_dir`改为需要评估的数据文件家,得到保存的结果: + + +```python +# 检测+识别模型inference模型预测 +python3 tools/infer/predict_system.py \ + --image_dir="../dataset/imgs/" \ + --det_model_dir="./pretrain_models/det_ppocr_v3_en_infer_PCB" \ + --det_limit_side_len=48 \ + --det_limit_type='min' \ + --det_db_unclip_ratio=2.5 \ + --rec_model_dir="./pretrain_models/rec_ppocr_v3_ch_infer_PCB" \ + --rec_image_shape="3, 48, 320" \ + --draw_img_save_dir=./det_rec_infer/ \ + --use_space_char=False \ + --use_angle_cls=False \ + --use_gpu=True +``` + +得到保存结果,文本检测识别可视化图保存在`det_rec_infer/`目录下,预测结果保存在`det_rec_infer/system_results.txt`中,格式如下:`0018.jpg [{"transcription": "E295", "points": [[88, 33], [137, 33], [137, 40], [88, 40]]}]` + +2)然后将步骤一保存的数据转换为端对端评测需要的数据格式: 修改 `tools/end2end/convert_ppocr_label.py`中的代码,convert_label函数中设置输入标签路径,Mode,保存标签路径等,对预测数据的GTlabel和预测结果的label格式进行转换。 +``` +ppocr_label_gt = "/home/aistudio/dataset/det_gt_val.txt" +convert_label(ppocr_label_gt, "gt", "./save_gt_label/") + +ppocr_label_gt = "/home/aistudio/PaddleOCR/PCB_result/det_rec_infer/system_results.txt" +convert_label(ppocr_label_gt, "pred", "./save_PPOCRV2_infer/") +``` + +运行`convert_ppocr_label.py`: + + +```python + python3 tools/end2end/convert_ppocr_label.py +``` + +得到如下结果: +``` +├── ./save_gt_label/ +├── ./save_PPOCRV2_infer/ +``` + +3) 最后,执行端对端评测,运行`tools/end2end/eval_end2end.py`计算端对端指标,运行方式如下: + + +```python +pip install editdistance +python3 tools/end2end/eval_end2end.py ./save_gt_label/ ./save_PPOCRV2_infer/ +``` + +使用`预训练模型+fine-tune'检测模型`、`预训练模型 + 2W张PCB图片funetune`识别模型,在300张PCB图片上评估得到如下结果,fmeasure为主要关注的指标: +
+
图8 端到端评估指标
+ +``` +注: 使用上述命令不能跑出该结果,因为数据集不相同,可以更换为自己训练好的模型,按上述流程运行 +``` + +# 8. Jetson部署 + +我们只需要以下步骤就可以完成Jetson nano部署模型,简单易操作: + +**1、在Jetson nano开发版上环境准备:** + +* 安装PaddlePaddle + +* 下载PaddleOCR并安装依赖 + +**2、执行预测** + +* 将推理模型下载到jetson + +* 执行检测、识别、串联预测即可 + +详细[参考流程](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/deploy/Jetson/readme_ch.md)。 + +# 9. 总结 + +检测实验分别使用PP-OCRv3预训练模型在PCB数据集上进行了直接评估、验证集padding、 fine-tune 3种方案,识别实验分别使用PP-OCRv3预训练模型在PCB数据集上进行了直接评估、 fine-tune、添加公开通用识别数据集、增加PCB图片数量4种方案,指标对比如下: + +* 检测 + + +| 序号 | 方案 | hmean | 效果提升 | 实验分析 | +| ---- | -------------------------------------------------------- | ------ | -------- | ------------------------------------- | +| 1 | PP-OCRv3英文超轻量检测预训练模型直接评估 | 64.64% | - | 提供的预训练模型具有泛化能力 | +| 2 | PP-OCRv3英文超轻量检测预训练模型 + 验证集padding直接评估 | 72.13% | +7.5% | padding可以提升尺寸较小图片的检测效果 | +| 3 | PP-OCRv3英文超轻量检测预训练模型 + fine-tune | 100% | +27.9% | fine-tune会提升垂类场景效果 | + +* 识别 + +| 序号 | 方案 | acc | 效果提升 | 实验分析 | +| ---- | ------------------------------------------------------------ | ------ | -------- | ------------------------------------------------------------ | +| 1 | PP-OCRv3中英文超轻量识别预训练模型直接评估 | 46.67% | - | 提供的预训练模型具有泛化能力 | +| 2 | PP-OCRv3中英文超轻量识别预训练模型 + fine-tune | 42.02% | -4.6% | 在数据量不足的情况,反而比预训练模型效果低(也可以通过调整超参数再试试) | +| 3 | PP-OCRv3中英文超轻量识别预训练模型 + fine-tune + 公开通用识别数据集 | 77% | +30% | 在数据量不足的情况下,可以考虑补充公开数据训练 | +| 4 | PP-OCRv3中英文超轻量识别预训练模型 + fine-tune + 增加PCB图像数量 | 99.99% | +23% | 如果能获取更多数据量的情况,可以通过增加数据量提升效果 | + +* 端到端 + +| det | rec | fmeasure | +| --------------------------------------------- | ------------------------------------------------------------ | -------- | +| PP-OCRv3英文超轻量检测预训练模型 + fine-tune | PP-OCRv3中英文超轻量识别预训练模型 + fine-tune + 增加PCB图像数量 | 93.3% | + +*结论* + +PP-OCRv3的检测模型在未经过fine-tune的情况下,在PCB数据集上也有64.64%的精度,说明具有泛化能力。验证集padding之后,精度提升7.5%,在图片尺寸较小的情况,我们可以通过padding的方式提升检测效果。经过 fine-tune 后能够极大的提升检测效果,精度达到100%。 + +PP-OCRv3的识别模型方案1和方案2对比可以发现,当数据量不足的情况,预训练模型精度可能比fine-tune效果还要高,所以我们可以先尝试预训练模型直接评估。如果在数据量不足的情况下想进一步提升模型效果,可以通过添加公开通用识别数据集,识别效果提升30%,非常有效。最后如果我们能够采集足够多的真实场景数据集,可以通过增加数据量提升模型效果,精度达到99.99%。 + +# 更多资源 + +- 更多深度学习知识、产业案例、面试宝典等,请参考:[awesome-DeepLearning](https://github.com/paddlepaddle/awesome-DeepLearning) + +- 更多PaddleOCR使用教程,请参考:[PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR/tree/dygraph) + + +- 飞桨框架相关资料,请参考:[飞桨深度学习平台](https://www.paddlepaddle.org.cn/?fr=paddleEdu_aistudio) + +# 参考 + +* 数据生成代码库:https://github.com/zcswdt/Color_OCR_image_generator diff --git "a/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/background/bg.jpg" "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/background/bg.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..3cb6eab819c3b7d4f68590d2cdc9d36351590197 Binary files /dev/null and "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/background/bg.jpg" differ diff --git "a/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/corpus/text.txt" "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/corpus/text.txt" new file mode 100644 index 0000000000000000000000000000000000000000..8b8cb793ef6755bf00ed8c154e24638b07a519c2 --- /dev/null +++ "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/corpus/text.txt" @@ -0,0 +1,30 @@ +5ZQ +I4UL +PWL +SNOG +ZL02 +1C30 +O3H +YHRS +N03S +1U5Y +JTK +EN4F +YKJ +DWNH +R42W +X0V +4OF5 +08AM +Y93S +GWE2 +0KR +9U2A +DBQ +Y6J +ROZ +K06 +KIEY +NZQJ +UN1B +6X4 \ No newline at end of file diff --git "a/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/det_background/1.png" "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/det_background/1.png" new file mode 100644 index 0000000000000000000000000000000000000000..8a49eaa6862113044e05d17e32941a0a20911426 Binary files /dev/null and "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/det_background/1.png" differ diff --git "a/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/det_background/2.png" "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/det_background/2.png" new file mode 100644 index 0000000000000000000000000000000000000000..c3fcc0c92826b97b5f6abd970f1a0580eede0f5d Binary files /dev/null and "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/det_background/2.png" differ diff --git "a/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/gen.py" "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/gen.py" new file mode 100644 index 0000000000000000000000000000000000000000..4c768067f998b6b4bbe0b2f5982f46a3f01fc872 --- /dev/null +++ "b/applications/PCB\345\255\227\347\254\246\350\257\206\345\210\253/gen_data/gen.py" @@ -0,0 +1,261 @@ +# copyright (c) 2020 PaddlePaddle Authors. All Rights Reserve. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +""" +This code is refer from: +https://github.com/zcswdt/Color_OCR_image_generator +""" +import os +import random +from PIL import Image, ImageDraw, ImageFont +import json +import argparse + + +def get_char_lines(txt_root_path): + """ + desc:get corpus line + """ + txt_files = os.listdir(txt_root_path) + char_lines = [] + for txt in txt_files: + f = open(os.path.join(txt_root_path, txt), mode='r', encoding='utf-8') + lines = f.readlines() + f.close() + for line in lines: + char_lines.append(line.strip()) + return char_lines + + +def get_horizontal_text_picture(image_file, chars, fonts_list, cf): + """ + desc:gen horizontal text picture + """ + img = Image.open(image_file) + if img.mode != 'RGB': + img = img.convert('RGB') + img_w, img_h = img.size + + # random choice font + font_path = random.choice(fonts_list) + # random choice font size + font_size = random.randint(cf.font_min_size, cf.font_max_size) + font = ImageFont.truetype(font_path, font_size) + + ch_w = [] + ch_h = [] + for ch in chars: + wt, ht = font.getsize(ch) + ch_w.append(wt) + ch_h.append(ht) + f_w = sum(ch_w) + f_h = max(ch_h) + + # add space + char_space_width = max(ch_w) + f_w += (char_space_width * (len(chars) - 1)) + + x1 = random.randint(0, img_w - f_w) + y1 = random.randint(0, img_h - f_h) + x2 = x1 + f_w + y2 = y1 + f_h + + crop_y1 = y1 + crop_x1 = x1 + crop_y2 = y2 + crop_x2 = x2 + + best_color = (0, 0, 0) + draw = ImageDraw.Draw(img) + for i, ch in enumerate(chars): + draw.text((x1, y1), ch, best_color, font=font) + x1 += (ch_w[i] + char_space_width) + crop_img = img.crop((crop_x1, crop_y1, crop_x2, crop_y2)) + return crop_img, chars + + +def get_vertical_text_picture(image_file, chars, fonts_list, cf): + """ + desc:gen vertical text picture + """ + img = Image.open(image_file) + if img.mode != 'RGB': + img = img.convert('RGB') + img_w, img_h = img.size + # random choice font + font_path = random.choice(fonts_list) + # random choice font size + font_size = random.randint(cf.font_min_size, cf.font_max_size) + font = ImageFont.truetype(font_path, font_size) + + ch_w = [] + ch_h = [] + for ch in chars: + wt, ht = font.getsize(ch) + ch_w.append(wt) + ch_h.append(ht) + f_w = max(ch_w) + f_h = sum(ch_h) + + x1 = random.randint(0, img_w - f_w) + y1 = random.randint(0, img_h - f_h) + x2 = x1 + f_w + y2 = y1 + f_h + + crop_y1 = y1 + crop_x1 = x1 + crop_y2 = y2 + crop_x2 = x2 + + best_color = (0, 0, 0) + draw = ImageDraw.Draw(img) + i = 0 + for ch in chars: + draw.text((x1, y1), ch, best_color, font=font) + y1 = y1 + ch_h[i] + i = i + 1 + crop_img = img.crop((crop_x1, crop_y1, crop_x2, crop_y2)) + crop_img = crop_img.transpose(Image.ROTATE_90) + return crop_img, chars + + +def get_fonts(fonts_path): + """ + desc: get all fonts + """ + font_files = os.listdir(fonts_path) + fonts_list=[] + for font_file in font_files: + font_path=os.path.join(fonts_path, font_file) + fonts_list.append(font_path) + return fonts_list + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument('--num_img', type=int, default=30, help="Number of images to generate") + parser.add_argument('--font_min_size', type=int, default=11) + parser.add_argument('--font_max_size', type=int, default=12, + help="Help adjust the size of the generated text and the size of the picture") + parser.add_argument('--bg_path', type=str, default='./background', + help='The generated text pictures will be pasted onto the pictures of this folder') + parser.add_argument('--det_bg_path', type=str, default='./det_background', + help='The generated text pictures will use the pictures of this folder as the background') + parser.add_argument('--fonts_path', type=str, default='../../StyleText/fonts', + help='The font used to generate the picture') + parser.add_argument('--corpus_path', type=str, default='./corpus', + help='The corpus used to generate the text picture') + parser.add_argument('--output_dir', type=str, default='./output/', help='Images save dir') + + + cf = parser.parse_args() + # save path + if not os.path.exists(cf.output_dir): + os.mkdir(cf.output_dir) + + # get corpus + txt_root_path = cf.corpus_path + char_lines = get_char_lines(txt_root_path=txt_root_path) + + # get all fonts + fonts_path = cf.fonts_path + fonts_list = get_fonts(fonts_path) + + # rec bg + img_root_path = cf.bg_path + imnames=os.listdir(img_root_path) + + # det bg + det_bg_path = cf.det_bg_path + bg_pics = os.listdir(det_bg_path) + + # OCR det files + det_val_file = open(cf.output_dir + 'det_gt_val.txt', 'w', encoding='utf-8') + det_train_file = open(cf.output_dir + 'det_gt_train.txt', 'w', encoding='utf-8') + # det imgs + det_save_dir = 'imgs/' + if not os.path.exists(cf.output_dir + det_save_dir): + os.mkdir(cf.output_dir + det_save_dir) + det_val_save_dir = 'imgs_val/' + if not os.path.exists(cf.output_dir + det_val_save_dir): + os.mkdir(cf.output_dir + det_val_save_dir) + + # OCR rec files + rec_val_file = open(cf.output_dir + 'rec_gt_val.txt', 'w', encoding='utf-8') + rec_train_file = open(cf.output_dir + 'rec_gt_train.txt', 'w', encoding='utf-8') + # rec imgs + rec_save_dir = 'rec_imgs/' + if not os.path.exists(cf.output_dir + rec_save_dir): + os.mkdir(cf.output_dir + rec_save_dir) + rec_val_save_dir = 'rec_imgs_val/' + if not os.path.exists(cf.output_dir + rec_val_save_dir): + os.mkdir(cf.output_dir + rec_val_save_dir) + + + val_ratio = cf.num_img * 0.2 # val dataset ratio + + print('start generating...') + for i in range(0, cf.num_img): + imname = random.choice(imnames) + img_path = os.path.join(img_root_path, imname) + + rnd = random.random() + # gen horizontal text picture + if rnd < 0.5: + gen_img, chars = get_horizontal_text_picture(img_path, char_lines[i], fonts_list, cf) + ori_w, ori_h = gen_img.size + gen_img = gen_img.crop((0, 3, ori_w, ori_h)) + # gen vertical text picture + else: + gen_img, chars = get_vertical_text_picture(img_path, char_lines[i], fonts_list, cf) + ori_w, ori_h = gen_img.size + gen_img = gen_img.crop((3, 0, ori_w, ori_h)) + + ori_w, ori_h = gen_img.size + + # rec imgs + save_img_name = str(i).zfill(4) + '.jpg' + if i < val_ratio: + save_dir = os.path.join(rec_val_save_dir, save_img_name) + line = save_dir + '\t' + char_lines[i] + '\n' + rec_val_file.write(line) + else: + save_dir = os.path.join(rec_save_dir, save_img_name) + line = save_dir + '\t' + char_lines[i] + '\n' + rec_train_file.write(line) + gen_img.save(cf.output_dir + save_dir, quality = 95, subsampling=0) + + # det img + # random choice bg + bg_pic = random.sample(bg_pics, 1)[0] + det_img = Image.open(os.path.join(det_bg_path, bg_pic)) + # the PCB position is fixed, modify it according to your own scenario + if bg_pic == '1.png': + x1 = 38 + y1 = 3 + else: + x1 = 34 + y1 = 1 + + det_img.paste(gen_img, (x1, y1)) + # text pos + chars_pos = [[x1, y1], [x1 + ori_w, y1], [x1 + ori_w, y1 + ori_h], [x1, y1 + ori_h]] + label = [{"transcription":char_lines[i], "points":chars_pos}] + if i < val_ratio: + save_dir = os.path.join(det_val_save_dir, save_img_name) + det_val_file.write(save_dir + '\t' + json.dumps( + label, ensure_ascii=False) + '\n') + else: + save_dir = os.path.join(det_save_dir, save_img_name) + det_train_file.write(save_dir + '\t' + json.dumps( + label, ensure_ascii=False) + '\n') + det_img.save(cf.output_dir + save_dir, quality = 95, subsampling=0) diff --git a/applications/README.md b/applications/README.md new file mode 100644 index 0000000000000000000000000000000000000000..017c2a9f6f696904e9bf2f1180104e66c90ee712 --- /dev/null +++ b/applications/README.md @@ -0,0 +1,78 @@ +[English](README_en.md) | 简体中文 + +# 场景应用 + +PaddleOCR场景应用覆盖通用,制造、金融、交通行业的主要OCR垂类应用,在PP-OCR、PP-Structure的通用能力基础之上,以notebook的形式展示利用场景数据微调、模型优化方法、数据增广等内容,为开发者快速落地OCR应用提供示范与启发。 + +- [教程文档](#1) + - [通用](#11) + - [制造](#12) + - [金融](#13) + - [交通](#14) + +- [模型下载](#2) + + + +## 教程文档 + + + +### 通用 + +| 类别 | 亮点 | 模型下载 | 教程 | +| ---------------------- | ------------ | -------------- | --------------------------------------- | +| 高精度中文识别模型SVTR | 比PP-OCRv3识别模型精度高3%,可用于数据挖掘或对预测效率要求不高的场景。| [模型下载](#2) | [中文](./高精度中文识别模型.md)/English | +| 手写体识别 | 新增字形支持 | | | + + + +### 制造 + +| 类别 | 亮点 | 模型下载 | 教程 | 示例图 | +| -------------- | ------------------------------ | -------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 数码管识别 | 数码管数据合成、漏识别调优 | [模型下载](#2) | [中文](./光功率计数码管字符识别/光功率计数码管字符识别.md)/English | | +| 液晶屏读数识别 | 检测模型蒸馏、Serving部署 | [模型下载](#2) | [中文](./液晶屏读数识别.md)/English | | +| 包装生产日期 | 点阵字符合成、过曝过暗文字识别 | [模型下载](#2) | [中文](./包装生产日期识别.md)/English | | +| PCB文字识别 | 小尺寸文本检测与识别 | [模型下载](#2) | [中文](./PCB字符识别/PCB字符识别.md)/English | | +| 电表识别 | 大分辨率图像检测调优 | [模型下载](#2) | | | +| 液晶屏缺陷检测 | 非文字字符识别 | | | | + + + +### 金融 + +| 类别 | 亮点 | 模型下载 | 教程 | 示例图 | +| -------------- | ------------------------ | -------------- | ----------------------------------- | ------------------------------------------------------------ | +| 表单VQA | 多模态通用表单结构化提取 | [模型下载](#2) | [中文](./多模态表单识别.md)/English | | +| 增值税发票 | 尽请期待 | | | | +| 印章检测与识别 | 端到端弯曲文本识别 | | | | +| 通用卡证识别 | 通用结构化提取 | | | | +| 身份证识别 | 结构化提取、图像阴影 | | | | +| 合同比对 | 密集文本检测、NLP串联 | | | | + + + +### 交通 + +| 类别 | 亮点 | 模型下载 | 教程 | 示例图 | +| ----------------- | ------------------------------ | -------------- | ----------------------------------- | ------------------------------------------------------------ | +| 车牌识别 | 多角度图像、轻量模型、端侧部署 | [模型下载](#2) | [中文](./轻量级车牌识别.md)/English | | +| 驾驶证/行驶证识别 | 尽请期待 | | | | +| 快递单识别 | 尽请期待 | | | | + + + +## 模型下载 + +如需下载上述场景中已经训练好的垂类模型,可以扫描下方二维码,关注公众号填写问卷后,加入PaddleOCR官方交流群获取20G OCR学习大礼包(内含《动手学OCR》电子书、课程回放视频、前沿论文等重磅资料) + +
+ +
+ +如果您是企业开发者且未在上述场景中找到合适的方案,可以填写[OCR应用合作调研问卷](https://paddle.wjx.cn/vj/QwF7GKw.aspx),免费与官方团队展开不同层次的合作,包括但不限于问题抽象、确定技术方案、项目答疑、共同研发等。如果您已经使用PaddleOCR落地项目,也可以填写此问卷,与飞桨平台共同宣传推广,提升企业技术品宣。期待您的提交! + + +traffic + diff --git a/applications/README_en.md b/applications/README_en.md new file mode 100644 index 0000000000000000000000000000000000000000..ae387643c981a1452dbb8e924f7bb49c2dfec5f0 --- /dev/null +++ b/applications/README_en.md @@ -0,0 +1,79 @@ +English| [简体中文](README.md) + +# Application + +PaddleOCR scene application covers general, manufacturing, finance, transportation industry of the main OCR vertical applications, on the basis of the general capabilities of PP-OCR, PP-Structure, in the form of notebook to show the use of scene data fine-tuning, model optimization methods, data augmentation and other content, for developers to quickly land OCR applications to provide demonstration and inspiration. + +- [Tutorial](#1) + - [General](#11) + - [Manufacturing](#12) + - [Finance](#13) + - [Transportation](#14) + +- [Model Download](#2) + + + +## Tutorial + + + +### General + +| Case | Feature | Model Download | Tutorial | +| ---------------------------------------------- | ---------------- | -------------------- | --------------------------------------- | +| High-precision Chineses recognition model SVTR | New model | [Model Download](#2) | [中文](./高精度中文识别模型.md)/English | +| Chinese handwriting recognition | New font support | | | + + + +### Manufacturing + +| Case | Feature | Model Download | Tutorial | Example | +| ------------------------------ | ------------------------------------------------------------ | -------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| Digital tube | Digital tube data sythesis, recognition model fine-tuning | [Model Download](#2) | [中文](./光功率计数码管字符识别/光功率计数码管字符识别.md)/English | | +| LCD screen | Detection model distillation, serving deployment | [Model Download](#2) | [中文](./液晶屏读数识别.md)/English | | +| Packaging production data | Dot matrix character synthesis, overexposure and overdark text recognition | [Model Download](#2) | [中文](./包装生产日期识别.md)/English | | +| PCB text recognition | Small size text detection and recognition | [Model Download](#2) | [中文](./PCB字符识别/PCB字符识别.md)/English | | +| Meter text recognition | High-resolution image detection fine-tuning | [Model Download](#2) | | | +| LCD character defect detection | Non-text character recognition | | | | + + + +### Finance + +| Case | Feature | Model Download | Tutorial | Example | +| ----------------------------------- | --------------------------------------------- | -------------------- | ----------------------------------- | ------------------------------------------------------------ | +| Form visual question and answer | Multimodal general form structured extraction | [Model Download](#2) | [中文](./多模态表单识别.md)/English | | +| VAT invoice | coming soon | | | | +| Seal detection and recognition | End-to-end curved text recognition | | | | +| Universal card recognition | Universal structured extraction | | | | +| ID card recognition | Structured extraction, image shading | | | | +| Contract key information extraction | Dense text detection, NLP concatenation | | | | + + + +### Transportation + +| Case | Feature | Model Download | Tutorial | Example | +| ----------------------------------------------- | ------------------------------------------------------------ | -------------------- | ----------------------------------- | ------------------------------------------------------------ | +| License plate recognition | Multi-angle images, lightweight models, edge-side deployment | [Model Download](#2) | [中文](./轻量级车牌识别.md)/English | | +| Driver's license/driving license identification | coming soon | | | | +| Express text recognition | coming soon | | | | + + + +## Model Download + +- For international developers: We're building a way to download these trained models, and since the current tutorials are Chinese, if you are good at both Chinese and English, or willing to polish English documents, please let us know in [discussion](https://github.com/PaddlePaddle/PaddleOCR/discussions). +- For Chinese developer: If you want to download the trained application model in the above scenarios, scan the QR code below with your WeChat, follow the PaddlePaddle official account to fill in the questionnaire, and join the PaddleOCR official group to get the 20G OCR learning materials (including "Dive into OCR" e-book, course video, application models and other materials) + +
+ +
+ + If you are an enterprise developer and have not found a suitable solution in the above scenarios, you can fill in the [OCR Application Cooperation Survey Questionnaire](https://paddle.wjx.cn/vj/QwF7GKw.aspx) to carry out different levels of cooperation with the official team **for free**, including but not limited to problem abstraction, technical solution determination, project Q&A, joint research and development, etc. If you have already used paddleOCR in your project, you can also fill out this questionnaire to jointly promote with the PaddlePaddle and enhance the technical publicity of enterprises. Looking forward to your submission! + + +trackgit-views + diff --git "a/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/corpus/digital.txt" "b/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/corpus/digital.txt" new file mode 100644 index 0000000000000000000000000000000000000000..26b06e784e779bdf97dfaa9b3ba8d4c0155b0718 --- /dev/null +++ "b/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/corpus/digital.txt" @@ -0,0 +1,43 @@ +46.39 +40.08 +89.52 +-71.93 +23.19 +-81.02 +-34.09 +05.87 +-67.80 +-51.56 +-34.58 +37.91 +56.98 +29.01 +-90.13 +35.55 +66.07 +-90.35 +-50.93 +42.42 +21.40 +-30.99 +-71.78 +25.60 +-48.69 +-72.28 +-17.55 +-99.93 +-47.35 +-64.89 +-31.28 +-90.01 +05.17 +30.91 +30.56 +-06.90 +79.05 +67.74 +-32.31 +94.22 +28.75 +51.03 +-58.96 diff --git "a/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/fonts/DS-DIGI.TTF" "b/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/fonts/DS-DIGI.TTF" new file mode 100644 index 0000000000000000000000000000000000000000..09258773c7219ad9e60b92b918e3c50b58f43c9e Binary files /dev/null and "b/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/fonts/DS-DIGI.TTF" differ diff --git "a/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/fonts/DS-DIGIB.TTF" "b/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/fonts/DS-DIGIB.TTF" new file mode 100644 index 0000000000000000000000000000000000000000..064ad478a510a9c581bb16d295f659256e1f920a Binary files /dev/null and "b/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/fonts/DS-DIGIB.TTF" differ diff --git "a/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253.md" "b/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253.md" new file mode 100644 index 0000000000000000000000000000000000000000..2a35cb170ef165faa6566e0059cca8364b7a6da6 --- /dev/null +++ "b/applications/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253/\345\205\211\345\212\237\347\216\207\350\256\241\346\225\260\347\240\201\347\256\241\345\255\227\347\254\246\350\257\206\345\210\253.md" @@ -0,0 +1,467 @@ +# 光功率计数码管字符识别 + +本案例将使用OCR技术自动识别光功率计显示屏文字,通过本章您可以掌握: + +- PaddleOCR快速使用 +- 数据合成方法 +- 数据挖掘方法 +- 基于现有数据微调 + +## 1. 背景介绍 + +光功率计(optical power meter )是指用于测量绝对光功率或通过一段光纤的光功率相对损耗的仪器。在光纤系统中,测量光功率是最基本的,非常像电子学中的万用表;在光纤测量中,光功率计是重负荷常用表。 + + + +目前光功率计缺少将数据直接输出的功能,需要人工读数。这一项工作单调重复,如果可以使用机器替代人工,将节约大量成本。针对上述问题,希望通过摄像头拍照->智能读数的方式高效地完成此任务。 + +为实现智能读数,通常会采取文本检测+文本识别的方案: + +第一步,使用文本检测模型定位出光功率计中的数字部分; + +第二步,使用文本识别模型获得准确的数字和单位信息。 + +本项目主要介绍如何完成第二步文本识别部分,包括:真实评估集的建立、训练数据的合成、基于 PP-OCRv3 和 SVTR_Tiny 两个模型进行训练,以及评估和推理。 + +本项目难点如下: + +- 光功率计数码管字符数据较少,难以获取。 +- 数码管中小数点占像素较少,容易漏识别。 + +针对以上问题, 本例选用 PP-OCRv3 和 SVTR_Tiny 两个高精度模型训练,同时提供了真实数据挖掘案例和数据合成案例。基于 PP-OCRv3 模型,在构建的真实评估集上精度从 52% 提升至 72%,SVTR_Tiny 模型精度可达到 78.9%。 + +aistudio项目链接: [光功率计数码管字符识别](https://aistudio.baidu.com/aistudio/projectdetail/4049044?contributionType=1) + +## 2. PaddleOCR 快速使用 + +PaddleOCR 旨在打造一套丰富、领先、且实用的OCR工具库,助力开发者训练出更好的模型,并应用落地。 + +![](https://github.com/PaddlePaddle/PaddleOCR/raw/release/2.5/doc/imgs_results/ch_ppocr_mobile_v2.0/test_add_91.jpg) + + +官方提供了适用于通用场景的高精轻量模型,首先使用官方提供的 PP-OCRv3 模型预测图片,验证下当前模型在光功率计场景上的效果。 + +- 准备环境 + +``` +python3 -m pip install -U pip +python3 -m pip install paddleocr +``` + + +- 测试效果 + +测试图: + +![](https://ai-studio-static-online.cdn.bcebos.com/8dca91f016884e16ad9216d416da72ea08190f97d87b4be883f15079b7ebab9a) + + +``` +paddleocr --lang=ch --det=Fase --image_dir=data +``` + +得到如下测试结果: + +``` +('.7000', 0.6885431408882141) +``` + +发现数字识别较准,然而对负号和小数点识别不准确。 由于PP-OCRv3的训练数据大多为通用场景数据,在特定的场景上效果可能不够好。因此需要基于场景数据进行微调。 + +下面就主要介绍如何在光功率计(数码管)场景上微调训练。 + + +## 3. 开始训练 + +### 3.1 数据准备 + +特定的工业场景往往很难获取开源的真实数据集,光功率计也是如此。在实际工业场景中,可以通过摄像头采集的方法收集大量真实数据,本例中重点介绍数据合成方法和真实数据挖掘方法,如何利用有限的数据优化模型精度。 + +数据集分为两个部分:合成数据,真实数据, 其中合成数据由 text_renderer 工具批量生成得到, 真实数据通过爬虫等方式在百度图片中搜索并使用 PPOCRLabel 标注得到。 + + +- 合成数据 + +本例中数据合成工具使用的是 [text_renderer](https://github.com/Sanster/text_renderer), 该工具可以合成用于文本识别训练的文本行数据: + +![](https://github.com/oh-my-ocr/text_renderer/raw/master/example_data/effect_layout_image/char_spacing_compact.jpg) + +![](https://github.com/oh-my-ocr/text_renderer/raw/master/example_data/effect_layout_image/color_image.jpg) + + +``` +export https_proxy=http://172.19.57.45:3128 +git clone https://github.com/oh-my-ocr/text_renderer +``` + +``` +import os +python3 setup.py develop +python3 -m pip install -r docker/requirements.txt +python3 main.py \ + --config example_data/example.py \ + --dataset img \ + --num_processes 2 \ + --log_period 10 +``` + +给定字体和语料,就可以合成较为丰富样式的文本行数据。 光功率计识别场景,目标是正确识别数码管文本,因此需要收集部分数码管字体,训练语料,用于合成文本识别数据。 + +将收集好的语料存放在 example_data 路径下: + +``` +ln -s ./fonts/DS* text_renderer/example_data/font/ +ln -s ./corpus/digital.txt text_renderer/example_data/text/ +``` + +修改 text_renderer/example_data/font_list/font_list.txt ,选择需要的字体开始合成: + +``` +python3 main.py \ + --config example_data/digital_example.py \ + --dataset img \ + --num_processes 2 \ + --log_period 10 +``` + +合成图片会被存在目录 text_renderer/example_data/digital/chn_data 下 + +查看合成的数据样例: + +![](https://ai-studio-static-online.cdn.bcebos.com/7d5774a273f84efba5b9ce7fd3f86e9ef24b6473e046444db69fa3ca20ac0986) + + +- 真实数据挖掘 + +模型训练需要使用真实数据作为评价指标,否则很容易过拟合到简单的合成数据中。没有开源数据的情况下,可以利用部分无标注数据+标注工具获得真实数据。 + + +1. 数据搜集 + +使用[爬虫工具](https://github.com/Joeclinton1/google-images-download.git)获得无标注数据 + +2. [PPOCRLabel](https://github.com/PaddlePaddle/PaddleOCR/tree/release/2.5/PPOCRLabel) 完成半自动标注 + +PPOCRLabel是一款适用于OCR领域的半自动化图形标注工具,内置PP-OCR模型对数据自动标注和重新识别。使用Python3和PyQT5编写,支持矩形框标注、表格标注、不规则文本标注、关键信息标注模式,导出格式可直接用于PaddleOCR检测和识别模型的训练。 + +![](https://github.com/PaddlePaddle/PaddleOCR/raw/release/2.5/PPOCRLabel/data/gif/steps_en.gif) + + +收集完数据后就可以进行分配了,验证集中一般都是真实数据,训练集中包含合成数据+真实数据。本例中标注了155张图片,其中训练集和验证集的数目为100和55。 + + +最终 `data` 文件夹应包含以下几部分: + +``` +|-data + |- synth_train.txt + |- real_train.txt + |- real_eval.txt + |- synthetic_data + |- word_001.png + |- word_002.jpg + |- word_003.jpg + | ... + |- real_data + |- word_001.png + |- word_002.jpg + |- word_003.jpg + | ... + ... +``` + +### 3.2 模型选择 + +本案例提供了2种文本识别模型:PP-OCRv3 识别模型 和 SVTR_Tiny: + +[PP-OCRv3 识别模型](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/PP-OCRv3_introduction.md):PP-OCRv3的识别模块是基于文本识别算法SVTR优化。SVTR不再采用RNN结构,通过引入Transformers结构更加有效地挖掘文本行图像的上下文信息,从而提升文本识别能力。并进行了一系列结构改进加速模型预测。 + +[SVTR_Tiny](https://arxiv.org/abs/2205.00159):SVTR提出了一种用于场景文本识别的单视觉模型,该模型在patch-wise image tokenization框架内,完全摒弃了序列建模,在精度具有竞争力的前提下,模型参数量更少,速度更快。 + +以上两个策略在自建中文数据集上的精度和速度对比如下: + +| ID | 策略 | 模型大小 | 精度 | 预测耗时(CPU + MKLDNN)| +|-----|-----|--------|----| --- | +| 01 | PP-OCRv2 | 8M | 74.8% | 8.54ms | +| 02 | SVTR_Tiny | 21M | 80.1% | 97ms | +| 03 | SVTR_LCNet(h32) | 12M | 71.9% | 6.6ms | +| 04 | SVTR_LCNet(h48) | 12M | 73.98% | 7.6ms | +| 05 | + GTC | 12M | 75.8% | 7.6ms | +| 06 | + TextConAug | 12M | 76.3% | 7.6ms | +| 07 | + TextRotNet | 12M | 76.9% | 7.6ms | +| 08 | + UDML | 12M | 78.4% | 7.6ms | +| 09 | + UIM | 12M | 79.4% | 7.6ms | + + +### 3.3 开始训练 + +首先下载 PaddleOCR 代码库 + +``` +git clone -b release/2.5 https://github.com/PaddlePaddle/PaddleOCR.git +``` + +PaddleOCR提供了训练脚本、评估脚本和预测脚本,本节将以 PP-OCRv3 中文识别模型为例: + +**Step1:下载预训练模型** + +首先下载 pretrain model,您可以下载训练好的模型在自定义数据上进行finetune + +``` +cd PaddleOCR/ +# 下载PP-OCRv3 中文预训练模型 +wget -P ./pretrain_models/ https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar +# 解压模型参数 +cd pretrain_models +tar -xf ch_PP-OCRv3_rec_train.tar && rm -rf ch_PP-OCRv3_rec_train.tar +``` + +**Step2:自定义字典文件** + +接下来需要提供一个字典({word_dict_name}.txt),使模型在训练时,可以将所有出现的字符映射为字典的索引。 + +因此字典需要包含所有希望被正确识别的字符,{word_dict_name}.txt需要写成如下格式,并以 `utf-8` 编码格式保存: + +``` +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +- +. +``` + +word_dict.txt 每行有一个单字,将字符与数字索引映射在一起,“3.14” 将被映射成 [3, 11, 1, 4] + +* 内置字典 + +PaddleOCR内置了一部分字典,可以按需使用。 + +`ppocr/utils/ppocr_keys_v1.txt` 是一个包含6623个字符的中文字典 + +`ppocr/utils/ic15_dict.txt` 是一个包含36个字符的英文字典 + +* 自定义字典 + +内置字典面向通用场景,具体的工业场景中,可能需要识别特殊字符,或者只需识别某几个字符,此时自定义字典会更提升模型精度。例如在光功率计场景中,需要识别数字和单位。 + +遍历真实数据标签中的字符,制作字典`digital_dict.txt`如下所示: + +``` +- +. +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +B +E +F +H +L +N +T +W +d +k +m +n +o +z +``` + + + + +**Step3:修改配置文件** + +为了更好的使用预训练模型,训练推荐使用[ch_PP-OCRv3_rec_distillation.yml](../../configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml)配置文件,并参考下列说明修改配置文件: + +以 `ch_PP-OCRv3_rec_distillation.yml` 为例: +``` +Global: + ... + # 添加自定义字典,如修改字典请将路径指向新字典 + character_dict_path: ppocr/utils/dict/digital_dict.txt + ... + # 识别空格 + use_space_char: True + + +Optimizer: + ... + # 添加学习率衰减策略 + lr: + name: Cosine + learning_rate: 0.001 + ... + +... + +Train: + dataset: + # 数据集格式,支持LMDBDataSet以及SimpleDataSet + name: SimpleDataSet + # 数据集路径 + data_dir: ./data/ + # 训练集标签文件 + label_file_list: + - ./train_data/digital_img/digital_train.txt #11w + - ./train_data/digital_img/real_train.txt #100 + - ./train_data/digital_img/dbm_img/dbm.txt #3w + ratio_list: + - 0.3 + - 1.0 + - 1.0 + 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: ./data + # 验证集标签文件 + label_file_list: + - ./train_data/digital_img/real_val.txt + transforms: + ... + - RecResizeImg: + # 修改 image_shape 以适应长文本 + image_shape: [3, 48, 320] + ... + loader: + # 单卡验证的batch_size + batch_size_per_card: 256 + ... +``` +**注意,训练/预测/评估时的配置文件请务必与训练一致。** + +**Step4:启动训练** + +*如果您安装的是cpu版本,请将配置文件中的 `use_gpu` 字段修改为false* + +``` +# GPU训练 支持单卡,多卡训练 +# 训练数码管数据 训练日志会自动保存为 "{save_model_dir}" 下的train.log + +#单卡训练(训练周期长,不建议) +python3 tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml -o Global.pretrained_model=./pretrain_models/ch_PP-OCRv3_rec_train/best_accuracy + +#多卡训练,通过--gpus参数指定卡号 +python3 -m paddle.distributed.launch --gpus '0,1,2,3' tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml -o Global.pretrained_model=./pretrain_models/en_PP-OCRv3_rec_train/best_accuracy +``` + + +PaddleOCR支持训练和评估交替进行, 可以在 `configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml` 中修改 `eval_batch_step` 设置评估频率,默认每500个iter评估一次。评估过程中默认将最佳acc模型,保存为 `output/ch_PP-OCRv3_rec_distill/best_accuracy` 。 + +如果验证集很大,测试将会比较耗时,建议减少评估次数,或训练完再进行评估。 + +### SVTR_Tiny 训练 + +SVTR_Tiny 训练步骤与上面一致,SVTR支持的配置和模型训练权重可以参考[算法介绍文档](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/algorithm_rec_svtr.md) + +**Step1:下载预训练模型** + +``` +# 下载 SVTR_Tiny 中文识别预训练模型和配置文件 +wget https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/rec_svtr_tiny_none_ctc_ch_train.tar +# 解压模型参数 +tar -xf rec_svtr_tiny_none_ctc_ch_train.tar && rm -rf rec_svtr_tiny_none_ctc_ch_train.tar +``` +**Step2:自定义字典文件** + +字典依然使用自定义的 digital_dict.txt + +**Step3:修改配置文件** + +配置文件中对应修改字典路径和数据路径 + +**Step4:启动训练** + +``` +## 单卡训练 +python tools/train.py -c rec_svtr_tiny_none_ctc_ch_train/rec_svtr_tiny_6local_6global_stn_ch.yml \ + -o Global.pretrained_model=./rec_svtr_tiny_none_ctc_ch_train/best_accuracy +``` + +### 3.4 验证效果 + +如需获取已训练模型,请扫码填写问卷,加入PaddleOCR官方交流群获取全部OCR垂类模型下载链接、《动手学OCR》电子书等全套OCR学习资料🎁 +
+ +
+将下载或训练完成的模型放置在对应目录下即可完成模型推理 + +* 指标评估 + +训练中模型参数默认保存在`Global.save_model_dir`目录下。在评估指标时,需要设置`Global.checkpoints`指向保存的参数文件。评估数据集可以通过 `configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml` 修改Eval中的 `label_file_path` 设置。 + +``` +# GPU 评估, Global.checkpoints 为待测权重 +python3 -m paddle.distributed.launch --gpus '0' tools/eval.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml -o Global.checkpoints={path/to/weights}/best_accuracy +``` + +* 测试识别效果 + +使用 PaddleOCR 训练好的模型,可以通过以下脚本进行快速预测。 + +默认预测图片存储在 `infer_img` 里,通过 `-o Global.checkpoints` 加载训练好的参数文件: + +根据配置文件中设置的 `save_model_dir` 和 `save_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-OCRv3/ch_PP-OCRv3_rec_distillation.yml -o Global.pretrained_model={path/to/weights}/best_accuracy Global.infer_img=test_digital.png +``` + +预测图片: + +![](https://ai-studio-static-online.cdn.bcebos.com/8dca91f016884e16ad9216d416da72ea08190f97d87b4be883f15079b7ebab9a) + + +得到输入图像的预测结果: + +``` +infer_img: test_digital.png + result: ('-70.00', 0.9998967) +``` diff --git "a/applications/\345\214\205\350\243\205\347\224\237\344\272\247\346\227\245\346\234\237\350\257\206\345\210\253.md" "b/applications/\345\214\205\350\243\205\347\224\237\344\272\247\346\227\245\346\234\237\350\257\206\345\210\253.md" new file mode 100644 index 0000000000000000000000000000000000000000..73c174c4f954d7cd348b57fc5d6b00f6c5dab64b --- /dev/null +++ "b/applications/\345\214\205\350\243\205\347\224\237\344\272\247\346\227\245\346\234\237\350\257\206\345\210\253.md" @@ -0,0 +1,685 @@ +# 一种基于PaddleOCR的产品包装生产日期识别模型 + +- [1. 项目介绍](#1-项目介绍) +- [2. 环境搭建](#2-环境搭建) +- [3. 数据准备](#3-数据准备) +- [4. 直接使用PP-OCRv3模型评估](#4-直接使用PPOCRv3模型评估) +- [5. 基于合成数据finetune](#5-基于合成数据finetune) + - [5.1 Text Renderer数据合成方法](#51-TextRenderer数据合成方法) + - [5.1.1 下载Text Renderer代码](#511-下载TextRenderer代码) + - [5.1.2 准备背景图片](#512-准备背景图片) + - [5.1.3 准备语料](#513-准备语料) + - [5.1.4 下载字体](#514-下载字体) + - [5.1.5 运行数据合成命令](#515-运行数据合成命令) + - [5.2 模型训练](#52-模型训练) +- [6. 基于真实数据finetune](#6-基于真实数据finetune) + - [6.1 python爬虫获取数据](#61-python爬虫获取数据) + - [6.2 数据挖掘](#62-数据挖掘) + - [6.3 模型训练](#63-模型训练) +- [7. 基于合成+真实数据finetune](#7-基于合成+真实数据finetune) + + +## 1. 项目介绍 + +产品包装生产日期是计算机视觉图像识别技术在工业场景中的一种应用。产品包装生产日期识别技术要求能够将产品生产日期从复杂背景中提取并识别出来,在物流管理、物资管理中得到广泛应用。 + +![](https://ai-studio-static-online.cdn.bcebos.com/d9e0533cc1df47ffa3bbe99de9e42639a3ebfa5bce834bafb1ca4574bf9db684) + + +- 项目难点 + +1. 没有训练数据 +2. 图像质量层次不齐: 角度倾斜、图片模糊、光照不足、过曝等问题严重 + +针对以上问题, 本例选用PP-OCRv3这一开源超轻量OCR系统进行包装产品生产日期识别系统的开发。直接使用PP-OCRv3进行评估的精度为62.99%。为提升识别精度,我们首先使用数据合成工具合成了3k数据,基于这部分数据进行finetune,识别精度提升至73.66%。由于合成数据与真实数据之间的分布存在差异,为进一步提升精度,我们使用网络爬虫配合数据挖掘策略得到了1k带标签的真实数据,基于真实数据finetune的精度为71.33%。最后,我们综合使用合成数据和真实数据进行finetune,将识别精度提升至86.99%。各策略的精度提升效果如下: + +| 策略 | 精度| +| :--------------- | :-------- | +| PP-OCRv3评估 | 62.99| +| 合成数据finetune | 73.66| +| 真实数据finetune | 71.33| +| 真实+合成数据finetune | 86.99| + +AIStudio项目链接: [一种基于PaddleOCR的包装生产日期识别方法](https://aistudio.baidu.com/aistudio/projectdetail/4287736) + +## 2. 环境搭建 + +本任务基于Aistudio完成, 具体环境如下: + +- 操作系统: Linux +- PaddlePaddle: 2.3 +- PaddleOCR: Release/2.5 +- text_renderer: master + +下载PaddlleOCR代码并安装依赖库: +```bash +git clone -b dygraph https://gitee.com/paddlepaddle/PaddleOCR + +# 安装依赖库 +cd PaddleOCR +pip install -r PaddleOCR/requirements.txt +``` + +## 3. 数据准备 + +本项目使用人工预标注的300张图像作为测试集。 + +部分数据示例如下: + +![](https://ai-studio-static-online.cdn.bcebos.com/39ff30e0ab0442579712255e6a9ea6b5271169c98e624e6eb2b8781f003bfea0) + + +标签文件格式如下: +```txt +数据路径 标签(中间以制表符分隔) +``` + +|数据集类型|数量| +|---|---| +|测试集| 300| + +数据集[下载链接](https://aistudio.baidu.com/aistudio/datasetdetail/149770),下载后可以通过下方命令解压: + +```bash +tar -xvf data.tar +mv data ${PaddleOCR_root} +``` + +数据解压后的文件结构如下: + +```shell +PaddleOCR +├── data +│ ├── mining_images # 挖掘的真实数据示例 +│ ├── mining_train.list # 挖掘的真实数据文件列表 +│ ├── render_images # 合成数据示例 +│ ├── render_train.list # 合成数据文件列表 +│ ├── val # 测试集数据 +│ └── val.list # 测试集数据文件列表 +| ├── bg # 合成数据所需背景图像 +│ └── corpus # 合成数据所需语料 +``` + +## 4. 直接使用PP-OCRv3模型评估 + +准备好测试数据后,可以使用PaddleOCR的PP-OCRv3模型进行识别。 + +- 下载预训练模型 + +首先需要下载PP-OCR v3中英文识别模型文件,下载链接可以在https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/ppocr_introduction.md#6 获取,下载命令: + +```bash +cd ${PaddleOCR_root} +mkdir ckpt +wget -nc -P ckpt https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar +pushd ckpt/ +tar -xvf ch_PP-OCRv3_rec_train.tar +popd +``` + +- 模型评估 + +使用以下命令进行PP-OCRv3评估: + +```bash +python tools/eval.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml \ + -o Global.checkpoints=ckpt/ch_PP-OCRv3_rec_train/best_accuracy \ + Eval.dataset.data_dir=./data \ + Eval.dataset.label_file_list=["./data/val.list"] + +``` + +其中各参数含义如下: + +```bash +-c: 指定使用的配置文件,ch_PP-OCRv3_rec_distillation.yml对应于OCRv3识别模型。 +-o: 覆盖配置文件中参数 +Global.checkpoints: 指定评估使用的模型文件路径 +Eval.dataset.data_dir: 指定评估数据集路径 +Eval.dataset.label_file_list: 指定评估数据集文件列表 +``` + +## 5. 基于合成数据finetune + +### 5.1 Text Renderer数据合成方法 + +#### 5.1.1 下载Text Renderer代码 + +首先从github或gitee下载Text Renderer代码,并安装相关依赖。 + +```bash +git clone https://gitee.com/wowowoll/text_renderer.git + +# 安装依赖库 +cd text_renderer +pip install -r requirements.txt +``` + +使用text renderer合成数据之前需要准备好背景图片、语料以及字体库,下面将逐一介绍各个步骤。 + +#### 5.1.2 准备背景图片 + +观察日常生活中常见的包装生产日期图片,我们可以发现其背景相对简单。为此我们可以从网上找一下图片,截取部分图像块作为背景图像。 + +本项目已准备了部分图像作为背景图片,在第3部分完成数据准备后,可以得到我们准备好的背景图像,示例如下: + +![](https://ai-studio-static-online.cdn.bcebos.com/456ae2acb27d4a94896c478812aee0bc3551c703d7bd40c9be4dc983c7b3fc8a) + + + +背景图像存放于如下位置: + +```shell +PaddleOCR +├── data +| ├── bg # 合成数据所需背景图像 +``` + +#### 5.1.3 准备语料 + +观察测试集生产日期图像,我们可以知道如下数据有如下特点: +1. 由年月日组成,中间可能以“/”、“-”、“:”、“.”或者空格间隔,也可能以汉字年月日分隔 +2. 有些生产日期包含在产品批号中,此时可能包含具体时间、英文字母或数字标识 + +基于以上两点,我们编写语料生成脚本: + +```python +import random +from random import choice +import os + +cropus_num = 2000 #设置语料数量 + +def get_cropus(f): + # 随机生成年份 + year = random.randint(0, 22) + # 随机生成月份 + month = random.randint(1, 12) + # 随机生成日期 + day_dict = {31: [1,3,5,7,8,10,12], 30: [4,6,9,11], 28: [2]} + for item in day_dict: + if month in day_dict[item]: + day = random.randint(0, item) + # 随机生成小时 + hours = random.randint(0, 24) + # 随机生成分钟 + minute = random.randint(0, 60) + # 随机生成秒数 + second = random.randint(0, 60) + + # 随机生成产品标识字符 + length = random.randint(0, 6) + file_id = [] + flag = 0 + my_dict = [i for i in range(48,58)] + [j for j in range(40, 42)] + [k for k in range(65,90)] # 大小写字母 + 括号 + + for i in range(1, length): + if flag: + if i == flag+2: #括号匹配 + file_id.append(')') + flag = 0 + continue + sel = choice(my_dict) + if sel == 41: + continue + if sel == 40: + if i == 1 or i > length-3: + continue + flag = i + my_ascii = chr(sel) + file_id.append(my_ascii) + file_id_str = ''.join(file_id) + + #随机生成产品标识字符 + file_id2 = random.randint(0, 9) + + rad = random.random() + if rad < 0.3: + f.write('20{:02d}{:02d}{:02d} {}'.format(year, month, day, file_id_str)) + elif 0.3 < rad < 0.5: + f.write('20{:02d}年{:02d}月{:02d}日'.format(year, month, day)) + elif 0.5 < rad < 0.7: + f.write('20{:02d}/{:02d}/{:02d}'.format(year, month, day)) + elif 0.7 < rad < 0.8: + f.write('20{:02d}-{:02d}-{:02d}'.format(year, month, day)) + elif 0.8 < rad < 0.9: + f.write('20{:02d}.{:02d}.{:02d}'.format(year, month, day)) + else: + f.write('{:02d}:{:02d}:{:02d} {:02d}'.format(hours, minute, second, file_id2)) + +if __name__ == "__main__": + file_path = '/home/aistudio/text_renderer/my_data/cropus' + if not os.path.exists(file_path): + os.makedirs(file_path) + file_name = os.path.join(file_path, 'books.txt') + f = open(file_name, 'w') + for i in range(cropus_num): + get_cropus(f) + if i < cropus_num-1: + f.write('\n') + + f.close() +``` + +本项目已准备了部分语料,在第3部分完成数据准备后,可以得到我们准备好的语料库,默认位置如下: + +```shell +PaddleOCR +├── data +│ └── corpus #合成数据所需语料 +``` + +#### 5.1.4 下载字体 + +观察包装生产日期,我们可以发现其使用的字体为点阵体。字体可以在如下网址下载: +https://www.fonts.net.cn/fonts-en/tag-dianzhen-1.html + +本项目已准备了部分字体,在第3部分完成数据准备后,可以得到我们准备好的字体,默认位置如下: + +```shell +PaddleOCR +├── data +│ └── fonts #合成数据所需字体 +``` + +下载好字体后,还需要在list文件中指定字体文件存放路径,脚本如下: + +```bash +cd text_renderer/my_data/ +touch fonts.list +ls /home/aistudio/PaddleOCR/data/fonts/* > fonts.list +``` + +#### 5.1.5 运行数据合成命令 + +完成数据准备后,my_data文件结构如下: + +```shell +my_data/ +├── cropus +│ └── books.txt #语料库 +├── eng.txt #字符列表 +└── fonts.list #字体列表 +``` + +在运行合成数据命令之前,还有两处细节需要手动修改: +1. 将默认配置文件`text_renderer/configs/default.yaml`中第9行enable的值设为`true`,即允许合成彩色图像。否则合成的都是灰度图。 + +```yaml + # color boundary is in R,G,B format + font_color: ++ enable: true #false +``` + +2. 将`text_renderer/textrenderer/renderer.py`第184行作如下修改,取消padding。否则图片两端会有一些空白。 + +```python +padding = random.randint(s_bbox_width // 10, s_bbox_width // 8) #修改前 +padding = 0 #修改后 +``` + +运行数据合成命令: + +```bash +cd /home/aistudio/text_renderer/ +python main.py --num_img=3000 \ + --fonts_list='./my_data/fonts.list' \ + --corpus_dir "./my_data/cropus" \ + --corpus_mode "list" \ + --bg_dir "/home/aistudio/PaddleOCR/data/bg/" \ + --img_width 0 +``` + +合成好的数据默认保存在`text_renderer/output`目录下,可进入该目录查看合成的数据。 + + +合成数据示例如下 +![](https://ai-studio-static-online.cdn.bcebos.com/d686a48d465a43d09fbee51924fdca42ee21c50e676646da8559fb9967b94185) + +数据合成好后,还需要生成如下格式的训练所需的标注文件, +``` +图像路径 标签 +``` + +使用如下脚本即可生成标注文件: + +```python +import random + +abspath = '/home/aistudio/text_renderer/output/default/' + +#标注文件生成路径 +fout = open('./render_train.list', 'w', encoding='utf-8') + +with open('./output/default/tmp_labels.txt','r') as f: + lines = f.readlines() + for item in lines: + label = item[9:] + filename = item[:8] + '.jpg' + fout.write(abspath + filename + '\t' + label) + + fout.close() +``` + +经过以上步骤,我们便完成了包装生产日期数据合成。 +数据位于`text_renderer/output`,标注文件位于`text_renderer/render_train.list`。 + +本项目提供了生成好的数据供大家体验,完成步骤3的数据准备后,可得数据路径位于: + +```shell +PaddleOCR +├── data +│ ├── render_images # 合成数据示例 +│ ├── render_train.list #合成数据文件列表 +``` + +### 5.2 模型训练 + +准备好合成数据后,我们可以使用以下命令,利用合成数据进行finetune: +```bash +cd ${PaddleOCR_root} +python tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml \ + -o Global.pretrained_model=./ckpt/ch_PP-OCRv3_rec_train/best_accuracy \ + Global.epoch_num=20 \ + Global.eval_batch_step='[0, 20]' \ + Train.dataset.data_dir=./data \ + Train.dataset.label_file_list=['./data/render_train.list'] \ + Train.loader.batch_size_per_card=64 \ + Eval.dataset.data_dir=./data \ + Eval.dataset.label_file_list=["./data/val.list"] \ + Eval.loader.batch_size_per_card=64 + +``` + +其中各参数含义如下: + +```txt +-c: 指定使用的配置文件,ch_PP-OCRv3_rec_distillation.yml对应于OCRv3识别模型。 +-o: 覆盖配置文件中参数 +Global.pretrained_model: 指定finetune使用的预训练模型 +Global.epoch_num: 指定训练的epoch数 +Global.eval_batch_step: 间隔多少step做一次评估 +Train.dataset.data_dir: 训练数据集路径 +Train.dataset.label_file_list: 训练集文件列表 +Train.loader.batch_size_per_card: 训练单卡batch size +Eval.dataset.data_dir: 评估数据集路径 +Eval.dataset.label_file_list: 评估数据集文件列表 +Eval.loader.batch_size_per_card: 评估单卡batch size +``` + +## 6. 基于真实数据finetune + + +使用合成数据finetune能提升我们模型的识别精度,但由于合成数据和真实数据之间的分布可能有一定差异,因此作用有限。为进一步提高识别精度,本节介绍如何挖掘真实数据进行模型finetune。 + +数据挖掘的整体思路如下: +1. 使用python爬虫从网上获取大量无标签数据 +2. 使用模型从大量无标签数据中构建出有效训练集 + +### 6.1 python爬虫获取数据 + +- 推荐使用[爬虫工具](https://github.com/Joeclinton1/google-images-download)获取无标签图片。 + +图片获取后,可按如下目录格式组织: + +```txt +sprider +├── file.list +├── data +│ ├── 00000.jpg +│ ├── 00001.jpg +... +``` + +### 6.2 数据挖掘 + +我们使用PaddleOCR对获取到的图片进行挖掘,具体步骤如下: +1. 使用 PP-OCRv3检测模型+svtr-tiny识别模型,对每张图片进行预测。 +2. 使用数据挖掘策略,得到有效图片。 +3. 将有效图片对应的图像区域和标签提取出来,构建训练集。 + + +首先下载预训练模型,PP-OCRv3检测模型下载链接:https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_infer.tar + +如需获取svtr-tiny高精度中文识别预训练模型,请扫码填写问卷,加入PaddleOCR官方交流群获取全部OCR垂类模型下载链接、《动手学OCR》电子书等全套OCR学习资料🎁 +
+ +
+ + +完成下载后,可将模型存储于如下位置: + +```shell +PaddleOCR +├── data +│ ├── rec_vit_sub_64_363_all/ # svtr_tiny高精度识别模型 +``` + +```bash +# 下载解压PP-OCRv3检测模型 +cd ${PaddleOCR_root} +wget -nc -P ckpt https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_infer.tar +pushd ckpt +tar -xvf ch_PP-OCRv3_det_infer.tar +popd ckpt +``` + +在使用PPOCRv3检测模型+svtr-tiny识别模型进行预测之前,有如下两处细节需要手动修改: +1. 将`tools/infer/predict_rec.py`中第110行`imgW`修改为`320` + +```python +#imgW = int((imgH * max_wh_ratio)) +imgW = 320 +``` + +2. 将`tools/infer/predict_system.py`第169行添加如下一行,将预测分数也写入结果文件中。 + +```python +"scores": rec_res[idx][1], +``` + +模型预测命令: +```bash +python tools/infer/predict_system.py \ + --image_dir="/home/aistudio/sprider/data" \ + --det_model_dir="./ckpt/ch_PP-OCRv3_det_infer/" \ + --rec_model_dir="/home/aistudio/PaddleOCR/data/rec_vit_sub_64_363_all/" \ + --rec_image_shape="3,32,320" +``` + +获得预测结果后,我们使用数据挖掘策略得到有效图片。具体挖掘策略如下: +1. 预测置信度高于95% +2. 识别结果包含字符‘20’,即年份 +3. 没有中文,或者有中文并且‘日’和'月'同时在识别结果中 + +```python +# 获取有效预测 + +import json +import re + +zh_pattern = re.compile(u'[\u4e00-\u9fa5]+') #正则表达式,筛选字符是否包含中文 + +file_path = '/home/aistudio/PaddleOCR/inference_results/system_results.txt' +out_path = '/home/aistudio/PaddleOCR/selected_results.txt' +f_out = open(out_path, 'w') + +with open(file_path, "r", encoding='utf-8') as fin: + lines = fin.readlines() + + +for line in lines: + flag = False + # 读取文件内容 + file_name, json_file = line.strip().split('\t') + preds = json.loads(json_file) + res = [] + for item in preds: + transcription = item['transcription'] #获取识别结果 + scores = item['scores'] #获取识别得分 + # 挖掘策略 + if scores > 0.95: + if '20' in transcription and len(transcription) > 4 and len(transcription) < 12: + word = transcription + if not(zh_pattern.search(word) and ('日' not in word or '月' not in word)): + flag = True + res.append(item) + save_pred = file_name + "\t" + json.dumps( + res, ensure_ascii=False) + "\n" + if flag ==True: + f_out.write(save_pred) + +f_out.close() +``` + +然后将有效预测对应的图像区域和标签提取出来,构建训练集。具体实现脚本如下: + +```python +import cv2 +import json +import numpy as np + +PATH = '/home/aistudio/PaddleOCR/inference_results/' #数据原始路径 +SAVE_PATH = '/home/aistudio/mining_images/' #裁剪后数据保存路径 +file_list = '/home/aistudio/PaddleOCR/selected_results.txt' #数据预测结果 +label_file = '/home/aistudio/mining_images/mining_train.list' #输出真实数据训练集标签list + +if not os.path.exists(SAVE_PATH): + os.mkdir(SAVE_PATH) + +f_label = open(label_file, 'w') + + +def get_rotate_crop_image(img, points): + """ + 根据检测结果points,从输入图像img中裁剪出相应的区域 + """ + assert len(points) == 4, "shape of points must be 4*2" + img_crop_width = int( + max( + np.linalg.norm(points[0] - points[1]), + np.linalg.norm(points[2] - points[3]))) + img_crop_height = int( + max( + np.linalg.norm(points[0] - points[3]), + np.linalg.norm(points[1] - points[2]))) + pts_std = np.float32([[0, 0], [img_crop_width, 0], + [img_crop_width, img_crop_height], + [0, img_crop_height]]) + M = cv2.getPerspectiveTransform(points, pts_std) + # 形变或倾斜,会做透视变换,reshape成矩形 + dst_img = cv2.warpPerspective( + img, + M, (img_crop_width, img_crop_height), + borderMode=cv2.BORDER_REPLICATE, + flags=cv2.INTER_CUBIC) + dst_img_height, dst_img_width = dst_img.shape[0:2] + if dst_img_height * 1.0 / dst_img_width >= 1.5: + dst_img = np.rot90(dst_img) + return dst_img + +def crop_and_get_filelist(file_list): + with open(file_list, "r", encoding='utf-8') as fin: + lines = fin.readlines() + + img_num = 0 + for line in lines: + img_name, json_file = line.strip().split('\t') + preds = json.loads(json_file) + for item in preds: + transcription = item['transcription'] + points = item['points'] + points = np.array(points).astype('float32') + #print('processing {}...'.format(img_name)) + + img = cv2.imread(PATH+img_name) + dst_img = get_rotate_crop_image(img, points) + h, w, c = dst_img.shape + newWidth = int((32. / h) * w) + newImg = cv2.resize(dst_img, (newWidth, 32)) + new_img_name = '{:05d}.jpg'.format(img_num) + cv2.imwrite(SAVE_PATH+new_img_name, dst_img) + f_label.write(SAVE_PATH+new_img_name+'\t'+transcription+'\n') + img_num += 1 + + +crop_and_get_filelist(file_list) +f_label.close() +``` + +### 6.3 模型训练 + +通过数据挖掘,我们得到了真实场景数据和对应的标签。接下来使用真实数据finetune,观察精度提升效果。 + + +利用真实数据进行finetune: + +```bash +cd ${PaddleOCR_root} +python tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml \ + -o Global.pretrained_model=./ckpt/ch_PP-OCRv3_rec_train/best_accuracy \ + Global.epoch_num=20 \ + Global.eval_batch_step='[0, 20]' \ + Train.dataset.data_dir=./data \ + Train.dataset.label_file_list=['./data/mining_train.list'] \ + Train.loader.batch_size_per_card=64 \ + Eval.dataset.data_dir=./data \ + Eval.dataset.label_file_list=["./data/val.list"] \ + Eval.loader.batch_size_per_card=64 +``` + +各参数含义参考第6部分合成数据finetune,只需要对训练数据路径做相应的修改: + +```txt +Train.dataset.data_dir: 训练数据集路径 +Train.dataset.label_file_list: 训练集文件列表 +``` + +示例使用我们提供的真实数据进行finetune,如想换成自己的数据,只需要相应的修改`Train.dataset.data_dir`和`Train.dataset.label_file_list`参数即可。 + +由于数据量不大,这里仅训练20个epoch即可。训练完成后,可以得到合成数据finetune后的精度为best acc=**71.33%**。 + +由于数量比较少,精度会比合成数据finetue的略低。 + + +## 7. 基于合成+真实数据finetune + +为进一步提升模型精度,我们结合使用合成数据和挖掘到的真实数据进行finetune。 + +利用合成+真实数据进行finetune,各参数含义参考第6部分合成数据finetune,只需要对训练数据路径做相应的修改: + +```txt +Train.dataset.data_dir: 训练数据集路径 +Train.dataset.label_file_list: 训练集文件列表 +``` + +生成训练list文件: +```bash +# 生成训练集文件list +cat /home/aistudio/PaddleOCR/data/render_train.list /home/aistudio/PaddleOCR/data/mining_train.list > /home/aistudio/PaddleOCR/data/render_mining_train.list +``` + +启动训练: +```bash +cd ${PaddleOCR_root} +python tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml \ + -o Global.pretrained_model=./ckpt/ch_PP-OCRv3_rec_train/best_accuracy \ + Global.epoch_num=40 \ + Global.eval_batch_step='[0, 20]' \ + Train.dataset.data_dir=./data \ + Train.dataset.label_file_list=['./data/render_mining_train.list'] \ + Train.loader.batch_size_per_card=64 \ + Eval.dataset.data_dir=./data \ + Eval.dataset.label_file_list=["./data/val.list"] \ + Eval.loader.batch_size_per_card=64 +``` + +示例使用我们提供的真实+合成数据进行finetune,如想换成自己的数据,只需要相应的修改Train.dataset.data_dir和Train.dataset.label_file_list参数即可。 + +由于数据量不大,这里仅训练40个epoch即可。训练完成后,可以得到合成数据finetune后的精度为best acc=**86.99%**。 + +可以看到,相较于原始PP-OCRv3的识别精度62.99%,使用合成数据+真实数据finetune后,识别精度能提升24%。 + +如需获取已训练模型,可以同样扫描上方二维码下载,将下载或训练完成的模型放置在对应目录下即可完成模型推理。 + +模型的推理部署方法可以参考repo文档: https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/deploy/README_ch.md diff --git "a/applications/\345\244\232\346\250\241\346\200\201\350\241\250\345\215\225\350\257\206\345\210\253.md" "b/applications/\345\244\232\346\250\241\346\200\201\350\241\250\345\215\225\350\257\206\345\210\253.md" index e64a22e169482ae51cadf8b25d75c5d98651e80b..471ca633c143635b1715f054efa6924c1d0a1eab 100644 --- "a/applications/\345\244\232\346\250\241\346\200\201\350\241\250\345\215\225\350\257\206\345\210\253.md" +++ "b/applications/\345\244\232\346\250\241\346\200\201\350\241\250\345\215\225\350\257\206\345\210\253.md" @@ -1,4 +1,33 @@ -# 1 项目说明 +# 多模态表单识别 +- [多模态表单识别](#多模态表单识别) + - [1 项目说明](#1-项目说明) + - [2 安装说明](#2-安装说明) + - [3 数据准备](#3-数据准备) + - [3.1 下载处理好的数据集](#31-下载处理好的数据集) + - [3.2 转换为PaddleOCR检测和识别格式](#32-转换为paddleocr检测和识别格式) + - [4 OCR](#4-ocr) + - [4.1 文本检测](#41-文本检测) + - [4.1.1 方案1:预训练模型](#411-方案1预训练模型) + - [4.1.2 方案2:XFUND数据集+fine-tune](#412-方案2xfund数据集fine-tune) + - [4.2 文本识别](#42-文本识别) + - [4.2.1 方案1:预训练模型](#421-方案1预训练模型) + - [4.2.2 方案2:XFUND数据集+finetune](#422-方案2xfund数据集finetune) + - [4.2.3 方案3:XFUND数据集+finetune+真实通用识别数据](#423-方案3xfund数据集finetune真实通用识别数据) + - [5 文档视觉问答(DOC-VQA)](#5-文档视觉问答doc-vqa) + - [5.1 SER](#51-ser) + - [5.1.1 模型训练](#511-模型训练) + - [5.1.2 模型评估](#512-模型评估) + - [5.1.3 模型预测](#513-模型预测) + - [5.2 RE](#52-re) + - [5.2.1 模型训练](#521-模型训练) + - [5.2.2 模型评估](#522-模型评估) + - [5.2.3 模型预测](#523-模型预测) + - [6 导出Excel](#6-导出excel) + - [获得模型](#获得模型) + - [更多资源](#更多资源) + - [参考链接](#参考链接) + +## 1 项目说明 计算机视觉在金融领域的应用覆盖文字识别、图像识别、视频识别等,其中文字识别(OCR)是金融领域中的核心AI能力,其应用覆盖客户服务、风险防控、运营管理等各项业务,针对的对象包括通用卡证票据识别(银行卡、身份证、营业执照等)、通用文本表格识别(印刷体、多语言、手写体等)以及一些金融特色票据凭证。通过因此如果能够在结构化信息提取时同时利用文字、页面布局等信息,便可增强不同版式下的泛化性。 @@ -16,39 +45,37 @@
图1 多模态表单识别流程图
-注:欢迎再AIStudio领取免费算力体验线上实训,项目链接: [多模态表单识别](https://aistudio.baidu.com/aistudio/projectdetail/3815918)(配备Tesla V100、A100等高级算力资源) +注:欢迎再AIStudio领取免费算力体验线上实训,项目链接: [多模态表单识别](https://aistudio.baidu.com/aistudio/projectdetail/3884375?contributionType=1) +## 2 安装说明 -# 2 安装说明 - - -下载PaddleOCR源码,本项目中已经帮大家打包好的PaddleOCR(已经修改好配置文件),无需下载解压即可,只需安装依赖环境~ +下载PaddleOCR源码,上述AIStudio项目中已经帮大家打包好的PaddleOCR(已经修改好配置文件),无需下载解压即可,只需安装依赖环境~ ```python -! unzip -q PaddleOCR.zip +unzip -q PaddleOCR.zip ``` ```python # 如仍需安装or安装更新,可以执行以下步骤 -! git clone https://github.com/PaddlePaddle/PaddleOCR.git -b dygraph -# ! git clone https://gitee.com/PaddlePaddle/PaddleOCR +# git clone https://github.com/PaddlePaddle/PaddleOCR.git -b dygraph +# git clone https://gitee.com/PaddlePaddle/PaddleOCR ``` ```python # 安装依赖包 -! pip install -U pip -! pip install -r /home/aistudio/PaddleOCR/requirements.txt -! pip install paddleocr +pip install -U pip +pip install -r /home/aistudio/PaddleOCR/requirements.txt +pip install paddleocr -! pip install yacs gnureadline paddlenlp==2.2.1 -! pip install xlsxwriter +pip install yacs gnureadline paddlenlp==2.2.1 +pip install xlsxwriter ``` -# 3 数据准备 +## 3 数据准备 这里使用[XFUN数据集](https://github.com/doc-analysis/XFUND)做为实验数据集。 XFUN数据集是微软提出的一个用于KIE任务的多语言数据集,共包含七个数据集,每个数据集包含149张训练集和50张验证集 @@ -59,7 +86,7 @@
图2 数据集样例,左中文,右法语
-## 3.1 下载处理好的数据集 +### 3.1 下载处理好的数据集 处理好的XFUND中文数据集下载地址:[https://paddleocr.bj.bcebos.com/dataset/XFUND.tar](https://paddleocr.bj.bcebos.com/dataset/XFUND.tar) ,可以运行如下指令完成中文数据集下载和解压。 @@ -69,13 +96,13 @@ ```python -! wget https://paddleocr.bj.bcebos.com/dataset/XFUND.tar -! tar -xf XFUND.tar +wget https://paddleocr.bj.bcebos.com/dataset/XFUND.tar +tar -xf XFUND.tar # XFUN其他数据集使用下面的代码进行转换 # 代码链接:https://github.com/PaddlePaddle/PaddleOCR/blob/release%2F2.4/ppstructure/vqa/helper/trans_xfun_data.py # %cd PaddleOCR -# !python3 ppstructure/vqa/tools/trans_xfun_data.py --ori_gt_path=path/to/json_path --output_path=path/to/save_path +# python3 ppstructure/vqa/tools/trans_xfun_data.py --ori_gt_path=path/to/json_path --output_path=path/to/save_path # %cd ../ ``` @@ -119,7 +146,7 @@ } ``` -## 3.2 转换为PaddleOCR检测和识别格式 +### 3.2 转换为PaddleOCR检测和识别格式 使用XFUND训练PaddleOCR检测和识别模型,需要将数据集格式改为训练需求的格式。 @@ -147,7 +174,7 @@ train_data/rec/train/word_002.jpg 用科技让复杂的世界更简单 ```python -! unzip -q /home/aistudio/data/data140302/XFUND_ori.zip -d /home/aistudio/data/data140302/ +unzip -q /home/aistudio/data/data140302/XFUND_ori.zip -d /home/aistudio/data/data140302/ ``` 已经提供转换脚本,执行如下代码即可转换成功: @@ -155,21 +182,20 @@ train_data/rec/train/word_002.jpg 用科技让复杂的世界更简单 ```python %cd /home/aistudio/ -! python trans_xfund_data.py +python trans_xfund_data.py ``` -# 4 OCR +## 4 OCR 选用飞桨OCR开发套件[PaddleOCR](https://github.com/PaddlePaddle/PaddleOCR/blob/dygraph/README_ch.md)中的PP-OCRv2模型进行文本检测和识别。PP-OCRv2在PP-OCR的基础上,进一步在5个方面重点优化,检测模型采用CML协同互学习知识蒸馏策略和CopyPaste数据增广策略;识别模型采用LCNet轻量级骨干网络、UDML 改进知识蒸馏策略和[Enhanced CTC loss](https://github.com/PaddlePaddle/PaddleOCR/blob/dygraph/doc/doc_ch/enhanced_ctc_loss.md)损失函数改进,进一步在推理速度和预测效果上取得明显提升。更多细节请参考PP-OCRv2[技术报告](https://arxiv.org/abs/2109.03144)。 - -## 4.1 文本检测 +### 4.1 文本检测 我们使用2种方案进行训练、评估: - **PP-OCRv2中英文超轻量检测预训练模型** - **XFUND数据集+fine-tune** -### **4.1.1 方案1:预训练模型** +#### 4.1.1 方案1:预训练模型 **1)下载预训练模型** @@ -195,8 +221,8 @@ PaddleOCR已经提供了PP-OCR系列模型,部分模型展示如下表所示 ```python %cd /home/aistudio/PaddleOCR/pretrain/ -! wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_distill_train.tar -! tar -xf ch_PP-OCRv2_det_distill_train.tar && rm -rf ch_PP-OCRv2_det_distill_train.tar +wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_det_distill_train.tar +tar -xf ch_PP-OCRv2_det_distill_train.tar && rm -rf ch_PP-OCRv2_det_distill_train.tar % cd .. ``` @@ -226,7 +252,7 @@ Eval.dataset.label_file_list:指向验证集标注文件 ```python %cd /home/aistudio/PaddleOCR -! python tools/eval.py \ +python tools/eval.py \ -c configs/det/ch_PP-OCRv2/ch_PP-OCRv2_det_distill.yml \ -o Global.checkpoints="./pretrain_models/ch_PP-OCRv2_det_distill_train/best_accuracy" ``` @@ -237,9 +263,9 @@ Eval.dataset.label_file_list:指向验证集标注文件 | -------- | -------- | | PP-OCRv2中英文超轻量检测预训练模型 | 77.26% | -使用文本检测预训练模型在XFUND验证集上评估,达到77%左右,充分说明ppocr提供的预训练模型有一定的泛化能力。 +使用文本检测预训练模型在XFUND验证集上评估,达到77%左右,充分说明ppocr提供的预训练模型具有泛化能力。 -### **4.1.2 方案2:XFUND数据集+fine-tune** +#### 4.1.2 方案2:XFUND数据集+fine-tune PaddleOCR提供的蒸馏预训练模型包含了多个模型的参数,我们提取Student模型的参数,在XFUND数据集上进行finetune,可以参考如下代码: @@ -281,7 +307,7 @@ Eval.dataset.transforms.DetResizeForTest:评估尺寸,添加如下参数 ```python -! CUDA_VISIBLE_DEVICES=0 python tools/train.py \ +CUDA_VISIBLE_DEVICES=0 python tools/train.py \ -c configs/det/ch_PP-OCRv2/ch_PP-OCRv2_det_student.yml ``` @@ -290,12 +316,18 @@ Eval.dataset.transforms.DetResizeForTest:评估尺寸,添加如下参数
图8 文本检测方案2-模型评估
-使用训练好的模型进行评估,更新模型路径`Global.checkpoints`,这里为大家提供训练好的模型`./pretrain/ch_db_mv3-student1600-finetune/best_accuracy` +使用训练好的模型进行评估,更新模型路径`Global.checkpoints`。如需获取已训练模型,请扫码填写问卷,加入PaddleOCR官方交流群获取全部OCR垂类模型下载链接、《动手学OCR》电子书等全套OCR学习资料🎁 + +
+ +
+ +将下载或训练完成的模型放置在对应目录下即可完成模型评估 ```python %cd /home/aistudio/PaddleOCR/ -! python tools/eval.py \ +python tools/eval.py \ -c configs/det/ch_PP-OCRv2/ch_PP-OCRv2_det_student.yml \ -o Global.checkpoints="pretrain/ch_db_mv3-student1600-finetune/best_accuracy" ``` @@ -305,7 +337,7 @@ Eval.dataset.transforms.DetResizeForTest:评估尺寸,添加如下参数 ```python %cd /home/aistudio/PaddleOCR/ -! python tools/eval.py \ +python tools/eval.py \ -c configs/det/ch_PP-OCRv2/ch_PP-OCRv2_det_student.yml \ -o Global.checkpoints="pretrain/ch_db_mv3-student1600/best_accuracy" ``` @@ -331,7 +363,7 @@ Eval.dataset.transforms.DetResizeForTest:评估尺寸,添加如下参数 # 加载配置文件`ch_PP-OCRv2_det_student.yml`,从`pretrain/ch_db_mv3-student1600-finetune`目录下加载`best_accuracy`模型 # inference模型保存在`./output/det_db_inference`目录下 %cd /home/aistudio/PaddleOCR/ -! python tools/export_model.py \ +python tools/export_model.py \ -c configs/det/ch_PP-OCRv2/ch_PP-OCRv2_det_student.yml \ -o Global.pretrained_model="pretrain/ch_db_mv3-student1600-finetune/best_accuracy" \ Global.save_inference_dir="./output/det_db_inference/" @@ -374,12 +406,11 @@ use_gpu:是否使用GPU | 方案 | hmeans | 结果分析 | | -------- | -------- | -------- | -| PP-OCRv2中英文超轻量检测预训练模型 | 77.26% | ppocr提供的预训练模型有一定的泛化能力 | +| PP-OCRv2中英文超轻量检测预训练模型 | 77.26% | ppocr提供的预训练模型有泛化能力 | | XFUND数据集 | 79.27% | | | XFUND数据集+finetune | 85.24% | finetune会提升垂类场景效果 | - -## 4.2 文本识别 +### 4.2 文本识别 我们分别使用如下3种方案进行训练、评估: @@ -387,8 +418,7 @@ use_gpu:是否使用GPU - XFUND数据集+fine-tune - XFUND数据集+fine-tune+真实通用识别数据 - -### **4.2.1 方案1:预训练模型** +#### 4.2.1 方案1:预训练模型 **1)下载预训练模型** @@ -401,8 +431,8 @@ use_gpu:是否使用GPU ```python %cd /home/aistudio/PaddleOCR/pretrain/ -! wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_train.tar -! tar -xf ch_PP-OCRv2_rec_train.tar && rm -rf ch_PP-OCRv2_rec_train.tar +wget https://paddleocr.bj.bcebos.com/PP-OCRv2/chinese/ch_PP-OCRv2_rec_train.tar +tar -xf ch_PP-OCRv2_rec_train.tar && rm -rf ch_PP-OCRv2_rec_train.tar % cd .. ``` @@ -424,7 +454,7 @@ Eval.dataset.label_file_list:指向验证集标注文件 ```python %cd /home/aistudio/PaddleOCR -! CUDA_VISIBLE_DEVICES=0 python tools/eval.py \ +CUDA_VISIBLE_DEVICES=0 python tools/eval.py \ -c configs/rec/ch_PP-OCRv2/ch_PP-OCRv2_rec_distillation.yml \ -o Global.checkpoints=./pretrain/ch_PP-OCRv2_rec_train/best_accuracy ``` @@ -435,9 +465,9 @@ Eval.dataset.label_file_list:指向验证集标注文件 | -------- | -------- | | PP-OCRv2中英文超轻量识别预训练模型 | 67.48% | -使用文本预训练模型在XFUND验证集上评估,acc达到67%左右,充分说明ppocr提供的预训练模型有一定的泛化能力。 +使用文本预训练模型在XFUND验证集上评估,acc达到67%左右,充分说明ppocr提供的预训练模型具有泛化能力。 -### **4.2.2 方案2:XFUND数据集+finetune** +#### 4.2.2 方案2:XFUND数据集+finetune 同检测模型,我们提取Student模型的参数,在XFUND数据集上进行finetune,可以参考如下代码: @@ -474,11 +504,9 @@ Eval.dataset.label_file_list:指向验证集标注文件 ``` 执行如下命令启动训练: - - ```python %cd /home/aistudio/PaddleOCR/ -! CUDA_VISIBLE_DEVICES=0 python tools/train.py \ +CUDA_VISIBLE_DEVICES=0 python tools/train.py \ -c configs/rec/ch_PP-OCRv2/ch_PP-OCRv2_rec.yml ``` @@ -493,7 +521,7 @@ Eval.dataset.label_file_list:指向验证集标注文件 ```python %cd /home/aistudio/PaddleOCR/ -! CUDA_VISIBLE_DEVICES=0 python tools/eval.py \ +CUDA_VISIBLE_DEVICES=0 python tools/eval.py \ -c configs/rec/ch_PP-OCRv2/ch_PP-OCRv2_rec.yml \ -o Global.checkpoints=./pretrain/rec_mobile_pp-OCRv2-student-finetune/best_accuracy ``` @@ -506,7 +534,7 @@ Eval.dataset.label_file_list:指向验证集标注文件 使用XFUND数据集+finetune训练,在验证集上评估达到72%左右,说明 finetune会提升垂类场景效果。 -### **4.2.3 方案3:XFUND数据集+finetune+真实通用识别数据** +#### 4.2.3 方案3:XFUND数据集+finetune+真实通用识别数据 接着我们在上述`XFUND数据集+finetune`实验的基础上,添加真实通用识别数据,进一步提升识别效果。首先准备真实通用识别数据,并上传到AIStudio: @@ -528,7 +556,7 @@ Train.dataset.ratio_list:动态采样 ```python %cd /home/aistudio/PaddleOCR/ -! CUDA_VISIBLE_DEVICES=0 python tools/train.py \ +CUDA_VISIBLE_DEVICES=0 python tools/train.py \ -c configs/rec/ch_PP-OCRv2/ch_PP-OCRv2_rec.yml ``` @@ -538,11 +566,11 @@ Train.dataset.ratio_list:动态采样
图16 文本识别方案3-模型评估
-使用训练好的模型进行评估,更新模型路径`Global.checkpoints`,这里为大家提供训练好的模型`./pretrain/rec_mobile_pp-OCRv2-student-readldata/best_accuracy` +使用训练好的模型进行评估,更新模型路径`Global.checkpoints`。 ```python -! CUDA_VISIBLE_DEVICES=0 python tools/eval.py \ +CUDA_VISIBLE_DEVICES=0 python tools/eval.py \ -c configs/rec/ch_PP-OCRv2/ch_PP-OCRv2_rec.yml \ -o Global.checkpoints=./pretrain/rec_mobile_pp-OCRv2-student-realdata/best_accuracy ``` @@ -580,7 +608,7 @@ Train.dataset.ratio_list:动态采样 ```python -! python tools/infer/predict_system.py \ +python tools/infer/predict_system.py \ --image_dir="./doc/vqa/input/zh_val_21.jpg" \ --det_model_dir="./output/det_db_inference/" \ --rec_model_dir="./output/rec_crnn_inference/" \ @@ -592,11 +620,11 @@ Train.dataset.ratio_list:动态采样 | 方案 | acc | 结果分析 | | -------- | -------- | -------- | -| PP-OCRv2中英文超轻量识别预训练模型 | 67.48% | ppocr提供的预训练模型有一定的泛化能力 | +| PP-OCRv2中英文超轻量识别预训练模型 | 67.48% | ppocr提供的预训练模型具有泛化能力 | | XFUND数据集+fine-tune |72.33% | finetune会提升垂类场景效果 | | XFUND数据集+fine-tune+真实通用识别数据 | 85.29% | 真实通用识别数据对于性能提升很有帮助 | -# 5 文档视觉问答(DOC-VQA) +## 5 文档视觉问答(DOC-VQA) VQA指视觉问答,主要针对图像内容进行提问和回答,DOC-VQA是VQA任务中的一种,DOC-VQA主要针对文本图像的文字内容提出问题。 @@ -608,14 +636,13 @@ PaddleOCR中DOC-VQA系列算法基于PaddleNLP自然语言处理算法库实现L ```python %cd pretrain #下载SER模型 -! wget https://paddleocr.bj.bcebos.com/pplayout/ser_LayoutXLM_xfun_zh.tar && tar -xvf ser_LayoutXLM_xfun_zh.tar +wget https://paddleocr.bj.bcebos.com/pplayout/ser_LayoutXLM_xfun_zh.tar && tar -xvf ser_LayoutXLM_xfun_zh.tar #下载RE模型 -! wget https://paddleocr.bj.bcebos.com/pplayout/re_LayoutXLM_xfun_zh.tar && tar -xvf re_LayoutXLM_xfun_zh.tar +wget https://paddleocr.bj.bcebos.com/pplayout/re_LayoutXLM_xfun_zh.tar && tar -xvf re_LayoutXLM_xfun_zh.tar %cd ../ ``` - -## 5.1 SER +### 5.1 SER SER: 语义实体识别 (Semantic Entity Recognition), 可以完成对图像中的文本识别与分类。 @@ -647,7 +674,7 @@ SER: 语义实体识别 (Semantic Entity Recognition), 可以完成对图像 ```python %cd /home/aistudio/PaddleOCR/ -! CUDA_VISIBLE_DEVICES=0 python tools/train.py -c configs/vqa/ser/layoutxlm.yml +CUDA_VISIBLE_DEVICES=0 python tools/train.py -c configs/vqa/ser/layoutxlm.yml ``` 最终会打印出`precision`, `recall`, `hmean`等指标。 在`./output/ser_layoutxlm/`文件夹中会保存训练日志,最优的模型和最新epoch的模型。 @@ -664,7 +691,7 @@ SER: 语义实体识别 (Semantic Entity Recognition), 可以完成对图像 ```python -! CUDA_VISIBLE_DEVICES=0 python tools/eval.py \ +CUDA_VISIBLE_DEVICES=0 python tools/eval.py \ -c configs/vqa/ser/layoutxlm.yml \ -o Architecture.Backbone.checkpoints=pretrain/ser_LayoutXLM_xfun_zh/ ``` @@ -684,7 +711,7 @@ SER: 语义实体识别 (Semantic Entity Recognition), 可以完成对图像 ```python -! CUDA_VISIBLE_DEVICES=0 python tools/infer_vqa_token_ser.py \ +CUDA_VISIBLE_DEVICES=0 python tools/infer_vqa_token_ser.py \ -c configs/vqa/ser/layoutxlm.yml \ -o Architecture.Backbone.checkpoints=pretrain/ser_LayoutXLM_xfun_zh/ \ Global.infer_img=doc/vqa/input/zh_val_42.jpg @@ -704,7 +731,7 @@ plt.figure(figsize=(48,24)) plt.imshow(img) ``` -## 5.2 RE +### 5.2 RE 基于 RE 任务,可以完成对图象中的文本内容的关系提取,如判断问题对(pair)。 @@ -729,7 +756,7 @@ plt.imshow(img) ```python -! CUDA_VISIBLE_DEVICES=0 python3 tools/train.py -c configs/vqa/re/layoutxlm.yml +CUDA_VISIBLE_DEVICES=0 python3 tools/train.py -c configs/vqa/re/layoutxlm.yml ``` 最终会打印出`precision`, `recall`, `hmean`等指标。 在`./output/re_layoutxlm/`文件夹中会保存训练日志,最优的模型和最新epoch的模型 @@ -744,7 +771,7 @@ plt.imshow(img) ```python -! CUDA_VISIBLE_DEVICES=0 python3 tools/eval.py \ +CUDA_VISIBLE_DEVICES=0 python3 tools/eval.py \ -c configs/vqa/re/layoutxlm.yml \ -o Architecture.Backbone.checkpoints=pretrain/re_LayoutXLM_xfun_zh/ ``` @@ -760,20 +787,14 @@ plt.imshow(img)
图26 RE-模型预测
- 使用OCR引擎 + SER + RE串联预测 - -使用如下命令即可完成OCR引擎 + SER + RE的串联预测, 以预训练SER和RE模型为例: - - +使用如下命令即可完成OCR引擎 + SER + RE的串联预测, 以预训练SER和RE模型为例, 最终会在config.Global.save_res_path字段所配置的目录下保存预测结果可视化图像以及预测结果文本文件,预测结果文本文件名为infer_results.txt。 - - ```python -%cd /home/aistudio/PaddleOCR -! CUDA_VISIBLE_DEVICES=0 python3 tools/infer_vqa_token_ser_re.py \ +cd /home/aistudio/PaddleOCR +CUDA_VISIBLE_DEVICES=0 python3 tools/infer_vqa_token_ser_re.py \ -c configs/vqa/re/layoutxlm.yml \ -o Architecture.Backbone.checkpoints=pretrain/re_LayoutXLM_xfun_zh/ \ Global.infer_img=test_imgs/ \ @@ -787,10 +808,9 @@ plt.imshow(img) test_imgs/t131.jpg {"政治面税": "群众", "性别": "男", "籍贯": "河北省邯郸市", "婚姻状况": "亏末婚口已婚口已娇", "通讯地址": "邯郸市阳光苑7号楼003", "民族": "汉族", "毕业院校": "河南工业大学", "户口性质": "口农村城镇", "户口地址": "河北省邯郸市", "联系电话": "13288888888", "健康状况": "健康", "姓名": "小六", "好高cm": "180", "出生年月": "1996年8月9日", "文化程度": "本科", "身份证号码": "458933777777777777"} ```` - +展示预测结果 ```python -# 展示预测结果 import cv2 from matplotlib import pyplot as plt %matplotlib inline @@ -800,7 +820,7 @@ plt.figure(figsize=(48,24)) plt.imshow(img) ``` -# 6 导出Excel +## 6 导出Excel
图27 导出Excel
@@ -859,7 +879,7 @@ with open('output/re/infer_results.txt', 'r', encoding='utf-8') as fin: workbook.close() ``` -# 更多资源 +## 更多资源 - 更多深度学习知识、产业案例、面试宝典等,请参考:[awesome-DeepLearning](https://github.com/paddlepaddle/awesome-DeepLearning) @@ -869,7 +889,7 @@ workbook.close() - 飞桨框架相关资料,请参考:[飞桨深度学习平台](https://www.paddlepaddle.org.cn/?fr=paddleEdu_aistudio) -# 参考链接 +## 参考链接 - LayoutXLM: Multimodal Pre-training for Multilingual Visually-rich Document Understanding, https://arxiv.org/pdf/2104.08836.pdf diff --git "a/applications/\346\266\262\346\231\266\345\261\217\350\257\273\346\225\260\350\257\206\345\210\253.md" "b/applications/\346\266\262\346\231\266\345\261\217\350\257\273\346\225\260\350\257\206\345\210\253.md" new file mode 100644 index 0000000000000000000000000000000000000000..ff2fb2cb4812f4f8366605b3c26af5b9aaaa290e --- /dev/null +++ "b/applications/\346\266\262\346\231\266\345\261\217\350\257\273\346\225\260\350\257\206\345\210\253.md" @@ -0,0 +1,616 @@ +# 基于PP-OCRv3的液晶屏读数识别 + +- [1. 项目背景及意义](#1-项目背景及意义) +- [2. 项目内容](#2-项目内容) +- [3. 安装环境](#3-安装环境) +- [4. 文字检测](#4-文字检测) + - [4.1 PP-OCRv3检测算法介绍](#41-PP-OCRv3检测算法介绍) + - [4.2 数据准备](#42-数据准备) + - [4.3 模型训练](#43-模型训练) + - [4.3.1 预训练模型直接评估](#431-预训练模型直接评估) + - [4.3.2 预训练模型直接finetune](#432-预训练模型直接finetune) + - [4.3.3 基于预训练模型Finetune_student模型](#433-基于预训练模型Finetune_student模型) + - [4.3.4 基于预训练模型Finetune_teacher模型](#434-基于预训练模型Finetune_teacher模型) + - [4.3.5 采用CML蒸馏进一步提升student模型精度](#435-采用CML蒸馏进一步提升student模型精度) + - [4.3.6 模型导出推理](#436-4.3.6-模型导出推理) +- [5. 文字识别](#5-文字识别) + - [5.1 PP-OCRv3识别算法介绍](#51-PP-OCRv3识别算法介绍) + - [5.2 数据准备](#52-数据准备) + - [5.3 模型训练](#53-模型训练) + - [5.4 模型导出推理](#54-模型导出推理) +- [6. 系统串联](#6-系统串联) + - [6.1 后处理](#61-后处理) +- [7. PaddleServing部署](#7-PaddleServing部署) + + +## 1. 项目背景及意义 +目前光学字符识别(OCR)技术在我们的生活当中被广泛使用,但是大多数模型在通用场景下的准确性还有待提高,针对于此我们借助飞桨提供的PaddleOCR套件较容易的实现了在垂类场景下的应用。 + +该项目以国家质量基础(NQI)为准绳,充分利用大数据、云计算、物联网等高新技术,构建覆盖计量端、实验室端、数据端和硬件端的完整计量解决方案,解决传统计量校准中存在的难题,拓宽计量检测服务体系和服务领域;解决无数传接口或数传接口不统一、不公开的计量设备,以及计量设备所处的环境比较恶劣,不适合人工读取数据。通过OCR技术实现远程计量,引领计量行业向智慧计量转型和发展。 + +## 2. 项目内容 +本项目基于PaddleOCR开源套件,以PP-OCRv3检测和识别模型为基础,针对液晶屏读数识别场景进行优化。 + +Aistudio项目链接:[OCR液晶屏读数识别](https://aistudio.baidu.com/aistudio/projectdetail/4080130) + +## 3. 安装环境 + +```python +# 首先git官方的PaddleOCR项目,安装需要的依赖 +# 第一次运行打开该注释 +# git clone https://gitee.com/PaddlePaddle/PaddleOCR.git +cd PaddleOCR +pip install -r requirements.txt +``` + +## 4. 文字检测 +文本检测的任务是定位出输入图像中的文字区域。近年来学术界关于文本检测的研究非常丰富,一类方法将文本检测视为目标检测中的一个特定场景,基于通用目标检测算法进行改进适配,如TextBoxes[1]基于一阶段目标检测器SSD[2]算法,调整目标框使之适合极端长宽比的文本行,CTPN[3]则是基于Faster RCNN[4]架构改进而来。但是文本检测与目标检测在目标信息以及任务本身上仍存在一些区别,如文本一般长宽比较大,往往呈“条状”,文本行之间可能比较密集,弯曲文本等,因此又衍生了很多专用于文本检测的算法。本项目基于PP-OCRv3算法进行优化。 + +### 4.1 PP-OCRv3检测算法介绍 +PP-OCRv3检测模型是对PP-OCRv2中的CML(Collaborative Mutual Learning) 协同互学习文本检测蒸馏策略进行了升级。如下图所示,CML的核心思想结合了①传统的Teacher指导Student的标准蒸馏与 ②Students网络之间的DML互学习,可以让Students网络互学习的同时,Teacher网络予以指导。PP-OCRv3分别针对教师模型和学生模型进行进一步效果优化。其中,在对教师模型优化时,提出了大感受野的PAN结构LK-PAN和引入了DML(Deep Mutual Learning)蒸馏策略;在对学生模型优化时,提出了残差注意力机制的FPN结构RSE-FPN。 +![](https://ai-studio-static-online.cdn.bcebos.com/c306b2f028364805a55494d435ab553a76cf5ae5dd3f4649a948ea9aeaeb28b8) + +详细优化策略描述请参考[PP-OCRv3优化策略](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/PP-OCRv3_introduction.md#2) + +### 4.2 数据准备 +[计量设备屏幕字符检测数据集](https://aistudio.baidu.com/aistudio/datasetdetail/127845)数据来源于实际项目中各种计量设备的数显屏,以及在网上搜集的一些其他数显屏,包含训练集755张,测试集355张。 + +```python +# 在PaddleOCR下创建新的文件夹train_data +mkdir train_data +# 下载数据集并解压到指定路径下 +unzip icdar2015.zip -d train_data +``` + +```python +# 随机查看文字检测数据集图片 +from PIL import Image +import matplotlib.pyplot as plt +import numpy as np +import os + + +train = './train_data/icdar2015/text_localization/test' +# 从指定目录中选取一张图片 +def get_one_image(train): + plt.figure() + files = os.listdir(train) + n = len(files) + ind = np.random.randint(0,n) + img_dir = os.path.join(train,files[ind]) + image = Image.open(img_dir) + plt.imshow(image) + plt.show() + image = image.resize([208, 208]) + +get_one_image(train) +``` +![det_png](https://ai-studio-static-online.cdn.bcebos.com/0639da09b774458096ae577e82b2c59e89ced6a00f55458f946997ab7472a4f8) + +### 4.3 模型训练 + +#### 4.3.1 预训练模型直接评估 +下载我们需要的PP-OCRv3检测预训练模型,更多选择请自行选择其他的[文字检测模型](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/models_list.md#1-%E6%96%87%E6%9C%AC%E6%A3%80%E6%B5%8B%E6%A8%A1%E5%9E%8B) + +```python +#使用该指令下载需要的预训练模型 +wget -P ./pretrained_models/ https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_distill_train.tar +# 解压预训练模型文件 +tar -xf ./pretrained_models/ch_PP-OCRv3_det_distill_train.tar -C pretrained_models +``` + +在训练之前,我们可以直接使用下面命令来评估预训练模型的效果: + +```python +# 评估预训练模型 +python tools/eval.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml -o Global.pretrained_model="./pretrained_models/ch_PP-OCRv3_det_distill_train/best_accuracy" +``` + +结果如下: + +| | 方案 |hmeans| +|---|---------------------------|---| +| 0 | PP-OCRv3中英文超轻量检测预训练模型直接预测 |47.5%| + +#### 4.3.2 预训练模型直接finetune +##### 修改配置文件 +我们使用configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml,主要修改训练轮数和学习率参相关参数,设置预训练模型路径,设置数据集路径。 另外,batch_size可根据自己机器显存大小进行调整。 具体修改如下几个地方: +``` +epoch:100 +save_epoch_step:10 +eval_batch_step:[0, 50] +save_model_dir: ./output/ch_PP-OCR_v3_det/ +pretrained_model: ./pretrained_models/ch_PP-OCRv3_det_distill_train/best_accuracy +learning_rate: 0.00025 +num_workers: 0 # 如果单卡训练,建议将Train和Eval的loader部分的num_workers设置为0,否则会出现`/dev/shm insufficient`的报错 +``` + +##### 开始训练 +使用我们上面修改的配置文件configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml,训练命令如下: + +```python +# 开始训练模型 +python tools/train.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml -o Global.pretrained_model=./pretrained_models/ch_PP-OCRv3_det_distill_train/best_accuracy +``` + +评估训练好的模型: + +```python +# 评估训练好的模型 +python tools/eval.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml -o Global.pretrained_model="./output/ch_PP-OCR_v3_det/best_accuracy" +``` + +结果如下: +| | 方案 |hmeans| +|---|---------------------------|---| +| 0 | PP-OCRv3中英文超轻量检测预训练模型直接预测 |47.5%| +| 1 | PP-OCRv3中英文超轻量检测预训练模型fintune |65.2%| + +#### 4.3.3 基于预训练模型Finetune_student模型 + +我们使用configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml,主要修改训练轮数和学习率参相关参数,设置预训练模型路径,设置数据集路径。 另外,batch_size可根据自己机器显存大小进行调整。 具体修改如下几个地方: +``` +epoch:100 +save_epoch_step:10 +eval_batch_step:[0, 50] +save_model_dir: ./output/ch_PP-OCR_v3_det_student/ +pretrained_model: ./pretrained_models/ch_PP-OCRv3_det_distill_train/student +learning_rate: 0.00025 +num_workers: 0 # 如果单卡训练,建议将Train和Eval的loader部分的num_workers设置为0,否则会出现`/dev/shm insufficient`的报错 +``` + +训练命令如下: + +```python +python tools/train.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml -o Global.pretrained_model=./pretrained_models/ch_PP-OCRv3_det_distill_train/student +``` + +评估训练好的模型: + +```python +# 评估训练好的模型 +python tools/eval.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml -o Global.pretrained_model="./output/ch_PP-OCR_v3_det_student/best_accuracy" +``` + +结果如下: +| | 方案 |hmeans| +|---|---------------------------|---| +| 0 | PP-OCRv3中英文超轻量检测预训练模型直接预测 |47.5%| +| 1 | PP-OCRv3中英文超轻量检测预训练模型fintune |65.2%| +| 2 | PP-OCRv3中英文超轻量检测预训练模型fintune学生模型 |80.0%| + +#### 4.3.4 基于预训练模型Finetune_teacher模型 + +首先需要从提供的预训练模型best_accuracy.pdparams中提取teacher参数,组合成适合dml训练的初始化模型,提取代码如下: + +```python +cd ./pretrained_models/ +# transform teacher params in best_accuracy.pdparams into teacher_dml.paramers +import paddle + +# load pretrained model +all_params = paddle.load("ch_PP-OCRv3_det_distill_train/best_accuracy.pdparams") +# print(all_params.keys()) + +# keep teacher params +t_params = {key[len("Teacher."):]: all_params[key] for key in all_params if "Teacher." in key} + +# print(t_params.keys()) + +s_params = {"Student." + key: t_params[key] for key in t_params} +s2_params = {"Student2." + key: t_params[key] for key in t_params} +s_params = {**s_params, **s2_params} +# print(s_params.keys()) + +paddle.save(s_params, "ch_PP-OCRv3_det_distill_train/teacher_dml.pdparams") + +``` + +我们使用configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_dml.yml,主要修改训练轮数和学习率参相关参数,设置预训练模型路径,设置数据集路径。 另外,batch_size可根据自己机器显存大小进行调整。 具体修改如下几个地方: +``` +epoch:100 +save_epoch_step:10 +eval_batch_step:[0, 50] +save_model_dir: ./output/ch_PP-OCR_v3_det_teacher/ +pretrained_model: ./pretrained_models/ch_PP-OCRv3_det_distill_train/teacher_dml +learning_rate: 0.00025 +num_workers: 0 # 如果单卡训练,建议将Train和Eval的loader部分的num_workers设置为0,否则会出现`/dev/shm insufficient`的报错 +``` + +训练命令如下: + +```python +python tools/train.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_dml.yml -o Global.pretrained_model=./pretrained_models/ch_PP-OCRv3_det_distill_train/teacher_dml +``` + +评估训练好的模型: + +```python +# 评估训练好的模型 +python tools/eval.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_dml.yml -o Global.pretrained_model="./output/ch_PP-OCR_v3_det_teacher/best_accuracy" +``` + +结果如下: +| | 方案 |hmeans| +|---|---------------------------|---| +| 0 | PP-OCRv3中英文超轻量检测预训练模型直接预测 |47.5%| +| 1 | PP-OCRv3中英文超轻量检测预训练模型fintune |65.2%| +| 2 | PP-OCRv3中英文超轻量检测预训练模型fintune学生模型 |80.0%| +| 3 | PP-OCRv3中英文超轻量检测预训练模型fintune教师模型 |84.8%| + +#### 4.3.5 采用CML蒸馏进一步提升student模型精度 + +需要从4.3.3和4.3.4训练得到的best_accuracy.pdparams中提取各自代表student和teacher的参数,组合成适合cml训练的初始化模型,提取代码如下: + +```python +# transform teacher params and student parameters into cml model +import paddle + +all_params = paddle.load("./pretrained_models/ch_PP-OCRv3_det_distill_train/best_accuracy.pdparams") +# print(all_params.keys()) + +t_params = paddle.load("./output/ch_PP-OCR_v3_det_teacher/best_accuracy.pdparams") +# print(t_params.keys()) + +s_params = paddle.load("./output/ch_PP-OCR_v3_det_student/best_accuracy.pdparams") +# print(s_params.keys()) + +for key in all_params: + # teacher is OK + if "Teacher." in key: + new_key = key.replace("Teacher", "Student") + #print("{} >> {}\n".format(key, new_key)) + assert all_params[key].shape == t_params[new_key].shape + all_params[key] = t_params[new_key] + + if "Student." in key: + new_key = key.replace("Student.", "") + #print("{} >> {}\n".format(key, new_key)) + assert all_params[key].shape == s_params[new_key].shape + all_params[key] = s_params[new_key] + + if "Student2." in key: + new_key = key.replace("Student2.", "") + print("{} >> {}\n".format(key, new_key)) + assert all_params[key].shape == s_params[new_key].shape + all_params[key] = s_params[new_key] + +paddle.save(all_params, "./pretrained_models/ch_PP-OCRv3_det_distill_train/teacher_cml_student.pdparams") +``` + +训练命令如下: + +```python +python tools/train.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml -o Global.pretrained_model=./pretrained_models/ch_PP-OCRv3_det_distill_train/teacher_cml_student Global.save_model_dir=./output/ch_PP-OCR_v3_det_finetune/ +``` + +评估训练好的模型: + +```python +# 评估训练好的模型 +python tools/eval.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml -o Global.pretrained_model="./output/ch_PP-OCR_v3_det_finetune/best_accuracy" +``` + +结果如下: +| | 方案 |hmeans| +|---|---------------------------|---| +| 0 | PP-OCRv3中英文超轻量检测预训练模型直接预测 |47.5%| +| 1 | PP-OCRv3中英文超轻量检测预训练模型fintune |65.2%| +| 2 | PP-OCRv3中英文超轻量检测预训练模型fintune学生模型 |80.0%| +| 3 | PP-OCRv3中英文超轻量检测预训练模型fintune教师模型 |84.8%| +| 4 | 基于2和3训练好的模型fintune |82.7%| + +如需获取已训练模型,请扫码填写问卷,加入PaddleOCR官方交流群获取全部OCR垂类模型下载链接、《动手学OCR》电子书等全套OCR学习资料🎁 +
+ +
+将下载或训练完成的模型放置在对应目录下即可完成模型推理。 + +#### 4.3.6 模型导出推理 +训练完成后,可以将训练模型转换成inference模型。inference 模型会额外保存模型的结构信息,在预测部署、加速推理上性能优越,灵活方便,适合于实际系统集成。 +##### 4.3.6.1 模型导出 +导出命令如下: + +```python +# 转化为推理模型 +python tools/export_model.py \ +-c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml \ +-o Global.pretrained_model=./output/ch_PP-OCR_v3_det_finetune/best_accuracy \ +-o Global.save_inference_dir="./inference/det_ppocrv3" + +``` + +##### 4.3.6.2 模型推理 +导出模型后,可以使用如下命令进行推理预测: + +```python +# 推理预测 +python tools/infer/predict_det.py --image_dir="train_data/icdar2015/text_localization/test/1.jpg" --det_model_dir="./inference/det_ppocrv3/Student" +``` + +## 5. 文字识别 +文本识别的任务是识别出图像中的文字内容,一般输入来自于文本检测得到的文本框截取出的图像文字区域。文本识别一般可以根据待识别文本形状分为规则文本识别和不规则文本识别两大类。规则文本主要指印刷字体、扫描文本等,文本大致处在水平线位置;不规则文本往往不在水平位置,存在弯曲、遮挡、模糊等问题。不规则文本场景具有很大的挑战性,也是目前文本识别领域的主要研究方向。本项目基于PP-OCRv3算法进行优化。 + +### 5.1 PP-OCRv3识别算法介绍 +PP-OCRv3的识别模块是基于文本识别算法[SVTR](https://arxiv.org/abs/2205.00159)优化。SVTR不再采用RNN结构,通过引入Transformers结构更加有效地挖掘文本行图像的上下文信息,从而提升文本识别能力。如下图所示,PP-OCRv3采用了6个优化策略。 +![](https://ai-studio-static-online.cdn.bcebos.com/d4f5344b5b854d50be738671598a89a45689c6704c4d481fb904dd7cf72f2a1a) + +优化策略汇总如下: +* SVTR_LCNet:轻量级文本识别网络 +* GTC:Attention指导CTC训练策略 +* TextConAug:挖掘文字上下文信息的数据增广策略 +* TextRotNet:自监督的预训练模型 +* UDML:联合互学习策略 +* UIM:无标注数据挖掘方案 + +详细优化策略描述请参考[PP-OCRv3优化策略](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/PP-OCRv3_introduction.md#3-%E8%AF%86%E5%88%AB%E4%BC%98%E5%8C%96) + +### 5.2 数据准备 +[计量设备屏幕字符识别数据集](https://aistudio.baidu.com/aistudio/datasetdetail/128714)数据来源于实际项目中各种计量设备的数显屏,以及在网上搜集的一些其他数显屏,包含训练集19912张,测试集4099张。 + +```python +# 解压下载的数据集到指定路径下 +unzip ic15_data.zip -d train_data +``` + +```python +# 随机查看文字检测数据集图片 +from PIL import Image +import matplotlib.pyplot as plt +import numpy as np +import os + +train = './train_data/ic15_data/train' +# 从指定目录中选取一张图片 +def get_one_image(train): + plt.figure() + files = os.listdir(train) + n = len(files) + ind = np.random.randint(0,n) + img_dir = os.path.join(train,files[ind]) + image = Image.open(img_dir) + plt.imshow(image) + plt.show() + image = image.resize([208, 208]) + +get_one_image(train) +``` + +![rec_png](https://ai-studio-static-online.cdn.bcebos.com/3de0d475c69746d0a184029001ef07c85fd68816d66d4beaa10e6ef60030f9b4) + +### 5.3 模型训练 +#### 下载预训练模型 +下载我们需要的PP-OCRv3识别预训练模型,更多选择请自行选择其他的[文字识别模型](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.5/doc/doc_ch/models_list.md#2-%E6%96%87%E6%9C%AC%E8%AF%86%E5%88%AB%E6%A8%A1%E5%9E%8B) + +```python +# 使用该指令下载需要的预训练模型 +wget -P ./pretrained_models/ https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar +# 解压预训练模型文件 +tar -xf ./pretrained_models/ch_PP-OCRv3_rec_train.tar -C pretrained_models +``` + +#### 修改配置文件 +我们使用configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml,主要修改训练轮数和学习率参相关参数,设置预训练模型路径,设置数据集路径。 另外,batch_size可根据自己机器显存大小进行调整。 具体修改如下几个地方: +``` + epoch_num: 100 # 训练epoch数 + save_model_dir: ./output/ch_PP-OCR_v3_rec + save_epoch_step: 10 + eval_batch_step: [0, 100] # 评估间隔,每隔100step评估一次 + cal_metric_during_train: true + pretrained_model: ./pretrained_models/ch_PP-OCRv3_rec_train/best_accuracy # 预训练模型路径 + character_dict_path: ppocr/utils/ppocr_keys_v1.txt + use_space_char: true # 使用空格 + + lr: + name: Cosine # 修改学习率衰减策略为Cosine + learning_rate: 0.0002 # 修改fine-tune的学习率 + warmup_epoch: 2 # 修改warmup轮数 + +Train: + dataset: + name: SimpleDataSet + data_dir: ./train_data/ic15_data/ # 训练集图片路径 + ext_op_transform_idx: 1 + label_file_list: + - ./train_data/ic15_data/rec_gt_train.txt # 训练集标签 + ratio_list: + - 1.0 + loader: + shuffle: true + batch_size_per_card: 64 + drop_last: true + num_workers: 4 +Eval: + dataset: + name: SimpleDataSet + data_dir: ./train_data/ic15_data/ # 测试集图片路径 + label_file_list: + - ./train_data/ic15_data/rec_gt_test.txt # 测试集标签 + ratio_list: + - 1.0 + loader: + shuffle: false + drop_last: false + batch_size_per_card: 64 + num_workers: 4 +``` + +在训练之前,我们可以直接使用下面命令来评估预训练模型的效果: + +```python +# 评估预训练模型 +python tools/eval.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml -o Global.pretrained_model="./pretrained_models/ch_PP-OCRv3_rec_train/best_accuracy" +``` + +结果如下: +| | 方案 |accuracy| +|---|---------------------------|---| +| 0 | PP-OCRv3中英文超轻量识别预训练模型直接预测 |70.4%| + +#### 开始训练 +我们使用上面修改好的配置文件configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml,预训练模型,数据集路径,学习率,训练轮数等都已经设置完毕后,可以使用下面命令开始训练。 + +```python +# 开始训练识别模型 +python tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml +``` + +训练完成后,可以对训练模型中最好的进行测试,评估命令如下: + +```python +# 评估finetune效果 +python tools/eval.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml -o Global.checkpoints="./output/ch_PP-OCR_v3_rec/best_accuracy" +``` + +结果如下: +| | 方案 |accuracy| +|---|---------------------------|---| +| 0 | PP-OCRv3中英文超轻量识别预训练模型直接预测 |70.4%| +| 1 | PP-OCRv3中英文超轻量识别预训练模型finetune |82.2%| + +如需获取已训练模型,请扫码填写问卷,加入PaddleOCR官方交流群获取全部OCR垂类模型下载链接、《动手学OCR》电子书等全套OCR学习资料🎁 +
+ +
+将下载或训练完成的模型放置在对应目录下即可完成模型推理。 + +### 5.4 模型导出推理 +训练完成后,可以将训练模型转换成inference模型。inference 模型会额外保存模型的结构信息,在预测部署、加速推理上性能优越,灵活方便,适合于实际系统集成。 +#### 模型导出 +导出命令如下: + +```python +# 转化为推理模型 +python tools/export_model.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml -o Global.pretrained_model="./output/ch_PP-OCR_v3_rec/best_accuracy" Global.save_inference_dir="./inference/rec_ppocrv3/" +``` + +#### 模型推理 +导出模型后,可以使用如下命令进行推理预测 + +```python +# 推理预测 +python tools/infer/predict_rec.py --image_dir="train_data/ic15_data/test/1_crop_0.jpg" --rec_model_dir="./inference/rec_ppocrv3/Student" +``` + +## 6. 系统串联 +我们将上面训练好的检测和识别模型进行系统串联测试,命令如下: + +```python +#串联测试 +python3 tools/infer/predict_system.py --image_dir="./train_data/icdar2015/text_localization/test/142.jpg" --det_model_dir="./inference/det_ppocrv3/Student" --rec_model_dir="./inference/rec_ppocrv3/Student" +``` + +测试结果保存在`./inference_results/`目录下,可以用下面代码进行可视化 + +```python +%cd /home/aistudio/PaddleOCR +# 显示结果 +import matplotlib.pyplot as plt +from PIL import Image +img_path= "./inference_results/142.jpg" +img = Image.open(img_path) +plt.figure("test_img", figsize=(30,30)) +plt.imshow(img) +plt.show() +``` + +![sys_res_png](https://ai-studio-static-online.cdn.bcebos.com/901ab741cb46441ebec510b37e63b9d8d1b7c95f63cc4e5e8757f35179ae6373) + +### 6.1 后处理 +如果需要获取key-value信息,可以基于启发式的规则,将识别结果与关键字库进行匹配;如果匹配上了,则取该字段为key, 后面一个字段为value。 + +```python +def postprocess(rec_res): + keys = ["型号", "厂家", "版本号", "检定校准分类", "计量器具编号", "烟尘流量", + "累积体积", "烟气温度", "动压", "静压", "时间", "试验台编号", "预测流速", + "全压", "烟温", "流速", "工况流量", "标杆流量", "烟尘直读嘴", "烟尘采样嘴", + "大气压", "计前温度", "计前压力", "干球温度", "湿球温度", "流量", "含湿量"] + key_value = [] + if len(rec_res) > 1: + for i in range(len(rec_res) - 1): + rec_str, _ = rec_res[i] + for key in keys: + if rec_str in key: + key_value.append([rec_str, rec_res[i + 1][0]]) + break + return key_value +key_value = postprocess(filter_rec_res) +``` + +## 7. PaddleServing部署 +首先需要安装PaddleServing部署相关的环境 + +```python +python -m pip install paddle-serving-server-gpu +python -m pip install paddle_serving_client +python -m pip install paddle-serving-app +``` + +### 7.1 转化检测模型 + +```python +cd deploy/pdserving/ +python -m paddle_serving_client.convert --dirname ../../inference/det_ppocrv3/Student/ \ + --model_filename inference.pdmodel \ + --params_filename inference.pdiparams \ + --serving_server ./ppocr_det_v3_serving/ \ + --serving_client ./ppocr_det_v3_client/ +``` + +### 7.2 转化识别模型 + +```python +python -m paddle_serving_client.convert --dirname ../../inference/rec_ppocrv3/Student \ + --model_filename inference.pdmodel \ + --params_filename inference.pdiparams \ + --serving_server ./ppocr_rec_v3_serving/ \ + --serving_client ./ppocr_rec_v3_client/ +``` + + +### 7.3 启动服务 +首先可以将后处理代码加入到web_service.py中,具体修改如下: +``` +# 代码153行后面增加下面代码 +def _postprocess(rec_res): + keys = ["型号", "厂家", "版本号", "检定校准分类", "计量器具编号", "烟尘流量", + "累积体积", "烟气温度", "动压", "静压", "时间", "试验台编号", "预测流速", + "全压", "烟温", "流速", "工况流量", "标杆流量", "烟尘直读嘴", "烟尘采样嘴", + "大气压", "计前温度", "计前压力", "干球温度", "湿球温度", "流量", "含湿量"] + key_value = [] + if len(rec_res) > 1: + for i in range(len(rec_res) - 1): + rec_str, _ = rec_res[i] + for key in keys: + if rec_str in key: + key_value.append([rec_str, rec_res[i + 1][0]]) + break + return key_value +key_value = _postprocess(rec_list) +res = {"result": str(key_value)} +# res = {"result": str(result_list)} +``` + +启动服务端 +```python +python web_service.py 2>&1 >log.txt +``` + +### 7.4 发送请求 +然后再开启一个新的终端,运行下面的客户端代码 + +```python +python pipeline_http_client.py --image_dir ../../train_data/icdar2015/text_localization/test/142.jpg +``` + +可以获取到最终的key-value结果: +``` +大气压, 100.07kPa +干球温度, 0000℃ +计前温度, 0000℃ +湿球温度, 0000℃ +计前压力, -0000kPa +流量, 00.0L/min +静压, 00000kPa +含湿量, 00.0 % +``` diff --git "a/applications/\350\275\273\351\207\217\347\272\247\350\275\246\347\211\214\350\257\206\345\210\253.md" "b/applications/\350\275\273\351\207\217\347\272\247\350\275\246\347\211\214\350\257\206\345\210\253.md" new file mode 100644 index 0000000000000000000000000000000000000000..1a63091b9289ba51bd2dd4de6ee51264cdb2bc79 --- /dev/null +++ "b/applications/\350\275\273\351\207\217\347\272\247\350\275\246\347\211\214\350\257\206\345\210\253.md" @@ -0,0 +1,832 @@ +# 一种基于PaddleOCR的轻量级车牌识别模型 + +- [1. 项目介绍](#1-项目介绍) +- [2. 环境搭建](#2-环境搭建) +- [3. 数据集准备](#3-数据集准备) + - [3.1 数据集标注规则](#31-数据集标注规则) + - [3.2 制作符合PP-OCR训练格式的标注文件](#32-制作符合pp-ocr训练格式的标注文件) +- [4. 实验](#4-实验) + - [4.1 检测](#41-检测) + - [4.1.1 预训练模型直接预测](#411-预训练模型直接预测) + - [4.1.2 CCPD车牌数据集fine-tune](#412-ccpd车牌数据集fine-tune) + - [4.1.3 CCPD车牌数据集fine-tune+量化训练](#413-ccpd车牌数据集fine-tune量化训练) + - [4.1.4 模型导出](#414-模型导出) + - [4.2 识别](#42-识别) + - [4.2.1 预训练模型直接预测](#421-预训练模型直接预测) + - [4.2.2 预训练模型直接预测+改动后处理](#422-预训练模型直接预测改动后处理) + - [4.2.3 CCPD车牌数据集fine-tune](#423-ccpd车牌数据集fine-tune) + - [4.2.4 CCPD车牌数据集fine-tune+量化训练](#424-ccpd车牌数据集fine-tune量化训练) + - [4.2.5 模型导出](#425-模型导出) + - [4.3 计算End2End指标](#43-计算End2End指标) + - [4.4 部署](#44-部署) + - [4.5 实验总结](#45-实验总结) + +## 1. 项目介绍 + +车牌识别(Vehicle License Plate Recognition,VLPR) 是计算机视频图像识别技术在车辆牌照识别中的一种应用。车牌识别技术要求能够将运动中的汽车牌照从复杂背景中提取并识别出来,在高速公路车辆管理,停车场管理和城市交通中得到广泛应用。 + +本项目难点如下: + +1. 车牌在图像中的尺度差异大、在车辆上的悬挂位置不固定 +2. 车牌图像质量层次不齐: 角度倾斜、图片模糊、光照不足、过曝等问题严重 +3. 边缘和端测场景应用对模型大小有限制,推理速度有要求 + +针对以上问题, 本例选用 PP-OCRv3 这一开源超轻量OCR系统进行车牌识别系统的开发。基于PP-OCRv3模型,在CCPD数据集达到99%的检测和94%的识别精度,模型大小12.8M(2.5M+10.3M)。基于量化对模型体积进行进一步压缩到5.8M(1M+4.8M), 同时推理速度提升25%。 + + + +aistudio项目链接: [基于PaddleOCR的轻量级车牌识别范例](https://aistudio.baidu.com/aistudio/projectdetail/3919091?contributionType=1) + +## 2. 环境搭建 + +本任务基于Aistudio完成, 具体环境如下: + +- 操作系统: Linux +- PaddlePaddle: 2.3 +- paddleslim: 2.2.2 +- PaddleOCR: Release/2.5 + +下载 PaddleOCR代码 + +```bash +git clone -b dygraph https://github.com/PaddlePaddle/PaddleOCR +``` + +安装依赖库 + +```bash +pip install -r PaddleOCR/requirements.txt +``` + +## 3. 数据集准备 + +所使用的数据集为 CCPD2020 新能源车牌数据集,该数据集为 + +该数据集分布如下: + +|数据集类型|数量| +|---|---| +|训练集| 5769| +|验证集| 1001| +|测试集| 5006| + +数据集图片示例如下: +![](https://ai-studio-static-online.cdn.bcebos.com/3bce057a8e0c40a0acbd26b2e29e4e2590a31bc412764be7b9e49799c69cb91c) + +数据集可以从这里下载 https://aistudio.baidu.com/aistudio/datasetdetail/101595 + +下载好数据集后对数据集进行解压 + +```bash +unzip -d /home/aistudio/data /home/aistudio/data/data101595/CCPD2020.zip +``` + +### 3.1 数据集标注规则 + +CPPD数据集的图片文件名具有特殊规则,详细可查看:https://github.com/detectRecog/CCPD + +具体规则如下: + +例如: 025-95_113-154&383_386&473-386&473_177&454_154&383_363&402-0_0_22_27_27_33_16-37-15.jpg + +每个名称可以分为七个字段,以-符号作为分割。这些字段解释如下。 + +- 025:车牌面积与整个图片区域的面积比。025 (25%) + +- 95_113:水平倾斜程度和垂直倾斜度。水平 95度 垂直 113度 + +- 154&383_386&473:左上和右下顶点的坐标。左上(154,383) 右下(386,473) + +- 386&473_177&454_154&383_363&402:整个图像中车牌的四个顶点的精确(x,y)坐标。这些坐标从右下角顶点开始。(386,473) (177,454) (154,383) (363,402) + +- 0_0_22_27_27_33_16:CCPD中的每个图像只有一个车牌。每个车牌号码由一个汉字,一个字母和五个字母或数字组成。有效的中文车牌由七个字符组成:省(1个字符),字母(1个字符),字母+数字(5个字符)。“ 0_0_22_27_27_33_16”是每个字符的索引。这三个数组定义如下。每个数组的最后一个字符是字母O,而不是数字0。我们将O用作“无字符”的符号,因为中文车牌字符中没有O。因此以上车牌拼起来即为 皖AY339S + +- 37:牌照区域的亮度。 37 (37%) + +- 15:车牌区域的模糊度。15 (15%) + +```python +provinces = ["皖", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑", "苏", "浙", "京", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤", "桂", "琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁", "新", "警", "学", "O"] +alphabets = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W','X', 'Y', 'Z', 'O'] +ads = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X','Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'O'] +``` + +### 3.2 制作符合PP-OCR训练格式的标注文件 + +在开始训练之前,可使用如下代码制作符合PP-OCR训练格式的标注文件。 + + +```python +import cv2 +import os +import json +from tqdm import tqdm +import numpy as np + +provinces = ["皖", "沪", "津", "渝", "冀", "晋", "蒙", "辽", "吉", "黑", "苏", "浙", "京", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤", "桂", "琼", "川", "贵", "云", "藏", "陕", "甘", "青", "宁", "新", "警", "学", "O"] +alphabets = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'O'] +ads = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'O'] + +def make_label(img_dir, save_gt_folder, phase): + crop_img_save_dir = os.path.join(save_gt_folder, phase, 'crop_imgs') + os.makedirs(crop_img_save_dir, exist_ok=True) + + f_det = open(os.path.join(save_gt_folder, phase, 'det.txt'), 'w', encoding='utf-8') + f_rec = open(os.path.join(save_gt_folder, phase, 'rec.txt'), 'w', encoding='utf-8') + + i = 0 + for filename in tqdm(os.listdir(os.path.join(img_dir, phase))): + str_list = filename.split('-') + if len(str_list) < 5: + continue + coord_list = str_list[3].split('_') + txt_list = str_list[4].split('_') + boxes = [] + for coord in coord_list: + boxes.append([int(x) for x in coord.split("&")]) + boxes = [boxes[2], boxes[3], boxes[0], boxes[1]] + lp_number = provinces[int(txt_list[0])] + alphabets[int(txt_list[1])] + ''.join([ads[int(x)] for x in txt_list[2:]]) + + # det + det_info = [{'points':boxes, 'transcription':lp_number}] + f_det.write('{}\t{}\n'.format(os.path.join(phase, filename), json.dumps(det_info, ensure_ascii=False))) + + # rec + boxes = np.float32(boxes) + img = cv2.imread(os.path.join(img_dir, phase, filename)) + # crop_img = img[int(boxes[:,1].min()):int(boxes[:,1].max()),int(boxes[:,0].min()):int(boxes[:,0].max())] + crop_img = get_rotate_crop_image(img, boxes) + crop_img_save_filename = '{}_{}.jpg'.format(i,'_'.join(txt_list)) + crop_img_save_path = os.path.join(crop_img_save_dir, crop_img_save_filename) + cv2.imwrite(crop_img_save_path, crop_img) + f_rec.write('{}/crop_imgs/{}\t{}\n'.format(phase, crop_img_save_filename, lp_number)) + i+=1 + f_det.close() + f_rec.close() + +def get_rotate_crop_image(img, points): + ''' + img_height, img_width = img.shape[0:2] + left = int(np.min(points[:, 0])) + right = int(np.max(points[:, 0])) + top = int(np.min(points[:, 1])) + bottom = int(np.max(points[:, 1])) + img_crop = img[top:bottom, left:right, :].copy() + points[:, 0] = points[:, 0] - left + points[:, 1] = points[:, 1] - top + ''' + assert len(points) == 4, "shape of points must be 4*2" + img_crop_width = int( + max( + np.linalg.norm(points[0] - points[1]), + np.linalg.norm(points[2] - points[3]))) + img_crop_height = int( + max( + np.linalg.norm(points[0] - points[3]), + np.linalg.norm(points[1] - points[2]))) + pts_std = np.float32([[0, 0], [img_crop_width, 0], + [img_crop_width, img_crop_height], + [0, img_crop_height]]) + M = cv2.getPerspectiveTransform(points, pts_std) + dst_img = cv2.warpPerspective( + img, + M, (img_crop_width, img_crop_height), + borderMode=cv2.BORDER_REPLICATE, + flags=cv2.INTER_CUBIC) + dst_img_height, dst_img_width = dst_img.shape[0:2] + if dst_img_height * 1.0 / dst_img_width >= 1.5: + dst_img = np.rot90(dst_img) + return dst_img + +img_dir = '/home/aistudio/data/CCPD2020/ccpd_green' +save_gt_folder = '/home/aistudio/data/CCPD2020/PPOCR' +# phase = 'train' # change to val and test to make val dataset and test dataset +for phase in ['train','val','test']: + make_label(img_dir, save_gt_folder, phase) +``` + +通过上述命令可以完成了`训练集`,`验证集`和`测试集`的制作,制作完成的数据集信息如下: + +| 类型 | 数据集 | 图片地址 | 标签地址 | 图片数量 | +| --- | --- | --- | --- | --- | +| 检测 | 训练集 | /home/aistudio/data/CCPD2020/ccpd_green/train | /home/aistudio/data/CCPD2020/PPOCR/train/det.txt | 5769 | +| 检测 | 验证集 | /home/aistudio/data/CCPD2020/ccpd_green/val | /home/aistudio/data/CCPD2020/PPOCR/val/det.txt | 1001 | +| 检测 | 测试集 | /home/aistudio/data/CCPD2020/ccpd_green/test | /home/aistudio/data/CCPD2020/PPOCR/test/det.txt | 5006 | +| 识别 | 训练集 | /home/aistudio/data/CCPD2020/PPOCR/train/crop_imgs | /home/aistudio/data/CCPD2020/PPOCR/train/rec.txt | 5769 | +| 识别 | 验证集 | /home/aistudio/data/CCPD2020/PPOCR/val/crop_imgs | /home/aistudio/data/CCPD2020/PPOCR/val/rec.txt | 1001 | +| 识别 | 测试集 | /home/aistudio/data/CCPD2020/PPOCR/test/crop_imgs | /home/aistudio/data/CCPD2020/PPOCR/test/rec.txt | 5006 | + +在普遍的深度学习流程中,都是在训练集训练,在验证集选择最优模型后在测试集上进行测试。在本例中,我们省略中间步骤,直接在训练集训练,在测试集选择最优模型,因此我们只使用训练集和测试集。 + +## 4. 实验 + +由于数据集比较少,为了模型更好和更快的收敛,这里选用 PaddleOCR 中的 PP-OCRv3 模型进行文本检测和识别,并且使用 PP-OCRv3 模型参数作为预训练模型。PP-OCRv3在PP-OCRv2的基础上,中文场景端到端Hmean指标相比于PP-OCRv2提升5%, 英文数字模型端到端效果提升11%。详细优化细节请参考[PP-OCRv3](../doc/doc_ch/PP-OCRv3_introduction.md)技术报告。 + +由于车牌场景均为端侧设备部署,因此对速度和模型大小有比较高的要求,因此还需要采用量化训练的方式进行模型大小的压缩和模型推理速度的加速。模型量化可以在基本不损失模型的精度的情况下,将FP32精度的模型参数转换为Int8精度,减小模型参数大小并加速计算,使用量化后的模型在移动端等部署时更具备速度优势。 + +因此,本实验中对于车牌检测和识别有如下3种方案: + +1. PP-OCRv3中英文超轻量预训练模型直接预测 +2. CCPD车牌数据集在PP-OCRv3模型上fine-tune +3. CCPD车牌数据集在PP-OCRv3模型上fine-tune后量化 + +### 4.1 检测 +#### 4.1.1 预训练模型直接预测 + +从下表中下载PP-OCRv3文本检测预训练模型 + +|模型名称|模型简介|配置文件|推理模型大小|下载地址| +| --- | --- | --- | --- | --- | +|ch_PP-OCRv3_det| 【最新】原始超轻量模型,支持中英文、多语种文本检测 |[ch_PP-OCRv3_det_cml.yml](https://github.com/PaddlePaddle/PaddleOCR/blob/dygraph/configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_cml.yml)| 3.8M |[推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_distill_train.tar)| + +使用如下命令下载预训练模型 + +```bash +mkdir models +cd models +wget https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_det_distill_train.tar +tar -xf ch_PP-OCRv3_det_distill_train.tar +cd /home/aistudio/PaddleOCR +``` + +预训练模型下载完成后,我们使用[ch_PP-OCRv3_det_student.yml](../configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml) 配置文件进行后续实验,在开始评估之前需要对配置文件中部分字段进行设置,具体如下: + +1. 模型存储和训练相关: + 1. Global.pretrained_model: 指向PP-OCRv3文本检测预训练模型地址 +2. 数据集相关 + 1. Eval.dataset.data_dir:指向测试集图片存放目录 + 2. Eval.dataset.label_file_list:指向测试集标注文件 + +上述字段均为必须修改的字段,可以通过修改配置文件的方式改动,也可在不需要修改配置文件的情况下,改变训练的参数。这里使用不改变配置文件的方式 。使用如下命令进行PP-OCRv3文本检测预训练模型的评估 + + +```bash +python tools/eval.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml -o \ + Global.pretrained_model=models/ch_PP-OCRv3_det_distill_train/student.pdparams \ + Eval.dataset.data_dir=/home/aistudio/data/CCPD2020/ccpd_green \ + Eval.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/test/det.txt] +``` +上述指令中,通过-c 选择训练使用配置文件,通过-o参数在不需要修改配置文件的情况下,改变训练的参数。 + +使用预训练模型进行评估,指标如下所示: + +| 方案 |hmeans| +|---------------------------|---| +| PP-OCRv3中英文超轻量检测预训练模型直接预测 |76.12%| + +#### 4.1.2 CCPD车牌数据集fine-tune + +**训练** + +为了进行fine-tune训练,我们需要在配置文件中设置需要使用的预训练模型地址,学习率和数据集等参数。 具体如下: + +1. 模型存储和训练相关: + 1. Global.pretrained_model: 指向PP-OCRv3文本检测预训练模型地址 + 2. Global.eval_batch_step: 模型多少step评估一次,这里设为从第0个step开始没隔772个step评估一次,772为一个epoch总的step数。 +2. 优化器相关: + 1. Optimizer.lr.name: 学习率衰减器设为常量 Const + 2. Optimizer.lr.learning_rate: 做 fine-tune 实验,学习率需要设置的比较小,此处学习率设为配置文件中的0.05倍 + 3. Optimizer.lr.warmup_epoch: warmup_epoch设为0 +3. 数据集相关: + 1. Train.dataset.data_dir:指向训练集图片存放目录 + 2. Train.dataset.label_file_list:指向训练集标注文件 + 3. Eval.dataset.data_dir:指向测试集图片存放目录 + 4. Eval.dataset.label_file_list:指向测试集标注文件 + +使用如下代码即可启动在CCPD车牌数据集上的fine-tune。 + +```bash +python tools/train.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml -o \ + Global.pretrained_model=models/ch_PP-OCRv3_det_distill_train/student.pdparams \ + Global.save_model_dir=output/CCPD/det \ + Global.eval_batch_step="[0, 772]" \ + Optimizer.lr.name=Const \ + Optimizer.lr.learning_rate=0.0005 \ + Optimizer.lr.warmup_epoch=0 \ + Train.dataset.data_dir=/home/aistudio/data/CCPD2020/ccpd_green \ + Train.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/train/det.txt] \ + Eval.dataset.data_dir=/home/aistudio/data/CCPD2020/ccpd_green \ + Eval.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/test/det.txt] +``` + +在上述命令中,通过`-o`的方式修改了配置文件中的参数。 + + +**评估** + +训练完成后使用如下命令进行评估 + + +```bash +python tools/eval.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml -o \ + Global.pretrained_model=output/CCPD/det/best_accuracy.pdparams \ + Eval.dataset.data_dir=/home/aistudio/data/CCPD2020/ccpd_green \ + Eval.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/test/det.txt] +``` + +使用预训练模型和CCPD车牌数据集fine-tune,指标分别如下: + +|方案|hmeans| +|---|---| +|PP-OCRv3中英文超轻量检测预训练模型直接预测|76.12%| +|PP-OCRv3中英文超轻量检测预训练模型 fine-tune|99%| + +可以看到进行fine-tune能显著提升车牌检测的效果。 + +#### 4.1.3 CCPD车牌数据集fine-tune+量化训练 + +此处采用 PaddleOCR 中提供好的[量化教程](../deploy/slim/quantization/README.md)对模型进行量化训练。 + +量化训练可通过如下命令启动: + +```bash +python3.7 deploy/slim/quantization/quant.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml -o \ + Global.pretrained_model=output/CCPD/det/best_accuracy.pdparams \ + Global.save_model_dir=output/CCPD/det_quant \ + Global.eval_batch_step="[0, 772]" \ + Optimizer.lr.name=Const \ + Optimizer.lr.learning_rate=0.0005 \ + Optimizer.lr.warmup_epoch=0 \ + Train.dataset.data_dir=/home/aistudio/data/CCPD2020/ccpd_green \ + Train.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/train/det.txt] \ + Eval.dataset.data_dir=/home/aistudio/data/CCPD2020/ccpd_green \ + Eval.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/test/det.txt] +``` + +量化后指标对比如下 + +|方案|hmeans| 模型大小 | 预测速度(lite) | +|---|---|------|------------| +|PP-OCRv3中英文超轻量检测预训练模型 fine-tune|99%| 2.5M | 223ms | +|PP-OCRv3中英文超轻量检测预训练模型 fine-tune+量化|98.91%| 1M | 189ms | + +可以看到通过量化训练在精度几乎无损的情况下,降低模型体积60%并且推理速度提升15%。 + +速度测试基于[PaddleOCR lite教程](../deploy/lite/readme_ch.md)完成。 + +#### 4.1.4 模型导出 + +使用如下命令可以将训练好的模型进行导出 + +* 非量化模型 +```bash +python tools/export_model.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml -o \ + Global.pretrained_model=output/CCPD/det/best_accuracy.pdparams \ + Global.save_inference_dir=output/det/infer +``` +* 量化模型 +```bash +python deploy/slim/quantization/export_model.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml -o \ + Global.pretrained_model=output/CCPD/det_quant/best_accuracy.pdparams \ + Global.save_inference_dir=output/det/infer +``` + +### 4.2 识别 +#### 4.2.1 预训练模型直接预测 + +从下表中下载PP-OCRv3文本识别预训练模型 + +|模型名称|模型简介|配置文件|推理模型大小|下载地址| +| --- | --- | --- | --- | --- | +|ch_PP-OCRv3_rec|【最新】原始超轻量模型,支持中英文、数字识别|[ch_PP-OCRv3_rec_distillation.yml](https://github.com/PaddlePaddle/PaddleOCR/blob/dygraph/configs/rec/PP-OCRv3/ch_PP-OCRv3_rec_distillation.yml)| 12.4M |[推理模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_infer.tar) / [训练模型](https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar) | + +使用如下命令下载预训练模型 + +```bash +mkdir models +cd models +wget https://paddleocr.bj.bcebos.com/PP-OCRv3/chinese/ch_PP-OCRv3_rec_train.tar +tar -xf ch_PP-OCRv3_rec_train.tar +cd /home/aistudio/PaddleOCR +``` + +PaddleOCR提供的PP-OCRv3识别模型采用蒸馏训练策略,因此提供的预训练模型中会包含`Teacher`和`Student`模型的参数,详细信息可参考[knowledge_distillation.md](../doc/doc_ch/knowledge_distillation.md)。 因此,模型下载完成后需要使用如下代码提取`Student`模型的参数: + +```python +import paddle +# 加载预训练模型 +all_params = paddle.load("models/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, "models/ch_PP-OCRv3_rec_train/student.pdparams") +``` + +预训练模型下载完成后,我们使用[ch_PP-OCRv3_rec.yml](../configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml) 配置文件进行后续实验,在开始评估之前需要对配置文件中部分字段进行设置,具体如下: + +1. 模型存储和训练相关: + 1. Global.pretrained_model: 指向PP-OCRv3文本识别预训练模型地址 +2. 数据集相关 + 1. Eval.dataset.data_dir:指向测试集图片存放目录 + 2. Eval.dataset.label_file_list:指向测试集标注文件 + +使用如下命令进行PP-OCRv3文本识别预训练模型的评估 + +```bash +python tools/eval.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml -o \ + Global.pretrained_model=models/ch_PP-OCRv3_rec_train/student.pdparams \ + Eval.dataset.data_dir=/home/aistudio/data/CCPD2020/PPOCR \ + Eval.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/test/rec.txt] +``` + +如需获取已训练模型,请扫码填写问卷,加入PaddleOCR官方交流群获取全部OCR垂类模型下载链接、《动手学OCR》电子书等全套OCR学习资料🎁 +
+ +
+ + +评估部分日志如下: +```bash +[2022/05/12 19:52:02] ppocr INFO: load pretrain successful from models/ch_PP-OCRv3_rec_train/best_accuracy +eval model:: 100%|██████████████████████████████| 40/40 [00:15<00:00, 2.57it/s] +[2022/05/12 19:52:17] ppocr INFO: metric eval *************** +[2022/05/12 19:52:17] ppocr INFO: acc:0.0 +[2022/05/12 19:52:17] ppocr INFO: norm_edit_dis:0.8656084923002452 +[2022/05/12 19:52:17] ppocr INFO: Teacher_acc:0.000399520574511545 +[2022/05/12 19:52:17] ppocr INFO: Teacher_norm_edit_dis:0.8657902943394548 +[2022/05/12 19:52:17] ppocr INFO: fps:1443.1801978719905 + +``` +使用预训练模型进行评估,指标如下所示: + +|方案|acc| +|---|---| +|PP-OCRv3中英文超轻量识别预训练模型直接预测|0%| + +从评估日志中可以看到,直接使用PP-OCRv3预训练模型进行评估,acc非常低,但是norm_edit_dis很高。因此,我们猜测是模型大部分文字识别是对的,只有少部分文字识别错误。使用如下命令进行infer查看模型的推理结果进行验证: + + +```bash +python tools/infer_rec.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml -o \ + Global.pretrained_model=models/ch_PP-OCRv3_rec_train/student.pdparams \ + Global.infer_img=/home/aistudio/data/CCPD2020/PPOCR/test/crop_imgs/0_0_0_3_32_30_31_30_30.jpg +``` + +输出部分日志如下: +```bash +[2022/05/01 08:51:57] ppocr INFO: train with paddle 2.2.2 and device CUDAPlace(0) +W0501 08:51:57.127391 11326 device_context.cc:447] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.0, Runtime API Version: 10.1 +W0501 08:51:57.132315 11326 device_context.cc:465] device: 0, cuDNN Version: 7.6. +[2022/05/01 08:52:00] ppocr INFO: load pretrain successful from models/ch_PP-OCRv3_rec_train/student +[2022/05/01 08:52:00] ppocr INFO: infer_img: /home/aistudio/data/CCPD2020/PPOCR/test/crop_imgs/0_0_3_32_30_31_30_30.jpg +[2022/05/01 08:52:00] ppocr INFO: result: {"Student": {"label": "皖A·D86766", "score": 0.9552637934684753}, "Teacher": {"label": "皖A·D86766", "score": 0.9917094707489014}} +[2022/05/01 08:52:00] ppocr INFO: success! +``` + +从infer结果可以看到,车牌中的文字大部分都识别正确,只是多识别出了一个`·`。针对这种情况,有如下两种方案: +1. 直接通过后处理去掉多识别的`·`。 +2. 进行 fine-tune。 + +#### 4.2.2 预训练模型直接预测+改动后处理 + +直接通过后处理去掉多识别的`·`,在后处理的改动比较简单,只需在 [ppocr/postprocess/rec_postprocess.py](../ppocr/postprocess/rec_postprocess.py) 文件的76行添加如下代码: +```python +text = text.replace('·','') +``` + +改动前后指标对比: + +|方案|acc| +|---|---| +|PP-OCRv3中英文超轻量识别预训练模型直接预测|0.2%| +|PP-OCRv3中英文超轻量识别预训练模型直接预测+后处理去掉多识别的`·`|90.97%| + +可以看到,去掉多余的`·`能大幅提高精度。 + +#### 4.2.3 CCPD车牌数据集fine-tune + +**训练** + +为了进行fine-tune训练,我们需要在配置文件中设置需要使用的预训练模型地址,学习率和数据集等参数。 具体如下: + +1. 模型存储和训练相关: + 1. Global.pretrained_model: 指向PP-OCRv3文本识别预训练模型地址 + 2. Global.eval_batch_step: 模型多少step评估一次,这里设为从第0个step开始没隔45个step评估一次,45为一个epoch总的step数。 +2. 优化器相关 + 1. Optimizer.lr.name: 学习率衰减器设为常量 Const + 2. Optimizer.lr.learning_rate: 做 fine-tune 实验,学习率需要设置的比较小,此处学习率设为配置文件中的0.05倍 + 3. Optimizer.lr.warmup_epoch: warmup_epoch设为0 +3. 数据集相关 + 1. Train.dataset.data_dir:指向训练集图片存放目录 + 2. Train.dataset.label_file_list:指向训练集标注文件 + 3. Eval.dataset.data_dir:指向测试集图片存放目录 + 4. Eval.dataset.label_file_list:指向测试集标注文件 + +使用如下命令启动 fine-tune + +```bash +python tools/train.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml -o \ + Global.pretrained_model=models/ch_PP-OCRv3_rec_train/student.pdparams \ + Global.save_model_dir=output/CCPD/rec/ \ + Global.eval_batch_step="[0, 90]" \ + Optimizer.lr.name=Const \ + Optimizer.lr.learning_rate=0.0005 \ + Optimizer.lr.warmup_epoch=0 \ + Train.dataset.data_dir=/home/aistudio/data/CCPD2020/PPOCR \ + Train.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/train/rec.txt] \ + Eval.dataset.data_dir=/home/aistudio/data/CCPD2020/PPOCR \ + Eval.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/test/rec.txt] +``` + +**评估** + +训练完成后使用如下命令进行评估 + +```bash +python tools/eval.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml -o \ + Global.pretrained_model=output/CCPD/rec/best_accuracy.pdparams \ + Eval.dataset.data_dir=/home/aistudio/data/CCPD2020/PPOCR \ + Eval.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/test/rec.txt] +``` + +使用预训练模型和CCPD车牌数据集fine-tune,指标分别如下: + +|方案| acc | +|---|--------| +|PP-OCRv3中英文超轻量识别预训练模型直接预测| 0% | +|PP-OCRv3中英文超轻量识别预训练模型直接预测+后处理去掉多识别的`·`| 90.97% | +|PP-OCRv3中英文超轻量识别预训练模型 fine-tune| 94.54% | + +可以看到进行fine-tune能显著提升车牌识别的效果。 + +#### 4.2.4 CCPD车牌数据集fine-tune+量化训练 + +此处采用 PaddleOCR 中提供好的[量化教程](../deploy/slim/quantization/README.md)对模型进行量化训练。 + +量化训练可通过如下命令启动: + +```bash +python3.7 deploy/slim/quantization/quant.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml -o \ + Global.pretrained_model=output/CCPD/rec/best_accuracy.pdparams \ + Global.save_model_dir=output/CCPD/rec_quant/ \ + Global.eval_batch_step="[0, 90]" \ + Optimizer.lr.name=Const \ + Optimizer.lr.learning_rate=0.0005 \ + Optimizer.lr.warmup_epoch=0 \ + Train.dataset.data_dir=/home/aistudio/data/CCPD2020/PPOCR \ + Train.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/train/rec.txt] \ + Eval.dataset.data_dir=/home/aistudio/data/CCPD2020/PPOCR \ + Eval.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/test/rec.txt] +``` + +量化后指标对比如下 + +|方案| acc | 模型大小 | 预测速度(lite) | +|---|--------|-------|------------| +|PP-OCRv3中英文超轻量识别预训练模型 fine-tune| 94.54% | 10.3M | 4.2ms | +|PP-OCRv3中英文超轻量识别预训练模型 fine-tune + 量化| 93.4% | 4.8M | 1.8ms | + +可以看到量化后能降低模型体积53%并且推理速度提升57%,但是由于识别数据过少,量化带来了1%的精度下降。 + +速度测试基于[PaddleOCR lite教程](../deploy/lite/readme_ch.md)完成。 + +#### 4.2.5 模型导出 + +使用如下命令可以将训练好的模型进行导出。 + +* 非量化模型 +```bash +python tools/export_model.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml -o \ + Global.pretrained_model=output/CCPD/rec/best_accuracy.pdparams \ + Global.save_inference_dir=output/CCPD/rec/infer +``` +* 量化模型 +```bash +python deploy/slim/quantization/export_model.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml -o \ + Global.pretrained_model=output/CCPD/rec_quant/best_accuracy.pdparams \ + Global.save_inference_dir=output/CCPD/rec_quant/infer +``` + +### 4.3 计算End2End指标 + +端到端指标可通过 [PaddleOCR内置脚本](../tools/end2end/readme.md) 进行计算,具体步骤如下: + +1. 导出模型 + +通过如下命令进行模型的导出。注意,量化模型导出时,需要配置eval数据集 + +```bash +# 检测模型 + +# 预训练模型 +python tools/export_model.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml -o \ + Global.pretrained_model=models/ch_PP-OCRv3_det_distill_train/student.pdparams \ + Global.save_inference_dir=output/ch_PP-OCRv3_det_distill_train/infer + +# 非量化模型 +python tools/export_model.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml -o \ + Global.pretrained_model=output/CCPD/det/best_accuracy.pdparams \ + Global.save_inference_dir=output/CCPD/det/infer + +# 量化模型 +python deploy/slim/quantization/export_model.py -c configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_student.yml -o \ + Global.pretrained_model=output/CCPD/det_quant/best_accuracy.pdparams \ + Global.save_inference_dir=output/CCPD/det_quant/infer \ + Eval.dataset.data_dir=/home/aistudio/data/CCPD2020/ccpd_green \ + Eval.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/test/det.txt] \ + Eval.loader.num_workers=0 + +# 识别模型 + +# 预训练模型 +python tools/export_model.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml -o \ + Global.pretrained_model=models/ch_PP-OCRv3_rec_train/student.pdparams \ + Global.save_inference_dir=output/ch_PP-OCRv3_rec_train/infer + +# 非量化模型 +python tools/export_model.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml -o \ + Global.pretrained_model=output/CCPD/rec/best_accuracy.pdparams \ + Global.save_inference_dir=output/CCPD/rec/infer + +# 量化模型 +python deploy/slim/quantization/export_model.py -c configs/rec/PP-OCRv3/ch_PP-OCRv3_rec.yml -o \ + Global.pretrained_model=output/CCPD/rec_quant/best_accuracy.pdparams \ + Global.save_inference_dir=output/CCPD/rec_quant/infer \ + Eval.dataset.data_dir=/home/aistudio/data/CCPD2020/PPOCR \ + Eval.dataset.label_file_list=[/home/aistudio/data/CCPD2020/PPOCR/test/rec.txt] +``` + +2. 用导出的模型对测试集进行预测 + +此处,分别使用PP-OCRv3预训练模型,fintune模型和量化模型对测试集的所有图像进行预测,命令如下: + +```bash +# PP-OCRv3中英文超轻量检测预训练模型,PP-OCRv3中英文超轻量识别预训练模型 +python3 tools/infer/predict_system.py --det_model_dir=models/ch_PP-OCRv3_det_distill_train/infer --rec_model_dir=models/ch_PP-OCRv3_rec_train/infer --det_limit_side_len=736 --det_limit_type=min --image_dir=/home/aistudio/data/CCPD2020/ccpd_green/test/ --draw_img_save_dir=infer/pretrain --use_dilation=true + +# PP-OCRv3中英文超轻量检测预训练模型+fine-tune,PP-OCRv3中英文超轻量识别预训练模型+fine-tune +python3 tools/infer/predict_system.py --det_model_dir=output/CCPD/det/infer --rec_model_dir=output/CCPD/rec/infer --det_limit_side_len=736 --det_limit_type=min --image_dir=/home/aistudio/data/CCPD2020/ccpd_green/test/ --draw_img_save_dir=infer/fine-tune --use_dilation=true + +# PP-OCRv3中英文超轻量检测预训练模型 fine-tune +量化,PP-OCRv3中英文超轻量识别预训练模型 fine-tune +量化 结果转换和评估 +python3 tools/infer/predict_system.py --det_model_dir=output/CCPD/det_quant/infer --rec_model_dir=output/CCPD/rec_quant/infer --det_limit_side_len=736 --det_limit_type=min --image_dir=/home/aistudio/data/CCPD2020/ccpd_green/test/ --draw_img_save_dir=infer/quant --use_dilation=true +``` + +3. 转换label并计算指标 + +将gt和上一步保存的预测结果转换为端对端评测需要的数据格式,并根据转换后的数据进行端到端指标计算 + +```bash +python3 tools/end2end/convert_ppocr_label.py --mode=gt --label_path=/home/aistudio/data/CCPD2020/PPOCR/test/det.txt --save_folder=end2end/gt + +# PP-OCRv3中英文超轻量检测预训练模型,PP-OCRv3中英文超轻量识别预训练模型 结果转换和评估 +python3 tools/end2end/convert_ppocr_label.py --mode=pred --label_path=infer/pretrain/system_results.txt --save_folder=end2end/pretrain +python3 tools/end2end/eval_end2end.py end2end/gt end2end/pretrain + +# PP-OCRv3中英文超轻量检测预训练模型,PP-OCRv3中英文超轻量识别预训练模型+后处理去掉多识别的`·` 结果转换和评估 +# 需手动修改后处理函数 +python3 tools/end2end/convert_ppocr_label.py --mode=pred --label_path=infer/post/system_results.txt --save_folder=end2end/post +python3 tools/end2end/eval_end2end.py end2end/gt end2end/post + +# PP-OCRv3中英文超轻量检测预训练模型 fine-tune,PP-OCRv3中英文超轻量识别预训练模型 fine-tune 结果转换和评估 +python3 tools/end2end/convert_ppocr_label.py --mode=pred --label_path=infer/fine-tune/system_results.txt --save_folder=end2end/fine-tune +python3 tools/end2end/eval_end2end.py end2end/gt end2end/fine-tune + +# PP-OCRv3中英文超轻量检测预训练模型 fine-tune +量化,PP-OCRv3中英文超轻量识别预训练模型 fine-tune +量化 结果转换和评估 +python3 tools/end2end/convert_ppocr_label.py --mode=pred --label_path=infer/quant/system_results.txt --save_folder=end2end/quant +python3 tools/end2end/eval_end2end.py end2end/gt end2end/quant +``` + +日志如下: +```bash +The convert label saved in end2end/gt +The convert label saved in end2end/pretrain +start testing... +hit, dt_count, gt_count 2 5988 5006 +character_acc: 70.42% +avg_edit_dist_field: 2.37 +avg_edit_dist_img: 2.37 +precision: 0.03% +recall: 0.04% +fmeasure: 0.04% +The convert label saved in end2end/post +start testing... +hit, dt_count, gt_count 4224 5988 5006 +character_acc: 81.59% +avg_edit_dist_field: 1.47 +avg_edit_dist_img: 1.47 +precision: 70.54% +recall: 84.38% +fmeasure: 76.84% +The convert label saved in end2end/fine-tune +start testing... +hit, dt_count, gt_count 4286 4898 5006 +character_acc: 94.16% +avg_edit_dist_field: 0.47 +avg_edit_dist_img: 0.47 +precision: 87.51% +recall: 85.62% +fmeasure: 86.55% +The convert label saved in end2end/quant +start testing... +hit, dt_count, gt_count 4349 4951 5006 +character_acc: 94.13% +avg_edit_dist_field: 0.47 +avg_edit_dist_img: 0.47 +precision: 87.84% +recall: 86.88% +fmeasure: 87.36% +``` + +各个方案端到端指标如下: + +|模型| 指标 | +|---|--------| +|PP-OCRv3中英文超轻量检测预训练模型
PP-OCRv3中英文超轻量识别预训练模型| 0.04% | +|PP-OCRv3中英文超轻量检测预训练模型
PP-OCRv3中英文超轻量识别预训练模型 + 后处理去掉多识别的`·`| 78.27% | +|PP-OCRv3中英文超轻量检测预训练模型+fine-tune
PP-OCRv3中英文超轻量识别预训练模型+fine-tune| 87.14% | +|PP-OCRv3中英文超轻量检测预训练模型+fine-tune+量化
PP-OCRv3中英文超轻量识别预训练模型+fine-tune+量化| 88% | + +从结果中可以看到对预训练模型不做修改,只根据场景下的具体情况进行后处理的修改就能大幅提升端到端指标到78.27%,在CCPD数据集上进行 fine-tune 后指标进一步提升到87.14%, 在经过量化训练之后,由于检测模型的recall变高,指标进一步提升到88%。但是这个结果仍旧不符合检测模型+识别模型的真实性能(99%*94%=93%),因此我们需要对 base case 进行具体分析。 + +在之前的端到端预测结果中,可以看到很多不符合车牌标注的文字被识别出来, 因此可以进行简单的过滤来提升precision + +为了快速评估,我们在 ` tools/end2end/convert_ppocr_label.py` 脚本的 58 行加入如下代码,对非8个字符的结果进行过滤 +```python +if len(txt) != 8: # 车牌字符串长度为8 + continue +``` + +此外,通过可视化box可以发现有很多框都是竖直翻转之后的框,并且没有完全框住车牌边界,因此需要进行框的竖直翻转以及轻微扩大,示意图如下: + +![](https://ai-studio-static-online.cdn.bcebos.com/59ab0411c8eb4dfd917fb2b6e5b69a17ee7ca48351444aec9ac6104b79ff1028) + +修改前后个方案指标对比如下: + + +各个方案端到端指标如下: + +|模型|base|A:识别结果过滤|B:use_dilation|C:flip_box|best| +|---|---|---|---|---|---| +|PP-OCRv3中英文超轻量检测预训练模型
PP-OCRv3中英文超轻量识别预训练模型|0.04%|0.08%|0.02%|0.05%|0.00%(A)| +|PP-OCRv3中英文超轻量检测预训练模型
PP-OCRv3中英文超轻量识别预训练模型 + 后处理去掉多识别的`·`|78.27%|90.84%|78.61%|79.43%|91.66%(A+B+C)| +|PP-OCRv3中英文超轻量检测预训练模型+fine-tune
PP-OCRv3中英文超轻量识别预训练模型+fine-tune|87.14%|90.40%|87.66%|89.98|92.5%(A+B+C)| +|PP-OCRv3中英文超轻量检测预训练模型+fine-tune+量化
PP-OCRv3中英文超轻量识别预训练模型+fine-tune+量化|88%|90.54%|88.5%|89.46%|92.02%(A+B+C)| + + +从结果中可以看到对预训练模型不做修改,只根据场景下的具体情况进行后处理的修改就能大幅提升端到端指标到91.66%,在CCPD数据集上进行 fine-tune 后指标进一步提升到92.5%, 在经过量化训练之后,指标变为92.02%。 + +### 4.4 部署 + +- 基于 Paddle Inference 的python推理 + +检测模型和识别模型分别 fine-tune 并导出为inference模型之后,可以使用如下命令基于 Paddle Inference 进行端到端推理并对结果进行可视化。 + +```bash +python tools/infer/predict_system.py \ + --det_model_dir=output/CCPD/det/infer/ \ + --rec_model_dir=output/CCPD/rec/infer/ \ + --image_dir="/home/aistudio/data/CCPD2020/ccpd_green/test/04131106321839081-92_258-159&509_530&611-527&611_172&599_159&509_530&525-0_0_3_32_30_31_30_30-109-106.jpg" \ + --rec_image_shape=3,48,320 +``` +推理结果如下 + +![](https://ai-studio-static-online.cdn.bcebos.com/76b6a0939c2c4cf49039b6563c4b28e241e11285d7464e799e81c58c0f7707a7) + +- 端侧部署 + +端侧部署我们采用基于 PaddleLite 的 cpp 推理。Paddle Lite是飞桨轻量化推理引擎,为手机、IOT端提供高效推理能力,并广泛整合跨平台硬件,为端侧部署及应用落地问题提供轻量化的部署方案。具体可参考 [PaddleOCR lite教程](../deploy/lite/readme_ch.md) + + +### 4.5 实验总结 + +我们分别使用PP-OCRv3中英文超轻量预训练模型在车牌数据集上进行了直接评估和 fine-tune 和 fine-tune +量化3种方案的实验,并基于[PaddleOCR lite教程](../deploy/lite/readme_ch.md)进行了速度测试,指标对比如下: + +- 检测 + +|方案|hmeans| 模型大小 | 预测速度(lite) | +|---|---|------|------------| +|PP-OCRv3中英文超轻量检测预训练模型直接预测|76.12%|2.5M| 233ms | +|PP-OCRv3中英文超轻量检测预训练模型 fine-tune|99%| 2.5M | 233ms | +|PP-OCRv3中英文超轻量检测预训练模型 fine-tune + 量化|98.91%| 1M | 189ms |fine-tune + +- 识别 + +|方案| acc | 模型大小 | 预测速度(lite) | +|---|--------|-------|------------| +|PP-OCRv3中英文超轻量识别预训练模型直接预测| 0% |10.3M| 4.2ms | +|PP-OCRv3中英文超轻量识别预训练模型直接预测+后处理去掉多识别的`·`| 90.97% |10.3M| 4.2ms | +|PP-OCRv3中英文超轻量识别预训练模型 fine-tune| 94.54% | 10.3M | 4,2ms | +|PP-OCRv3中英文超轻量识别预训练模型 fine-tune + 量化| 93.4% | 4.8M | 1.8ms | + + +- 端到端指标如下: + +|方案|fmeasure|模型大小|预测速度(lite) | +|---|---|---|---| +|PP-OCRv3中英文超轻量检测预训练模型
PP-OCRv3中英文超轻量识别预训练模型|0.08%|12.8M|298ms| +|PP-OCRv3中英文超轻量检测预训练模型
PP-OCRv3中英文超轻量识别预训练模型 + 后处理去掉多识别的`·`|91.66%|12.8M|298ms| +|PP-OCRv3中英文超轻量检测预训练模型+fine-tune
PP-OCRv3中英文超轻量识别预训练模型+fine-tune|92.5%|12.8M|298ms| +|PP-OCRv3中英文超轻量检测预训练模型+fine-tune+量化
PP-OCRv3中英文超轻量识别预训练模型+fine-tune+量化|92.02%|5.8M|224ms| + + +**结论** + +PP-OCRv3的检测模型在未经过fine-tune的情况下,在车牌数据集上也有一定的精度,经过 fine-tune 后能够极大的提升检测效果,精度达到99%。在使用量化训练后检测模型的精度几乎无损,并且模型大小压缩60%。 + +PP-OCRv3的识别模型在未经过fine-tune的情况下,在车牌数据集上精度为0,但是经过分析可以知道,模型大部分字符都预测正确,但是会多预测一个特殊字符,去掉这个特殊字符后,精度达到90%。PP-OCRv3识别模型在经过 fine-tune 后识别精度进一步提升,达到94.4%。在使用量化训练后识别模型大小压缩53%,但是由于数据量多少,带来了1%的精度损失。 + +从端到端结果中可以看到对预训练模型不做修改,只根据场景下的具体情况进行后处理的修改就能大幅提升端到端指标到91.66%,在CCPD数据集上进行 fine-tune 后指标进一步提升到92.5%, 在经过量化训练之后,指标轻微下降到92.02%但模型大小降低54%。 diff --git "a/applications/\351\253\230\347\262\276\345\272\246\344\270\255\346\226\207\350\257\206\345\210\253\346\250\241\345\236\213.md" "b/applications/\351\253\230\347\262\276\345\272\246\344\270\255\346\226\207\350\257\206\345\210\253\346\250\241\345\236\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..4e71e23300ccc14d24627458c0852776e0adeae3 --- /dev/null +++ "b/applications/\351\253\230\347\262\276\345\272\246\344\270\255\346\226\207\350\257\206\345\210\253\346\250\241\345\236\213.md" @@ -0,0 +1,107 @@ +# 高精度中文场景文本识别模型SVTR + +## 1. 简介 + +PP-OCRv3是百度开源的超轻量级场景文本检测识别模型库,其中超轻量的场景中文识别模型SVTR_LCNet使用了SVTR算法结构。为了保证速度,SVTR_LCNet将SVTR模型的Local Blocks替换为LCNet,使用两层Global Blocks。在中文场景中,PP-OCRv3识别主要使用如下优化策略([详细技术报告](../doc/doc_ch/PP-OCRv3_introduction.md)): +- GTC:Attention指导CTC训练策略; +- TextConAug:挖掘文字上下文信息的数据增广策略; +- TextRotNet:自监督的预训练模型; +- UDML:联合互学习策略; +- UIM:无标注数据挖掘方案。 + +其中 *UIM:无标注数据挖掘方案* 使用了高精度的SVTR中文模型进行无标注文件的刷库,该模型在PP-OCRv3识别的数据集上训练,精度对比如下表。 + +|中文识别算法|模型|UIM|精度| +| --- | --- | --- |--- | +|PP-OCRv3|SVTR_LCNet| w/o |78.4%| +|PP-OCRv3|SVTR_LCNet| w |79.4%| +|SVTR|SVTR-Tiny|-|82.5%| + +aistudio项目链接: [高精度中文场景文本识别模型SVTR](https://aistudio.baidu.com/aistudio/projectdetail/4263032) + +## 2. SVTR中文模型使用 + +### 环境准备 + + +本任务基于Aistudio完成, 具体环境如下: + +- 操作系统: Linux +- PaddlePaddle: 2.3 +- PaddleOCR: dygraph + +下载 PaddleOCR代码 + +```bash +git clone -b dygraph https://github.com/PaddlePaddle/PaddleOCR +``` + +安装依赖库 + +```bash +pip install -r PaddleOCR/requirements.txt -i https://mirror.baidu.com/pypi/simple +``` + +### 快速使用 + +获取SVTR中文模型文件,请扫码填写问卷,加入PaddleOCR官方交流群获取全部OCR垂类模型下载链接、《动手学OCR》电子书等全套OCR学习资料🎁 +
+ +
+ +```bash +# 解压模型文件 +tar xf svtr_ch_high_accuracy.tar +``` + +预测中文文本,以下图为例: +![](../doc/imgs_words/ch/word_1.jpg) + +预测命令: + +```bash +# CPU预测 +python tools/infer_rec.py -c configs/rec/rec_svtrnet_ch.yml -o Global.pretrained_model=./svtr_ch_high_accuracy/best_accuracy Global.infer_img=./doc/imgs_words/ch/word_1.jpg Global.use_gpu=False + +# GPU预测 +#python tools/infer_rec.py -c configs/rec/rec_svtrnet_ch.yml -o Global.pretrained_model=./svtr_ch_high_accuracy/best_accuracy Global.infer_img=./doc/imgs_words/ch/word_1.jpg Global.use_gpu=True +``` + +可以看到最后打印结果为 +- result: 韩国小馆 0.9853458404541016 + +0.9853458404541016为预测置信度。 + +### 推理模型导出与预测 + +inference 模型(paddle.jit.save保存的模型) 一般是模型训练,把模型结构和模型参数保存在文件中的固化模型,多用于预测部署场景。 训练过程中保存的模型是checkpoints模型,保存的只有模型的参数,多用于恢复训练等。 与checkpoints模型相比,inference 模型会额外保存模型的结构信息,在预测部署、加速推理上性能优越,灵活方便,适合于实际系统集成。 + +运行识别模型转inference模型命令,如下: + +```bash +python tools/export_model.py -c configs/rec/rec_svtrnet_ch.yml -o Global.pretrained_model=./svtr_ch_high_accuracy/best_accuracy Global.save_inference_dir=./inference/svtr_ch +``` + +转换成功后,在目录下有三个文件: +```shell +inference/svtr_ch/ + ├── inference.pdiparams # 识别inference模型的参数文件 + ├── inference.pdiparams.info # 识别inference模型的参数信息,可忽略 + └── inference.pdmodel # 识别inference模型的program文件 +``` + +inference模型预测,命令如下: + +```bash +# CPU预测 +python3 tools/infer/predict_rec.py --image_dir="./doc/imgs_words/ch/word_1.jpg" --rec_algorithm='SVTR' --rec_model_dir=./inference/svtr_ch/ --rec_image_shape='3, 32, 320' --rec_char_dict_path=ppocr/utils/ppocr_keys_v1.txt --use_gpu=False + +# GPU预测 +#python3 tools/infer/predict_rec.py --image_dir="./doc/imgs_words/ch/word_1.jpg" --rec_algorithm='SVTR' --rec_model_dir=./inference/svtr_ch/ --rec_image_shape='3, 32, 320' --rec_char_dict_path=ppocr/utils/ppocr_keys_v1.txt --use_gpu=True +``` + +**注意** + +- 使用SVTR算法时,需要指定--rec_algorithm='SVTR' +- 如果使用自定义字典训练的模型,需要将--rec_char_dict_path=ppocr/utils/ppocr_keys_v1.txt修改为自定义的字典 +- --rec_image_shape='3, 32, 320' 该参数不能去掉 diff --git a/configs/det/ch_PP-OCRv2/ch_PP-OCRv2_det_dml.yml b/configs/det/ch_PP-OCRv2/ch_PP-OCRv2_det_dml.yml index f3ad966488dbc2f6f7ca12033bc4a3d35e1b3bd7..8b160f63538d51dc57b08ba83f7ebf019e3c9dbb 100644 --- a/configs/det/ch_PP-OCRv2/ch_PP-OCRv2_det_dml.yml +++ b/configs/det/ch_PP-OCRv2/ch_PP-OCRv2_det_dml.yml @@ -65,7 +65,7 @@ Loss: - ["Student", "Teacher"] maps_name: "thrink_maps" weight: 1.0 - act: "softmax" + # act: None model_name_pairs: ["Student", "Teacher"] key: maps - DistillationDBLoss: diff --git a/configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_dml.yml b/configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_dml.yml index 3f30ada13f2f1c3c01ba8886bbfba006da516f17..c85fc4b781c2c1aeadf92e0f02685386116a7c3e 100644 --- a/configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_dml.yml +++ b/configs/det/ch_PP-OCRv3/ch_PP-OCRv3_det_dml.yml @@ -60,7 +60,7 @@ Loss: - ["Student", "Student2"] maps_name: "thrink_maps" weight: 1.0 - act: "softmax" + # act: None model_name_pairs: ["Student", "Student2"] key: maps - DistillationDBLoss: diff --git a/configs/rec/rec_svtrnet.yml b/configs/rec/rec_svtrnet.yml index 233d5e276577cad0144456ef7df1e20de99891f9..f3195948553233dd315fd6b7e923e608d99cbb65 100644 --- a/configs/rec/rec_svtrnet.yml +++ b/configs/rec/rec_svtrnet.yml @@ -83,8 +83,7 @@ Train: img_mode: BGR channel_first: False - CTCLabelEncode: # Class handling label - - RecResizeImg: - character_dict_path: + - SVTRRecResizeImg: image_shape: [3, 64, 256] padding: False - KeepKeys: @@ -98,14 +97,13 @@ Train: Eval: dataset: name: LMDBDataSet - data_dir: ./train_data/data_lmdb_release/validation/ + data_dir: ./train_data/data_lmdb_release/evaluation/ transforms: - DecodeImage: # load image img_mode: BGR channel_first: False - CTCLabelEncode: # Class handling label - - RecResizeImg: - character_dict_path: + - SVTRRecResizeImg: image_shape: [3, 64, 256] padding: False - KeepKeys: diff --git a/configs/rec/rec_svtrnet_ch.yml b/configs/rec/rec_svtrnet_ch.yml new file mode 100644 index 0000000000000000000000000000000000000000..0d3f63d125ea12fa097fe49454b04423710e2f68 --- /dev/null +++ b/configs/rec/rec_svtrnet_ch.yml @@ -0,0 +1,155 @@ +Global: + use_gpu: true + epoch_num: 100 + log_smooth_window: 20 + print_batch_step: 10 + save_model_dir: ./output/rec/svtr_ch_all/ + save_epoch_step: 10 + eval_batch_step: + - 0 + - 2000 + cal_metric_during_train: true + pretrained_model: null + checkpoints: null + save_inference_dir: null + use_visualdl: false + infer_img: doc/imgs_words/ch/word_1.jpg + character_dict_path: ppocr/utils/ppocr_keys_v1.txt + max_text_length: 25 + infer_mode: false + use_space_char: true + save_res_path: ./output/rec/predicts_svtr_tiny_ch_all.txt +Optimizer: + name: AdamW + beta1: 0.9 + beta2: 0.99 + epsilon: 8.0e-08 + weight_decay: 0.05 + no_weight_decay_name: norm pos_embed + one_dim_param_no_weight_decay: true + lr: + name: Cosine + learning_rate: 0.0005 + warmup_epoch: 2 +Architecture: + model_type: rec + algorithm: SVTR + Transform: null + Backbone: + name: SVTRNet + img_size: + - 32 + - 320 + out_char_num: 40 + out_channels: 96 + patch_merging: Conv + embed_dim: + - 64 + - 128 + - 256 + depth: + - 3 + - 6 + - 3 + num_heads: + - 2 + - 4 + - 8 + mixer: + - Local + - Local + - Local + - Local + - Local + - Local + - Global + - Global + - Global + - Global + - Global + - Global + local_mixer: + - - 7 + - 11 + - - 7 + - 11 + - - 7 + - 11 + last_stage: true + prenorm: false + Neck: + name: SequenceEncoder + encoder_type: reshape + Head: + name: CTCHead +Loss: + name: CTCLoss +PostProcess: + name: CTCLabelDecode +Metric: + name: RecMetric + main_indicator: acc +Train: + dataset: + name: SimpleDataSet + data_dir: ./train_data + label_file_list: + - ./train_data/train_list.txt + ext_op_transform_idx: 1 + transforms: + - DecodeImage: + img_mode: BGR + channel_first: false + - RecConAug: + prob: 0.5 + ext_data_num: 2 + image_shape: + - 32 + - 320 + - 3 + - RecAug: null + - CTCLabelEncode: null + - SVTRRecResizeImg: + image_shape: + - 3 + - 32 + - 320 + padding: true + - KeepKeys: + keep_keys: + - image + - label + - length + loader: + shuffle: true + batch_size_per_card: 256 + drop_last: true + num_workers: 8 +Eval: + dataset: + name: SimpleDataSet + data_dir: ./train_data + label_file_list: + - ./train_data/val_list.txt + transforms: + - DecodeImage: + img_mode: BGR + channel_first: false + - CTCLabelEncode: null + - SVTRRecResizeImg: + image_shape: + - 3 + - 32 + - 320 + padding: true + - KeepKeys: + keep_keys: + - image + - label + - length + loader: + shuffle: false + drop_last: false + batch_size_per_card: 256 + num_workers: 2 +profiler_options: null diff --git a/deploy/android_demo/app/src/main/cpp/native.cpp b/deploy/android_demo/app/src/main/cpp/native.cpp index ced932556f09244d1e9e962e7b75461203a7cc3a..4961e5ecf141bb50701ecf9c3654a54f062937ce 100644 --- a/deploy/android_demo/app/src/main/cpp/native.cpp +++ b/deploy/android_demo/app/src/main/cpp/native.cpp @@ -47,7 +47,7 @@ str_to_cpu_mode(const std::string &cpu_mode) { std::string upper_key; std::transform(cpu_mode.cbegin(), cpu_mode.cend(), upper_key.begin(), ::toupper); - auto index = cpu_mode_map.find(upper_key); + auto index = cpu_mode_map.find(upper_key.c_str()); if (index == cpu_mode_map.end()) { LOGE("cpu_mode not found %s", upper_key.c_str()); return paddle::lite_api::LITE_POWER_HIGH; @@ -116,4 +116,4 @@ Java_com_baidu_paddle_lite_demo_ocr_OCRPredictorNative_release( ppredictor::OCR_PPredictor *ppredictor = (ppredictor::OCR_PPredictor *)java_pointer; delete ppredictor; -} \ No newline at end of file +} diff --git a/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/OCRPredictorNative.java b/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/OCRPredictorNative.java index 622da2a3f9a1233167e777e62b687c1f246df01f..41fa183dea1d968582dbedf4e831c55b043ae00f 100644 --- a/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/OCRPredictorNative.java +++ b/deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/OCRPredictorNative.java @@ -54,7 +54,7 @@ public class OCRPredictorNative { } public void destory() { - if (nativePointer > 0) { + if (nativePointer != 0) { release(nativePointer); nativePointer = 0; } diff --git a/deploy/cpp_infer/docs/windows_vs2019_build.md b/deploy/cpp_infer/docs/windows_vs2019_build.md index 4f391d925008b4bffcbd123e937eb608f502c646..bcaefa46f83a30a4c232add78dc2e9f521b9f84f 100644 --- a/deploy/cpp_infer/docs/windows_vs2019_build.md +++ b/deploy/cpp_infer/docs/windows_vs2019_build.md @@ -109,8 +109,10 @@ CUDA_LIB、CUDNN_LIB、TENSORRT_DIR、WITH_GPU、WITH_TENSORRT 运行之前,将下面文件拷贝到`build/Release/`文件夹下 1. `paddle_inference/paddle/lib/paddle_inference.dll` -2. `opencv/build/x64/vc15/bin/opencv_world455.dll` -3. 如果使用openblas版本的预测库还需要拷贝 `paddle_inference/third_party/install/openblas/lib/openblas.dll` +2. `paddle_inference/third_party/install/onnxruntime/lib/onnxruntime.dll` +3. `paddle_inference/third_party/install/paddle2onnx/lib/paddle2onnx.dll` +4. `opencv/build/x64/vc15/bin/opencv_world455.dll` +5. 如果使用openblas版本的预测库还需要拷贝 `paddle_inference/third_party/install/openblas/lib/openblas.dll` ### Step4: 预测 diff --git a/deploy/lite/config.txt b/deploy/lite/config.txt index 4c68105d39031830a8222b3d88163aebc8cac257..dda0d2b0320544d3a82f59b0672c086c64d83d3d 100644 --- a/deploy/lite/config.txt +++ b/deploy/lite/config.txt @@ -4,4 +4,5 @@ det_db_box_thresh 0.5 det_db_unclip_ratio 1.6 det_db_use_dilate 0 det_use_polygon_score 1 -use_direction_classify 1 \ No newline at end of file +use_direction_classify 1 +rec_image_height 32 \ No newline at end of file diff --git a/deploy/lite/crnn_process.cc b/deploy/lite/crnn_process.cc index 7528f36fe6316c84724891a4421c047fbdd33fa2..dd39cd389d3b50107883760e01b3bf52e29cc7ac 100644 --- a/deploy/lite/crnn_process.cc +++ b/deploy/lite/crnn_process.cc @@ -19,24 +19,28 @@ const std::vector rec_image_shape{3, 32, 320}; -cv::Mat CrnnResizeImg(cv::Mat img, float wh_ratio) { +cv::Mat CrnnResizeImg(cv::Mat img, float wh_ratio, int rec_image_height) { int imgC, imgH, imgW; imgC = rec_image_shape[0]; + imgH = rec_image_height; imgW = rec_image_shape[2]; - imgH = rec_image_shape[1]; - imgW = int(32 * wh_ratio); + imgW = int(imgH * wh_ratio); - float ratio = static_cast(img.cols) / static_cast(img.rows); + float ratio = float(img.cols) / float(img.rows); int resize_w, resize_h; + if (ceilf(imgH * ratio) > imgW) resize_w = imgW; else - resize_w = static_cast(ceilf(imgH * ratio)); + resize_w = int(ceilf(imgH * ratio)); + cv::Mat resize_img; cv::resize(img, resize_img, cv::Size(resize_w, imgH), 0.f, 0.f, cv::INTER_LINEAR); - + cv::copyMakeBorder(resize_img, resize_img, 0, 0, 0, + int(imgW - resize_img.cols), cv::BORDER_CONSTANT, + {127, 127, 127}); return resize_img; } diff --git a/deploy/lite/crnn_process.h b/deploy/lite/crnn_process.h index 29e67906976198210394c4960786105bf884dce8..ed7a3167069538a0c40d1bc01f0073c36cb7e461 100644 --- a/deploy/lite/crnn_process.h +++ b/deploy/lite/crnn_process.h @@ -26,7 +26,7 @@ #include "opencv2/imgcodecs.hpp" #include "opencv2/imgproc.hpp" -cv::Mat CrnnResizeImg(cv::Mat img, float wh_ratio); +cv::Mat CrnnResizeImg(cv::Mat img, float wh_ratio, int rec_image_height); std::vector ReadDict(std::string path); diff --git a/deploy/lite/ocr_db_crnn.cc b/deploy/lite/ocr_db_crnn.cc index 1ffbbacb74545b0bbea4957e25b6235225bad02b..fde0d07d6c1af769610865da1697e6eef0442899 100644 --- a/deploy/lite/ocr_db_crnn.cc +++ b/deploy/lite/ocr_db_crnn.cc @@ -162,7 +162,8 @@ void RunRecModel(std::vector>> boxes, cv::Mat img, std::vector charactor_dict, std::shared_ptr predictor_cls, int use_direction_classify, - std::vector *times) { + std::vector *times, + int rec_image_height) { std::vector mean = {0.5f, 0.5f, 0.5f}; std::vector scale = {1 / 0.5f, 1 / 0.5f, 1 / 0.5f}; @@ -183,7 +184,7 @@ void RunRecModel(std::vector>> boxes, cv::Mat img, float wh_ratio = static_cast(crop_img.cols) / static_cast(crop_img.rows); - resize_img = CrnnResizeImg(crop_img, wh_ratio); + resize_img = CrnnResizeImg(crop_img, wh_ratio, rec_image_height); resize_img.convertTo(resize_img, CV_32FC3, 1 / 255.f); const float *dimg = reinterpret_cast(resize_img.data); @@ -444,7 +445,7 @@ void system(char **argv){ //// load config from txt file auto Config = LoadConfigTxt(det_config_path); int use_direction_classify = int(Config["use_direction_classify"]); - + int rec_image_height = int(Config["rec_image_height"]); auto charactor_dict = ReadDict(dict_path); charactor_dict.insert(charactor_dict.begin(), "#"); // blank char for ctc charactor_dict.push_back(" "); @@ -473,7 +474,7 @@ void system(char **argv){ std::vector rec_times; RunRecModel(boxes, srcimg, rec_predictor, rec_text, rec_text_score, - charactor_dict, cls_predictor, use_direction_classify, &rec_times); + charactor_dict, cls_predictor, use_direction_classify, &rec_times, rec_image_height); //// visualization auto img_vis = Visualization(srcimg, boxes); @@ -590,12 +591,16 @@ void rec(int argc, char **argv) { std::string batchsize = argv[6]; std::string img_dir = argv[7]; std::string dict_path = argv[8]; + std::string config_path = argv[9]; if (strcmp(argv[4], "FP32") != 0 && strcmp(argv[4], "INT8") != 0) { std::cerr << "Only support FP32 or INT8." << std::endl; exit(1); } + auto Config = LoadConfigTxt(config_path); + int rec_image_height = int(Config["rec_image_height"]); + std::vector cv_all_img_names; cv::glob(img_dir, cv_all_img_names); @@ -630,7 +635,7 @@ void rec(int argc, char **argv) { std::vector rec_text_score; std::vector times; RunRecModel(boxes, srcimg, rec_predictor, rec_text, rec_text_score, - charactor_dict, cls_predictor, 0, ×); + charactor_dict, cls_predictor, 0, ×, rec_image_height); //// print recognized text for (int i = 0; i < rec_text.size(); i++) { diff --git a/deploy/lite/readme.md b/deploy/lite/readme.md index 9926e2dd8c973b25b5397fd5825f790528ede279..a1bef8120e52dd91db0fda4ac2a4d91cc2800818 100644 --- a/deploy/lite/readme.md +++ b/deploy/lite/readme.md @@ -34,7 +34,7 @@ For the compilation process of different development environments, please refer ### 1.2 Prepare Paddle-Lite library There are two ways to obtain the Paddle-Lite library: -- 1. Download directly, the download link of the Paddle-Lite library is as follows: +- 1. [Recommended] Download directly, the download link of the Paddle-Lite library is as follows: | Platform | Paddle-Lite library download link | |---|---| @@ -43,7 +43,9 @@ There are two ways to obtain the Paddle-Lite library: Note: 1. The above Paddle-Lite library is compiled from the Paddle-Lite 2.10 branch. For more information about Paddle-Lite 2.10, please refer to [link](https://github.com/PaddlePaddle/Paddle-Lite/releases/tag/v2.10). -- 2. [Recommended] Compile Paddle-Lite to get the prediction library. The compilation method of Paddle-Lite is as follows: + **Note: It is recommended to use paddlelite>=2.10 version of the prediction library, other prediction library versions [download link](https://github.com/PaddlePaddle/Paddle-Lite/tags)** + +- 2. Compile Paddle-Lite to get the prediction library. The compilation method of Paddle-Lite is as follows: ``` git clone https://github.com/PaddlePaddle/Paddle-Lite.git cd Paddle-Lite @@ -104,21 +106,17 @@ If you directly use the model in the above table for deployment, you can skip th If the model to be deployed is not in the above table, you need to follow the steps below to obtain the optimized model. -The `opt` tool can be obtained by compiling Paddle Lite. +- Step 1: Refer to [document](https://www.paddlepaddle.org.cn/lite/v2.10/user_guides/opt/opt_python.html) to install paddlelite, which is used to convert paddle inference model to paddlelite required for running nb model ``` -git clone https://github.com/PaddlePaddle/Paddle-Lite.git -cd Paddle-Lite -git checkout release/v2.10 -./lite/tools/build.sh build_optimize_tool +pip install paddlelite==2.10 # The paddlelite version should be the same as the prediction library version ``` - -After the compilation is complete, the opt file is located under build.opt/lite/api/, You can view the operating options and usage of opt in the following ways: - +After installation, the following commands can view the help information ``` -cd build.opt/lite/api/ -./opt +paddle_lite_opt ``` +Introduction to paddle_lite_opt parameters: + |Options|Description| |---|---| |--model_dir|The path of the PaddlePaddle model to be optimized (non-combined form)| @@ -131,6 +129,8 @@ cd build.opt/lite/api/ `--model_dir` is suitable for the non-combined mode of the model to be optimized, and the inference model of PaddleOCR is the combined mode, that is, the model structure and model parameters are stored in a single file. +- Step 2: Use paddle_lite_opt to convert the inference model to the mobile model format. + The following takes the ultra-lightweight Chinese model of PaddleOCR as an example to introduce the use of the compiled opt file to complete the conversion of the inference model to the Paddle-Lite optimized model ``` @@ -240,6 +240,7 @@ det_db_thresh 0.3 # Used to filter the binarized image of DB prediction, det_db_box_thresh 0.5 # DDB post-processing filter box threshold, if there is a missing box detected, it can be reduced as appropriate det_db_unclip_ratio 1.6 # Indicates the compactness of the text box, the smaller the value, the closer the text box to the text use_direction_classify 0 # Whether to use the direction classifier, 0 means not to use, 1 means to use +rec_image_height 32 # The height of the input image of the recognition model, the PP-OCRv3 model needs to be set to 48, and the PP-OCRv2 model needs to be set to 32 ``` 5. Run Model on phone @@ -258,8 +259,15 @@ After the above steps are completed, you can use adb to push the file to the pho cd /data/local/tmp/debug export LD_LIBRARY_PATH=${PWD}:$LD_LIBRARY_PATH # The use of ocr_db_crnn is: - # ./ocr_db_crnn Detection model file Orientation classifier model file Recognition model file Test image path Dictionary file path - ./ocr_db_crnn ch_PP-OCRv2_det_slim_opt.nb ch_PP-OCRv2_rec_slim_opt.nb ch_ppocr_mobile_v2.0_cls_opt.nb ./11.jpg ppocr_keys_v1.txt + # ./ocr_db_crnn Mode Detection model file Orientation classifier model file Recognition model file Hardware Precision Threads Batchsize Test image path Dictionary file path + ./ocr_db_crnn system ch_PP-OCRv2_det_slim_opt.nb ch_PP-OCRv2_rec_slim_opt.nb ch_ppocr_mobile_v2.0_cls_slim_opt.nb arm8 INT8 10 1 ./11.jpg config.txt ppocr_keys_v1.txt True +# precision can be INT8 for quantitative model or FP32 for normal model. + +# Only using detection model +./ocr_db_crnn det ch_PP-OCRv2_det_slim_opt.nb arm8 INT8 10 1 ./11.jpg config.txt + +# Only using recognition model +./ocr_db_crnn rec ch_PP-OCRv2_rec_slim_opt.nb arm8 INT8 10 1 word_1.jpg ppocr_keys_v1.txt config.txt ``` If you modify the code, you need to recompile and push to the phone. @@ -283,3 +291,7 @@ A2: Replace the .jpg test image under ./debug with the image you want to test, a Q3: How to package it into the mobile APP? A3: This demo aims to provide the core algorithm part that can run OCR on mobile phones. Further, PaddleOCR/deploy/android_demo is an example of encapsulating this demo into a mobile app for reference. + +Q4: When running the demo, an error is reported `Error: This model is not supported, because kernel for 'io_copy' is not supported by Paddle-Lite.` + +A4: The problem is that the installed paddlelite version does not match the downloaded prediction library version. Make sure that the paddleliteopt tool matches your prediction library version, and try to switch to the nb model again. diff --git a/deploy/lite/readme_ch.md b/deploy/lite/readme_ch.md index 99a543d0d60455443dd872c56a5832c8ca0ff4e9..0793827fe647c470944fc36e2b243c8f7e704e99 100644 --- a/deploy/lite/readme_ch.md +++ b/deploy/lite/readme_ch.md @@ -8,7 +8,7 @@ - [2.1 模型优化](#21-模型优化) - [2.2 与手机联调](#22-与手机联调) - [FAQ](#faq) - + 本教程将介绍基于[Paddle Lite](https://github.com/PaddlePaddle/Paddle-Lite) 在移动端部署PaddleOCR超轻量中文检测、识别模型的详细步骤。 @@ -32,7 +32,7 @@ Paddle Lite是飞桨轻量化推理引擎,为手机、IOT端提供高效推理 ### 1.2 准备预测库 预测库有两种获取方式: -- 1. 直接下载,预测库下载链接如下: +- 1. [推荐]直接下载,预测库下载链接如下: | 平台 | 预测库下载链接 | |---|---| @@ -41,7 +41,9 @@ Paddle Lite是飞桨轻量化推理引擎,为手机、IOT端提供高效推理 注:1. 上述预测库为PaddleLite 2.10分支编译得到,有关PaddleLite 2.10 详细信息可参考 [链接](https://github.com/PaddlePaddle/Paddle-Lite/releases/tag/v2.10) 。 -- 2. [推荐]编译Paddle-Lite得到预测库,Paddle-Lite的编译方式如下: +**注:建议使用paddlelite>=2.10版本的预测库,其他预测库版本[下载链接](https://github.com/PaddlePaddle/Paddle-Lite/tags)** + +- 2. 编译Paddle-Lite得到预测库,Paddle-Lite的编译方式如下: ``` git clone https://github.com/PaddlePaddle/Paddle-Lite.git cd Paddle-Lite @@ -102,22 +104,16 @@ Paddle-Lite 提供了多种策略来自动优化原始的模型,其中包括 如果要部署的模型不在上述表格中,则需要按照如下步骤获得优化后的模型。 -模型优化需要Paddle-Lite的opt可执行文件,可以通过编译Paddle-Lite源码获得,编译步骤如下: +- 步骤1:参考[文档](https://www.paddlepaddle.org.cn/lite/v2.10/user_guides/opt/opt_python.html)安装paddlelite,用于转换paddle inference model为paddlelite运行所需的nb模型 ``` -# 如果准备环境时已经clone了Paddle-Lite,则不用重新clone Paddle-Lite -git clone https://github.com/PaddlePaddle/Paddle-Lite.git -cd Paddle-Lite -git checkout release/v2.10 -# 启动编译 -./lite/tools/build.sh build_optimize_tool +pip install paddlelite==2.10 # paddlelite版本要与预测库版本一致 ``` - -编译完成后,opt文件位于`build.opt/lite/api/`下,可通过如下方式查看opt的运行选项和使用方式; +安装完后,如下指令可以查看帮助信息 ``` -cd build.opt/lite/api/ -./opt +paddle_lite_opt ``` +paddle_lite_opt 参数介绍: |选项|说明| |---|---| |--model_dir|待优化的PaddlePaddle模型(非combined形式)的路径| @@ -130,6 +126,8 @@ cd build.opt/lite/api/ `--model_dir`适用于待优化的模型是非combined方式,PaddleOCR的inference模型是combined方式,即模型结构和模型参数使用单独一个文件存储。 +- 步骤2:使用paddle_lite_opt将inference模型转换成移动端模型格式。 + 下面以PaddleOCR的超轻量中文模型为例,介绍使用编译好的opt文件完成inference模型到Paddle-Lite优化模型的转换。 ``` @@ -148,7 +146,7 @@ wget https://paddleocr.bj.bcebos.com/dygraph_v2.0/slim/ch_ppocr_mobile_v2.0_cls 转换成功后,inference模型目录下会多出`.nb`结尾的文件,即是转换成功的模型文件。 -注意:使用paddle-lite部署时,需要使用opt工具优化后的模型。 opt 工具的输入模型是paddle保存的inference模型 +注意:使用paddle-lite部署时,需要使用opt工具优化后的模型。 opt工具的输入模型是paddle保存的inference模型 ### 2.2 与手机联调 @@ -234,13 +232,14 @@ ppocr_keys_v1.txt # 中文字典 ... ``` -2. `config.txt` 包含了检测器、分类器的超参数,如下: +2. `config.txt` 包含了检测器、分类器、识别器的超参数,如下: ``` max_side_len 960 # 输入图像长宽大于960时,等比例缩放图像,使得图像最长边为960 det_db_thresh 0.3 # 用于过滤DB预测的二值化图像,设置为0.-0.3对结果影响不明显 -det_db_box_thresh 0.5 # DB后处理过滤box的阈值,如果检测存在漏框情况,可酌情减小 +det_db_box_thresh 0.5 # 检测器后处理过滤box的阈值,如果检测存在漏框情况,可酌情减小 det_db_unclip_ratio 1.6 # 表示文本框的紧致程度,越小则文本框更靠近文本 use_direction_classify 0 # 是否使用方向分类器,0表示不使用,1表示使用 +rec_image_height 32 # 识别模型输入图像的高度,PP-OCRv3模型设置为48,PP-OCRv2模型需要设置为32 ``` 5. 启动调试 @@ -259,8 +258,14 @@ use_direction_classify 0 # 是否使用方向分类器,0表示不使用,1 cd /data/local/tmp/debug export LD_LIBRARY_PATH=${PWD}:$LD_LIBRARY_PATH # 开始使用,ocr_db_crnn可执行文件的使用方式为: - # ./ocr_db_crnn 检测模型文件 方向分类器模型文件 识别模型文件 测试图像路径 字典文件路径 - ./ocr_db_crnn ch_PP-OCRv2_det_slim_opt.nb ch_PP-OCRv2_rec_slim_opt.nb ch_ppocr_mobile_v2.0_cls_slim_opt.nb ./11.jpg ppocr_keys_v1.txt + # ./ocr_db_crnn 预测模式 检测模型文件 方向分类器模型文件 识别模型文件 运行硬件 运行精度 线程数 batchsize 测试图像路径 参数配置路径 字典文件路径 是否使用benchmark参数 + ./ocr_db_crnn system ch_PP-OCRv2_det_slim_opt.nb ch_PP-OCRv2_rec_slim_opt.nb ch_ppocr_mobile_v2.0_cls_slim_opt.nb arm8 INT8 10 1 ./11.jpg config.txt ppocr_keys_v1.txt True + +# 仅使用文本检测模型,使用方式如下: +./ocr_db_crnn det ch_PP-OCRv2_det_slim_opt.nb arm8 INT8 10 1 ./11.jpg config.txt + +# 仅使用文本识别模型,使用方式如下: +./ocr_db_crnn rec ch_PP-OCRv2_rec_slim_opt.nb arm8 INT8 10 1 word_1.jpg ppocr_keys_v1.txt config.txt ``` 如果对代码做了修改,则需要重新编译并push到手机上。 @@ -284,3 +289,7 @@ A2:替换debug下的.jpg测试图像为你想要测试的图像,adb push 到 Q3:如何封装到手机APP中? A3:此demo旨在提供能在手机上运行OCR的核心算法部分,PaddleOCR/deploy/android_demo是将这个demo封装到手机app的示例,供参考 + +Q4:运行demo时遇到报错`Error: This model is not supported, because kernel for 'io_copy' is not supported by Paddle-Lite.` + +A4:问题是安装的paddlelite版本和下载的预测库版本不匹配,确保paddleliteopt工具和你的预测库版本匹配,重新转nb模型试试。 diff --git a/deploy/pdserving/ocr_reader.py b/deploy/pdserving/ocr_reader.py index 75f0f3d5c3aea488f82ec01a72e20310663d565b..d488cc0920391eded6c08945597b5c938b7c7a42 100644 --- a/deploy/pdserving/ocr_reader.py +++ b/deploy/pdserving/ocr_reader.py @@ -339,7 +339,7 @@ class CharacterOps(object): class OCRReader(object): def __init__(self, algorithm="CRNN", - image_shape=[3, 32, 320], + image_shape=[3, 48, 320], char_type="ch", batch_num=1, char_dict_path="./ppocr_keys_v1.txt"): @@ -356,7 +356,7 @@ class OCRReader(object): def resize_norm_img(self, img, max_wh_ratio): imgC, imgH, imgW = self.rec_image_shape if self.character_type == "ch": - imgW = int(32 * max_wh_ratio) + imgW = int(imgH * max_wh_ratio) h = img.shape[0] w = img.shape[1] ratio = w / float(h) @@ -377,7 +377,7 @@ class OCRReader(object): def preprocess(self, img_list): img_num = len(img_list) norm_img_batch = [] - max_wh_ratio = 0 + max_wh_ratio = 320/48. for ino in range(img_num): h, w = img_list[ino].shape[0:2] wh_ratio = w * 1.0 / h diff --git a/deploy/pdserving/web_service.py b/deploy/pdserving/web_service.py index f05806ce030238144568a3ca137798a9132027e4..d8491dc572fa2c5c4186a426ce689254d312cb45 100644 --- a/deploy/pdserving/web_service.py +++ b/deploy/pdserving/web_service.py @@ -63,7 +63,6 @@ class DetOp(Op): dt_boxes_list = self.post_func(det_out, [ratio_list]) dt_boxes = self.filter_func(dt_boxes_list[0], [self.ori_h, self.ori_w]) out_dict = {"dt_boxes": dt_boxes, "image": self.raw_im} - return out_dict, None, "" @@ -86,7 +85,7 @@ class RecOp(Op): dt_boxes = copy.deepcopy(self.dt_list) feed_list = [] img_list = [] - max_wh_ratio = 0 + max_wh_ratio = 320/48. ## Many mini-batchs, the type of feed_data is list. max_batch_size = 6 # len(dt_boxes) @@ -150,7 +149,8 @@ class RecOp(Op): for i in range(dt_num): text = rec_list[i] dt_box = self.dt_list[i] - result_list.append([text, dt_box.tolist()]) + if text[1] >= 0.5: + result_list.append([text, dt_box.tolist()]) res = {"result": str(result_list)} return res, None, "" diff --git a/deploy/slim/quantization/README_en.md b/deploy/slim/quantization/README_en.md index 33b2c4784afa4be68c8b9db1a02d83013c886655..c6796ae9dc256496308e432023c45ef1026c3d92 100644 --- a/deploy/slim/quantization/README_en.md +++ b/deploy/slim/quantization/README_en.md @@ -73,4 +73,4 @@ python deploy/slim/quantization/export_model.py -c configs/det/ch_ppocr_v2.0/ch_ The numerical range of the quantized model parameters derived from the above steps is still FP32, but the numerical range of the parameters is int8. The derived model can be converted through the `opt tool` of PaddleLite. -For quantitative model deployment, please refer to [Mobile terminal model deployment](../../lite/readme_en.md) +For quantitative model deployment, please refer to [Mobile terminal model deployment](../../lite/readme.md) diff --git a/doc/doc_ch/PP-OCRv3_introduction.md b/doc/doc_ch/PP-OCRv3_introduction.md index b8a6ad1245bdd6f5e7d3a4e5a674ef46a13fe414..ddeb78d74fb92991b9a8da752fb62850ae41102d 100644 --- a/doc/doc_ch/PP-OCRv3_introduction.md +++ b/doc/doc_ch/PP-OCRv3_introduction.md @@ -185,7 +185,7 @@ UDML(Unified-Deep Mutual Learning)联合互学习是PP-OCRv2中就采用的 **(6)UIM:无标注数据挖掘方案** -UIM(Unlabeled Images Mining)是一种非常简单的无标注数据挖掘方案。核心思想是利用高精度的文本识别大模型对无标注数据进行预测,获取伪标签,并且选择预测置信度高的样本作为训练数据,用于训练小模型。使用该策略,识别模型的准确率进一步提升到79.4%(+1%)。 +UIM(Unlabeled Images Mining)是一种非常简单的无标注数据挖掘方案。核心思想是利用高精度的文本识别大模型对无标注数据进行预测,获取伪标签,并且选择预测置信度高的样本作为训练数据,用于训练小模型。使用该策略,识别模型的准确率进一步提升到79.4%(+1%)。实际操作中,我们使用全量数据集训练高精度SVTR-Tiny模型(acc=82.5%)进行数据挖掘,点击获取[模型下载地址和使用教程](../../applications/高精度中文识别模型.md)。
diff --git a/doc/doc_ch/algorithm_det_east.md b/doc/doc_ch/algorithm_det_east.md index b89018e3468aa7772af69da469e81c16e9d43dc9..104e70927749796e1fb02027d123ab1c8da1d8f0 100644 --- a/doc/doc_ch/algorithm_det_east.md +++ b/doc/doc_ch/algorithm_det_east.md @@ -26,8 +26,8 @@ |模型|骨干网络|配置文件|precision|recall|Hmean|下载链接| | --- | --- | --- | --- | --- | --- | --- | -|EAST|ResNet50_vd|88.71%| 81.36%| 84.88%| [训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/det_r50_vd_east_v2.0_train.tar)| -|EAST| MobileNetV3| 78.2%| 79.1%| 78.65%| [训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/det_r50_vd_east_v2.0_train.tar)| +|EAST|ResNet50_vd|[det_r50_vd_east.yml](../../configs/det/det_r50_vd_east.yml)|88.71%| 81.36%| 84.88%| [训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/det_r50_vd_east_v2.0_train.tar)| +|EAST|MobileNetV3|[det_mv3_east.yml](../../configs/det/det_mv3_east.yml)| 78.2%| 79.1%| 78.65%| [训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/det_mv3_east_v2.0_train.tar)| diff --git a/doc/doc_ch/dataset/layout_datasets.md b/doc/doc_ch/dataset/layout_datasets.md index e7055b4e607aae358a9ec1e93f3640b2b68ea4a1..728a9be5fdd33a78482adb1e705afea7117a3037 100644 --- a/doc/doc_ch/dataset/layout_datasets.md +++ b/doc/doc_ch/dataset/layout_datasets.md @@ -15,8 +15,8 @@ - **数据简介**:publaynet数据集的训练集合中包含35万张图像,验证集合中包含1.1万张图像。总共包含5个类别,分别是: `text, title, list, table, figure`。部分图像以及标注框可视化如下所示。
- - + +
- **下载地址**:https://developer.ibm.com/exchanges/data/all/publaynet/ @@ -30,8 +30,8 @@ - **数据简介**:CDLA据集的训练集合中包含5000张图像,验证集合中包含1000张图像。总共包含10个类别,分别是: `Text, Title, Figure, Figure caption, Table, Table caption, Header, Footer, Reference, Equation`。部分图像以及标注框可视化如下所示。
- - + +
- **下载地址**:https://github.com/buptlihang/CDLA @@ -45,8 +45,8 @@ - **数据简介**:TableBank数据集包含Latex(训练集187199张,验证集7265张,测试集5719张)与Word(训练集73383张,验证集2735张,测试集2281张)两种类别的文档。仅包含`Table` 1个类别。部分图像以及标注框可视化如下所示。
- - + +
- **下载地址**:https://doc-analysis.github.io/tablebank-page/index.html diff --git a/doc/doc_ch/detection.md b/doc/doc_ch/detection.md index 8a71b75c249b794e7ecda0ad14dc8cd2f07447e0..26b6471c5f59c872bb22367ee4119b8a2a76fa0b 100644 --- a/doc/doc_ch/detection.md +++ b/doc/doc_ch/detection.md @@ -64,7 +64,7 @@ python3 -m paddle.distributed.launch --gpus '0,1,2,3' tools/train.py -c configs/ ``` -上述指令中,通过-c 选择训练使用configs/det/det_db_mv3.yml配置文件。 +上述指令中,通过-c 选择训练使用configs/det/det_mv3_db.yml配置文件。 有关配置文件的详细解释,请参考[链接](./config.md)。 您也可以通过-o参数在不需要修改yml文件的情况下,改变训练的参数,比如,调整训练的学习率为0.0001 diff --git a/doc/doc_ch/inference_ppocr.md b/doc/doc_ch/inference_ppocr.md index 472c0003f963d6f65fa2d0babbf6b9c7d0ec9b80..3ac9faa12fdc158f38bee16aef49e6878a60a590 100644 --- a/doc/doc_ch/inference_ppocr.md +++ b/doc/doc_ch/inference_ppocr.md @@ -7,7 +7,8 @@ - [1. 文本检测模型推理](#1-文本检测模型推理) - [2. 文本识别模型推理](#2-文本识别模型推理) - [2.1 超轻量中文识别模型推理](#21-超轻量中文识别模型推理) - - [2.2 多语言模型的推理](#22-多语言模型的推理) + - [2.2 英文识别模型推理](#22-英文识别模型推理) + - [2.3 多语言模型的推理](#23-多语言模型的推理) - [3. 方向分类模型推理](#3-方向分类模型推理) - [4. 文本检测、方向分类和文字识别串联推理](#4-文本检测方向分类和文字识别串联推理) @@ -78,9 +79,29 @@ python3 tools/infer/predict_rec.py --image_dir="./doc/imgs_words/ch/word_4.jpg" Predicts of ./doc/imgs_words/ch/word_4.jpg:('实力活力', 0.9956803321838379) ``` + + +### 2.2 英文识别模型推理 + +英文识别模型推理,可以执行如下命令, 注意修改字典路径: + +``` +# 下载英文数字识别模型: +wget https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_rec_infer.tar +tar xf en_PP-OCRv3_rec_infer.tar +python3 tools/infer/predict_rec.py --image_dir="./doc/imgs_words/en/word_1.png" --rec_model_dir="./en_PP-OCRv3_rec_infer/" --rec_char_dict_path="ppocr/utils/en_dict.txt" +``` + +![](../imgs_words/en/word_1.png) + +执行命令后,上图的预测结果为: + +``` +Predicts of ./doc/imgs_words/en/word_1.png: ('JOINT', 0.998160719871521) +``` -### 2.2 多语言模型的推理 +### 2.3 多语言模型的推理 如果您需要预测的是其他语言模型,可以在[此链接](./models_list.md#%E5%A4%9A%E8%AF%AD%E8%A8%80%E8%AF%86%E5%88%AB%E6%A8%A1%E5%9E%8B)中找到对应语言的inference模型,在使用inference模型预测时,需要通过`--rec_char_dict_path`指定使用的字典路径, 同时为了得到正确的可视化结果,需要通过 `--vis_font_path` 指定可视化的字体路径,`doc/fonts/` 路径下有默认提供的小语种字体,例如韩文识别: ``` diff --git a/doc/doc_ch/knowledge_distillation.md b/doc/doc_ch/knowledge_distillation.md index 2adba3659e101fe214d31b805d0800fd5128595c..ff474797b8a086896df5d886e013e470c716aa87 100644 --- a/doc/doc_ch/knowledge_distillation.md +++ b/doc/doc_ch/knowledge_distillation.md @@ -591,8 +591,9 @@ Metric: #### 2.2.5 检测蒸馏模型finetune PP-OCRv3检测蒸馏有两种方式: -- 采用ch_PP-OCRv3_det_cml.yml,采用cml蒸馏,同样Teacher模型设置为PaddleOCR提供的模型或者您训练好的大模型 +- 采用ch_PP-OCRv3_det_cml.yml,采用CML蒸馏,同样Teacher模型设置为PaddleOCR提供的模型或者您训练好的大模型。 - 采用ch_PP-OCRv3_det_dml.yml,采用DML的蒸馏,两个Student模型互蒸馏的方法,在PaddleOCR采用的数据集上相比单独训练Student模型有1%-2%的提升。 +> 如果您在自己的场景中没有训练过高精度大模型,或原始PP-OCR模型在您的场景中表现不好,则无法使用CML训练以达到更高精度,更应该采用DML训练 在具体fine-tune时,需要在网络结构的`pretrained`参数中设置要加载的预训练模型。 diff --git a/doc/doc_ch/ocr_book.md b/doc/doc_ch/ocr_book.md index 2760494af44e84e8670a36b61fc57ed907d96906..8697e29a55ca41273b86f127a77f7b02c378bda2 100644 --- a/doc/doc_ch/ocr_book.md +++ b/doc/doc_ch/ocr_book.md @@ -1,6 +1,6 @@ # 《动手学OCR》电子书 -《动手学OCR》是PaddleOCR团队携手复旦大学青年研究员陈智能、中国移动研究院视觉领域资深专家黄文辉等产学研同仁,以及OCR开发者共同打造的结合OCR前沿理论与代码实践的教材。主要特色如下: +《动手学OCR》是PaddleOCR团队携手华中科技大学博导/教授,IAPR Fellow 白翔、复旦大学青年研究员陈智能、中国移动研究院视觉领域资深专家黄文辉、中国工商银行大数据人工智能实验室研究员等产学研同仁,以及OCR开发者共同打造的结合OCR前沿理论与代码实践的教材。主要特色如下: - 覆盖从文本检测识别到文档分析的OCR全栈技术 - 紧密结合理论实践,跨越代码实现鸿沟,并配套教学视频 diff --git a/doc/doc_ch/ppocr_introduction.md b/doc/doc_ch/ppocr_introduction.md index 59de124e2ab855d0b4abb90d0a356aefd6db586d..bd62087c8b212098cba6b0ee1cbaf413ab23015f 100644 --- a/doc/doc_ch/ppocr_introduction.md +++ b/doc/doc_ch/ppocr_introduction.md @@ -30,11 +30,11 @@ PP-OCR系统pipeline如下: PP-OCR系统在持续迭代优化,目前已发布PP-OCR和PP-OCRv2两个版本: -PP-OCR从骨干网络选择和调整、预测头部的设计、数据增强、学习率变换策略、正则化参数选择、预训练模型使用以及模型自动裁剪量化8个方面,采用19个有效策略,对各个模块的模型进行效果调优和瘦身(如绿框所示),最终得到整体大小为3.5M的超轻量中英文OCR和2.8M的英文数字OCR。更多细节请参考PP-OCR技术方案 https://arxiv.org/abs/2009.09941 +PP-OCR从骨干网络选择和调整、预测头部的设计、数据增强、学习率变换策略、正则化参数选择、预训练模型使用以及模型自动裁剪量化8个方面,采用19个有效策略,对各个模块的模型进行效果调优和瘦身(如绿框所示),最终得到整体大小为3.5M的超轻量中英文OCR和2.8M的英文数字OCR。更多细节请参考[PP-OCR技术报告](https://arxiv.org/abs/2009.09941)。 #### PP-OCRv2 -PP-OCRv2在PP-OCR的基础上,进一步在5个方面重点优化,检测模型采用CML协同互学习知识蒸馏策略和CopyPaste数据增广策略;识别模型采用LCNet轻量级骨干网络、UDML 改进知识蒸馏策略和[Enhanced CTC loss](./enhanced_ctc_loss.md)损失函数改进(如上图红框所示),进一步在推理速度和预测效果上取得明显提升。更多细节请参考PP-OCRv2[技术报告](https://arxiv.org/abs/2109.03144)。 +PP-OCRv2在PP-OCR的基础上,进一步在5个方面重点优化,检测模型采用CML协同互学习知识蒸馏策略和CopyPaste数据增广策略;识别模型采用LCNet轻量级骨干网络、UDML 改进知识蒸馏策略和[Enhanced CTC loss](./enhanced_ctc_loss.md)损失函数改进(如上图红框所示),进一步在推理速度和预测效果上取得明显提升。更多细节请参考[PP-OCRv2技术报告](https://arxiv.org/abs/2109.03144)。 #### PP-OCRv3 @@ -48,7 +48,7 @@ PP-OCRv3系统pipeline如下:
-更多细节请参考PP-OCRv3[技术报告](./PP-OCRv3_introduction.md)。 +更多细节请参考[PP-OCRv3技术报告](https://arxiv.org/abs/2206.03001v2) 👉[中文简洁版](./PP-OCRv3_introduction.md) diff --git a/doc/doc_ch/quickstart.md b/doc/doc_ch/quickstart.md index e425cdd8a87d320554e61c72e05001875d022e43..997ead3e773a20a5fd2cea4fc10a98ad35e1a05a 100644 --- a/doc/doc_ch/quickstart.md +++ b/doc/doc_ch/quickstart.md @@ -201,3 +201,7 @@ im_show.save('result.jpg') 通过本节内容,相信您已经熟练掌握PaddleOCR whl包的使用方法并获得了初步效果。 PaddleOCR是一套丰富领先实用的OCR工具库,打通数据、模型训练、压缩和推理部署全流程,您可以参考[文档教程](../../README_ch.md#文档教程),正式开启PaddleOCR的应用之旅。 + + +trackgit-views + diff --git a/doc/doc_ch/recognition.md b/doc/doc_ch/recognition.md index 8457df69ff4c09b196b0f0f91271a92344217d75..52cef725d22903742e03c48b6e6972879c8ad2fe 100644 --- a/doc/doc_ch/recognition.md +++ b/doc/doc_ch/recognition.md @@ -550,4 +550,4 @@ inference/en_PP-OCRv3_rec/ Q1: 训练模型转inference 模型之后预测效果不一致? -**A**:此类问题出现较多,问题多是trained model预测时候的预处理、后处理参数和inference model预测的时候的预处理、后处理参数不一致导致的。可以对比训练使用的配置文件中的预处理、后处理和预测时是否存在差异。 +**A**:此类问题出现较多,问题多是trained model预测时候的预处理、后处理参数和inference model预测的时候的预处理、后处理参数不一致导致的。可以对比训练使用的配置文件中的预处理、后处理和预测时是否存在差异。更多内容请参考[FAQ](./FAQ.md#210-%E6%A8%A1%E5%9E%8B%E6%95%88%E6%9E%9C%E4%B8%8E%E6%95%88%E6%9E%9C%E4%B8%8D%E4%B8%80%E8%87%B4). diff --git a/doc/doc_ch/update.md b/doc/doc_ch/update.md index 07591ea126f5b168389657141673142c084e67ad..7851be62ddf22373e5e88b538f4e3d3605ee2461 100644 --- a/doc/doc_ch/update.md +++ b/doc/doc_ch/update.md @@ -4,8 +4,7 @@ - 半自动标注工具[PPOCRLabelv2](../../PPOCRLabel):新增表格文字图像、图像关键信息抽取任务和不规则文字图像的标注功能; - OCR产业落地工具集:打通22种训练部署软硬件环境与方式,覆盖企业90%的训练部署环境需求 - 交互式OCR开源电子书[《动手学OCR》](./ocr_book.md),覆盖OCR全栈技术的前沿理论与代码实践,并配套教学视频。 -- 2022.5.7 添加对[Weights & Biases](https://docs.wandb.ai/)训练日志记录工具的支持。 -- 2021.12.21 《OCR十讲》课程开讲,12月21日起每晚八点半线上授课! 【免费】报名地址:https://aistudio.baidu.com/aistudio/course/introduce/25207 +- 2021.12.21 《动手学OCR·十讲》课程开讲,12月21日起每晚八点半线上授课! 【免费】[报名地址](https://aistudio.baidu.com/aistudio/course/introduce/25207)。 - 2021.12.21 发布PaddleOCR v2.4。OCR算法新增1种文本检测算法(PSENet),3种文本识别算法(NRTR、SEED、SAR);文档结构化算法新增1种关键信息提取算法(SDMGR),3种DocVQA算法(LayoutLM、LayoutLMv2,LayoutXLM)。 - 2021.9.7 发布PaddleOCR v2.3,发布[PP-OCRv2](#PP-OCRv2),CPU推理速度相比于PP-OCR server提升220%;效果相比于PP-OCR mobile 提升7%。 - 2021.8.3 发布PaddleOCR v2.2,新增文档结构分析[PP-Structure](https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.2/ppstructure/README_ch.md)工具包,支持版面分析与表格识别(含Excel导出)。 @@ -29,7 +28,7 @@ - 2020.7.9 添加支持空格的识别模型,识别效果,预测及训练方式请参考快速开始和文本识别训练相关文档 - 2020.7.9 添加数据增强、学习率衰减策略,具体参考[配置文件](./config.md) - 2020.6.8 添加[数据集](dataset/datasets.md),并保持持续更新 -- 2020.6.5 支持 `attetnion` 模型导出 `inference_model` +- 2020.6.5 支持 `attention` 模型导出 `inference_model` - 2020.6.5 支持单独预测识别时,输出结果得分 - 2020.5.30 提供超轻量级中文OCR在线体验 - 2020.5.30 模型预测、训练支持Windows系统 diff --git a/doc/doc_en/PP-OCRv3_introduction_en.md b/doc/doc_en/PP-OCRv3_introduction_en.md index c6599e48099a4e9443dced4a37919642ab26467a..815ad9b0e5a7ff2dec36ceaef995212d122a9f89 100644 --- a/doc/doc_en/PP-OCRv3_introduction_en.md +++ b/doc/doc_en/PP-OCRv3_introduction_en.md @@ -101,7 +101,7 @@ Considering that the features of some channels will be suppressed if the convolu The recognition module of PP-OCRv3 is optimized based on the text recognition algorithm [SVTR](https://arxiv.org/abs/2205.00159). RNN is abandoned in SVTR, and the context information of the text line image is more effectively mined by introducing the Transformers structure, thereby improving the text recognition ability. -The recognition accuracy of SVTR_inty outperforms PP-OCRv2 recognition model by 5.3%, while the prediction speed nearly 11 times slower. It takes nearly 100ms to predict a text line on CPU. Therefore, as shown in the figure below, PP-OCRv3 adopts the following six optimization strategies to accelerate the recognition model. +The recognition accuracy of SVTR_tiny outperforms PP-OCRv2 recognition model by 5.3%, while the prediction speed nearly 11 times slower. It takes nearly 100ms to predict a text line on CPU. Therefore, as shown in the figure below, PP-OCRv3 adopts the following six optimization strategies to accelerate the recognition model.
@@ -200,7 +200,7 @@ UDML (Unified-Deep Mutual Learning) is a strategy proposed in PP-OCRv2 which is **(6)UIM:Unlabeled Images Mining** -UIM (Unlabeled Images Mining) is a very simple unlabeled data mining strategy. The main idea is to use a high-precision text recognition model to predict unlabeled images to obtain pseudo-labels, and select samples with high prediction confidence as training data for training lightweight models. Using this strategy, the accuracy of the recognition model is further improved to 79.4% (+1%). +UIM (Unlabeled Images Mining) is a very simple unlabeled data mining strategy. The main idea is to use a high-precision text recognition model to predict unlabeled images to obtain pseudo-labels, and select samples with high prediction confidence as training data for training lightweight models. Using this strategy, the accuracy of the recognition model is further improved to 79.4% (+1%). In practice, we use the full data set to train the high-precision SVTR_Tiny model (acc=82.5%) for data mining. [SVTR_Tiny model download and tutorial](../../applications/高精度中文识别模型.md).
diff --git a/doc/doc_en/detection_en.md b/doc/doc_en/detection_en.md index 76e0f8509b92dfaae62dce7ba2b4b73d39da1600..8972581009fffabab815501521a2978f49b7692e 100644 --- a/doc/doc_en/detection_en.md +++ b/doc/doc_en/detection_en.md @@ -51,7 +51,7 @@ python3 tools/train.py -c configs/det/det_mv3_db.yml \ -o Global.pretrained_model=./pretrain_models/MobileNetV3_large_x0_5_pretrained ``` -In the above instruction, use `-c` to select the training to use the `configs/det/det_db_mv3.yml` configuration file. +In the above instruction, use `-c` to select the training to use the `configs/det/det_mv3_db.yml` configuration file. For a detailed explanation of the configuration file, please refer to [config](./config_en.md). You can also use `-o` to change the training parameters without modifying the yml file. For example, adjust the training learning rate to 0.0001 diff --git a/doc/doc_en/inference_ppocr_en.md b/doc/doc_en/inference_ppocr_en.md index 935f92f5144f582630a45edcc886b609ecdc82da..0f57b0ba6b226c19ecb1e0b60afdfa34302b8e78 100755 --- a/doc/doc_en/inference_ppocr_en.md +++ b/doc/doc_en/inference_ppocr_en.md @@ -8,7 +8,8 @@ This article introduces the use of the Python inference engine for the PP-OCR mo - [Text Detection Model Inference](#text-detection-model-inference) - [Text Recognition Model Inference](#text-recognition-model-inference) - [1. Lightweight Chinese Recognition Model Inference](#1-lightweight-chinese-recognition-model-inference) - - [2. Multilingual Model Inference](#2-multilingual-model-inference) + - [2. English Recognition Model Inference](#2-english-recognition-model-inference) + - [3. Multilingual Model Inference](#3-multilingual-model-inference) - [Angle Classification Model Inference](#angle-classification-model-inference) - [Text Detection Angle Classification and Recognition Inference Concatenation](#text-detection-angle-classification-and-recognition-inference-concatenation) @@ -76,10 +77,31 @@ After executing the command, the prediction results (recognized text and score) ```bash Predicts of ./doc/imgs_words_en/word_10.png:('PAIN', 0.988671) ``` + +### 2. English Recognition Model Inference - +For English recognition model inference, you can execute the following commands,you need to specify the dictionary path used by `--rec_char_dict_path`: -### 2. Multilingual Model Inference +``` +# download en model: +wget https://paddleocr.bj.bcebos.com/PP-OCRv3/english/en_PP-OCRv3_det_infer.tar +tar xf en_PP-OCRv3_det_infer.tar +python3 tools/infer/predict_rec.py --image_dir="./doc/imgs_words/en/word_1.png" --rec_model_dir="./en_PP-OCRv3_det_infer/" --rec_char_dict_path="ppocr/utils/en_dict.txt" +``` + +![](../imgs_words/en/word_1.png) + + +After executing the command, the prediction result of the above figure is: + +``` +Predicts of ./doc/imgs_words/en/word_1.png: ('JOINT', 0.998160719871521) +``` + + + + +### 3. Multilingual Model Inference If you need to predict [other language models](./models_list_en.md#Multilingual), when using inference model prediction, you need to specify the dictionary path used by `--rec_char_dict_path`. At the same time, in order to get the correct visualization results, You need to specify the visual font path through `--vis_font_path`. There are small language fonts provided by default under the `doc/fonts` path, such as Korean recognition: diff --git a/doc/doc_en/ppocr_introduction_en.md b/doc/doc_en/ppocr_introduction_en.md index b13d7f9bf1915de4bbbbec7b384d278e1d7ab8b4..5c0f6d2d7e5f82fce9a29b286a7e27b97306833a 100644 --- a/doc/doc_en/ppocr_introduction_en.md +++ b/doc/doc_en/ppocr_introduction_en.md @@ -29,10 +29,10 @@ PP-OCR pipeline is as follows: PP-OCR system is in continuous optimization. At present, PP-OCR and PP-OCRv2 have been released: -PP-OCR adopts 19 effective strategies from 8 aspects including backbone network selection and adjustment, prediction head design, data augmentation, learning rate transformation strategy, regularization parameter selection, pre-training model use, and automatic model tailoring and quantization to optimize and slim down the models of each module (as shown in the green box above). The final results are an ultra-lightweight Chinese and English OCR model with an overall size of 3.5M and a 2.8M English digital OCR model. For more details, please refer to the PP-OCR technical article (https://arxiv.org/abs/2009.09941). +PP-OCR adopts 19 effective strategies from 8 aspects including backbone network selection and adjustment, prediction head design, data augmentation, learning rate transformation strategy, regularization parameter selection, pre-training model use, and automatic model tailoring and quantization to optimize and slim down the models of each module (as shown in the green box above). The final results are an ultra-lightweight Chinese and English OCR model with an overall size of 3.5M and a 2.8M English digital OCR model. For more details, please refer to the [PP-OCR technical report](https://arxiv.org/abs/2009.09941). #### PP-OCRv2 -On the basis of PP-OCR, PP-OCRv2 is further optimized in five aspects. The detection model adopts CML(Collaborative Mutual Learning) knowledge distillation strategy and CopyPaste data expansion strategy. The recognition model adopts LCNet lightweight backbone network, U-DML knowledge distillation strategy and enhanced CTC loss function improvement (as shown in the red box above), which further improves the inference speed and prediction effect. For more details, please refer to the technical report of PP-OCRv2 (https://arxiv.org/abs/2109.03144). +On the basis of PP-OCR, PP-OCRv2 is further optimized in five aspects. The detection model adopts CML(Collaborative Mutual Learning) knowledge distillation strategy and CopyPaste data expansion strategy. The recognition model adopts LCNet lightweight backbone network, U-DML knowledge distillation strategy and enhanced CTC loss function improvement (as shown in the red box above), which further improves the inference speed and prediction effect. For more details, please refer to the [PP-OCRv2 technical report](https://arxiv.org/abs/2109.03144). #### PP-OCRv3 @@ -46,7 +46,7 @@ PP-OCRv3 pipeline is as follows:
-For more details, please refer to [PP-OCRv3 technical report](./PP-OCRv3_introduction_en.md). +For more details, please refer to [PP-OCRv3 technical report](https://arxiv.org/abs/2206.03001v2). ## 2. Features diff --git a/doc/doc_en/whl_en.md b/doc/doc_en/whl_en.md index d81e5532cf1db0193abf61b972420bdc3bacfd0b..64757ad18bbe422b7e2f60c896f600458e3ce2fd 100644 --- a/doc/doc_en/whl_en.md +++ b/doc/doc_en/whl_en.md @@ -1,4 +1,4 @@ -# Paddleocr Package +# PaddleOCR Package ## 1 Get started quickly ### 1.1 install package diff --git a/paddleocr.py b/paddleocr.py index 470dc60da3b15195bcd401aff5e50be5a2cfd13e..f6aca07ab5653b563337b000bc5eb2cce892ca6e 100644 --- a/paddleocr.py +++ b/paddleocr.py @@ -446,7 +446,7 @@ class PaddleOCR(predict_system.TextSystem): """ ocr with paddleocr args: - img: img for ocr, support ndarray, img_path and list or ndarray + img: img for ocr, support ndarray, img_path and list of ndarray det: use text detection or not. If false, only rec will be exec. Default is True rec: use text recognition or not. If false, only det will be exec. Default is True cls: use angle classifier or not. Default is True. If true, the text with rotation of 180 degrees can be recognized. If no text is rotated by 180 degrees, use cls=False to get better performance. Text with rotation of 90 or 270 degrees can be recognized even if cls=False. diff --git a/ppocr/data/imaug/__init__.py b/ppocr/data/imaug/__init__.py index 548832fb0d116ba2de622bd97562b591d74501d8..65497e63f9da03d8fc1fd1aa6baba673461ab8bc 100644 --- a/ppocr/data/imaug/__init__.py +++ b/ppocr/data/imaug/__init__.py @@ -23,7 +23,8 @@ from .random_crop_data import EastRandomCropData, RandomCropImgMask from .make_pse_gt import MakePseGt from .rec_img_aug import RecAug, RecConAug, RecResizeImg, ClsResizeImg, \ - SRNRecResizeImg, NRTRRecResizeImg, SARRecResizeImg, PRENResizeImg + SRNRecResizeImg, NRTRRecResizeImg, SARRecResizeImg, PRENResizeImg, \ + SVTRRecResizeImg from .ssl_img_aug import SSLRotateResize from .randaugment import RandAugment from .copy_paste import CopyPaste diff --git a/ppocr/data/imaug/copy_paste.py b/ppocr/data/imaug/copy_paste.py index 0b3386c896792bd670cd2bfc757eb3b80f22bac4..79343da60fd40f8dc0ffe8927398b70cb751b532 100644 --- a/ppocr/data/imaug/copy_paste.py +++ b/ppocr/data/imaug/copy_paste.py @@ -35,10 +35,12 @@ class CopyPaste(object): point_num = data['polys'].shape[1] src_img = data['image'] src_polys = data['polys'].tolist() + src_texts = data['texts'] src_ignores = data['ignore_tags'].tolist() ext_data = data['ext_data'][0] ext_image = ext_data['image'] ext_polys = ext_data['polys'] + ext_texts = ext_data['texts'] ext_ignores = ext_data['ignore_tags'] indexs = [i for i in range(len(ext_ignores)) if not ext_ignores[i]] @@ -53,7 +55,7 @@ class CopyPaste(object): src_img = cv2.cvtColor(src_img, cv2.COLOR_BGR2RGB) ext_image = cv2.cvtColor(ext_image, cv2.COLOR_BGR2RGB) src_img = Image.fromarray(src_img).convert('RGBA') - for poly, tag in zip(select_polys, select_ignores): + for idx, poly, tag in zip(select_idxs, select_polys, select_ignores): box_img = get_rotate_crop_image(ext_image, poly) src_img, box = self.paste_img(src_img, box_img, src_polys) @@ -62,6 +64,7 @@ class CopyPaste(object): for _ in range(len(box), point_num): box.append(box[-1]) src_polys.append(box) + src_texts.append(ext_texts[idx]) src_ignores.append(tag) src_img = cv2.cvtColor(np.array(src_img), cv2.COLOR_RGB2BGR) h, w = src_img.shape[:2] @@ -70,6 +73,7 @@ class CopyPaste(object): src_polys[:, :, 1] = np.clip(src_polys[:, :, 1], 0, h) data['image'] = src_img data['polys'] = src_polys + data['texts'] = src_texts data['ignore_tags'] = np.array(src_ignores) return data diff --git a/ppocr/data/imaug/label_ops.py b/ppocr/data/imaug/label_ops.py index 8b017b3219993328287d91a047e598eebaded198..c20eef2c8c4481d46fae3f9006946b7a1b5c6bda 100644 --- a/ppocr/data/imaug/label_ops.py +++ b/ppocr/data/imaug/label_ops.py @@ -23,7 +23,7 @@ import string from shapely.geometry import LineString, Point, Polygon import json import copy - +from scipy.spatial import distance as dist from ppocr.utils.logging import get_logger @@ -74,9 +74,10 @@ class DetLabelEncode(object): s = pts.sum(axis=1) rect[0] = pts[np.argmin(s)] rect[2] = pts[np.argmax(s)] - diff = np.diff(pts, axis=1) - rect[1] = pts[np.argmin(diff)] - rect[3] = pts[np.argmax(diff)] + tmp = np.delete(pts, (np.argmin(s), np.argmax(s)), axis=0) + diff = np.diff(np.array(tmp), axis=1) + rect[1] = tmp[np.argmin(diff)] + rect[3] = tmp[np.argmax(diff)] return rect def expand_points_num(self, boxes): @@ -443,7 +444,9 @@ class KieLabelEncode(object): elif 'key_cls' in ann.keys(): labels.append(ann['key_cls']) else: - raise ValueError("Cannot found 'key_cls' in ann.keys(), please check your training annotation.") + raise ValueError( + "Cannot found 'key_cls' in ann.keys(), please check your training annotation." + ) edges.append(ann.get('edge', 0)) ann_infos = dict( image=data['image'], diff --git a/ppocr/data/imaug/rec_img_aug.py b/ppocr/data/imaug/rec_img_aug.py index 7483dffe5b6d9a0a2204702757fcb49762a1cc7a..2c897dce07a7867b9dd2eed1e7b24fa046336f8c 100644 --- a/ppocr/data/imaug/rec_img_aug.py +++ b/ppocr/data/imaug/rec_img_aug.py @@ -207,6 +207,21 @@ class PRENResizeImg(object): return data +class SVTRRecResizeImg(object): + def __init__(self, image_shape, padding=True, **kwargs): + self.image_shape = image_shape + self.padding = padding + + def __call__(self, data): + img = data['image'] + + norm_img, valid_ratio = resize_norm_img(img, self.image_shape, + self.padding) + data['image'] = norm_img + data['valid_ratio'] = valid_ratio + return data + + def resize_norm_img_sar(img, image_shape, width_downsample_ratio=0.25): imgC, imgH, imgW_min, imgW_max = image_shape h = img.shape[0] diff --git a/ppocr/losses/basic_loss.py b/ppocr/losses/basic_loss.py index 2df96ea2642d10a50eb892d738f89318dc5e0f4c..a0ab10fbbaccaf6781598d5e788813d3febe07e4 100644 --- a/ppocr/losses/basic_loss.py +++ b/ppocr/losses/basic_loss.py @@ -57,17 +57,27 @@ class CELoss(nn.Layer): class KLJSLoss(object): def __init__(self, mode='kl'): assert mode in ['kl', 'js', 'KL', 'JS' - ], "mode can only be one of ['kl', 'js', 'KL', 'JS']" + ], "mode can only be one of ['kl', 'KL', 'js', 'JS']" self.mode = mode def __call__(self, p1, p2, reduction="mean"): - loss = paddle.multiply(p2, paddle.log((p2 + 1e-5) / (p1 + 1e-5) + 1e-5)) - - if self.mode.lower() == "js": + if self.mode.lower() == 'kl': + loss = paddle.multiply(p2, + paddle.log((p2 + 1e-5) / (p1 + 1e-5) + 1e-5)) loss += paddle.multiply( p1, paddle.log((p1 + 1e-5) / (p2 + 1e-5) + 1e-5)) loss *= 0.5 + elif self.mode.lower() == "js": + loss = paddle.multiply( + p2, paddle.log((2 * p2 + 1e-5) / (p1 + p2 + 1e-5) + 1e-5)) + loss += paddle.multiply( + p1, paddle.log((2 * p1 + 1e-5) / (p1 + p2 + 1e-5) + 1e-5)) + loss *= 0.5 + else: + raise ValueError( + "The mode.lower() if KLJSLoss should be one of ['kl', 'js']") + if reduction == "mean": loss = paddle.mean(loss, axis=[1, 2]) elif reduction == "none" or reduction is None: @@ -95,7 +105,7 @@ class DMLLoss(nn.Layer): self.act = None self.use_log = use_log - self.jskl_loss = KLJSLoss(mode="js") + self.jskl_loss = KLJSLoss(mode="kl") def _kldiv(self, x, target): eps = 1.0e-10 diff --git a/ppocr/losses/rec_aster_loss.py b/ppocr/losses/rec_aster_loss.py index fbb99d29a638540b02649a8912051339c08b22dd..52605e46db35339cc22f7f1e6642456bfaf02f11 100644 --- a/ppocr/losses/rec_aster_loss.py +++ b/ppocr/losses/rec_aster_loss.py @@ -27,12 +27,12 @@ class CosineEmbeddingLoss(nn.Layer): self.epsilon = 1e-12 def forward(self, x1, x2, target): - similarity = paddle.fluid.layers.reduce_sum( + similarity = paddle.sum( x1 * x2, dim=-1) / (paddle.norm( x1, axis=-1) * paddle.norm( x2, axis=-1) + self.epsilon) one_list = paddle.full_like(target, fill_value=1) - out = paddle.fluid.layers.reduce_mean( + out = paddle.mean( paddle.where( paddle.equal(target, one_list), 1. - similarity, paddle.maximum( diff --git a/ppocr/losses/table_att_loss.py b/ppocr/losses/table_att_loss.py index d7fd99e6952aacc0182a482ca5ae5ddaf959a026..51377efa2b5e802fe9f9fc1973c74deb00fc4816 100644 --- a/ppocr/losses/table_att_loss.py +++ b/ppocr/losses/table_att_loss.py @@ -19,7 +19,6 @@ from __future__ import print_function import paddle from paddle import nn from paddle.nn import functional as F -from paddle import fluid class TableAttentionLoss(nn.Layer): def __init__(self, structure_weight, loc_weight, use_giou=False, giou_weight=1.0, **kwargs): @@ -36,13 +35,13 @@ class TableAttentionLoss(nn.Layer): :param bbox:[[x1,y1,x2,y2], [x1,y1,x2,y2],,,] :return: loss ''' - ix1 = fluid.layers.elementwise_max(preds[:, 0], bbox[:, 0]) - iy1 = fluid.layers.elementwise_max(preds[:, 1], bbox[:, 1]) - ix2 = fluid.layers.elementwise_min(preds[:, 2], bbox[:, 2]) - iy2 = fluid.layers.elementwise_min(preds[:, 3], bbox[:, 3]) + ix1 = paddle.maximum(preds[:, 0], bbox[:, 0]) + iy1 = paddle.maximum(preds[:, 1], bbox[:, 1]) + ix2 = paddle.minimum(preds[:, 2], bbox[:, 2]) + iy2 = paddle.minimum(preds[:, 3], bbox[:, 3]) - iw = fluid.layers.clip(ix2 - ix1 + 1e-3, 0., 1e10) - ih = fluid.layers.clip(iy2 - iy1 + 1e-3, 0., 1e10) + iw = paddle.clip(ix2 - ix1 + 1e-3, 0., 1e10) + ih = paddle.clip(iy2 - iy1 + 1e-3, 0., 1e10) # overlap inters = iw * ih @@ -55,12 +54,12 @@ class TableAttentionLoss(nn.Layer): # ious ious = inters / uni - ex1 = fluid.layers.elementwise_min(preds[:, 0], bbox[:, 0]) - ey1 = fluid.layers.elementwise_min(preds[:, 1], bbox[:, 1]) - ex2 = fluid.layers.elementwise_max(preds[:, 2], bbox[:, 2]) - ey2 = fluid.layers.elementwise_max(preds[:, 3], bbox[:, 3]) - ew = fluid.layers.clip(ex2 - ex1 + 1e-3, 0., 1e10) - eh = fluid.layers.clip(ey2 - ey1 + 1e-3, 0., 1e10) + ex1 = paddle.minimum(preds[:, 0], bbox[:, 0]) + ey1 = paddle.minimum(preds[:, 1], bbox[:, 1]) + ex2 = paddle.maximum(preds[:, 2], bbox[:, 2]) + ey2 = paddle.maximum(preds[:, 3], bbox[:, 3]) + ew = paddle.clip(ex2 - ex1 + 1e-3, 0., 1e10) + eh = paddle.clip(ey2 - ey1 + 1e-3, 0., 1e10) # enclose erea enclose = ew * eh + eps diff --git a/ppocr/metrics/rec_metric.py b/ppocr/metrics/rec_metric.py index 515b9372e38a7213cde29fdc9834ed6df45a0a80..6a13129eddc419c4bde70cd2c5a0c018035d63cd 100644 --- a/ppocr/metrics/rec_metric.py +++ b/ppocr/metrics/rec_metric.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -import Levenshtein +from rapidfuzz.distance import Levenshtein import string @@ -45,8 +45,7 @@ class RecMetric(object): if self.is_filter: pred = self._normalize_text(pred) target = self._normalize_text(target) - norm_edit_dis += Levenshtein.distance(pred, target) / max( - len(pred), len(target), 1) + norm_edit_dis += Levenshtein.normalized_distance(pred, target) if pred == target: correct_num += 1 all_num += 1 diff --git a/ppocr/modeling/backbones/kie_unet_sdmgr.py b/ppocr/modeling/backbones/kie_unet_sdmgr.py index 545e4e7511e58c3d8220e9ec0be35474deba8806..4b1bd8030060b26acb9e60bd671a5b23d936347b 100644 --- a/ppocr/modeling/backbones/kie_unet_sdmgr.py +++ b/ppocr/modeling/backbones/kie_unet_sdmgr.py @@ -175,12 +175,7 @@ class Kie_backbone(nn.Layer): img, relations, texts, gt_bboxes, tag, img_size) x = self.img_feat(img) boxes, rois_num = self.bbox2roi(gt_bboxes) - feats = paddle.fluid.layers.roi_align( - x, - boxes, - spatial_scale=1.0, - pooled_height=7, - pooled_width=7, - rois_num=rois_num) + feats = paddle.vision.ops.roi_align( + x, boxes, spatial_scale=1.0, output_size=7, boxes_num=rois_num) feats = self.maxpool(feats).squeeze(-1).squeeze(-1) return [relations, texts, feats] diff --git a/ppocr/modeling/backbones/rec_resnet_fpn.py b/ppocr/modeling/backbones/rec_resnet_fpn.py index a7e876a2bd52a0ea70479c2009a291e4e2f8ce1f..79efd6e41e231ecad99aa4d01a8226a8550bd1ef 100644 --- a/ppocr/modeling/backbones/rec_resnet_fpn.py +++ b/ppocr/modeling/backbones/rec_resnet_fpn.py @@ -18,7 +18,6 @@ from __future__ import print_function from paddle import nn, ParamAttr from paddle.nn import functional as F -import paddle.fluid as fluid import paddle import numpy as np diff --git a/ppocr/modeling/heads/rec_srn_head.py b/ppocr/modeling/heads/rec_srn_head.py index 8d59e4711a043afd9234f430a62c9876c0a8f6f4..1070d8cd648eb686c0a2e66df092b7dc6de29c42 100644 --- a/ppocr/modeling/heads/rec_srn_head.py +++ b/ppocr/modeling/heads/rec_srn_head.py @@ -20,13 +20,11 @@ import math import paddle from paddle import nn, ParamAttr from paddle.nn import functional as F -import paddle.fluid as fluid import numpy as np from .self_attention import WrapEncoderForFeature from .self_attention import WrapEncoder from paddle.static import Program from ppocr.modeling.backbones.rec_resnet_fpn import ResNetFPN -import paddle.fluid.framework as framework from collections import OrderedDict gradient_clip = 10 diff --git a/ppocr/modeling/heads/self_attention.py b/ppocr/modeling/heads/self_attention.py index 6c27fdbe434166e9277cc8d695bce2743cbd8ec6..6e4c65e3931ae74a0fde2a16694a69fdfa69b5ed 100644 --- a/ppocr/modeling/heads/self_attention.py +++ b/ppocr/modeling/heads/self_attention.py @@ -22,7 +22,6 @@ import paddle from paddle import ParamAttr, nn from paddle import nn, ParamAttr from paddle.nn import functional as F -import paddle.fluid as fluid import numpy as np gradient_clip = 10 @@ -288,10 +287,10 @@ class PrePostProcessLayer(nn.Layer): "layer_norm_%d" % len(self.sublayers()), paddle.nn.LayerNorm( normalized_shape=d_model, - weight_attr=fluid.ParamAttr( - initializer=fluid.initializer.Constant(1.)), - bias_attr=fluid.ParamAttr( - initializer=fluid.initializer.Constant(0.))))) + weight_attr=paddle.ParamAttr( + initializer=paddle.nn.initializer.Constant(1.)), + bias_attr=paddle.ParamAttr( + initializer=paddle.nn.initializer.Constant(0.))))) elif cmd == "d": # add dropout self.functors.append(lambda x: F.dropout( x, p=dropout_rate, mode="downscale_in_infer") @@ -324,7 +323,7 @@ class PrepareEncoder(nn.Layer): def forward(self, src_word, src_pos): src_word_emb = src_word - src_word_emb = fluid.layers.cast(src_word_emb, 'float32') + src_word_emb = paddle.cast(src_word_emb, 'float32') src_word_emb = paddle.scale(x=src_word_emb, scale=self.src_emb_dim**0.5) src_pos = paddle.squeeze(src_pos, axis=-1) src_pos_enc = self.emb(src_pos) @@ -367,7 +366,7 @@ class PrepareDecoder(nn.Layer): self.dropout_rate = dropout_rate def forward(self, src_word, src_pos): - src_word = fluid.layers.cast(src_word, 'int64') + src_word = paddle.cast(src_word, 'int64') src_word = paddle.squeeze(src_word, axis=-1) src_word_emb = self.emb0(src_word) src_word_emb = paddle.scale(x=src_word_emb, scale=self.src_emb_dim**0.5) diff --git a/ppocr/postprocess/db_postprocess.py b/ppocr/postprocess/db_postprocess.py index 27b428ef2e73c9abf81d3881b23979343c8595b2..1c42cd55cd8f85dff3df90e2f5365ccde8a725f3 100755 --- a/ppocr/postprocess/db_postprocess.py +++ b/ppocr/postprocess/db_postprocess.py @@ -38,6 +38,7 @@ class DBPostProcess(object): unclip_ratio=2.0, use_dilation=False, score_mode="fast", + visual_output=False, **kwargs): self.thresh = thresh self.box_thresh = box_thresh @@ -51,6 +52,7 @@ class DBPostProcess(object): self.dilation_kernel = None if not use_dilation else np.array( [[1, 1], [1, 1]]) + self.visual = visual_output def boxes_from_bitmap(self, pred, _bitmap, dest_width, dest_height): ''' @@ -169,12 +171,19 @@ class DBPostProcess(object): cv2.fillPoly(mask, contour.reshape(1, -1, 2).astype(np.int32), 1) return cv2.mean(bitmap[ymin:ymax + 1, xmin:xmax + 1], mask)[0] + def visual_output(self, pred): + im = np.array(pred[0] * 255).astype(np.uint8) + cv2.imwrite("db_probability_map.png", im) + print("The probalibity map is visualized in db_probability_map.png") + def __call__(self, outs_dict, shape_list): pred = outs_dict['maps'] if isinstance(pred, paddle.Tensor): pred = pred.numpy() pred = pred[:, 0, :, :] segmentation = pred > self.thresh + if self.visual: + self.visual_output(pred) boxes_batch = [] for batch_index in range(pred.shape[0]): diff --git a/ppocr/utils/save_load.py b/ppocr/utils/save_load.py index b09f1db6e938e8eb99148d69efce016f1cbe8628..3647111fddaa848a75873ab689559c63dd6d4814 100644 --- a/ppocr/utils/save_load.py +++ b/ppocr/utils/save_load.py @@ -177,9 +177,9 @@ def save_model(model, model.backbone.model.save_pretrained(model_prefix) metric_prefix = os.path.join(model_prefix, 'metric') # save metric and config + with open(metric_prefix + '.states', 'wb') as f: + pickle.dump(kwargs, f, protocol=2) if is_best: - with open(metric_prefix + '.states', 'wb') as f: - pickle.dump(kwargs, f, protocol=2) logger.info('save best model is to {}'.format(model_prefix)) else: logger.info("save model in {}".format(model_prefix)) diff --git a/ppstructure/docs/kie.md b/ppstructure/docs/kie.md index 35498b33478d1010fd2548dfcb8586b4710723a1..8fd5a7921e67922b69c9da1f72f7bb514c95323a 100644 --- a/ppstructure/docs/kie.md +++ b/ppstructure/docs/kie.md @@ -19,6 +19,24 @@ SDMGR是一个关键信息提取算法,将每个检测到的文本区域分类 wget https://paddleocr.bj.bcebos.com/dygraph_v2.1/kie/wildreceipt.tar && tar xf wildreceipt.tar ``` +数据集格式: +``` +./wildreceipt +├── class_list.txt # box内的文本类别,比如金额、时间、日期等。 +├── dict.txt # 识别的字典文件,数据集中包含的字符列表 +├── wildreceipt_train.txt # 训练数据标签文件 +└── wildreceipt_test.txt # 评估数据标签文件 +└── image_files/ # 图像数据文件夹 +``` + +其中标签文件里的格式为: +``` +" 图像文件名 json.dumps编码的图像标注信息" +image_files/Image_16/11/d5de7f2a20751e50b84c747c17a24cd98bed3554.jpeg [{"label": 1, "transcription": "SAFEWAY", "points": [[550.0, 190.0], [937.0, 190.0], [937.0, 104.0], [550.0, 104.0]]}, {"label": 25, "transcription": "TM", "points": [[1048.0, 211.0], [1074.0, 211.0], [1074.0, 196.0], [1048.0, 196.0]]}, {"label": 25, "transcription": "ATOREMGRTOMMILAZZO", "points": [[535.0, 239.0], [833.0, 239.0], [833.0, 200.0], [535.0, 200.0]]}, {"label": 5, "transcription": "703-777-5833", "points": [[907.0, 256.0], [1081.0, 256.0], [1081.0, 223.0], [907.0, 223.0]]}...... +``` + +**注:如果您希望在自己的数据集上训练,建议按照上述数据个数准备数据集。** + 执行预测: ``` diff --git a/ppstructure/docs/kie_en.md b/ppstructure/docs/kie_en.md index 1fe38b0b399e9290526dafa5409673dc87026db7..e895ee88d65911f4151096f56c17c9c13af3277c 100644 --- a/ppstructure/docs/kie_en.md +++ b/ppstructure/docs/kie_en.md @@ -18,6 +18,22 @@ This section provides a tutorial example on how to quickly use, train, and evalu wget https://paddleocr.bj.bcebos.com/dygraph_v2.1/kie/wildreceipt.tar && tar xf wildreceipt.tar ``` +The dataset format are as follows: +``` +./wildreceipt +├── class_list.txt # The text category inside the box, such as amount, time, date, etc. +├── dict.txt # A recognized dictionary file, a list of characters contained in the dataset +├── wildreceipt_train.txt # training data label file +└── wildreceipt_test.txt # testing data label file +└── image_files/ # image dataset file +``` + +The format in the label file is: +``` +" The image file path Image annotation information encoded by json.dumps" +image_files/Image_16/11/d5de7f2a20751e50b84c747c17a24cd98bed3554.jpeg [{"label": 1, "transcription": "SAFEWAY", "points": [[550.0, 190.0], [937.0, 190.0], [937.0, 104.0], [550.0, 104.0]]}, {"label": 25, "transcription": "TM", "points": [[1048.0, 211.0], [1074.0, 211.0], [1074.0, 196.0], [1048.0, 196.0]]}, {"label": 25, "transcription": "ATOREMGRTOMMILAZZO", "points": [[535.0, 239.0], [833.0, 239.0], [833.0, 200.0], [535.0, 200.0]]}, {"label": 5, "transcription": "703-777-5833", "points": [[907.0, 256.0], [1081.0, 256.0], [1081.0, 223.0], [907.0, 223.0]]}...... +``` + Download the pretrained model and predict the result: ```shell diff --git a/ppstructure/table/table_metric/table_metric.py b/ppstructure/table/table_metric/table_metric.py index 9aca98ad785d4614a803fa5a277a6e4a27b3b078..923a9c0071d083de72a2a896d6f62037373d4e73 100755 --- a/ppstructure/table/table_metric/table_metric.py +++ b/ppstructure/table/table_metric/table_metric.py @@ -9,7 +9,7 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # Apache 2.0 License for more details. -import distance +from rapidfuzz.distance import Levenshtein from apted import APTED, Config from apted.helpers import Tree from lxml import etree, html @@ -39,17 +39,6 @@ class TableTree(Tree): class CustomConfig(Config): - @staticmethod - def maximum(*sequences): - """Get maximum possible value - """ - return max(map(len, sequences)) - - def normalized_distance(self, *sequences): - """Get distance from 0 to 1 - """ - return float(distance.levenshtein(*sequences)) / self.maximum(*sequences) - def rename(self, node1, node2): """Compares attributes of trees""" #print(node1.tag) @@ -58,23 +47,12 @@ class CustomConfig(Config): if node1.tag == 'td': if node1.content or node2.content: #print(node1.content, ) - return self.normalized_distance(node1.content, node2.content) + return Levenshtein.normalized_distance(node1.content, node2.content) return 0. class CustomConfig_del_short(Config): - @staticmethod - def maximum(*sequences): - """Get maximum possible value - """ - return max(map(len, sequences)) - - def normalized_distance(self, *sequences): - """Get distance from 0 to 1 - """ - return float(distance.levenshtein(*sequences)) / self.maximum(*sequences) - def rename(self, node1, node2): """Compares attributes of trees""" if (node1.tag != node2.tag) or (node1.colspan != node2.colspan) or (node1.rowspan != node2.rowspan): @@ -90,21 +68,10 @@ class CustomConfig_del_short(Config): node1_content = ['####'] if len(node2_content) < 3: node2_content = ['####'] - return self.normalized_distance(node1_content, node2_content) + return Levenshtein.normalized_distance(node1_content, node2_content) return 0. class CustomConfig_del_block(Config): - @staticmethod - def maximum(*sequences): - """Get maximum possible value - """ - return max(map(len, sequences)) - - def normalized_distance(self, *sequences): - """Get distance from 0 to 1 - """ - return float(distance.levenshtein(*sequences)) / self.maximum(*sequences) - def rename(self, node1, node2): """Compares attributes of trees""" if (node1.tag != node2.tag) or (node1.colspan != node2.colspan) or (node1.rowspan != node2.rowspan): @@ -120,7 +87,7 @@ class CustomConfig_del_block(Config): while ' ' in node2_content: print(node2_content.index(' ')) node2_content.pop(node2_content.index(' ')) - return self.normalized_distance(node1_content, node2_content) + return Levenshtein.normalized_distance(node1_content, node2_content) return 0. class TEDS(object): diff --git a/ppstructure/vqa/README.md b/ppstructure/vqa/README.md index e3a10671ddb6494eb15073e7ac007aa1e8e6a32a..3bfca3049731534aaa6799d79ec29af7f4219078 100644 --- a/ppstructure/vqa/README.md +++ b/ppstructure/vqa/README.md @@ -192,7 +192,7 @@ Finally, `precision`, `recall`, `hmean` and other indicators will be printed Use the following command to complete the series prediction of `OCR engine + SER`, taking the pretrained SER model as an example: ```shell -CUDA_VISIBLE_DEVICES=0 python3 tools/infer_vqa_token_ser.py -c configs/vqa/ser/layoutxlm.yml -o Architecture.Backbone.checkpoints=pretrain/ser_LayoutXLM_xfun_zh/Global.infer_img=doc/vqa/input/zh_val_42.jpg +CUDA_VISIBLE_DEVICES=0 python3 tools/infer_vqa_token_ser.py -c configs/vqa/ser/layoutxlm.yml -o Architecture.Backbone.checkpoints=pretrain/ser_LayoutXLM_xfun_zh/ Global.infer_img=doc/vqa/input/zh_val_42.jpg ```` Finally, the prediction result visualization image and the prediction result text file will be saved in the directory configured by the `config.Global.save_res_path` field. The prediction result text file is named `infer_results.txt`. @@ -203,7 +203,7 @@ First use the `tools/infer_vqa_token_ser.py` script to complete the prediction o ```shell export CUDA_VISIBLE_DEVICES=0 -python3 tools/eval_with_label_end2end.py --gt_json_path XFUND/zh_val/xfun_normalize_val.json --pred_json_path output_res/infer_results.txt +python3 ppstructure/vqa/tools/eval_with_label_end2end.py --gt_json_path XFUND/zh_val/xfun_normalize_val.json --pred_json_path output_res/infer_results.txt ```` @@ -247,7 +247,7 @@ Finally, `precision`, `recall`, `hmean` and other indicators will be printed Use the following command to complete the series prediction of `OCR engine + SER + RE`, taking the pretrained SER and RE models as an example: ```shell export CUDA_VISIBLE_DEVICES=0 -python3 tools/infer_vqa_token_ser_re.py -c configs/vqa/re/layoutxlm.yml -o Architecture.Backbone.checkpoints=pretrain/re_LayoutXLM_xfun_zh/Global.infer_img=doc/vqa/input/zh_val_21.jpg -c_ser configs/vqa/ser/layoutxlm. yml -o_ser Architecture.Backbone.checkpoints=pretrain/ser_LayoutXLM_xfun_zh/ +python3 tools/infer_vqa_token_ser_re.py -c configs/vqa/re/layoutxlm.yml -o Architecture.Backbone.checkpoints=pretrain/re_LayoutXLM_xfun_zh/ Global.infer_img=doc/vqa/input/zh_val_21.jpg -c_ser configs/vqa/ser/layoutxlm. yml -o_ser Architecture.Backbone.checkpoints=pretrain/ser_LayoutXLM_xfun_zh/ ```` Finally, the prediction result visualization image and the prediction result text file will be saved in the directory configured by the `config.Global.save_res_path` field. The prediction result text file is named `infer_results.txt`. diff --git a/ppstructure/vqa/README_ch.md b/ppstructure/vqa/README_ch.md index b677dc07bce6c1a752d753b6a1c538b4d3f99271..abf8e4883c25d3092baa5d1fcc86d1571d04ac93 100644 --- a/ppstructure/vqa/README_ch.md +++ b/ppstructure/vqa/README_ch.md @@ -198,7 +198,7 @@ CUDA_VISIBLE_DEVICES=0 python3 tools/infer_vqa_token_ser.py -c configs/vqa/ser/l ```shell export CUDA_VISIBLE_DEVICES=0 -python3 tools/eval_with_label_end2end.py --gt_json_path XFUND/zh_val/xfun_normalize_val.json --pred_json_path output_res/infer_results.txt +python3 ppstructure/vqa/tools/eval_with_label_end2end.py --gt_json_path XFUND/zh_val/xfun_normalize_val.json --pred_json_path output_res/infer_results.txt ``` ### 5.3 RE diff --git a/ppstructure/vqa/tools/eval_with_label_end2end.py b/ppstructure/vqa/tools/eval_with_label_end2end.py index b13ffb568fd9610fee5d5a246c501ed5b90de91a..b0fd84363f450dfb7e4ef18e53adc17ef088cf18 100644 --- a/ppstructure/vqa/tools/eval_with_label_end2end.py +++ b/ppstructure/vqa/tools/eval_with_label_end2end.py @@ -20,7 +20,7 @@ from shapely.geometry import Polygon import numpy as np from collections import defaultdict import operator -import Levenshtein +from rapidfuzz.distance import Levenshtein import argparse import json import copy diff --git a/requirements.txt b/requirements.txt index b15176db3eb42c381c1612f404fd15c6b020b3dc..976d29192abbbf89b8ee6064c0b4ec48d43ad268 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ lmdb tqdm numpy visualdl -python-Levenshtein +rapidfuzz opencv-contrib-python==4.4.0.46 cython lxml diff --git a/test_tipc/test_train_inference_python.sh b/test_tipc/test_train_inference_python.sh index fe98cb00f6cc428995d7f91db55895e0f1cd9bfd..2c9a7e73e6843921b0aba176a725aed4629c5476 100644 --- a/test_tipc/test_train_inference_python.sh +++ b/test_tipc/test_train_inference_python.sh @@ -329,6 +329,7 @@ else set_save_model=$(func_set_params "${save_model_key}" "${save_log}") if [ ${#gpu} -le 2 ];then # train with cpu or single gpu + eval ${env} cmd="${python} ${run_train} ${set_use_gpu} ${set_save_model} ${set_epoch} ${set_pretrain} ${set_autocast} ${set_batchsize} ${set_train_params1} ${set_amp_config} " elif [ ${#ips} -le 26 ];then # train with multi-gpu cmd="${python} -m paddle.distributed.launch --gpus=${gpu} ${run_train} ${set_use_gpu} ${set_save_model} ${set_epoch} ${set_pretrain} ${set_autocast} ${set_batchsize} ${set_train_params1} ${set_amp_config}" diff --git a/tools/export_model.py b/tools/export_model.py index c0cbcd361cec31c51616a7154836c234f076a86e..8ccaea2908b6e6121e0d30f2769f6e93bef49392 100755 --- a/tools/export_model.py +++ b/tools/export_model.py @@ -31,7 +31,12 @@ from ppocr.utils.logging import get_logger from tools.program import load_config, merge_config, ArgsParser -def export_single_model(model, arch_config, save_path, logger, quanter=None): +def export_single_model(model, + arch_config, + save_path, + logger, + input_shape=None, + quanter=None): if arch_config["algorithm"] == "SRN": max_text_length = arch_config["Head"]["max_text_length"] other_shape = [ @@ -64,7 +69,7 @@ def export_single_model(model, arch_config, save_path, logger, quanter=None): else: other_shape = [ paddle.static.InputSpec( - shape=[None, 3, 64, 256], dtype="float32"), + shape=[None] + input_shape, dtype="float32"), ] model = to_static(model, input_spec=other_shape) elif arch_config["algorithm"] == "PREN": @@ -76,7 +81,7 @@ def export_single_model(model, arch_config, save_path, logger, quanter=None): else: infer_shape = [3, -1, -1] if arch_config["model_type"] == "rec": - infer_shape = [3, 32, -1] # for rec model, H must be 32 + infer_shape = [3, 48, -1] # for rec model, H must be 32 if "Transform" in arch_config and arch_config[ "Transform"] is not None and arch_config["Transform"][ "name"] == "TPS": @@ -157,6 +162,13 @@ def main(): arch_config = config["Architecture"] + if arch_config["algorithm"] == "SVTR" and arch_config["Head"][ + "name"] != 'MultiHead': + input_shape = config["Eval"]["dataset"]["transforms"][-2][ + 'SVTRRecResizeImg']['image_shape'] + else: + input_shape = None + if arch_config["algorithm"] in ["Distillation", ]: # distillation model archs = list(arch_config["Models"].values()) for idx, name in enumerate(model.model_name_list): @@ -165,7 +177,8 @@ def main(): sub_model_save_path, logger) else: save_path = os.path.join(save_path, "inference") - export_single_model(model, arch_config, save_path, logger) + export_single_model( + model, arch_config, save_path, logger, input_shape=input_shape) if __name__ == "__main__": diff --git a/tools/infer/predict_det.py b/tools/infer/predict_det.py index 5f2675d667c2aab8186886a60d8d447f43419954..cf495c59c25cfe24ed0987b56cbe810579f1d542 100755 --- a/tools/infer/predict_det.py +++ b/tools/infer/predict_det.py @@ -24,6 +24,7 @@ import cv2 import numpy as np import time import sys +from scipy.spatial import distance as dist import tools.infer.utility as utility from ppocr.utils.logging import get_logger @@ -154,9 +155,10 @@ class TextDetector(object): s = pts.sum(axis=1) rect[0] = pts[np.argmin(s)] rect[2] = pts[np.argmax(s)] - diff = np.diff(pts, axis=1) - rect[1] = pts[np.argmin(diff)] - rect[3] = pts[np.argmax(diff)] + tmp = np.delete(pts, (np.argmin(s), np.argmax(s)), axis=0) + diff = np.diff(np.array(tmp), axis=1) + rect[1] = tmp[np.argmin(diff)] + rect[3] = tmp[np.argmax(diff)] return rect def clip_det_res(self, points, img_height, img_width): diff --git a/tools/infer/predict_system.py b/tools/infer/predict_system.py index 625d365f45c578d051974d7174e26246e9bc2442..1fac2918a15c8b1b858b83d032ecfd889679e6f9 100755 --- a/tools/infer/predict_system.py +++ b/tools/infer/predict_system.py @@ -114,11 +114,14 @@ def sorted_boxes(dt_boxes): _boxes = list(sorted_boxes) for i in range(num_boxes - 1): - if abs(_boxes[i + 1][0][1] - _boxes[i][0][1]) < 10 and \ - (_boxes[i + 1][0][0] < _boxes[i][0][0]): - tmp = _boxes[i] - _boxes[i] = _boxes[i + 1] - _boxes[i + 1] = tmp + for j in range(i, 0, -1): + if abs(_boxes[j + 1][0][1] - _boxes[j][0][1]) < 10 and \ + (_boxes[j + 1][0][0] < _boxes[j][0][0]): + tmp = _boxes[j] + _boxes[j] = _boxes[j + 1] + _boxes[j + 1] = tmp + else: + break return _boxes @@ -135,7 +138,7 @@ def main(args): logger.info("In PP-OCRv3, rec_image_shape parameter defaults to '3, 48, 320', " "if you are using recognition model with PP-OCRv2 or an older version, please set --rec_image_shape='3,32,320") - + # warm up 10 times if args.warmup: img = np.random.uniform(0, 255, [640, 640, 3]).astype(np.uint8) @@ -198,7 +201,12 @@ def main(args): text_sys.text_detector.autolog.report() text_sys.text_recognizer.autolog.report() - with open(os.path.join(draw_img_save_dir, "system_results.txt"), 'w', encoding='utf-8') as f: + if args.total_process_num > 1: + save_results_path = os.path.join(draw_img_save_dir, f"system_results_{args.process_id}.txt") + else: + save_results_path = os.path.join(draw_img_save_dir, "system_results.txt") + + with open(save_results_path, 'w', encoding='utf-8') as f: f.writelines(save_results) diff --git a/tools/infer/utility.py b/tools/infer/utility.py index d27aec63edd2fb5c0240ff0254ce1057b62162b0..6d9935a70e79bb20c5f6380783911ef141b0be17 100644 --- a/tools/infer/utility.py +++ b/tools/infer/utility.py @@ -55,6 +55,7 @@ def init_args(): parser.add_argument("--max_batch_size", type=int, default=10) parser.add_argument("--use_dilation", type=str2bool, default=False) parser.add_argument("--det_db_score_mode", type=str, default="fast") + parser.add_argument("--vis_seg_map", type=str2bool, default=False) # EAST parmas parser.add_argument("--det_east_score_thresh", type=float, default=0.8) parser.add_argument("--det_east_cover_thresh", type=float, default=0.1) @@ -276,6 +277,7 @@ def create_predictor(args, mode, logger): min_input_shape = {"x": [1, 3, imgH, 10]} max_input_shape = {"x": [args.rec_batch_num, 3, imgH, 2304]} opt_input_shape = {"x": [args.rec_batch_num, 3, imgH, 320]} + config.exp_disable_tensorrt_ops(["transpose2"]) elif mode == "cls": min_input_shape = {"x": [1, 3, 48, 10]} max_input_shape = {"x": [args.rec_batch_num, 3, 48, 1024]} @@ -587,7 +589,7 @@ def text_visual(texts, def base64_to_cv2(b64str): import base64 data = base64.b64decode(b64str.encode('utf8')) - data = np.fromstring(data, np.uint8) + data = np.frombuffer(data, np.uint8) data = cv2.imdecode(data, cv2.IMREAD_COLOR) return data diff --git a/tools/infer_kie.py b/tools/infer_kie.py index 0cb0b8702cbd7ea74a7b7fcff69122731578a1bd..187b27adb20aec6418f7c32a09c15cefcbbcd29d 100755 --- a/tools/infer_kie.py +++ b/tools/infer_kie.py @@ -89,6 +89,29 @@ def draw_kie_result(batch, node, idx_to_cls, count): cv2.imwrite(save_path, vis_img) logger.info("The Kie Image saved in {}".format(save_path)) +def write_kie_result(fout, node, data): + """ + Write infer result to output file, sorted by the predict label of each line. + The format keeps the same as the input with additional score attribute. + """ + import json + label = data['label'] + annotations = json.loads(label) + max_value, max_idx = paddle.max(node, -1), paddle.argmax(node, -1) + node_pred_label = max_idx.numpy().tolist() + node_pred_score = max_value.numpy().tolist() + res = [] + for i, label in enumerate(node_pred_label): + pred_score = '{:.2f}'.format(node_pred_score[i]) + pred_res = { + 'label': label, + 'transcription': annotations[i]['transcription'], + 'score': pred_score, + 'points': annotations[i]['points'], + } + res.append(pred_res) + res.sort(key=lambda x: x['label']) + fout.writelines([json.dumps(res, ensure_ascii=False) + '\n']) def main(): global_config = config['Global'] @@ -116,7 +139,7 @@ def main(): warmup_times = 0 count_t = [] - with open(save_res_path, "wb") as fout: + with open(save_res_path, "w") as fout: with open(config['Global']['infer_img'], "rb") as f: lines = f.readlines() for index, data_line in enumerate(lines): @@ -141,6 +164,8 @@ def main(): node = F.softmax(node, -1) count_t.append(time.time() - st) draw_kie_result(batch, node, idx_to_cls, index) + write_kie_result(fout, node, data) + fout.close() logger.info("success!") logger.info("It took {} s for predict {} images.".format( np.sum(count_t), len(count_t)))