cover_image

来也OCR测试系统的实践

摄影师王同学 来也技术团队
2022年11月23日 01:47


一.前言

在工业界,深度学习已经逐渐从“以模型为中心”转向“以数据驱动为中心”,绝大多数时候模型容量都可以满足要求,只需要持续增加目标场景的训练数据,就可以优化模型从而满足产品效果。“以数据驱动为中心”工作模式提升效果速度快,也可以在有限的算法工程师人力下,通过不同场景的数据就能产出不同应用模型,极大提高模型生产和迭代优化的效率。

如业界非常出名的特斯拉Autopilot数据引擎框架,就是非常典型的“数据驱动为中心”

图片

在来也最近一年里,我们逐渐也开始朝“数据驱动”的方式迈进,这种模式下,需要对数据、算法、模型、算力、推理、测试等系统有较高的集成和整合能力,而在所有环节中,测试系统对数据驱动至关重要,测试系统决定着模型是否能投产,还有指导模型优化人员如何通过数据来优化模型。

在本文中,我们将简述来也OCR测试系统一些关键设计理念和实践。

二.总览

这部分将简述我们数据驱动的流程以及测试系统设计核心需求。

在来也内部的OCR上,我们数据驱动的流程图如下

图片

流程图中实线部分代表这个环节在每次模型训练都会走到;虚线则表示这个环节有可能在某次训练中走不到(代表这次训练未产出满足生产环境的模型)

而测试系统是流程图的左下角这两个紫色的棱形块。

背景:在来也我们已经有很多的OCR能力,而在本文中我们全部以通用OCR说明,通用OCR关注的是识别字符的F1;而为了保证测试的客观性和全面性,对每个能力我们都会设置不同场景的测试集合,比如通用识别我们设置了超过80个不同场景的子测试集合。

再回到测试系统上,我们优化模型核心关注的测试结果可以从宏观和微观两个方向展开,也就是测试系统需要关注的地方,宏观上主要以量化的指标查看和对比为主,主要分为以下功能点:

  • 指标查看和筛选

  • 指标趋势变化查看

  • 指标对比查看

希望通过指标的宏观分析,就可以知道以下3个信息:

  • 这次优化效果是变好还是变化、从而决定是否发布到生产环境

  • 和历史最好版本比较那些子集合有提升和那些有下降,从下降子集合进一步分析如何优化

  • 和我们的竞品比提升多少,那些子集合不如竞品

微观主要是具体分析单张图片识别的效果从而指导模型优化,主要分以下功能点

  • 标注Diff

  • 历史版本Diff

  • 中间结果Trace

以下将展开说这些功能点

三.宏观分析

1.指标查看和筛选

在这一部分,主要关注某次测试任务的核心量化指标,并可以根据指标排序得到欠佳的子集合,以此作为入口分析badcase

图片

而且从这里我们可以关联到这次模型训练所用模型代码版本、训练数据以及版本号,方便算法工程师未来在复现模型中回溯这些关键信息。

2.指标趋势变化查看

在模型优化中,不能保证每个子测试集合都效果提升,但是我们要避免指标变化幅度过大(可能这个集合训练样本量不够或者新加入训练集合与这个集合有冲突),所以我们需要关注子集合的变化趋势,快速得知最佳和最差效果,从而进一步分析效果方差很大的原因,避免评价指标方差很大

图片

3.指标对比查看

这个是宏观分析上最常用的功能,来确认每次效果优化是否有提升,以及具体子集合的效果变化从而做下一步的分析优化

图片

在这个功能上,我们把任意一次完整的测试称为一个版本,所以一个版本可以是:生产环境、测试环境、竞品、轻量CPU模型的完整一次测试结果。我们实现锁定一个版本(pin)和任意另外一个版本对比分析,为了方便查找那些子集合差异过大,支持根据不同评价指标的diff值排序

图片

例如通过上图,我们可以得知,这次优化中有5个子测试集合效果有下降需要关注。

四.微观分析

当通过宏观的指标,发现一些集合效果不理想时,就需要微观的分析发现具体的错误,从而补充数据优化模型。

1.标注Diff

通过宏观分析的指标入口可以直接跳转到Diff页面,这个功能主要是通过可视化的方式,得知端到端的模型结果和真值的差异。

Diff 页面可以自动对比模型结果和标注的差异值,并将不一致的地方在图片上可视化的展示出来,如下图

图片

如对于通用文本,我们对漏识别、错误识别、误召回会用不同底色的bbox作为背景(bbox为模型返回或者标注的文字bbox),当鼠标点击具体的bbox区域时,会自动展开不一致的地方并高亮明细,如点击第一个“5.1 幼儿游戏概述”,会出现以下结果

图片

通过刚才的快速操作,模型优化人员就知道我们需要补充更多手写的“、”字符集合从而解决这个场景的问题。

2.历史版本Diff

历史版本Diff的主要使用方法和Diff一致,主要是给模型优化人员提供这样的输入,上次模型“那些地方可以做对,而这次没法做对”,方便回溯问题从而解决。比如通过历史版本diff,发现一个自然场景的集合上,上次高曝光的可以很好的识别对但这次不成,很快定位这次训练调低了曝光增强概率导致的原因。

3.中间结果Trace

一个完整的OCR产品,经常是由多个模型组合而成,比如在来也的通用OCR由4个深度学习模型组成:角度检测、文本检测、文本识别、语义纠错,这4个模型也需要配套的前后处理,

在来也我们在线服务采用微服务的架构设计模式,所以来也的通用OCR由6个微服务+1组 tensorflow serving微服务组成,这些微服务之间通过grpc交互。一个完整的请求上边所有微服务都会参与,如果一张图识别不好,需要快速定位具体是那个环节的问题,比如可能是文本检测的bbox裁掉部分文字区域。

为此我们增强了分布式追踪opentracing的协议增加了图片trace的功能,接入了内部的SDK,当请求触发了强制采样会记录中间结果、并将整个链路上的结果聚合起来方便分析;不强制采样的话则不做任何操作完全不用担心性能损耗,下边是一个Golang的接入

Go
//当强制采样时,调用这个方法才会生效
values := make(
map[string][]byte)
for idx, jpg := range in.JpegImgs {
   values[resp.Items[idx].Content] = jpg
}
// values为要记录的图片,map[string][]byte,其中map的key为图片的注释文本,
// 建议用json结构化,方便记录多项信息
// "ocr-text-rec" 为trace的method,会将values的图片存储到method的文件夹下,
// 多个图片会并行上传
tracing.LogImages(ctx, "ocr-text-rec", values)

需要触发trace时,只需要在源头请求的header注入x-b3-img-sampled-id 参数既可

Python
def get_header():
    headers ={}
    material = hashlib.md5(
str(time.time_ns()).encode("UTF-8")).hexdigest()
    headers["x-b3-img-sampled-id"] = material
   
return headers
requests.post(host, json.dumps(req),headers=get_header())

如下图是一个trace的结果

图片

通过ocr-text-rec 分组名得知这组是识别微服务的trace结果,图片和文字分别为识别模型收到的请求和返回的结果,通过trace分析,可以快速得知那个环节产生了错误,如下代表检测出现检测不完整的错误:

图片

五.总结

通过上述测试系统的开发,我们确保生产环境模型的持续稳健提升、提供的效率工具非常方便工程师定位问题,极大的加速了内部模型迭代优化的效率,未来我们还将持续分享我们在“以数据驱动为中心”和MLOPS上的一些经验。

继续滑动看下一个
来也技术团队
向上滑动看下一个