摘要:本案例我们利用视频字幕识别中的文字检测与识别模型,增加预训练Bert进行纠错

本文分享自华为云社区《Bert特调OCR》,作者:杜甫盖房子。

做这个项目的初衷是发现图比较糊/检测框比较长的时候,OCR会有一些错误识别,所以想对识别结果进行纠错。一个很自然的想法是利用语义信息进行纠错,其实在OCR训练时加入语义信息也有不少工作,感兴趣的朋友可以了解一下,为了更大程度复用已有的项目,我们决定保留现有OCR单元,在之后加入独立语义纠错模块进行纠错。

本案例我们利用视频字幕识别中的文字检测与识别模型,增加预训练Bert进行纠错,最终效果如下:

我们使用ModelBox Windows SDK进行开发,如果还没有安装SDK,可以参考ModelBox端云协同AI开发套件(Windows)设备注册篇ModelBox端云协同AI开发套件(Windows)SDK安装篇完成设备注册与SDK安装。

技能开发

这个应用对应的ModelBox版本已经做成模板放在华为云OBS中,可以用sdk中的solution.bat工具下载,接下来我们给出该应用在ModelBox中的完整开发过程:

1)下载模板

执行.\solution.bat -l可看到当前公开的技能模板:

  1. ███@DESKTOP-UUVFMTP MINGW64 /d/DEMO/modelbox-win10-x64-1.5.1
  2. $ ./solution.bat -l
  3. start download desc.json
  4. 3942.12KB/S, percent=100.00%
  5. Solutions name:
  6. mask_det_yolo3
  7. ...
  8. doc_ocr_db_crnn_bert

结果中的doc_ocr_db_crnn_bert即为文档识别应用模板,下载模板:

  1. ███@DESKTOP-UUVFMTP MINGW64 /d/DEMO/modelbox-win10-x64-1.5.1
  2. $ ./solution.bat -s doc_ocr_db_crnn_bert
  3. ...

solution.bat工具的参数中,-l 代表list,即列出当前已有的模板名称;-s 代表solution-name,即下载对应名称的模板。下载下来的模板资源,将存放在ModelBox核心库的solution目录下。

2)创建工程

ModelBox sdk目录下使用create.bat创建doc_ocr工程

  1. ███@DESKTOP-UUVFMTP MINGW64 /d/DEMO/modelbox-win10-x64-1.5.1
  2. $ ./create.bat -t server -n doc_ocr -s doc_ocr_db_crnn_bert
  3. sdk version is modelbox-win10-x64-1.5.1
  4. success: create doc_ocr in D:\DEMO\modelbox-win10-x64-1.5.1\workspace

create.bat工具的参数中,-t 表示创建事务的类别,包括工程(server)、Python功能单元(Python)、推理功能单元(infer)等;-n 代表name,即创建事务的名称;-s 代表solution-name,表示将使用后面参数值代表的模板创建工程,而不是创建空的工程。

