宜信OCR技术探索与实践|直播速记
时间:2022-07-22
本文章向大家介绍宜信OCR技术探索与实践|直播速记,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
分享实录
一、OCR概述
1.1 OCR技术演进
- 传统图像,冈萨雷斯的图像处理。
- 信号处理、频域分析以及各类算法:SIFT、HOG、HOUGH、Harris、Canny…都很赞。
- 从2016年以后业界基本上都已经转向深度了,因为效果真的特别好。
1.2 OCR技术商业服务
- 身份证卡证类相对容易些,但是要做到复杂场景的,也不是那么容易。
- 发票、业务单据相对复杂,除了识别,更重要的是版面分析。
- 最近表格识别比较火,各家都在努力实现,微软的开放tablebank数据集
- 移动端backboneMobileNet,或者是tesseract+opencv
二、我们的业务场景
2.1 业务需求
满足业务是第一需要,不同于大厂,对外服务API,要求大并发那么强,多样性品类完备,我们更强调单品要做到尽量达到业务要求,更强调定制化,可以分布走,业务上可以给反馈不断改进。
2.2 识别过程中需要解决的问题
三、OCR算法详解
3.1 算法概述——分享原则
大家一定要自己弄细节,读代码、甚至自己动手撸,自己训练,调参,排错,才能有真正的体会和理解,只讲我认为每个算法里面不太好理解,重点,以及容易忽略的点,跟同行一起交流,沟通。
一个模型,要全面深入了解,需要:
- 目标、目的、意义是啥?
- 网络结构啥样?
- loss是啥?
- 样本咋做?
- 后处理干了啥
3.2 算法概述——三大板块
- 文字检测:把文字框住,缩小到最小范围内,从而降低识别难度。
- 文字识别:检测出文字后,就可以通过识别工具(算法)来识别出文字,如中间图。
- 版面分析:当文字识别出来后,我们得出的是文字和相应的坐标,可是当真正业务中要得到的不仅仅是这个,需要有一个结构,如何通过识别出的文字排版成为一个有逻辑结构的单据或者内容,这个工作也超级复杂。关于版面分析这方面,后面会有团队里面经验非常丰富的伙伴和大家分享。
3.3 算法概述——检测算法
- 表中从下往上的检测算法排序按照效果:越来越好
- 从anchorbased(也就是右边所示的最下面的那张图),现在逐渐转向pixel-based(像素级别)(右边所示的中间的那张图),主要是语义分割的技术效果实在是太好了。
CTPN:找框的一个算法。
预测最终结果是:10个anchor的y坐标偏移,和高度的调整值,还有它是不是前景的概率。输出是前后景概率N,10,2,y、w调整值N,10,2。它只适合横向,或者纵向,不能同时。
- 一个模型主要从以下几个方面理解
- 亮点和核心思路是:预测框和文本线构造算法
- loss是啥(损失函数):anchor前后景概率、y、w调整
- label怎么做:大框,弄成小框,然后正负样本均衡
- 后处理
- 算法被命名为EAST(Efficient and Accuracy Scene Text),因为它是一个高效和准确的场景文本检测pipeline。
- 首先,将图像送到FCN网络结构中并且生成单通道像素级的文本分数特征图和多通道几何图形特征图。文本区域采用了两种几何形状:旋转框(RBOX)和水平(QUAD),并为每个几何形状设计了不同的损失函数;然后,将阈值应用于每个预测区域,其中评分超过预定阈值的几何形状被认为是有效的,并且保存以用于随后的非极大抑制。NMS之后的结果被认为是pipeline的最终结果。
- 最后预测:scoremap,textbox,textrotation
- 标注是:一个蒙版mask,一个4张图,上下左右的距离,还有个角度:一共3个。
- 对应就可以出loss了。每个点预测出来,加上角度,就是1个框,太多了框,所以要做LANMS(合并算法)的合并。为何不直接用socremap,我认为是置信度不够,所以要再加上bbox来加强验证。
PSENet是一种新的实例分割网络,它有两方面的优势。首先,psenet作为一种基于分割的方法,能够对任意形状的文本进行定位.其次,该模型提出了一种渐进的尺度扩展算法,该算法可以成功地识别相邻文本实例。
- FPN,左面用resnet50。为何是resnet50,原因是效果不错,参数适中。
- 论文里是6个尺度,一个不行么?我理解是彻底分开不同行,逐渐扩大,渐进尺度可以防止彼此交叉哈
- FPN和UNET都是concat,FCN是add,这个细节。
- 使用DB模块之后,二值化操作就变成了可微的,可以加到网络里一起训练。
网络输出
- probabilitymap,代表像素点是文本的概率
- thresholdmap,每个像素点的阈值
- binarymap,由1,2计算得到,计算公式为DB公式
label制作
- probabilitymap, 按照pse的方式制作即可,收缩比例设置为0.4
- thresholdmap, 将文本框分别向内向外收缩和扩张d(根据第一步收缩时计算得到)个像素,然后计算收缩框和扩张框之间差集部分里每个像素点到原始图像边界的归一化距离。
3.4 算法概述——识别算法
- Atttenion:Attention-basedExtraction of Structured Information from Street View Imagery-2017最早的尝试
非常经典的算法,主要的核心是CTC算法:Connectionist Temporal Classification (CTC)适合那种不知道输入输出是否对齐的情况使用的算法,所以CTC适合语音识别和手写字符识别的任务。
缺点:不能精确地联系特征向量与输入图像中对应的目标区域,这种现象称为attention drift。
Muturaltraining:
- 我们知道什么?什么字符,第几个?这个信息!
- 哪个字符?找到那个字符,第几个?然后和样本里的顺序比
- 第几个是啥字符?和对应位置的字符比
- 所以样本中不能存在重复字符。
四、我们的实践
4.1 实践之路
- 非单据:宽高比,白像素比例等
- 旋转角整:前面讲过了,通过旋转模型,以及投影分布
- 多单据:多张单据在一起,通过投影,阈值超参配置
- 表格识别:采用mask-rcnn的方法,来找出大表边缘
- 后处理:通过NLP纠错,后面会详细的讲
4.2 实践之路——旋转模型
#####大方向判断
第一版:
- VGG做backbone,全连接,四分类
- 样本:人工标注、增强
- 正确率90%
第二版:
- 做切割,256x256
- 使用MSER找备选
- 训练小图
- 众数选出最可能方向
- 正确率99.7%
微调
- 每旋转1°做纵向投影
- 方差最大的角度为微调角度
4.3 我们遇到的坑
- 把crnn论文论文中的自定义cnn网络,换成resnet,但是resnet是缩小32倍,所以要拉长一些,到512。
- 首先是:样本集是1000万 (50万张,置信度单字95%+)100万真实 +100万常用字(造) + 200万数字时间英文(造)+ 600万其他汉字(造)大概需要3-4天
- 接下来进行训练:Resnet50,5-6天;Resize扩大,1024,=>512x8,256x8
过程中需要对greedy算法进行改进:
=>beam_search/merge_repeated=True
单独测是有问题,但是在置信度很高的情况下,两者差距很小,但是得到了极大的速度改进,28秒=>10秒,batch=128,size是512x32
- 因为有crnn的prob,所以纠错就有的放矢,把怀疑的字,替换成某个字,
- Prob有个细节,如果是挨着的字,“ 我 我 ”,就取最大的prob,
- 是根据一个字画相近度,对怀疑字替换的原则,是和原来识别字笔画最相近的,又是通过编辑距离。
4.4 我们的经验
1、 开发经验
2、生产经验
Tensorflow容器
- 模型部署使用官方推荐的tensorflowserving,容器方式
- 没有开启Batching,自己控制batch
- 宿主机只需要显卡驱动•容器内包含CUDA、cuDNN,免去版本适配
服务容器:
- 自己定义了Web容器基础镜像
- 自动构建容器、动态编排
本文作者:宜信技术学院 刘创
- JFinal极速开发框架使用笔记(三) 分析Model和ActiveRecord
- JFinal极速开发框架使用笔记(四) _JFinalDemoGenerator实体类生成及映射自动化
- Python语言做数据探索教程
- Java常用工具类之时间转换(注释乱码,全)
- Java常用工具类之RegexpUtils,正则表达式工具类
- 短信接口发送验证码倒计时以及提交验证
- Java常用工具类之IO流工具类
- JFinal极速开发框架使用笔记
- JavaWeb项目之电话本,两个版本,以及总结反思
- 工作中问题记录
- Java导出数据生成Excel表格
- Layui常见问题
- layui动态设置下拉框数据,根据后台数据设置选中
- BCryptPasswordEncoder加密及判断密码是否相同
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- graphSAGE的python实现
- 【python-leetcode111-树的宽度遍历】二叉树的最小深度
- 基于TypeScript封装Axios笔记(四)
- spring之泛型依赖注入
- 【python-leetcode113-树的深度遍历】路径总和Ⅱ
- spring之为什么要使用AOP(面向切面编程)?
- useContext更佳实践
- 【论文笔记】张航和李沐等提出:ResNeSt: Split-Attention Networks(ResNet改进版本)
- [前端]GOFLY项目-响应式登录页的设计和实现
- [GO] golang练习项目-gorm与mysql的增删查改操作
- 设计模式~门面模式
- c语言之define和typedef的区别
- TSINGSEE青犀视频官网全新改版即将上线,系统界面迎来整体升级
- c语言之带参数的宏定义
- spring AOP之基于xml配置文件的方式来配置AOP