拒绝空谈 AI 设想!手把手教你构建实时、高可用的 AI 调度平台
当前人工智能飞速发展,机器学习的精度和性能也在不断提高,由机器学习引导的技术正在默默改变着大家的生活,并创造出很多新的商业机会和价值。
人工智能目前最直接的出发点就是让计算机能将人眼看到的、人耳听到的媒体转化为计算机可以理解的对象,计算机只能处理量化的数据和信息,对于如何从音视频和其它媒体中挖掘出其内在的数据是人工智能领域在不断探索的方向,因为数据即价值。目前视频和图片资源数据量巨大,如果能将其中的数据挖掘并量化出来,将产生巨大的商业价值。
从目前技术方向看AI还是比较接地气的技术方向,我们不断看到越来越多AI真实落地的场景,并切实的解决人们工作生活中的问题。目前生产系统中大多深度学习推理计算任务(Inference)基于单机作业,对于商业化的系统,当Inference任务量很大的时候没有合适的平台适用。
传统大数据平台大都专注于数据和计算,而机器学习任务则更关注算法并且需要提前加载模型,而且需要对连续的有关联性的数据做分析跟踪等处理,所以设计一款Scale Out、实时性和高可靠的调度平台非常重要。
计算设备
CUDA的广泛应用造就了GPU计算的崛起,用NVIDIA的显卡进行深度学习的加速训练是最常用的一种设备,其中使用最多的是GTX1080 Ti显卡,不过NVIDIA声称不再支持用户消费级显卡进行深度学习训练,这样以后只能买更昂贵的Tesla GPU,所以以后发展成什么样还是个未知数。
CUDA GPU计算除了这种高功耗的显卡,还有NVIDIA Jetson TX2这种低功耗嵌入式平台,这种平台的CPU是ARM架构,GPU是Pascal GPU。
图1 NVIDIA Jetson TX2
对于移动端或许不能使用CUDA的平台则直接使用CPU进行计算,并结合NNPACK库进行加速,NNPACK由Facebook开发,是一个加速神经网络计算的加速包,NNPACK可以在多核CPU平台上提高卷积层计算性能,通常会有2-3倍的性能提升。
Movidius是英特尔推出的基于Myraid2芯片的神经元计算棒,将所有的功能封装到了U盘大小的设备中,用户只需要将计算棒插入USB接口中,就可以进行高效的机器学习推理任务。
通常只需要一个树莓派级别的载体作为宿主机就可以直接使用,如果单个计算棒的性能不够,还可以使用多个进行加速,取得线性加速比。
深度学习平台
目前机器学习实践的过程主要有两个阶段,首先是模型训练,用标注数据集对目标场景进行训练,使模型足够收敛,达到一定精度。然后是用训练好的模型进行推理,对新数据进行分类检测,提取媒体数据中的特征数据。
目前常用的深度学习平台主要有TensorFlow、Keras、MXNet和PyTorch等,各有优缺点,目前还没有哪一个具有绝对的优势,处于百花齐放的阶段。
调度需求
目前AI正在飞速发展,所以计算设备比较多样,计算环境往往是异构的。包含桌面机、GPU服务器和移动端等一些低功耗平台,同时也可以直接使用云端GPU资源组成Hybrid计算环境,这些需求对调度的框架提出了新的要求:
实时性:实时性能大幅提高AI场景的用户体验,和离线的大数据处理不同,需要以最低的延时处理完深度学习计算任务,比如无人机上的图像处理,需要以几乎实时的性能完成深度学习计算;
高可用:对一些特征提取的场景,数据的完整性非常重要,单个节点的故障不会引起业务的中断,调度系统需具备HA和Failover功能;
Scale out:对于AI企业来说,以灵活的方式扩展计算能力显得非常重要,不同的用户会提出不同的部署模型和不同的调度策略,当计算任务增多的时候,横向扩展便非常必要;
细粒度:不同的深度学习模型具有不同的网络深度,对资源的消耗也不尽相同,较深的网络需要较大的内存或者显存,同时有些网络后处理需要较多的CPU时间;
多维度:目前深度学习的网络层数也是比较多,层数越多模型就越大,这就要求消耗更多的显存和内存。也有一些经过删枝精简的模型适用于Mobile平台和其它低功耗平台,每种计算模型对GPU、CPU、显存和内存的需求都不一致,所以必须使用多维度MDS(multidimensional scheduling)对资源进行分配和均衡。
图2 系统架构
设计实现
1、多级调度
深度学习计算任务的处理过程是将原始数据放到神经网络中进行卷积和各种运算处理,所以运行之前需要先把网络模型加载到内存或者显存中,模型的加载和卸载需要较大的时间,所以一次模型的加载需要尽可能多的处理数据,但是作为调度系统考虑到balance,不能占用太长时间,所以需要对每个提交AI计算任务的session定义如下资源占比:
Fixed Workers:系统中只要有可用资源就优先分配足额的worker数量,这些worker是pre-start,以最快的速度来处理session中提交过来的计算作业,确保用户的计算作业能及时得到处理,保证作业处理的实时性;
Dynamic Share Ratio:当fixed workers配置的资源不能满足作业的计算需求,导致session中pending作业较多的时候,通过配置dynamic share ratio,按照配置的资源使用份额,申请额外的worker来加速处理当前session,所有session中的pending作业竞争按照share ratio比重分配可用资源。
2、Scheduler Policy
调度系统支持以下调度策略:
先来先服务:默认调度策略,先提交的作业优先调度派发作业到满足资源需求节点运行;
优先级调度:对作业和session设置不同优先级,调度系统有限处理高优先级的作业;
独占式调度:独占式调度可以让作业独占节点的计算资源。调度系统把作业调度到满足资源需求得节点,在作业完成前,不会让其他作业使用该节点资源,从而实现独占该节点资源的目的;
抢占式调度:抢占式调度可以让一个处于等待状态的高优先级作业,强行抢占一个正在运行的低优先级作业的计算资源。使得高优先级作业可以使用该计算资源,低优先级的作业在高优先级作业完成后,会尽快的恢复低优先级作业的运行;
GPU绑定调度:将作业调度派发到指定的GPU卡运行,避免多个作业共享GPU导致相互干扰,实现GPU的绑定调度,提高作业运行效率。
3、Scheduler Policy Plugin
随着应用的不断发展,用户对调度策略也会有不同的需求,除了系统提供的调度策略,调度系统还支持用户开发自己的调度策略,以满足不同的作业调度需求,调度系统以插件模式方式加载用户自定义调度策略,实现调度策略的深度定制,提高调度策略的灵活性和可配性。
4、Cloud Plugin
当本地集群没有足够的资源来处理时,可以通过Cloud Plugin动态申请云端计算资源,这样便可以组成Hybrid Cluster以增强本地集群的算力,目前可选的公有云提供商也比较多,可以同时申请多个公有云的资源组成多云Cluster。
5、资源的分配和计算
调度系统提供2种资源分配和计算的方式,一种是按照每种模型作业的资源需求固定分配,一种是通过调度系统自动调整每种模型作业对资源的需求,实现自适应的资源分配。
固定分配:作业在申请计算资源时,如果通过调度系统按照作业的需求分配资源,有可能会出现作业申请资源过多,作业在实际使用计算资源时没有充分利用现有的计算资源,导致计算资源的浪费。因此调度系统提供资源固定分配模式,每种模型作业按照使用的经验值,配置模型作业的资源消耗,调度系统在启动作业时会自动计算系统所有的资源池,按照节点的负载信息和作业资源配置情况给每个作业分配相应的资源,确保作业能分配到满足的资源,不会引起资源的竞争,提高资源的使用效率,待作业运行完毕,调度系统及时将作业的资源回收,下一轮调度时,分配给其他作业使用;
自适应分配:当作业的资源需求配置和实际使用的资源误差较小时,固定分配模式能满足每种作业的资源需求,但是如果配置的资源需求和作业实际使用过程中使用的资源误差较大。比如模型加载后,不同的输入数据对资源的需求都不一样,如果配置固定的资源需求,会导致部分作业资源需求得不到满足,实时性得不到保证,而部分作业又使用不完分配的资源,导致了资源的浪费,调度系统提供资源自适应分配方式,作业启动时,先给作业分配一个最低阈值的资源需求,然后调度系统在运行过程中,不断收集作业资源使用情况,根据作业实际资源使用情况,动态调整作业的资源需求,实现自适应的资源分配,提高资源的使用效率。
6、API
调度系统提供相应的API开发接口,方便对调度系统进行定制化开发,满足用户的特殊需求,主要提供以下API接口:
集群:查询集群状态、集群相关信息;
作业:实现作业的提交、查询和控制等;
节点:节点状态查询、资源监控和节点控制等;
调度策略:实现用户自定义的调度策略;
资源:查询集群资源使用情况、吞吐量等。
7、Block Host/GPU
人工智能作业在应用中对计算任务的顺序和完整性有比较高的要求,比如视频的计算任务需要按照视频帧的顺序进行处理完整才能得到最终能的统计数据。所以对集群的硬件计算设备有比较高的要求,调度系统提供以下2个功能,方便实现硬件的扩展和维护:
Block GPU:基于成本考虑,大部分企业不会直接选择Tesla GPU进行计算,一个Tesla P4专业GPU的价格是GTX1080Ti的4-5倍,但是性能却只有2倍左右, 当然GTX1080Ti是消费级的GPU,作为企业应用的话稳定性肯定比不上Tesla P4,所以一定要考虑GPU出现故障的场景,这时候就需要单独Block故障GPU,在调度系统中标记排除,不再将作业派发到这类GPU,确保计算作业的正常处理,但是其他可用的GPU可以继续分配作业使用;
Block Host:作为长时间运行的GPU服务器也有可能随时出现故障导致作业不能正常结束,调度系统通过命令行接口,可以Block该故障机器,将机器标记成不可用状态,确保没有新的作业派发到该节点运行,以免影响整个作业执行的顺序和完整性。另外,如果需要对该节点进行维护升级,可以通过Block Host功能,在不影响已经运行的作业情况下,调度系统不派发新的作业到该节点,直到节点上的作业运行完毕,方便对设备进行维护升级。
8、High Available
HA在商业系统中是不可或缺的功能,往往体现在系统设计的各个层面。
作业维度:作为调度系统,必须保证每一个提交进去的作业被正确执行,作业运行过程中很有可能因为各种原因发生错误,首先需要做的就是本地Retry,当本地Retry到一定次数后需要考虑Host环境因素由调度系统调度到其它机器进行Retry,如果再次失败到一定次数,可以标记Task为Fail。另外,对于支持检查点的作业(checkpoint),调度系统提供接口支持定期对作业进行checkpoint,方便作业及时恢复和迁移,对于不支持检查点的作业,调度系统对每个作业的运行状态记录相应的events,当调度系统重启后,能根据events恢复作业的运行状态,确保作业的正常运行;
GPU维度:AI计算使用的GPU一般都是高端显卡,功耗有比较大,在测试和应用场景中经常会发生GPU无法使用的作业,当一些作业连续在同一个GPU上失败后,调度系统需要将该GPU标记,并在后续的调度中排除该GPU的使用,确保作业能正常的运行;
节点维度:类似于GPU维度,调度系统如果检测到计算主机不可用,需要将该主机上目前运行的任务重新分配到其它计算节点继续执行,将该计算主机标记并排除到后续的调度中,同时当该主机恢复后能继续加入到计算列表中进行任务分配;
Scheduler维度:Scheduler具有Master scheduler和Slave Scheduler,通过ETCD选举Leader进行调度,Scheduler需要启动多于3个节点,当Master Scheduler进程离线后,ETCD可以确保选出一个新的Mastre scheduler接管当前的调度任务,同时Master Scheduler需要实时同步当前资源分配计划到ETCD cluster,在新的Scheduler启动后快速从ETCD同步数据恢复现场,保证集群可用性。
9、算法编排
一个完整的人工智能应用,在一个流程中可能会用到好几个模型算法,为了能快速适用于不同客户的AI需求而不用频繁修改代码,需要能快速组织出一个新的流程,类似于集群和容器的编排,算法编排用于快速定义一个机器学习程序的计算流程以实现一个完整的商业需求。
将不同的算法功能模块抽象为公共算法模块,这些算法模块组织成流水线来完成一个完整的算法输入和输出。输入参数为采集过来或者实时的原始数据,比如文本、视频、图片和视频流等,输出就是具体检测跟踪或者提取的结构化数据,可以用来存储到关系型数据库或者NoSQL数据库。
通过模型编排组织起来的算法流水线能够以最快的速度进行AI处理,可以极大提高AI产品的实时性和性能。
图3 算法编排
作者:吕金明,系统架构师,长期从事分布式计算以及大数据相关的研发工作,以及大数据产品的集成,如Spark、Docker、Kubernetes、Tensorflow等开源框架及技术。李松松,高级软件开发工程师,一直从事分布式计算、集群作业调度系统以及HPC相关的研发工作。
声明:本文为作者投稿,版权归其个人所有。
热 文 推 荐
☞ iPhone 大降价;谷歌再爆丑闻;京东云金山云回应合并传闻 | 极客头条
☞ 从 C++98 到 C++17,元编程是如何演进的? | 技术头条
☞ 刚刚!程序员集体荣获2个冠军,这份2018 IT报告还说这些!
print_r('点个好看吧!');
var_dump('点个好看吧!');
NSLog(@"点个好看吧!");
System.out.println("点个好看吧!");
console.log("点个好看吧!");
print("点个好看吧!");
printf("点个好看吧!\n");
cout << "点个好看吧!" << endl;
Console.WriteLine("点个好看吧!");
fmt.Println("点个好看吧!");
Response.Write("点个好看吧!");
alert("点个好看吧!")
echo "点个好看吧!"