workspace目录下将创建出doc_ocr工程,工程内容如下所示:

  1. doc_ocr
  2. |--bin
  3. |--main.bat:应用执行入口
  4. |--mock_task.toml:应用在本地执行时的输入输出配置,此应用为http服务
  5. |--CMake:存放一些自定义CMake函数
  6. |--data:存放应用运行所需要的图片、视频、文本、配置等数据
  7. |--char_meta.txt:字形拆解文件,用来计算字形相似度
  8. |--character_keys.txtOCR算法的字符集合
  9. |--GB2312.ttf:中文字体文件
  10. |--test_http.py:应用测试脚本
  11. |--text.jpg:应用测试图片
  12. |--vocab.txttokenizer配置文件
  13. |--dependence
  14. |--modelbox_requirements.txt:应用运行依赖的外部库在此文件定义,本应用依赖pyclipperShapelypillow等工具包
  15. |--etc
  16. |--flowunit:应用所需的功能单元存放在此目录
  17. |--cpp:存放C++功能单元编译后的动态链接库,此应用没有C++功能单元
  18. |--bert_preprocessbert预处理功能单元,条件功能单元,判断是否需要纠错
  19. |--collapse_position:归拢单句纠错结果
  20. |--collapse_sentence:归拢全文纠错结果
  21. |--det_post:文字检测后处理功能单元
  22. |--draw_ocrocr结果绘制功能单元
  23. |--expand_img:展开功能单元,展开文字检测结果
  24. |--expand_position:展开功能单元,展开bert预处理结果
  25. |--match_position:匹配纠错结果
  26. |--ocr_postocr后处理功能单元
  27. |--flowunit_cpp:存放C++功能单元的源代码,此应用没有C++功能单元
  28. |--graph:存放流程图
  29. |--doc_ocr.toml:默认流程图,http服务
  30. |--modelbox.confmodelbox相关配置
  31. |--hilens_data_dir:存放应用输出的结果文件、日志、性能统计信息
  32. |--model:推理功能单元目录
  33. |--bertBert推理功能能单元
  34. |--bert.toml:语义推理配置文件
  35. |--bert.onnx:语义推理模型
  36. |--det:文字检测推理功能单元
  37. |--det.toml:文字检测推理功能单元的配置文件
  38. |--det.onnx:文字检测onnx模型
  39. |--ocr:文字识别推理功能单元
  40. |--ocr.toml:文字识别推理功能单元的配置文件
  41. |--ocr.onnx:文字识别onnx模型
  42. |--build_project.sh:应用构建脚本
  43. |--CMakeLists.txt
  44. |--rpm:打包rpm时生成的目录,将存放rpm包所需数据
  45. |--rpm_copyothers.shrpm打包时的辅助脚本

3)查看流程图

doc_ocr工程graph目录下存放流程图,默认的流程图doc_ocr.toml与工程同名,将流程图可视化:

图示中,灰色部分为预置功能单元,其余颜色为我们实现的功能单元,其中绿色为一般通用功能单元,红色为推理功能单元,蓝色为条件功能单元,黄色为展开归拢功能单元。HTTP接收图解码后做预处理,接着是文字检测,模型后处理得到检测框,经过条件功能判断,检测到文字的图送入展开功能单元,切图进行文字识别,文字识别结果送入bert预处理单元判断是否需要进行纠错,如需纠错则再展开并行进行语义推理,不需要纠错的就直接进行结果绘制并返回。而未检测到文字的帧则直接返回。

4)核心逻辑

本应用核心逻辑中的文字检测与识别可以参考【ModelBox OCR实战营】视频字幕识别中的相关介绍,本文重点介绍文字纠错部分。

首先查看纠错预处理功能单元bert_preprocess

  1. def process(self, data_context):
  2. in_feat = data_context.input("in_feat")
  3. out_feat = data_context.output("out_feat")
  4. out_bert = data_context.output("out_bert")
  5.  
  6. for buffer_feat in in_feat:
  7. ocr_data = json.loads(buffer_feat.as_object())['ocr_result']
  8. score_data = json.loads(json.loads(buffer_feat.as_object())['result_score'])
  9.  
  10. text_to_process = []
  11. text_to_pass = []
  12. err_positions = []
  13. for i, (sent, p) in enumerate(zip(ocr_data, score_data)):
  14. if not do_correct_filter(sent, self.max_seq_length):
  15. text_to_pass.append((i, sent))
  16. else:
  17. err_pos = find_err_pos_by_prob(p, self.prob_threshold)
  18. if not err_pos:
  19. text_to_pass.append((i, sent))
  20. else:
  21. text_to_process.append(sent)
  22. err_positions.append(err_pos)
  23. if not text_to_process:
  24. out_feat.push_back(buffer_feat)
  25. else:
  26. out_dict = []
  27. texts_numfree = [self.number.sub(lambda m: self.rep[re.escape(m.group(0))], s) for s in text_to_process]
  28. err_positions = check_error_positions(texts_numfree, err_positions)
  29. if err_positions is None:
  30. err_positions = [range(len(d)) for d in texts_numfree]
  31. batch_data = BatchData(texts_numfree, err_positions, self.tokenizer, self.max_seq_length)
  32. input_ids, input_mask, segment_ids, masked_lm_positions = batch_data.data
  33. ...
  34. return modelbox.Status.StatusCode.STATUS_SUCCESS

