来源:腾讯云 作者:刘裕忠和张文波
https://cloud.tencent.com/developer/article/1005480
导语:在这个飞速发展的时代,我们有幸的见证了互联网的萌芽到爆发,移动互联网的兴起到鼎盛,目睹了诺基亚雅虎的兴衰,也见证了腾讯阿里走到全球市值十强;随着谷歌AlphaGo的横空出世,又让我们快速的切换到一个新的AI时代,而在这个AI时代,图像识别技术作为其基础能力之一,也在快速发展中,今天来聊聊图像识别的服务运行框架。
一、图像识别的业务应用
在聊框架之前,先简单说一下背景知识,图像识别作为人工智能领域中最基础的能力之一,是每个互联网巨头及AI公司的兵家必争之地,小到广告图片过滤大到国家安全宇宙探索都有着非常广阔的应用场景,例如在广告图片过滤、纸质文档电子化、聊天/网页图片鉴黄、银行证券自助开户、人脸门禁安防等业务中都有了比较普及的应用,在这些业务中图像识别技术扮演着非常重要的角色,用好了图像识别,一方面能大大提高工作效率,另一方面能提供更好的用户体验。例如在广告图片过滤的业务中,从人工处理到自动处理,在效率和准确率都有显著的提升。
二、图片识别的算法类型
不同的应用场景会有不同的识别类型,而不同的识别类型自然会有不同的算法,按我们现有的业务大概做了梳理,分为如下几类,当然这只是其中一部分,就不班门弄斧了,毕竟这个范围太广了。
文字识别技术
图像内容理解
-
人脸检测与分析
-
明星脸识别
-
物体检测
-
图像特征识别
其它分类…
在这些不同的算法中,又有不同的构成方式,如采用传统的文字识别,是单阶段处理的,即一个算法即可完成识别处理;而在采用深度学习算法后,识别的过程大部分拆分为两个阶段:文字检测,获取图像中文字的所在位置,文字识别,分析所在位置的文字内容,即多阶段算法;还有更多阶段的算法类型,如gif分为图像拆分、检测、识别、结果合并等阶段。
三、如何提供图像识别的服务?
图像识别从算法研究、模型训练到规模化的提供服务,卷入的资源及处理的流程都是非常多的,但在开发阶段主要分为如下两个阶段:
-
算法研究&模型训练: 主要由算法研究人员进行算法研究及模型训练,这里涉及到paper研究及算法实现,对各种图片集的模型训练等,这个也是图像识别最核心也最关键的工作,在这个阶段的输出通常是用C/C++编写的算法SO及训练好的模型文件。
-
框架开发&算法集成: 主要由后台开发人员进行服务框架的开发及算法SO的集成运行,即把算法研究人员研究好的算法及模型文件集成到服务框架中,提供稳定的图像识别服务。
我们都知道C++在运算密集型的程序中优势比较大,所以在算法的实现上大部分都采用了C++,而在服务框架的编写上,实现方式就比较多样化了,有用C++也有java的或者其它语言实现的, 这方面我们综合对比了java和c++的性能及稳定性,两者其实相差无几,而java因为其生态的强大,在编写效率上有很大的优势,能快速开发完成,且有更好的移植性,所以在服务框架的实现上,我们采用了java,通过jni调用SO来实现。简单调用流程如下:
JavaServer -> Jni框架SO -> 算法SO.
四、我们的解决方案
一个系统的成型并不是孤立存在的,如果要规模化的提供稳定服务,必须是完备的一个系统,这里简单描述一下我们的整体实现方案,系统架构上主要分为三层:接入层、系统层、算法层,再加上存储系统、告警监控系统、日志系统等构成一套完整的解决方案。
-
接入层: 主要做一些输入输出的适配,如协议适配、参数适配、结果适配等。
-
系统层: 图像识别服务运行的系统框架,加载运行算法SO,提供稳定的识别服务,即图像识别服务框架,本篇文章的重点,会在第五点进行比较大篇幅的介绍
-
算法层: 主要由算法人员研究实现 各种识别类型的算法及模型文件
-
存储系统: 图片及结果存储
-
监控告警: 监控服务的运行状态,在异常时进行告警
-
日志系统: 请求日志的存储,为问题的跟踪排查提供依据
五、轻量级图像识别服务框架
1. 整体架构
在打造一个框架之前,先来理一下图像识别服务的核心需求:
-
高性能: 识别请求需要快速返回
-
高可靠: 持续稳定的提供服务,局部异常不影响整体服务
-
动态扩容: 在流量增大时,能动态扩容,来应对持续增长的业务请求
-
多算法支持: 兼容多种算法,无论是单阶段还是多阶段,都一一兼容
针对上述的要求,我们借鉴了业界及公司内的架构方案,打造了轻量级图像识别服务框架,架构图如下:
-
master: 接收接入层的请求,进行请求拆分、请求调度、结果合并等
-
worker: 实际执行算法的进程载体,主要包含算法SO/模型的加载、更新,进行算法的执行
-
zookeeper: 典型的分布式一致性服务软件,这里主要用于存储worker心跳信息、算法映射关系、算法执行计划、算法静态/动态快照信息等
-
configserver: 监听worker心跳并实时更新动态快照,触发master更新路由规则及动态连接池
2. 框架运行态
为了更好的说明这个框架,需要对运行态进行解剥,这里先分解一下这个框架的配置信息,主要分为静态和动态两种,静态配置由运维进行配置,动态信息由运行时决定。
-
算法映射关系: 即什么业务的什么识别类型调用哪个识别算法的哪个版本,正常情况是识别类型就决定了某个算法,但为了更灵活的业务支撑模式,我们细化了实现,即不同的业务相同的识别也可以适配不同的算法版本;
-
算法执行计划: 这个算法有哪些执行步骤,比如上面说到的场景图像文字识别,包含2个步骤:文字检测、文字识别,那么此处算法的执行计划就有2个步骤;
-
静态快照: 通常在分布式框架中,是没有静态快照的,这个主要是因为框架支撑的算法及版本都比较多,太过灵活的话会导致运维对整个集群的管理不好把控,所以加入了静态快照这个配置,从而对整个集群做到心中有数。静态快照主要用于配置执行步骤所在的服务器ip及端口,即各个算法执行步骤的部署情况,如文字检测算法部署在192.168.11.1的8001~8010端口,文字识别算法部署在192.168.22.2的8001~8010端口;
-
动态快照: 是静态快照的运行时,即configserver根据worker的存活状态更新后的快照信息,如果某个服务器的worker挂了,动态快照就要剔除掉这个服务地址,如果恢复之后则把这个服务地址重新添加到动态快照;
-
请求过程说明: master -> worker1 - > master -> worker2 -> master
-
master解析参数,根据业务类型、识别类型获取识别算法
-
获取识别类型的步骤进行算法调用,maser会根据执行计划的步骤调用worker的算法
-
master在调用完最后一个步骤后进行结果汇总并返回
-
3. 算法与框架的解耦
一个好的算法运行框架,应该尽可能减少对算法的干扰,而自身又要也少受算法的影响,这样就能为算法研究和系统开发提供一种高效的合作方式,为此我们对算法和框架做了解耦,框架的部署不依赖于算法,算法的开发也不依赖于框架,只需要把算法在生成SO时做一层简单的适配即可。如下是框架与算法SO的关系:
框架部署好之后,worker会启动SO的扫描线程,只需把算法SO及模型文件放入到指定目录,框架就会进行加载完成SO的上线。
4. 多版本算法的兼容
业务形态的各式各样,也决定了框架应该有更灵活的支撑模式,如不同的业务对同一识别类型有不同的侧重点,那么算法的版本也会有差别,框架对此做了一些调整,如下图所示,各个业务的银行卡算法是采用了不同的版本。
5. 容灾及集群热更新
一个好的系统,应该是稳定可靠的,容灾是必须的,在这方面,我们借助了zookeeper这个典型的分布式一致性软件,实现了快速恢复的容错机制:
-
worker: 在启动的时候与zookeeper建立临时节点维持心跳信息
-
configserver: 监听worker在zookeeper的心跳信息,如果worker断连或重连,configserver立刻感知到并修改动态快照
-
master: 监听zookeeper上的动态快照信息,动态快照一发生变更立刻修改路由规则及路由连接池
通过这几个角色的配合,在worker节点出现异常的情况下,master在迅速就完成了切换,保证了系统的稳定。这种机制也支持了集群的热更新,在需要对某个worker进行更新时,先对worker进行下线,master感知后不向此worker发请求,完成更新启动后,master再跟其重新建立连接并发送请求。
6. 全链路追踪
虽然说框架具备了高可靠,但是很多情况下还是无法避免算法内部的core dump,在这种情况下,恢复服务是第一的,这里我们做了进程的监听,如果发现进程core dump会立刻拉起;但在恢复服务之后,问题的复现及分析又是一个难点,在这里,我们做了一个全链路的跟踪,在框架的参数构造中增加了traceId这个参数,能从接入、系统、算法、存储跟踪到这个请求,快速拿到错误图片进行沙箱环境的复现及分析。
7. 为什么说轻量级?
在上述过程中,基本上把系统的实现方式描述了一遍,可能很多人会有疑问,为什么说这个框架是轻量级的,归纳了几点,认为这个框架还算是比较轻量的。
-
逻辑轻量:master专注于路由管理、请求转发,结果合并,worker专注于算法调用,没有任何多余的逻辑
-
参数轻量:参数中只有图片内容、识别类型、业务类型、traceId,没有多余的参数
-
系统侵入少:算法框架互相独立 ,一个框架兼容多种算法,但互不侵入
-
系统依赖少:除了依赖于zookeeper,没有其它第三方依赖
六、框架的一些思考
此次采集java/c++混合语言编程来实现图像识别服务的提供,还是我们在框架上的第一次探索,虽然当前满足了稳定的服务提供,但是框架的提升还有很多路要走,这个会结合着业务的推广而不断提升。同时也为我们的框架设计提供了新的思路,利用好编程语言的优势在业务支撑上能事半功倍。
再者为了支持深度学习版本的算法,我们也开发了docker版本,方便于后续快速部署到gpu集群,同时提供了单机版及SDK版为一些业务的快速接入提供更多的可选方式。罗马并非一日建成,我们会持续优化架构,力争提供一个稳定高效的图像识别服务,为更多的业务提供优质的服务。