中文站

网易易盾深度学习模型工程化实践

深度学习大热之后受到大量关注,大部分刚接触深度学习的同学,注意力大都集中在如何调整参数/数据/网络结构,如何达到预期的精度/召回率/准确率等。

然而,深度学习模型应用的整个流程里面还有一个重要的环节,就是模型部署上线。一个模型只有部署上线了,这个模型的价值才能得到体现。

所以我们今天不讨论如何训练模型,我们关注一下如何将训练好的模型部署上线。


模型生命周期  

模型部署上线,就是将模型封装成一个在线服务,并分配相应的资源,将在线服务运行在服务器上,实时接收请求,返回predict结果。封装在线服务的方式有很多,可以选择一些成熟的框架比如http / thrift / gRPC等,选择一款适合自己项目的即可,我们重点关注怎么部署。

模型部署 v0.1 - 裸机部署

顾名思义,就是直接在物理服务器上安装配置好相应的环境,直接将工程代码/模型文件部署到物理服务器上运行,看起来好像很简单直接,但是实际操作起来问题很多。实际服务器可能会有2块GPU甚至4块GPU,所以一台服务器通常需要部署多个模型应用,而在同一台服务器上部署多个应用碰到的最常见的问题,就是环境问题。

环境问题的复杂性表现在以下几个方面:

(1)依赖管理复杂:由于各种原因,线上服务器的操作系统版本可能会不一致,比如系统有CentOS6/7、Debian8/9,甚至内核版本也会有一些差异,依赖包管理工作变得非常复杂;

(2)容易产生依赖冲突:各个模型应用依赖的包版本很容易产生冲突,比如一个应用依赖了opencv2,另一个应用依赖了opencv3,在没有很好的隔离的情况下,会出现各种兼容性问题;

(3)配置/部署效率低下:某一台服务器部署了A应用,某一天A应用下线了,想要部署B应用,可能会面临遗留环境冲突问题,甚至需要重装系统从零开始。碰上线上服务需要紧急扩容的情况,这种环境问题更是容易让人手忙脚乱。


                                                           模型部署复杂的环境/依赖  

                                                           模型部署v0.2 - 容器技术  

为了将开发运维从复杂的环境管理工作中解放出来,我们引入了容器技术。容器是一种轻量级、可移植、自包含的软件打包技术,使应用程序可以在几乎任何地方以相同的方式运行。

简单的说,容器包含两部分:

(1)程序;(2)程序依赖的环境

每个程序都自带依赖环境,并且相互隔离,这很好的解决了裸机部署带来的各个应用之间的依赖冲突问题,对宿主机的环境依赖很小,真正实现了 “Build Once, Run Anywhere” 的口号。借助nvidia官方提供的 nvidia-docker 组件,将nvidia设备映射到容器内部,我们可以很容易的实现快速的模型应用部署上线。


                                                              容器化环境隔离

但容器技术并没有解决所有问题,其中一个问题就是资源管理和调度问题,由于一台服务器需要部署多个应用,每个应用都需要分配1块GPU,这就要求我们手动维护好分配记录,例如:

应用 A 部署在 Server0 服务器上,分配了第0块GPU;

应用B部署在Server0 / Server1服务器上,分配了第1块GPU;

...

这种管理工作在集群规模小的时候可以手动管理,但是在集群规模大了之后就很混乱、很复杂了,而且也容易错——尤其是当今天易盾日均请求量达到十亿量级以上的时候,仅靠手动管理已无法想象。

更为严峻的是,因为没有对应用的资源做隔离,通过这种方式部署的应用,相互之间会产生资源竞争问题。例如一台服务器上运行了 A / B / C 应用,此时A应用由于程序Bug将CPU资源耗尽,此时在同一台服务器上的B / C应用也会受到牵连影响。

                                                            模型部署v0.3 - Kubernetes

为了解决资源调度问题,我们引入了Kubernetes。Kubernetes 是一个开源系统,用于容器化应用的自动部署、扩缩和管理。在Kubernetes里有一个“资源”的概念,比如CPU和内存都是资源类型,我们可以通过Kubernetes对运行的容器进行资源管理,例如:

我们对运行的nginx容器申请了64M内存和1核CPU,并且限制这个容器最多只能使用128M内存和2核CPU,如果nginx程序尝试申请超过128M内存,就会被kubernetes系统kill掉重新拉起来,确保不会影响其他应用。借助nvidia官方提供的 k8s-device-plugin 插件,nvidia GPU也被抽象成一种资源类型,这时候我们就可以像申请CPU/内存一样申请GPU资源。

上述示例中我们为 model-app这个应用申请了4核CPU、8G内存、1块GPU,申请提交之后,Kubernetes会分配好对应的资源,并自动调度。开发运维人员的视角从“某台服务部署了xx应用”转换为“这个kubenetes集群的资源使用情况”,这极大的简化了运维管理工作

Kubernetes自带了dashboard组件,监控方案可以用prometheus+grafana,基本的运维和监控管理都可以实现,但毕竟是开源版本,部分功能还不能满足我们的运维开发需求,经过一番定制开发,我们基于Kubernetes开发出了适合自己的集开发运维于一体的一站式管理平台。

                                                        易盾某项目的资源汇总信息

                                                                             总结

由于易盾业务发展迅猛,网易安全部商业化易盾仅仅三年多一点的时间,网易易盾就已拥有超过26万的开发者,服务客户达数千家。这也使得这块技术,从最早的裸机手动部署,到半自动的容器部署,再到全自动的kubernetes部署。

每一次进步都伴随着效率的提升,解放了大量的开发运维人员精力,让开发运维人员可以投入更多的精力到值得关注的产品功能上。与此同时,也使得易盾的机器学习模型,从训练完成到上线应用,仅需要数分钟就可以实现落地,从而及时帮助某些有紧急需求的客户。

参考资料

https://www.docker.com/

https://github.com/NVIDIA/nvidia-docker

https://github.com/NVIDIA/k8s-device-plugin

https://kubernetes.io/zh/

相关阅读:

基于DNN的人脸识别中的反欺诈机制

人工智能图片鉴黄原理和应用

特征选择之经典三刀

机器(深度)学习计算架构,从HPC到云架构