预处理单元对通过do_correct_filter函数对OCR结果进行判断,只对大于3个字的中文字符进行纠错:

  1. def do_correct_filter(text, max_seq_length):
  2. if re.search(re.compile(r'[a-zA-ZA-Za-z]'), text):
  3. return False
  4. if len(re.findall(re.compile(r'[\u4E00-\u9FA5]'), text)) < 3:
  5. return False
  6. if len(text) > max_seq_length - 2:
  7. return False
  8. return True

通过find_err_pos_by_prob函数定位需要纠错的字符,只对OCR置信度小于阈值的字符进行纠错:

  1. def find_err_pos_by_prob(prob, prob_threshold):
  2. if not prob:
  3. return []
  4. err_pos = [i for i, p in enumerate(prob) if p < prob_threshold]
  5. return err_pos

如有需要纠错的字符,则将该句编码,进行语义推理。

语义推理后,通过collapse_position对推理结果进行解码,在match_position功能单元中使用shape_similarity函数计算语义推理结果与OCR结果的字符相似度:

  1. def shape_similarity(self, char1, char2):
  2. decomp1 = self.decompose_text(char1)
  3. decomp2 = self.decompose_text(char2)
  4. similarity = 0.0
  5. ed = edit_distance(safe_encode_string(decomp1), safe_encode_string(decomp2))
  6. normalized_ed = ed / max(len(decomp1), len(decomp2), 1)
  7. similarity = max(similarity, 1 - normalized_ed)
  8. return similarity

其中,decompose_text函数将单个汉字编码为笔划级别的IDS,如:

华: ⿱⿰⿰丿丨⿻乚丿⿻一丨


  1. +----+
  2. | |
  3. +----+

  4. +----+ +----+
  5. | | | |
  6. +----+ +----+

  7. +----+ +----+
  8. | | | |
  9. +----+ +----+
  10. 丿 丿

计算语义推理结果字符与原OCR结果字符相似度之后,综合语义推理置信度与相似度判断是否接收纠错结果:

  1. def accept_correct(self, confidence, similarity):
  2. if confidence + similarity >= self.all_conf \
  3. and confidence >= self.confidence_conf \
  4. and similarity >= self.similarity_conf:
  5. return True
  6. return False

5)三方依赖库

本应用依赖pyclipper、Shapely、pillow等工具包,ModelBox应用不需要手动安装三方依赖库,只需要配置在dependence\modelbox_requirements.txt,应用在编译时会自动安装。

技能运行

在项目目录下执行.\bin\main.bat运行应用,为了方便观察纠错结果,我们将日志切换为info:

  1. ███@DESKTOP-UUVFMTP MINGW64 /d/DEMO/modelbox-win10-x64-1.5.1/workspace/doc_ocr
  2. $ ./bin/main.bat default info
  3. ...
  4. [2022-12-27 15:20:40,043][ INFO][httpserver_sync_receive.cc:188 ] Start server at http://0.0.0.0:8083/v1/ocr_bert

另起终端,进入项目data目录下,运行test_http.py脚本进行测试:

  1. ███@DESKTOP-UUVFMTP MINGW64 /d/DEMO/modelbox-win10-x64-1.5.1/workspace/doc_ocr/data
  2. $ python test_http.py

可以在技能运行日志中观察到接受的纠错结果:

  1. [2022-12-27 15:22:40,700][ INFO][match_position\match_position.py:51 ] confidence: 0.99831665, similarity: 0.6470588235294117, ->

同时,在data目录下可以看到应用返回的结果图片:

点击关注,第一时间了解华为云新鲜技术~

