腾讯音乐栾鹏:cube-studio 开源一站式云原生机器学习平台
分享嘉宾:栾鹏 腾讯音乐 高级数据工程师
编辑整理:许世杰 西电
出品平台:DataFunTalk
导读: 本文将分享腾讯音乐云原生一站式机器学习平台的功能及未来规划。开源地址:
https://github.com/tencentmusic/cube-studio
可一键快速部署到私有化集群。
文章包括以下几大部分:
- 一站式工程化
- 分布式加速
- 推理闭环
- 边缘计算
01 一站式工程化
在没有端到端的机器学习平台之前,流程比较复杂繁琐。
开发一套完整地机器学习流程,需要人工介入很多问题:
- 向运维申请机器
- 评估cpu和gpu资源
- 对大数据量场景申请分布式存储
- 存储膨胀,持续向运维申请更多算力资源
- 算法开发环境,大多用自己熟悉的框架版本
- 代码开发会绑定机器,则机器故障或裁撤时很棘手
- 迁移或离职交接难
- 打标、自动化处理等任务占据cpu时间且资源不共享,导致gpu利用率不高
- 任务编排,通过不同同学间的共享文档或存储交互,写shell脚本执行
- 很多团队缺乏算法后台工程师,不具备高性能部署、在线运维等能力
针对这些问题,我们提出了一套完整的云原生的一站式解决方案,能够方便地进行私有化部署,适用于推广搜、音视图文本等场景训练和推理。
其中平台底层统筹算力,不需要用户关注,支持用户自定义资源,支持共有和私有资源控制,存储也是类似,进行统一规划,同时并支持用户私有资源或平台公有资源。
在基础能力层,平台或用户可以自己封装分布式框架(例如分布式训练框架),训练框架之上是直接接触用户的一站式端到端的功能,包括在线开发、参数调优、模型编排、模型部署、分布式能力以模型市场的形式开放给用户开发和使用。
1. 平台核心能力介绍
- 统筹算力
平台基于云原生建设,linux内核进行标准化。内核版本低会导致容器之间的带宽效率低,而分布式训练对内核的通信要求比较高,故对内核进行了升级和标准化,容器带宽达到了20Gb/s。cpu采用大核心的配置,方便调度pod资源。gpu是异构的,需要结合用户需求选择,但不建议在训练中使用vgpu,不然容易出现算力零散的问题。界面操作支持自定义私有docker仓库,用户可以自行配置。
- 多集群部署
部署方面,涉及训练、调试、服务化等集群资源分配问题,也涉及多项目部署/多区域部署的资源分配问题,同时还有公有资源和私有资源共存的问题,全部这些管理需求在平台ui端通过项目选择进行管理,平台控制和用户控制相结合的管理方式,像训练/调试部署至各自集群由平台控制,用户需要使用私有资源,则可在项目组中配置该组对应的资源池。
- 分布式存储
开发、训练、存储使用统一的分布式存储,用户不需要感知数据在哪里。只要在平台启动容器,则/mnt/username指定目录下就是个人数据,用户之间数据是隔离屏蔽的,互相不可见。对音视频领域的数据在组内共享的问题,此场景下不同用户间的数据需要可见,对此也支持组模式的存储共享。
另外,平台支持自带存储资源或使用平台公有资源的不同服务形式,公有资源建议使用高性能的ssd ceph,对接外部存储使用性价比高的cfs进行链路打通。
- 在线开发
开源版本集成了jupyter、vscode等开发工具,可以创建多个cpu/gpu实例。开发者可在notebook镜像中集成公司内部常规linux开发工具(git/spark客户端等)。使用在线开发的切换成本相对低很多,针对特殊场景开发者可以加入类似tesnorboard/pandas等插件,制作定制化notebook,进一步提升使用效率。
cube同时集成在线开发镜像构建功能,对Dockerfile进行包装,屏蔽实现细节,对算法同学,仅执行命令行即可实现镜像打包。
- Pipeline编排
直接使用airflow/argo等调度组件,但没有编排界面,直接编辑yaml也很麻烦。 所以我们单独开发了模板市场和pipeline编排工具,并在开源中提供多种分布式模板 。例如分布式的tf/pytorch/mxnet/kaldi/horovod分布式训练,ray/volcano分布式数据处理或nni分布式超参搜索。用户通过拖拉拽方式编排pipeline,配置执行参数后就可运行。
- 模板开发
模板市场的模板是注册进去的,用户和平台都可操作。流程比较简单:准备镜像,标注清楚该镜像的参数、类型、限制条件、用户提示等,使用标准化的注册流程注册至平台后,平台用户就可使用该模板。模板开发者多为平台方或使用方组织架构内特定工程人员。
- 单任务调试
Pipeline的调试多集中于单task的调试,每个task可能是单机或分布式task,对于单机task可以进入命令行直接运行,对于分布式task,可以直接查看全部日志的聚合结果,而不必逐个pod查看,同时可以查看每个task的资源使用情况。在音视频领域,因数据量大,资源利用率的优化对整体耗时的提升有明显帮助。
- Pipeline调试
使用kubeflow的任务流调试查看,支持任务流重试,运行状态,实时/离线日志等。
- 定时调度
重新开发定时调度,支持模板命令、补录、重试、忽略、依赖、并发限制。
- 超参搜索
nni超参搜索需要用户编写侵入性上报代码。
#上报当前迭代目标值
nni.report_intermediate_result(test_acc)
#上报最终目标值
nni.report_final_result(test_acc)
#接收超参数为输入参数
parser.add_argumen(‘—batch_size’, type=int)
katlib超参搜索是Kubeflow自带的,要求按照规范上报日志,分析每次训练的变化。
通过上面的方案,整个ml流程操作简单,通过模板,使用可视化托拉拽的方式构建ML任务流,支持数据拉取、处理、训练、校验、部署,快速搭建流程。
但是搭建好后会发现虽然编排流程简化了,但是运行时间并没有减少,耗时主要集中在数据处理和训练上。数据处理分为结构化和非结构化数据处理,对于结构化数据处理,像sql等形式目前还是采用公司已有的大数据spark平台,对于非结构化数据处理/训练以及结构化数据的训练部分的耗时,考虑使用分布式的加速方式。
02 分布式加速
分布式加速存在以下问题:
分布式框架选择多,如果封装一套标准的分布式框架,则用户侧的迁移成本高,且训练逻辑脱离平台后可能不通用。从算法角度看,算法同学手里的算法很多是直接参考其他开源算法,梳理代码已经比较耗时,再去适配平台封装的分布式框架是很困难的,并且开源的项目里面很多已经携带了分布式的代码。
1. 分布式框架
- 平台底层以k8s为核心调度部署各种类型的分布式集群;
- 在此外面封装了一层框架层分布式,将用户常用的分布式框架例如分布式sklearn-lib、tf、pytorch、volcano、ray、spark、mxnet、kaldi、nni等分布式框架均集成进来;
- 更外一层是算法/功能层面,将音视频图像分布式文件处理、传统机器学习分布式、推荐算法分布式、音视频文本算法分布式、多模态算法分布式等集成进来,对于没有的算法,用户侧也可以将自己实现的分布式方案以模板化的形式注册进来。
2. 存储+通信
解决了分布式框架问题之后,性能不一定会加速。
直面的第一个问题就是存储io。平台侧封装的模板可以定向优化,部分通用性模板开放性较高,不对用户逻辑做限制,仅对用户提供分布式能力,此类模板用户的训练性能可能存在io瓶颈,很难将io优化全部下放至用户代码层进行优化,所以我们在io层做了一层全局优化。从cfs切换到ssd ceph,最终性能达到G级别的写入和7-8G级别的读取,满足大部分训练需求。
随后发现cpu使用率明显上升,但此时网络索引问题成为下一个需要的解决的问题,特别是音视频领域。在推荐场景下,一般是csv格式的大文件(10G+),数量相对少,但是在音视频文本领域,存在上千万的大量小文件,容易卡在高频率的网络请求上。平台的文件存储在远端的分布式存储中,但是计算集群可能是不同网络的私有集群。在当前网段新建ssd ceph,抵消网络异地或者跨网段时延。定向优化后,训练性能在GPU上再提升3倍以上。
在此基础上支持用户私有资源的使用能力,我们开放给用户配置使用私有存储,打通标注平台(ceph类的对象存储或者cfs存储),允许用户直接挂载过来,这样与外部数据标注或者数据集平台联动。
经过存储优化后,可以看到io的耗时占比在链路中明显下降,但是通信时延占比超过总耗时的55%,排查之后发现是linux的tcp内核bug,使用高版本linux 4.14+已修复,容器间带宽提升至20Gb/s,则通信问题也降级为次要问题。
3. 资源利用率
对cpu分布式任务,用户可自己借助多进程、协程提升单个pod的cpu利用率。此部分倾向于让用户申请更多worker数提升性能。对于用户没有主动优化cpu利用的情况,支持通过系统的监控和智能调整优化方案将该任务的资源申请值调整至合理的范围,进而提升cpu使用率。
gpu比较特殊,平台在训练过程中对gpu的占用为整卡占用的方式,因为在训练中使用vgpu非常容易出现卡零碎浪费的情况,并且即使使用vgpu,并处理好零碎卡的问题,提升了平台整体gpu利用率,但任务耗时没有降低。故平台方倾向于提升用户占用的gpu卡的单卡利用率,进而提升单个分布式任务的运行效率。
gpu利用率低的核心问题是gpu等待时间太长,可能cpu处理或io等操作,包括优化磁盘存储、数据加载、网络通信、预处理、cpu上的模型保存。
对用户完全自行开发的代码,平台方会根据监控配合用户进行针对性优化,提升gpu的利用率。例如对临时性的高频文件使用内存映射磁盘(libariry库);训练框架io加载的并行参数优化;计算和数据同域分布;音视频的小文件合并成大文件;专用并行io库;cpu数据处理和gpu计算分隔成两个任务处理,降低cpu和gpu切换开销;使用gpu来进行处理;batchsize调整把gpu打满。实际实践中,wenet分布式音频提升30-50倍的效果(200h音频文件单卡训练3天,现在1.8万h音频22v100,4天训练时长)。
4. 共享GPU
对于一些场景,平台或用户不能投入人力定向优化,比如推荐中cpu & gpu混合任务场景,更倾向于使用共享gpu的方案。
在云原生多机多卡训练中,大部分框架每个worker默认会占用卡的全部显存。但是因为代码处理可能并不能将单卡的核全部利用起来,这种场景可以配置单个卡上跑更多worker,对应的整个环境变量的配置跟随变动,例如pytorch的WORLD_SIZE,RANK,LOCAL_RANK。
至于每张卡上启动多少个进程来共享同一张卡,需要结合最先达到瓶颈的资源,考虑cpu和gpu的配比情况来看,比如对推荐场景,一般是cpu先达到瓶颈。gpu机器设备上cpu资源相对少的特性(3个纯cpu机器算力有200多核,但4卡gpu机器只有60个核cpu),cpu和gpu是一个相对匹配的算力。在共享gpu的方案中,根据哪一个资源(cpu/gpu)优先达到瓶颈,就可结束进程增加。
另外一些分布式多机多卡训练,本身就是共享gpu卡的,比如在Kaldi语音识别中,默认显存占用率为50%,移植到k8s中后,修改从申请50%显存调整至20%,则并发数就可以增加,利用率直线上升。
5. Scheduler调度
解决cpu和gpu使用率问题后,下面需要解决多个分布式任务之间,或者一个分布式任务不同的pod之间能够跑得更稳定,降低相互影响的概率。调度层是由k8s的过滤和打分策略来决定,能让用户在使用时充分利用资源。
- 首先是批调度能力 ,针对分布式任务间的资源竞争死锁问题,加入kube-batch的gang。
调度能力,只有当一个分布式任务所需资源全部满足时才开始调度,避免死锁。
- 另外是亲密度和调度算法的调整:对cpu型任务倾向于把不同的任务分配到不同的cpu机器上避免单机瓶颈;对gpu任务,多个任务尽量分配到同一个gpu机器上,减少网络通信消耗;对同一pipeline中的不同任务,尽量部署到不同的机器上,避免存在相似任务任务达到单机瓶颈,因为有些任务受机器白名单限制等;对于不同的pipeline,放到算力相对空闲的机器上,平衡集群使用率。
6. 资源组均衡
因为gpu机器资源比较昂贵,直接新采购一批gpu,让算法同学迁移,成本是比较高的,并且现存的gpu是保存在各个业务线自己的手里面,所以平台支持多集群多项目的资源池管理。对资源的管理分为公有项目组和私有项目组,项目组的资源可分为可共享资源和不可共享资源。在资源紧张时,将可共享资源共享出来供其他项目组使用,用完之后再归还,以此应对某个项目组突发训练大任务的情况。
7. 数据倾斜
分布式训练结构这里分为三类。
无状态的分发任务 (计算到当前步骤时现场进行任务分发),这种情况不存在数据倾斜问题。
有序的无状态任务 (提前分配好任务,申请多少worker,每个worker分配什么任务,会在训练前进行分配),会存在任务倾斜问题。
分角色有序任务(提前分配好任务,但到达特定步骤时,worker之间会相互通信信息),这种情况也会存在数据倾斜,但此类问题较难调整,会涉及到算法的变动,容易影响算法准确率。
这里仅说一下有序的无状态任务。例如一个任务提前分布好每个worker的内容,当数据分配不均匀和部分worker受其他机器worker影响时,性能会下降,此时每个worker剩余任务数量就不一样,导致用户任务迟迟不能完成,不能推进其他事情。部分用户强制终止,重新分配剩余任务。
对于参数可共享的任务,通过共享内存将内容直接放到远端处理。对于参数不可共享的任务,例如tf加载模型,模型变量无法共享(很多线程锁存在,导致模型参数不能序列化到其他机器),这种情况建议使用队列方式,消费者根据当前gpu资源弹性伸缩,并且可以在单卡上启动多个消费者,保证gpu的利用率。
8. 优化方案总结
综上,平台对分布式训练的优化,分成四块:
- 在用户代码层面,深入进程内部进行优化;
- 在数据层面,避免数据倾斜、优化数据加载;
- 物理层面,优化大文件、带宽问题;
- 在此之上,使用共享gpu提升使用率,动态cpu算力调整,上层优化任务调度,亲密性,多项目组的资源共享等。
03 推理闭环
1. 数据链路实时闭环
开源平台不包含数据部分,主要是因为公司内部存在很多标注平台、特征平台等。引入这些平台,直接进行模型训练,执行刚才提到的pipeline流程,大模型、分布式、多集群的调度、优化gpu利用率。模型上线后,在线推理部分包括工具化管理、加速、hpa、服务pipeline,通过流量复制做音视频在线数据直接回到标注平台进行新数据打标,重新导入模型训练。
2. 模型服务化分层
模型推理部分平台构建了一套模型管理的工具,通过服务网格做分流和复制,服务内部使用http框架,服务切分为模型前/后置处理和推理。模型推理使用tensorrt做横向和纵向的gpu加速,同时支持tf、onnx、pytorch、用户自定义镜像。用户自定义一般是用户的算法工程人员将组内模型封装成镜像,而不是使用平台的镜像封装。平台方更多是提供零代码发布的能力。服务管理主要是模型管理、代码管理、镜像管理,云原生服务的hpa能力,除了自带的cpu和内存指标,平台支持prometheus adapter,根据gpu利用率、时延等可以采集的指标做资源弹性伸缩,同时开放接口给到用户,可对接用户外部平台,进行性能和资源分析。
3. 稀疏embedding大模型实时训练
部分场景有实时训练的需求,自研的TMEPS,对接流式数据,用户需要将加工好的实时特征上报至实时队列中,平台将订阅队列,对大规模稀疏模型集成tfra,这里有 两个主要功能 :
- 将embedding模型参数放到kv中,训练集群ps内存仅保留dense部分。
- 动态参数准入准出,可以大幅压缩模型体积。dense部分热更的方式更新到推理端,稀疏embedding部分,推理服务接收推理请求时,现场lookup 读取kv数据库,同时整个模型会使用离线模型进行日更处理,这一部分也逐渐开源到github。
04 边缘计算
通过边缘集群的形式,在中心节点部署平台,并将边缘节点加入调度,每个私有网用户,通过项目组,将notebook, pipeline, service部署在边缘节点:
- 避免数据到中心节点的带宽传输
- 避免中心节点的算力成本,充分利用边缘节点算力
- 避免边缘节点的运维成本
01/分享嘉宾