大家好,我是哲销宇来自旗鼓360智能工程部的积极学习工程师今天由我给大家介绍一下我们的工作DGL Creator以及如何在Kubernetes之上使用DGL框架来运行一个单节点或者多节点的DGL分布式训练任务如果开发者朋友们有更多的问题或者思考也欢迎在这个分享之后联系我或者直接在我们的项目report给提一数现在我们的report拖桿在我们自己公司的github组织下我们也一直在积极配合Conflow开源组织并期待和平到上游的社区希望明年年初的某个时间大家可以在社区里见到我们好的,在今天的赛行里头我会围绕五个点跟大家分享一下DGL Creator相关的话题首先第一部分我将介绍一下DGL Creator和DGL的背景比如简单聊聊什么是图书您网络什么是紧还有就是DGL是个什么样的框架接下来第二部分我将简单介绍原生的DGL分布式训练方案以及如何在VM或者物理机上去执行原生方案但是在生产级别的集群中这种执行方案具有哪些挑战呢之后第三部分我将引出我们提出的这个方案将如何去解决这些问题和挑战以及怎样利用DGL Creator负能DGL在K8s上进行训练紧接着第四部分我将深度讲解一下DGL Creator的设计和实现最后我会谈谈DGL Creator将会朝着哪些优化点继续前进这里有一些名词需要提前解释一下有助于大家理解某些表述的上下文第一个就是DGL Run我们开发的一个基于DGL的工作流脚本该脚本可以在容器级别控制切图分布式训练和一些工具函数的按序调用第二个就是Watcher Loop我们开发的基于MPI Operator中Coop Control Deliver组建的变种该变种不仅可以跟踪所有的功能负载的就续状态也可以跟踪所有工作负载的完成状态其中Coop Control相关的功能被我们移除了所以我们更新了名字那么移除了Coop Control我们放到了一个新的镜像里头就是Coop Control当捞的一个迷你镜像它完成原来Coop Control Delivery组建中下载所依赖的Coop Control二键质文件的工作最后一个是IP Config 一个文本文件用于纪录DGL训练时server所需要的各个训练工作负载的网络信息如PoName,IP,端口,GPU数量等首先第一点我们先来了解一下DGL operator和DGL的背景DGL框架是由AWS,AI Lab及NYU团队联合创造并开发的在我们360内部我们有像搜索和商量化这样的业务团队想去尝试GNN及Graph Inviting的需求所以我们团队承担了这个项目并且将它应用于我们的纪录说日上及KBiS日上这个是DGL.AI是DGL的网站它的全称是DGraph Library聚焦于解决图神经网络的应用场景好,首先我们来聊一聊GNN近两年GNN在搜索推荐知识图股等领域有着着成效的成果但是经过大部分开发者的实践比如TensorFlow,PyTorx,MSNet和其他的一些深度学习框架虽然能够胜任GNN的场景可他们并不能给出现一个或者创造一个GNN模型带来很好的体验开发者们不仅需要搭建GNN网络有时候还需要额外的精力去处理内存血路、内存爆炸等问题除此之外,这些常见的深度学框架默认都是基于绸密的Tensor表示但是一个GNN程序往往不是遵循这样的范围大部分时间开发者其实都是在对西输数据进行操作OK,那么GNN究竟是什么样子的呢接下来我将举一个GNN中GraphSage的网络模型公众化的简单例子它也是工业上普遍使用的图模型的除形大家可以看到左上角这里一开始假如你手里有一份表格式的数据级类似SV你然后将它们烙得进内存并把这份表格式数据通过节点和编的数据结构转换成一个大图就比如说这个数据级是关于论文所引的那么可以遇见到最终的大图中节点们都是论文,编则是云关系然后大家可以再往右边看下面右边有一个图这个代表的是GraphSage前向传播的三个步骤第一个步骤就是对于已经选好的出发的节点我们需要去采样它的邻居然后将这些采样后的第二步就是将采样后的邻居的inviting传告该节点上来通过一个聚合函数聚合这些邻居信息以便更新这些节点的inviting第三步就是利用更新后的inviting可以去预测该节点的label当然可以看到我右上角也列出来了除了去预测该节点的label不同的算法或者网络模型也可以解决节点分类图分类或者编预测的问题因此大家可以看到基因在未给模型的这些数据训练迭代时的逻辑表达这些地方并没有像CNN那么直观所以为了让用户给更容易的大件基因模型予亚马逊和NYU合作开发的DGL框架DGL框架建立于TF、PyTorps、MXNet这些MXNet深度框架之上设计并实现了很多基于Torps API进行了计划进行进行优化并且真正的使得开发者们可以构建开箱机用的基因模型DGL生态也有很多高层的库为了特定的领域打造的比如DGLKE和DGL Life ScienceDGL其实还有一些比较核心的既有点有兴趣同学可以研究一下比如说Message Passing这里我们就不再做展开了下面我们就进入正题了讨论一下DGL分布式的应用在工业界数据科学家或者机器学习公众是需要开发并搭建的基于DGL的基因模型需要有时去处理上百万上千万甚至上亿的点过边的大规模图数据所以去年的DGL推出了分布式训练的这种模式以适应大家去处理大规模图数据的需求这里给大家简单描述一下DGL分布式的架构DGL采用完全分布式的方案将数据和计算同时分布在一组计算资源中做分布式训练时DGL会将一张图切为多张紫图每一台机器各负责一张紫图为了并进化计算DGL在集群所有的机器上运行相同的训练脚本大家可以往左手边看每一台机子里头就是一个大的工作负载里头它的紫模块为server sampler和trainerserver主要是在存储紫图的每台机子上运行目的是将图数据提供给trainersampler是与server经营交互将节点和边采样以生成用于训练的小批次数据trainer包含多个与server交互的类它们分别是来获取小批达数据特征先入及紫图数据的通过上文的介绍我们可以预想到由于今天算法模型的独特性DGL在设计分布式训练时做了很多框架计算层面的考量比如平衡高性能异用性 复杂度等因素所以最终呈现在我们面前的是一个极其优秀的框架层的完整体系大家可以跟随我给的链接一步一步去执行实验性的DGL原生分布式的执行方案DGL团队给我们了一个从算法框架层面角度实践分布式训练的完整指导没有对基础设施层有任何的预设接下来我们将来更深入的讨论刚刚我们提到的这种DGL提供的原生分布式训练执行方案在生产集群里会面临哪些挑战其实主要是因为自动化程度不足导致了一些问题比如开发者需要预先启动多台物理机或者VM的环境第二个就是需要自行收集他们的IP 端口和GPU的使用个数手动将他们记录在ipconfig文件里第三点另外在这样的环境中开发者需要预先配置好免密的SSH全线第四点在partition切图的过程中你需要在master节点手动出发这个角度命令第五点就是并且你如果你需要去尝试分布式切图或者我们可能会后面提到你还会需要去自行安装parmatis的组件在分布式训练的过程中你还是需要在master节点手动出发这个角度命令最后一点就是当分布式训练结束后多台物理机或VM的环境以及GPU等计算资源需要手动的关闭或释放然后用于其他的业务无法做到无介入的资源释放自动化虽然DGL原生的分布式训练的执行方案很完整但对于生产级别集群的中端用户来讲还是存在一定困难的尤其是对于高成本的计算资源的变排调度和再利用就比如新款的这些GPU所以我们团队如何去解决这个问题呢我们自然而然的想到了operator这个体系它可以帮我们自动按虚创建所有的分布式需要的工作负载自动升升IPconfig无需手动去预先去设置多机间的SSH免疫免密可以帮我们自动去安装Parametix的组件自动出发训练或者切除命令自动释放工作负载对于高成本的这些计算资源可以动态的编排和调度OK 此外就是从operator的角度来看我们仅希望去解决自动化这个问题所以我们没有cover具体DGL内部是如何进行分布式训练的如果有cover这朋友们有感兴趣的可以点击这个链接了解更多的DGL分布式训练的策略和哲学OK 下面我们将从顶层架构给大家梳理一下我们这个DGL operator这个组件相关的一些内容OK 在我们的DGL operator的解决方案当中利用两部分使得DGL工作负载可以自动化第一部分就是主要的处于CooperNetix层的DGL operator组件我们这个operator还遵循Cubeflow社区的operator饭式我们下面可能会称这一部分为系统层第二部分是处于容器内的DGL Run脚本以及相关的工具函数控制DGL运行时的工作流我们下面会称这部分为硬层依靠K8S和operator的机制系统层将DGL图神经网络训练过程抽象为也去管理一个有状态的多容器应用对于每一个DGL训练任务首先系统层在硬层运行前开始进行任务的一些准备工作比如说自动创建所有的工作负载的实力自动生成IP Confec文件然后硬层在进行一步接一步的工作流期间需要系统层的配合完成每一个阶段比如说在工作负载内进行数据级载入切图和训练的时候还有一些工具函数有时候他们需要在彼此配合才能完成某些工作那么从各位开发者朋友们的角度我们的工具将如何使用呢用户只需要在KBS集群里提交一个我们提供好的压谋然后DGL Job自定义的资源就会加入集群随着镜像的成功拉取DGL Prater就付出好了接着用户需要将自己写的且符合DGL原生分布式策略的兄连大码与上门提到的DGL Run一同根据我们提供的Dalker File逻辑封装成业务镜像最后用户再提交一个带有训练参数业务镜像地址的压谋文件训练人物就自动的跑起来了OK 第四部分我们来探究一下DGL Prater的一些实现首先回顾两个概念数据载入和切分数据载入的Data loading是一样就是把表格结构化的数据转换成图结构化的数据Partitioning其实就是把一个大图切分成一个n个字图下面我们定一个最基本的DGL工作流这个工作流是DGL Prater支持的一个最默认的一个工作流是一个单接点的loading和单接点的Partitioning是一个多接点的分布式捶拎基于基本的DGL工作流我们可以拓展可能有三种场景的工作流现在都是在我们的DGL Prater有支持了第一个就是刚才提到的基本DGL工作流第二个就是一个无切途的工作流它用DGL内置的图数据然后去直接进行训练它主要是预讯验证一些你的初期的一些基因模型的一些想法进行一个单级的一个训练第三个是PowerMetis的这个工作流它是在基本DGL工作流上的一个拓展它把DGL API Partitioning单线程的切图换成了一个多进程的方案可以做到并行切图的一个能力然后依然是做备给多级点的这个捶拎进行一个分布式的一个训练我们接下来去介绍一下我们的工作负载有几种角色第一个就是WorkerPold它去真正执行多级训练的工作负载的Pold然后第二个是PartitionerPartitionerPold是执行单级切图工作负载的Pold最后一个是LauncherPold在这个Kubernetes中是控制整个DGL生命周期的Pold这个Pold包含多个Ninus Container容器和一个主容器这个主容器负责发送训练任务给WorkerPoldOK 第一个这个工作流就是先介绍一个简单的就是这个无切图的这个单级点训练刚才提到了我们在Python脚本中实际上是用DGL.data来获取GraphData然后直接进行训练然后可以看到右侧的压某然后在PartitionerMode写个skip就可以使用到简单的工作流第二个工作流是我们默认的DGL的基本的工作流我们管它叫做DGL API切图及分布式训练的工作流OK 接下来我们来详细的看一下这个基本的DGL工作流及DGL API切图及分布式训练这个工作流的具体的流程首先我们来看一下系统从Operator这层的工作流第一步首先创建一个ConfigMap它包含里头包含一个KubaEXGC.sh文件和一个IPConfig文件KubaEXGC.sh是一个工具脚本用于触发KubaControlEXGC远程执行命令第二步去创建RBAC资源是一些权限从而允许远程命令的执行第三步就是创建KubaControl当劳的容器我们之前前面也提到了它是一个是Launcher和PartitionerPold里头的一个InitialConditioner他们因为要去进行一些远程命令的执行所以它得需要有KubaControl的二进证文件在这两个Pold里我们分别再把它放到一个MTDR里头下载放进去然后它们Pold里头所有的容器都可以共享是用KubaControl然后第四点是创建PartitionerPold里头的主容器它去运行DGL RUN里头关于切图的命令相应的一些参数真正去执行DGL API式的切图但现在您的切图后面会着重去给大家看一下DGL这个功能流我们在Operator的功能里头就不过多地追溯它了下一步就是当你PartitionerPold完成了就是刚才我提到的切图这DGL RUN切图这部分完成了那么我们创建的WaterloopPartitioner它就可以结束了因为它实际上是在一直监听的PartitionerPold什么时候能完成完成了它就结束了就可以往下走了第六步是创建多个WorkerPold直到符合期望的复本数你想有几个多级训练就是这个会有一个匹配直到匹配到了复本数然后并且默认执行的命令是一句sleep然后你在创建的时候它可能会大家都是并发的去创建所以得需要有一个WaterloopWorker这个langePold里头的另外一个监听状态的Indian Container它负责等待所有的WorkerPold都准备就绪了都是Running状态然后就随即继续下面的流程当所有的Worker都是就绪状态那么langePold中的容器就可以把DGL RUN中的训练这部分的命令去参数下发下去真正地去执行WorkerPold间的DGL分布式训练最后当所有的都执行完了DGL job也结束了全部的工作负载机器需求的这些资源都已经被释放了我们这里边再去延伸一下第4步就是我DGL的一些工作流还有第8步里头DGL的一些内容在英文层DGL这层的工作流是第4步它在当运行到Operator第4步的时候它这边就是先去运行DGL库里头的切图API将各个切好的自图落盘然后DGL RUN它去继续触发库不扛手CP这个命令将所有自图数据从PartiniumPold的考回LauncherPold然后PartiniumPold就完成了就销毁了第三步在LauncherPold的容器里头这是刚才Operator提到的工作流的第8步DGL RUN去触发一个库不扛手CP的命令将每一个自图从LauncherPold的分别分发到相应的WorkPold里头下一步就是将这个自图分发完毕DGL RUN会给每一个WorkPold下发相应的训练任务然后WorkPold就会自己去执行自己相应的训练任务它们就可以迅起来了最后当它迅完了LauncherPold也会变为完成状态然后WorkPold完成了之后也会被删除这个是一个压谋这里可能有一点点小感兴趣同学可以去看一看我们网站上的Gatehub上的我这里就不给大家具体的去介绍这些参数了但是大家注意的是第七行PartitionMode这里要写DGL API这是我们默认的DGL API的工作流然后再我们介绍我们支持的最后一个工作流Parametis病情切图及分布式训练的工作流这个工作流刚才也提到了它是我们定义的基本的DGL默认的工作流里头它有一个升级版它实际上把Partitioning从单线程的切比如你图很大你还得需要很大的资源然后还有是一个单线程的那就会很慢这里就用一个Parametis这个方案把这个部分加速把这个图通过这个多进程的程式进行切它就速度就变快了这里我就不再重复的去介绍这部分了我就提一下它不同点这里还是第一步 第二步 第三步都是一样的这里有变化是第四步第四步它的变化主要是存在于DGL这一侧它从DGL API的单线程的切图变成多进程的这里也没有一个没有区别我们就把这点就过掉了我们在这里去介绍一下实际上真正变化的主要是在1.1步1.1这个环节DGL让它去运行一个基于Parametis的多进程切图工具将它切好的紫图就落盘了后面的命令基本上是一致的然后我在这里提一下就是Parametis是我们内置在我们的document file里头了就是你只要准备我们document file的逻辑Parametis是不需要你自己去care的我们已经帮你去做好了编译的命令然后你直接用就可以了OK 这里实际上已经把我们线型的这套DGL operator的支持的东西都已经呈现给大家了最后就是这一部分我们将给大家来介绍一下我们被来的一些规划首先大家可以看到刚才我提到了就我们这个工作流实际上是123支持了这三种工作流但实际上就是我们可能大家更期待的就是会不会有一种可能性我们把多进程再升级一步变成多机的切图这里其实要跟大家提一下首先如果说你的任务或者说你GN如果真的可以在单击里头能跑通或者说单击能work的话尽量选择单击的模式因为你把它从一个大图切成多个小图多个紫图这种方案实际上还是有损的但是你要再考虑到这个图如果你的图真的很大然后可能就是你要需要全衡一下你觉得切图这种分属训练意出大 你还是要朝这条路走所以我们接下来会去想考虑一下去支持第四种工作流就是把这个病型的切图多进程的切图变成一个纯分布饰的纯多个多机的切图这种方式我们也在用来探索当中如果有比较了解这款的朋友可以帮我们去contribute你的这部分ideaOK 这里我再把刚才这个工作流如果我们真的纯只是dist metis的思路如果不全的话我们来看一下真正的全分布饰切图及训练是什么样子的这里就相当于前三步还是一样的OK 从第四步开始就把partitioner全都去掉了在worker里头去进行所有的任务只要worker全都ready了我们就进行一个全流程的djl的分布饰的流程闲切图 再训练之类的一样子的流程所以在djl run这一层的工作流也会发生变化就比如说它不再是运行djl API的命令也不是运行part metis的命令而是运行一个叫做dist metis的切图命令然后它直接就把此图数据落盘了我们也刚才大家上面留意的话其实也看到了一个通信的问题在里头这里连这个通信的问题都不存在了直接就是远离切图 切完图了就去训练OK 那这个很容易理解但是这个还是存在我们在探索当中里头也有很多细节并没有还没有放到PVD里头来希望如果真的有同学可以比较了解这块可以一起来去想一想然后这是第一个未来的规划点第二个未来的规划点就是刚才也提到了就是实际上大家在我们看我们这个方案的时候里头可能注意到了实际上我们是基于最小依赖的思想我们所有我们的方案里头会存在这么一步就是把全部字图从partisan点考回luncher然后第二步再从luncher考到把这个字各个字图分别分发到相当的worker pool里头这里头实际上有多一层通信的损耗在里头我们试过 但是没有采用的方案有两个第一个是luncher pool的这些切图这样的话如果说你这个计算资源特别大就是你这个图虽然切完了但是训练没训练完那你这个没训练完的话你这个luncher pool的不会变成这compete的状态那你这部分资源其实就没办法释放OK 那这个第二步第二个方案就是在partisaner pool的然后去进行分发字图一方面这个方案partisaner pool的需要比较高的权限而且luncher pool的需要与partisaner pool的进行一个实施的切分状态的一些同步或者轮寻使原本就比较复杂的状态机制就更加复杂了所以就是我们放弃了这两个方案以现在这个方案呈现给大家当然了我们也会去继续思考其下一个步怎么去做比如我们其中我们不想引入分布式FS或者共享FS主要是想给出一个最小依赖的方案当然了这个用户可以自行选择自己这个期望的方式从而通过FS这层把这个通信的给去掉这个大家可以自己去改造接下来我们也会继续去研究与集成更完备的FS和PVC的方案然后用户们开箱集用OK 我主要讲的内容就是这么多谢谢大家