时间:2024-07-28
徐治理,霍龙社,曹云飞,崔煜喆(中国联通研究院,北京 100176)
近年来AI技术取得了革命性的进步,算法方面从统计学习方法到深度学习,算法的广度、深度不断扩展,丰富度和复杂度不断提高[1]。同时,也涌现出一批能提供常用开发工具的深度学习框架,如Tensorflow、Pytorch 等,广受AI 开发者欢迎。AI 的应用范围也在不断扩展,从推荐系统到自然语言处理、计算机视觉、语音处理等各个领域都有了成熟的算法和模型[2]。人工智能技术的关注点也从提高算法精度、模型性能扩展到了怎样让其应用到实际的生产环境中。
在人工智能算法模型开发、训练完成后,需要将其部署到互联网云端以便用户实时访问。但目前AI模型的封装和部署还存在较多问题。AI 模型开发丰富的框架和工具使在生产中配置模型运行环境非常复杂,尤其是在需要运行多个模型时,更是会面对工具和版本的各种冲突。AI 模型运行需要较多的计算资源,在实际运行中如何对AI模型服务占用的资源进行灵活的管理和及时的调度也是亟待解决的问题。AI技术对很多用户来说是一个新的领域,对包含AI服务代码的开发和部署需要很多前置知识,找到一种能灵活支持对各种AI 模型进行封装并能实现自动化发布和部署的技术具有十分重要的意义。
人工智能模型部署方式根据处理数据的实时性,分为离线模型和在线模型[3]。在线模型根据使用的技术、适配的框架又分为专用模型部署、通用模型部署等。在线模型部署后的运行管理方式也有很多种,目前最热门和有发展前景的就是云原生服务网格[4]。
离线模型是最简单的模型部署方式,虽然出现最早但是目前仍被广泛使用。当在业务流程中AI 模型处理过程不需要实时完成时,根据需要隔一段时间运行一次。离线模型对处理数据的时效性要求较低,所以对部署条件和实现的性能的要求比较宽松,也没有固定的部署模式,甚至可以将训练好的模型直接拿来使用,也是最早的AI模型使用方式。
1.2.1 模型封装
将算法工程师训练好的模型重构或继续开发成一个网络服务是在企业中比较常见的上线方式[5]。模型服务通过常用开发框架封装为一个后端服务,提供http 端口对外提供服务。应用中提前将训练好的模型加载,通过消息中间件将待预测数据传入接口进行推断得到最终结果。这种处理模型的方式每次部署新模型都需要在服务器中重新配置AI模型运行环境,每次模型的部署都带来大量重复工作。
部分机器学习框架提供了模型服务工具,模型训练完成后直接使用工具将其封装为一个服务。比如Google提供了Tensorflow Serving,直接利用模型开发配置好的环境以docker 形式封装,对外提供Restful API[6]。但框架提供的Serving 工具兼容性很差,不同框架需要手动转换文件类型,对于其他框架独有的算子不能提供支持。
1.2.2 模型部署
对于封装好的模型可以直接部署在服务器中,但这种方式难以进行灵活的资源管理和调度,对于AI模型这种需要占用大量算力资源的服务,需要更灵活和自动化的方式进行管理,云原生和服务网格则是当前热门的研究方向。
云原生是一种构建和运行程序的方法,被设计在云平台上运行,充分发挥其弹性和分布式的优势[7]。云原生计算基金会(Cloud Native Computing Foundatio),给出了云原生应用的三大特征:容器化封装、动态和自动化管理、面向微服务[8]。基于CNCF 云原生技术开发的应用,能够在使用这一技术架构的平台上实现畅通无阻的部署。云原生技术以容器的形式部署微服务并进行管理,基于微服务架构提高灵活性和可维护性,借助敏捷方法、DevOps 支持持续迭代和运维自动化,利用云平台设施实现弹性伸缩、动态调度、优化资源利用率[9]。非常适合作为AI 模型的部署方式。
服务网格是指用于微服务应用的可配置基础架构层(configurable infrastructure layer),负责处理微服务间复杂的服务请求[10]。通常,服务网格使用一系列的轻量级网络代理来实现,网络代理和应用代码分别部署。使用服务网格能为云原生带来以下4个方面的好处:业务逻辑与分布式架构完全解耦、一体化的链路管理、弹性伸缩能力和动态化链路管理;在安全上服务网格提供透明的认证机制、通道加密、服务访问授权等安全能力;为运维人员提供强大的调用链;监控和调用日志收集输出的能力[11]。
为了帮助AI 模型开发者简单、快速、自动化地实现模型部署,本文提出了一种基于云原生服务网格的AI 模型部署方案。模型开发者完成训练的模型一般由模型参数文件与模型运行控制代码2 个部分组成,模型参数文件存储了训练好的AI模型结构和参数,运行代码控制模型的加载和启动并包含调用AI 模型的接口方法。AI 模型的基本工作流程为调用模型接口方法,输入参数为符合模型需要的特征数据,返回模型执行推断过程后的结果。
本文重点解决的问题就是将AI 模型代码中的直接调用AI 模型的接口方法转换成在云平台上能供用户调用的Restful API。为了实现该目的,本方案设计了3个步骤:模型打包、微服务镜像生成和模型部署运行。模型打包是为后续模型微服务生成做准备,需要由开发者使用撰写打包脚本调用模型打包工具在本地完成。
将AI 模型的模型参数文件和运行文件看作一个整体,对外提供模型推断接口。模型开发者撰写模型打包代码,打包代码一般选择对不同语言兼容性较好脚本语言,方便调用不同框架下开发的AI 模型的接口。
打包脚本会根据业务需要声明模型将要对外提供Restful API 服务的接口方法,明确声明方法的函数名、参数类型和个数,以及返回值类型。下面为一个伪代码接口声明示例:
from AI_model import predict # 导入AI 模型中的predict方法
def function(para1:num,para2:List[str])→str:#声明封装方法的名称、参数和返回值
return predict(para1,para2)# 调用AI 模型的predict方法
声明的方法调用AI 模型提供的接口,完成对AI模型接口的二次封装。二次封装所写的服务接口方法根据AI 模型微服务部署后所提供的服务的逻辑开发,将会在微服务部署后被内部的模型运行器调用。
对于打包脚本中服务逻辑的开发,当逻辑复杂时应单独写在另一个代码文件中,将其称为模型服务脚本,模型服务脚本处于AI模型文件和打包脚本中间的位置,完成AI 模型方法接口更上层的业务逻辑开发,进一步将打包过程和服务逻辑解耦。在模型服务脚本中也能完成数据结构转换,将模型打包脚本中定义的接口参数数据结构转换为AI 模型接口所需要的数据结构。
运行脚本会调用模型打包工具,打包工具中定义了服务接口的类,并将所有二次封装的接口实例化为服务接口类对象。模型打包工具首先运行服务接口方法实例化过程。实例化过程首先处理模型的参数等属性。每个二次封装的接口方法服务类中的属性包括了接口方法名称、接收参数的类型和个数、返回值类型,以及其中直接或间接调用的所有函数对象。
图1给出了调用树结构示意。
模型打包工具首先读取二次封装的方法,获取方法属性信息,验证方法的定义代码完整包含服务类的各个属性。对于传递的参数类型,接口为了保证通用性,要求只能使用基本数据类型,不能传递用户自己定义的类实例。服务类接口方法的参数会保存在模型基本信息文件中,供后续模型管理工具调用。
图1 调用树结构示意图
最后将得到的服务接口方法对象保存进文件。模型打包工具获取运行当前脚本和服务接口方法需要加载的上下文信息,将其和实例化的服务接口对象和相关上下文序列化,序列化是将对象转换为字节流的过程,序列化的对象被写入二进制文件中保存。采用序列化的方式传递对象。
用户在模型打包过程中需要编写模型运行依赖列表,模型打包工具会将其保存为文件添加到模型打包文件中,用来在微服务镜像生成过程中配置环境。模型打包工具在解析模型服务接口声明时,也会将模型名、服务接口方法名等记录下来保存在模型属性文件中。模型打包工具会分4 个部分保存模型文件,生成模型压缩包,最后得到模型打包文件目录,其中包括AI 模型代码、接口服务实例文件、模型环境配置文件和模型属性文件,打包过程示意图如图2所示。
通过模型打包,尽可能地降低不同模型之间的差异性,在接口层面实现统一,为后续利用统一的基础镜像和模型运行器完成模型微服务镜像生成提供基础。
模型打包过程已经完成了模型接口和文件的标准化,所以微服务镜像生成过程将通过代码自动完成。新的模型微服务镜像由安装了模型运行器的Linux 镜像作为基础镜像,每个AI 模型微服务镜像都基于基础镜像,再向上添加新层组建生成。
图2 模型打包过程示意图
微服务镜像生成代码调用容器接口API,执行镜像生成流程。首先将AI 模型文件和二次封装接口实例文件拷贝到镜像中。然后根据环境配置文件,使用对应的包管理工具配置AI模型和接口脚本运行环境。封装好的模型微服务将通过镜像仓库统一管理。
AI 模型提供服务在生产中存在的一个很大问题就是服务的实时性不能保证,从数据传输到模型推断计算,各个环节都会带来延迟。基于云原生服务网格的部署方案的跨平台特性,能让模型部署在靠近调用来源的边缘云MEC 节点上,尽可能地减小通信成本。而弹性扩缩容的特性,让容器管理平台在出现大量并发服务请求时能及时作出反应,部署更多的微服务容器,更快速地处理请求。
AI 模型微服务部署于云原生容器堆栈中,实现根据生产环境需要对AI 模型的动态部署、持续交付;利用云平台控制部署的AI模型服务弹性伸缩,充分利用算力资源,节约运行成本。云原生也为模型的部署提供了优秀的跨平台属性,解决了跨平台部署的可移植问题,通过服务网格动态管理,实现AI模型发布、部署的高度自动化。
打包脚本和模型运行器实现一个“打包—解包”的过程。经由打包脚本生成的格式化后的AI模型,由模型运行器恢复、加载、调用,对外提供服务。
模型运行器是使用Web 框架开发的实现Restful API 的一个应用,在模型微服务镜像被部署后运行该应用对外提供服务。该应用对外接收外部用户请求,接收用户发来的待处理数据;验证被请求的模型方法是否存在,接受的数据是否符合接口要求;对内调用模型方法。模型运行完成后,模型运行器将处理结果返回。
模型运行器获取调用AI 模型接口的过程分为2个部分,首先模型运行器读取打包文件中记载了模型服务接口列表的模型属性文件,使用模板引擎生成配置文件。在建立Web 应用时,读取生成的模板引擎,生成对不同模型服务Restful API的路由。然后获取服务接口的具体操作逻辑。模型运行器中导入了和模型打包工具相同的模型接口定义类,在读取保存模型接口实例列表的文件后,将二进制数据反序列化,恢复类实例,从而获得服务接口列表和每个接口的参数、返回值属性。既实现了不修改运行器代码即可调用AI 模型方法,又提高安全性,防止了容器内的AI 模型调用逻辑的篡改。模型运行器对外开放Restful API接口,将服务端口映射出来,接收外部对AI 模型微服务的请求。因为恢复了接口实例,这些方法实例的调用栈最终指向AI 模型提供的接口,将AI 模型文件拷贝进模型镜像中,AI 模型文件与模型运行器相对路径必须要与模型打包过程中AI 模型和封装脚本的相对路径相同,通过接口实例即可调用镜像中模型文件。恢复后的微服务镜像内调用过程如图3所示。
用户发送的http请求json格式的请求示例如下。
图3 模型运行器功能示意图
请求头中说明了请求体中数据的编码方式和模型微服务返回推断结果时结果数据的编码方式,请求体为对应格式的数据。请求体可以使用protobuf 等其他编码方式,需要在运行器代码中添加对应的编解码代码和工具即可。
微服务镜像部署后,内部的模型运行器启动,加载接口实例二进制文件,获取当前运行模型的所有接口信息,实现对模型提供的各个推断方法的调用。AI模型服务启动后,生产环境其他服务即可访问接口、发送特征数据调用AI 模型进行推理,过程如图4 所示。
为了解决AI 模型在互联网生产环境中的自动化部署问题,本文提出了基于云原生服务网格的AI模型微服务化和跨平台部署方案,其主要包括模型打包、微服务生成和AI 模型微服务部署与运行。该方案主要技术点已经在中国联通CubeAI 智立方AI 应用共享与能力开放平台(https://cubeai.dimpt.com)的开发和运营中得到了实施与验证,证实了技术可行性和实用性的代码已经全栈开源。CubeAI 平台实现了对绝大多数AI 开发框架的支持,已经部署上线AI 模型50 多个,涵盖运维网优、营销客服、人脸识别、图像处理、自然语言处理等领域,将持续赋能中国联通智能网络和创新业务。
我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自各大过期杂志,内容仅供学习参考,不准确地方联系删除处理!