网易易盾深度学习模型工程化实践 – 作者:wangyiyunyidun

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

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

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

1.png

模型生命周期

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

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

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

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

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

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

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

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

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

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

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

  • 程序

  • 程序依赖的环境

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

2.png

容器化环境隔离

但容器技术并没有解决所有问题,其中一个问题就是资源管理和调度问题,由于一台服务器需要部署多个应用,每个应用都需要分配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对运行的容器进行资源管理,例如:

apiVersion: v1
kind: Pod
metadata:  
name: nginx
spec: 
 containers:  
- name: nginx    
image: nginx       
resources:      
requests:        
memory: "64Mi"        
cpu: "1"      
limits:        
memory: "128Mi"        
cpu: "2"
我们对运行的nginx容器申请了64M内存和1核CPU,并且限制这个容器最多只能使用128M内存和2核CPU,如果nginx程序尝试申请超过128M内存,就会被kubernetes系统kill掉重新拉起来,确保不会影响其他应用。借助nvidia官方提供的 k8s-device-plugin 插件,nvidia GPU也被抽象成一种资源类型,这时候我们就可以像申请CPU/内存一样申请GPU资源。
apiVersion: v1
kind: Pod
metadata:  
name: model
-appspec:  
containers: 
 - name: model-app   
 image: model-app:v0.3    
resources:     
 requests:        cpu: 4       
 memory: "8Gi"       
 nvidia.com/gpu: "1"     
 limits:        
cpu: 4        
memory: "10Gi"      
  nvidia.com/gpu: "1"

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

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

3.png

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

总结

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

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

参考资料

https://www.docker.com/

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

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

https://kubernetes.io/zh/

来源:freebuf.com 2019-12-13 20:14:15 by: wangyiyunyidun

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论