基于OCR进行Bert独立语义纠错实践的更多相关文章

  1. 字节跳动流式数据集成基于Flink Checkpoint两阶段提交的实践和优化

    背景 字节跳动开发套件数据集成团队(DTS ,Data Transmission Service)在字节跳动内基于 Flink 实现了流批一体的数据集成服务.其中一个典型场景是 Kafka/ByteM ...

  2. 基于nginx+lua+redis高性能api应用实践

    基于nginx+lua+redis高性能api应用实践 前言 比较传统的服务端程序(PHP.FAST CGI等),大多都是通过每产生一个请求,都会有一个进程与之相对应,请求处理完毕后相关进程自动释放. ...

  3. QCon技术干货:个推基于Docker和Kubernetes的微服务实践

    2016年伊始,Docker无比兴盛,如今Kubernetes万人瞩目.在这个无比需要创新与速度的时代,由容器.微服务.DevOps构成的云原生席卷整个IT界.在近期举办的QCon全球软件开发大会上, ...

  4. 基于 Apache Hudi 极致查询优化的探索实践

    摘要:本文主要介绍 Presto 如何更好的利用 Hudi 的数据布局.索引信息来加速点查性能. 本文分享自华为云社区<华为云基于 Apache Hudi 极致查询优化的探索实践!>,作者 ...

  5. atitit.基于http json api 接口设计 最佳实践 总结o7

    atitit.基于http  json  api 接口设计 最佳实践 总结o7 1. 需求:::服务器and android 端接口通讯 2 2. 接口开发的要点 2 2.1. 普通参数 meth,p ...

  6. 基于OCR的SeeTest框架可行性分析总结

    总的来说相比其他几个免费框架,SeeTest功能更全面和易用,但收费有点昂贵:License 3500/年:多平台和多语言(基于OCR)还需要额外购买,分别是500/Year和1750$/.详情请查看 ...

  7. DCOS实践分享(3):基于Mesos 和 Docker 企业级移动应用实践分享

    2016年1月24日 8:00—19:00 北京万豪酒店(东城区建国门南大街7号) @Container大会是由国内容器社区DockOne组织的专为一线开发者和运维工程师设计的顶级容器技术会议,会议强 ...

  8. 基于Armitage的MSF自动化集成攻击实践

    基于Armitage的MSF自动化集成攻击实践 目录 0x01 实践环境 0x02 预备知识 0x03 Armitage基础配置 0x04 Nmap:Armitage下信息搜集与漏洞扫描 0x05 A ...

  9. 基于vue2.0打造移动商城页面实践 vue实现商城购物车功能 基于Vue、Vuex、Vue-router实现的购物商城(原生切换动画)效果

    基于vue2.0打造移动商城页面实践 地址:https://www.jianshu.com/p/2129bc4d40e9 vue实现商城购物车功能 地址:http://www.jb51.net/art ...

  10. 基于 Spring Cloud 的微服务架构实践指南(下)

    show me the code and talk to me,做的出来更要说的明白 本文源码,请点击learnSpringCloud 我是布尔bl,你的支持是我分享的动力! 一.引入 上回 基于 S ...

随机推荐

  1. Transformer_Detection-(DETR) 引入视觉领域的首创DETR (ECCV2020)

    End-to-End Object Detection with Transformers paper: https://link.zhihu.com/?target=https%3A//arxiv. ...

  2. Verilog中端口的连接规则

    摘自于(15条消息) Verilog中端口应该设置为wire形还是reg形_CLL_caicai的博客-CSDN博客, 以及(15条消息) Verilog端口连接规则_「已注销」的博客-CSDN博客_ ...

  3. Flowable 中文文档

    中文文档:https://tkjohn.github.io/flowable-userguide/#bpmnInclusiveGatewayGraphicalNotation

  4. Ubuntu系统设置普通用户最大文件打开数

    背景: Elasticsearch启动报错: ERROR:  bootstrap checks failedmax file descriptors [4096] for elasticsearch ...

  5. linux 获取文件名

    https://blog.csdn.net/liuyuedechuchu/article/details/123778605

  6. C Ⅷ

    数组  int number[100];   //这个数组可以放100个数 int x; int cnt = 0; double sum = 0; scanf("%d", & ...

  7. 关与python面向对象的认识

    面向对象编程 类:从一堆对象中以抽象的方式把相同的特征归类得到. 抽象类 类 实列 子类抽象为父类,子类继承父类特征. 类实例化为实例,实例抽象为类. class Human(object): cen ...

  8. vue3-使用百度地图遇到的坑-地图实例化

    1.创建地图实例 原因:在使用vue3为了只定义一次地图实例,在所有方法中使用,直接使用如下定义方式: setup() { const data = reactive({ bmap: null,}) ...

  9. 手写深度比较isEqual函数

    function isObject(obj){ return typeof obj ==='object'&&obj!==null } functon isEqual(obj1,obj ...

  10. vue自动展示一、二级路由

    在vue项目中使用路由可以很方便的跳转要显示的页面 在初始页面当中,首先要显示的路由怎么实现呢? 只需要在index.js页面中存放路由的children:[...]最后加上 redirect:&qu ...