算法工程化
背景
将相关算法部署,并提供一个 or 多个http接口,服务于业务方。
算法
大学中所学的数据结构课本上说:算法是指解决问题或执行任务的有序步骤集合。当然,如此描述的算法,相当准确。但是,对于实际工程落地而言,还是过于:抽象。
这里面描述的算法,是指:算法同学所交付的可执行文件 or
so库,例如:视频压缩领域的:264算法,交付的产品:集成到ffmepg中的libx264。例如:如下命令,是使用:libx264算法真正去压缩一个视频的命令,那么:对于实际工程落地而言,所提供的带上libx264的ffmpeg可执行程序,可以简单地理解成:算法
1 | ffmpeg -i source.mov -s 1280x720 -profile:v high444 -c:v libx264 -preset veryslow -crf 30 -r 30 -g 120 -keyint_min 30 -sc_threshold 40 -bf 3 -b_strategy 2 -refs 5 -c:a libfdk_aac -profile:a aac_low -b:a 128k -movflags faststart -max_muxing_queue_size 9999 -f mp4 -loglevel error 720_3.mp4 -y |
模型
在计算机科学和机器学习领域,模型是对现实世界问题或系统的一种简化或抽象。如此描述模型,如同算法一样,相当准确,可惜:对于实际工程落地而言,还是:过于:抽象 +
空。因此,站在实际工程落地而言,所谓模型:其实是指:模型技术人员,已经训练好的,可以提供部署的文件zip包。
工程化
基于此,所谓算法工程化,就是:将算法技术人员,交付过来的东西(可执行文件 or so库 or zip包 or docker镜像等等),在cpu机器
or gpu机器部署起来,提供一个http接口,服务于业务。
需求提炼
在实际项目中,算法、模型要能标准化部署起来,并服务于实际业务,应该满足以下条件:
1、标准化部署
算法、模型,的入参、出参,千变万化,但是,期望在部署它们时,能够有一个标准化姿势,以减轻算法、模型的部署成本。
2、成本最低
部署在cpu or gpu上时,期望所花费的成本最低。
a、能够以最快的速度加载模型,避免成本的浪费
b、当流量低时,能够自动回收闲置的CPU、GPU资源
c、多个模型,流量切换时,能够自动释放资源,自动扩容资源
3、调参
算法、模型部署好后,期望能够快速知道它的处理效果如何,输入一批预先设定好的图片、视频 + 相关参数,能够快速得到结果,并且及时反馈:当前算法、模型是否ok
4、版本迭代
算法、模型版本迭代时,能够快速训练,出结果,验证通过后,能够快速发布
下载
对于图片、视频而言,业务方传送过来的一般是:各种各样的url地址,如何基于这些url地址,以快速且以最低的成本下载到本地磁盘?
1、分片下载?form表单下载?
2、公网域名如何转为内网域名下载?公网域名所带来的cdn成本很贵,而一般内网域名下载,不需要钱。
3、有些算法,并不需要下载整个视频 or 整个图片,下载一段视频即可触发cpu计算,获取结果,例如:计算视频的meta信息
4、有些url有鉴权参数 + 有限期限制,如何将过期的url,重新算成有效?
5、多云部署,单元化下载,能够节省非常多的成本
上传
经过算法、模型的计算后,一般会产生:新的图片s or 视频s,如何将结果,快速切最低成本上传到小文件存储系统里(例如:阿里云的oss)
1、分片上传?form表单上传?
2、多云自动切换?
3、如何自动产生不冲突的文件名称?
工作目录
1、待触发计算的文件,最好防在本地磁盘里,不太建议使用:云盘等涉及到网络IO的解决方案。
2、算法、模型在计算过程中,很大大概率会产生一些中间文件,因此,需要一个本地临时目录来存储。
基础镜像
镜像如何分发
有些算法、模型执行,依赖的服务镜像非常大,集群分发时,部署有点慢,如何预热加速?
问题分析
当业务方反馈问题,如何快速找到算法、模型的入参 + 出参?协助相关技术人员分析问题。
更新迭代
分析并解决完问题后,如何快速部署新的版本到线上,需设计一套更新迭代机制,快速服务于业务方?
多版本管理
线上部署的函数,最好有多版本,方便快速回滚到旧。
业界方案
faas:提出一个抽象的概念:function as a service,通过函数,对算法、模型,再次封装,并提供http服务,为业务方服务。
当然了,也可以提以下新的概念
1、aaas,算法 as a service
2、maas:模型 as a service,
3、FMaaS:基础模型即服务,
无论叫啥名字,它们的核心本质是一样的。
解决方案
整体系统架构图如下:
函数
通过函数的概念,对算法、模型,再次封装,支持的接入形态:shell、python、so库等
报文设计
算法、模型,只处理本地文件,并产出结果到本地文件中,因此,需要做以下2件事情:
1、需要为:算法、模型发起计算时创建好:本地执行的环境。
2、参数、结果灵活传递。
如下图所示:
业务报文设计
1、请求报文
1 | { |
2、响应报文
1 | { |
3、回调报文
1 | { |
函数交互报文
1、函数入参报文
1 | { |
备注:
a、如果pre_download为false,则local_path为空,remote_url有值,函数基于remote_url进行处理。
b、如果pre_download为true,则local_path一定不为空,宿主程序会帮忙下载图片,函数基于:local_path进行处理即可
c、函数里面的代码逻辑,可处理:pre_download,也可不处理,按照一定的规则即可。
2、函数出参报文
成功:
1 | { |
失败:
1 | { |
MQ代理消费
不建议处理进程直接对接MQ,特别是:kafka时,强烈建议:增加一层:MQ代理消费进程,具体如下图所示:
具体原因:
1、因为处理进程,都是cpu or gpu密集型业务,cpu跑100%是很正常的事情,如果此时,处理进程直怼kafka,容易导致:kafka认为消费进程卡死,触发partition一直reblance。
2、处理进程尽量轻量,若:集成了kafka的SDK,会变的有点重,还不如:使用标准的http协议。
并发度
触发器:可以同时消费1个 or 2个以上的消息,因此,需要实现精准度控制并发消费。举个例子:
功能 | 并发度 | 说明 | 备注 |
---|---|---|---|
图片处理 | 2个以上 | 图片处理,一般不太费cpu,完全可以提高cpu利用率 | |
视频拼接 | 2个以上 | 部分场景的视频拼接,仅仅只需要解封装,不怎么费cpu,但是,费:io | |
视频编解码 | 1个 | 非常费cpu,因此,一个pod只能处理一笔业务 | |
视频编解码 | 1个 | 非常费cpu,因此,一个pod只能处理一笔业务 |
备注:
1、并发度的评判标准,可以是:cpu的利用率 + 业务场景(例如:是否是付费用户)等等具体的指标。
多进程通讯
如:工程化所述,交付到工程团队的形态,一般都是:二进制可执行文件 or so库 or
快速开始的代码块等,而整套体系要跑起来,都会涉及:多进程通讯,一般有以下三种进程:
进程 | 是否存在 | 负责团队 | 说明 | 备注 |
---|---|---|---|---|
处理进程 | 是 | 工程团队 | 1、消费报文 ,2、下载文件,创建函数执行的环境信息 3、调用函数 4、收集结果 5、清理环境信息 |
|
函数进程 | 是 | 工程团队 + 算法、模型团队一起 | 一般是:shell、python、go等代码包 | |
算法进程 | 否 | 算法、模型团队 or 业界开源的算法、模型 | 如果算法同学提供的是:so库,则不一定存在算法进程 |
入参、出参
方式 | 作用 | 说明 |
---|---|---|
管道 | 通过std in传入入参信息,再通过stdout,传出结果信息 | |
文件 | 子进程将处理结果写入文件,再通过stdout透传文件地址信息,父进程根据文件地址读取结果信息 |
父子进程状态控制
状态 | 作用 | 说明 |
---|---|---|
优雅关闭 | 当父进程收到重启等信息号,停止消费,等待:子进程执行完毕后,正常退出 | |
主动强制退出 | 当父进程收到强制退出信息号, 直接kill -9,强制子进程,异常退出 | |
被动退出 | 当子进程卡死后,父进程超时退出时,kill -9 触发子进程强制,异常退出 |
pipeline机制
1、站在业务的视角,函数的功能,一般都比较原子化,而复杂的业务功能,常常需要多个函数串联执行,例如:想要获取某张图片缩略后的宽高信息。
2、站在技术的视角,复杂的业务,是个dag流程,而不同节点执行,若在不同的公有云(或者物理机)上,常常涉及到:多次下载同一个文件,浪费:内网带宽
甚至是公网带宽。如何优化处理耗时 or 节省公网带宽成本?就需要尽量让:数据不动,让业务配置动起来。
基于2点,就需要让处理进程通过类似:pipelie的方式,执行某个业务。
算法镜像
尽量做到:每个函数所依赖的算法,是独立的,自包含的,不太建议:依赖于基础镜像,不然,后续维护成本比较高。