2017-05-12 21:53:30 horsefoot 阅读数 22078

为什么需要集群管理与调度

上文我们简单介绍了深度学习、分布式CPU+GPU集群的实现原理,以及分布式深度学习的原理,我们简单回顾一下:

分布式CPU+GPU集群的实现:


GPU集群并行模式即为多GPU并行中各种并行模式的扩展,如上图所示。节点间采用InfiniBand通信,节点间的GPU通过RMDA通信,节点内多GPU之间采用基于infiniband的通信。

分布深度学习框架的实现:

如下图所示,在tensorflow中,计算节点称做worker节点,Worker节点主要完成模型的训练与计算。参数服务器可以是多台机器组成的集群,类似分布式的存储架构,涉及到数据的同步,一致性等等, 一般是key-value的形式,可以理解为一个分布式的key-value内存数据库,然后再加上一些参数更新的操作,采取这种方式可以几百亿的参数分散到不同的机器上去保存和更新,解决参数存储和更新的性能问题。

在分布式深度学习框架运行时,可以将深度学习框架部署到具体的物理集群,PS服务器可以挑选如下图中的node0、node1…,worker节点可以挑选如下图中的node i,node N-1


集群的具体配置,参数服务器可以不用GPU,worker节点因为需要进行模型计算,所在的服务器需要配置GPU卡。

至此,我们基本搭建了一个深度学习的硬件集群,同时也将深度学习框架部署到了深度学习的服务器集群,但是,整个深度学习集群(包括软硬件),可能是公司内部的共享资产,每个项目组都需要使用,那么,采取上述方式部署便会带来如下问题:

1.   要求项目组必须使用统一的深度学习框架,统一的深度学习框架的版本,否则不同项目组完成的训练代码有可能不工作,如果每次为了适应某个项目组的要求去重新部署框架,工作量巨大,而且耗时耗力;

2.   其中一个项目组在使用集群时,其他项目组往往需要等待,导致集群的资源使用率较低;

3.   服务器集群中任何一台硬件出现问题,都会影响整个集群的使用。

集群管理与调度实现的两种思路

基于Kubernetes平台

Kubernetes是Google开源的容器集群管理系统,其提供应用部署、维护、 扩展机制等功能,利用Kubernetes能方便地管理跨机器运行容器化的应用,其主要功能如下:

1) 使用Docker对应用程序包装(package)、实例化(instantiate)、运行(run)。

2) 以集群的方式运行、管理跨机器的容器。

3) 解决Docker跨机器容器之间的通讯问题。

4) Kubernetes的自我修复机制使得容器集群总是运行在用户期望的状态。

Kubernetes自1.3开始支持GPU,但当时只能最多支持单GPU的调度,自1.6开始,已经支持多GPU的调度,更多关于Kubernetes的与GPU介绍可以参考本系列未来的第3篇:分布式机器学习的两种集群方案介绍之基于Kubernetes的实现,这里不太多赘述。

如果要完成基于Kubernetes的集群调度管理深度学习框架,需要将深度学习框架运行到容器之中。系统整体架构图将变为:

这里面涉及到一个Kubernetes集群调度的问题,即Kubernetes如何将ps、worker所在容器所需要的CPU、GPU、内存、存储进行调度,以满足需求。

集群经过Kubernetes进行管理以后,分布式深度学习框架运行在容器中,容器通过Kubernetes进行调度以满足所需的模型训练资源,因此能够很好的满足集群资源多部门共享的要求。我们看对以下问题的解决。

1.   要求项目组必须使用统一的深度学习框架,并要求统一版本,否则不同项目组完成的训练代码有可能不工作,如果每次为了适应某个项目组的要求去重新部署框架,工作量巨大,而且耗时耗力;

解决:基于容器+ Kubernetes平台,每个项目组可以很容易的申请自己所需要的深度学习框架,tensorflow、caffe等,同时同一种深度学习框架的多种版本支持也不在话下。

2.   其中一个项目组在使用集群时,其他项目组往往需要等待,即使集群的资源使用率较低;

解决:只要集群有利用率没达到100%,便可以方便地为其他项目组部署深度学习环境。

3.   服务器集群中任何一台硬件出现问题,都会影响整个集群的使用;

解决:通过Kubernetes的调度,完成底层硬件的容错。

天云软件基于Kubernetes平台研发的SkyForm ECP平台,已经完整的支持了GPU调度,同时也集成了tensorflow,caffe等深度学习框架。

基于MPI并行调度

我们此处引入HPC领域中的MPI集群作业调度管理解决方案,因为在神经元网络(也包括含更多隐层的深度学习场景下),上一层神经元计算完成以后才能进行下一层神经元网络的计算,这与MPI的计算思路不谋而合。MPI是高性能计算(HPC)应用中广泛使用的编程接口,用于并行化大规模问题的执行,在大多数情况下,需要通过集群作业调度管理软件来启动和监视在集群主机上执行的MPI任务。此方法的主要目标是使集群作业调度管理软件能够跟踪和控制组成MPI作业的进程。

一些集群作业调度管理软件,如IBM Platform LSF、天云软件SkyForm OpenLava等,可以跟踪MPI任务的CPU、内存、GPU的使用。我们把每个深度学习的计算作为MPI作业,通过天云软件OpenLava作业调度管理软件进行集群统一的资源管理与分配,具体的实现思路如下:


基于集群作业调度管理的解决方案,也能很好的满足深度学习集群多部门共享,多作业并发运行的特性,且能兼顾效率。

其中天云软件SkyForm Openlava是一个增强的、基于开源OpenLava并兼容IBM® Spectrum LSFTM的企业级工作负载调度器,并针对半导体研发、深度学习等的工作负载做了设计与优化。不论是现场物理集群部署,虚拟基础设施部署,还是云中部署,客户都不用支付高昂的许可证费用。具体的openlava介绍,可参考网站openlava.net。

另外,在深度学习框架需要基于MPI方式运行时,往往需要进行重新编译,并不是所有的版本都支持。
2017-09-25 10:12:49 csdngkk 阅读数 37
云平台分布式调度系统的演进—658人已学习
课程介绍    
201709251009275852.jpg
    深度介绍公有云后台的内部架构设计与实现。首先从云计算的核心挑战开始,分析在大规模集群当中云的分布式调度系统需要解决哪些主要问题,然后详细讲述业界的一个发展历程,尤其是OpenStack在这个历程中的意义和价值,以及一些新兴的开源软件对云调度系统的总结和反思。后会重点讲述腾讯云VStation基于腾讯的海量后台经验,如何设计腾讯云的后台架构和经验总结,并与OpenStack做一个对比。
课程收益
    愿意了解云平台内部实现的技术人员。
讲师介绍
    CSDN公开课更多讲师课程
    CSDN线上公开课全掌握!
课程大纲
  第1章:云平台分布式调度系统的演进
    1.云平台分布式调度系统的演进  47:58
大家可以点击【查看详情】查看我的课程
2018-07-27 17:17:32 zhaoyuyuan88 阅读数 337

自主研发深度融合CAE仿真的高性能作业调度软件之GRID-MASTER产品定位

    科百华自主研发的深度融合高性能作业调度软件GRID-MASTER,投入到生产环境当中受到用户的广泛认可。

微信图片_20180111104039.jpg

1、从Windows到Linux是仿真的一个飞跃,即使不懂Linux的仿真人员也能用好GRID-MASTER

      目前95%以上的HPC集群运行在以稳定安全的企业版Linux平台上,而我们绝大部分仿真人员是从Windows单机软件开始接触和使用CAE软件的,这两者之间使用方式有着巨大的差别.GRID-MASTER的出现让不懂Linux的仿真人员在Linux集群系统上进行仿真计算,而不用直接操作Linux集群.

微信图片_20180111110617.jpg

2、尽管应用人员趋于分散,也能到完善、便捷、稳定的提交环境从而提高集群的使用效率

    在仿真软件与计算资源不断增长和集中的同时,而应用人员却趋于分散。这往往给软硬件资源管理和高效使用这些资源带来的瓶颈。GRID-MASTER致力于构建完善、便捷、稳定的作业提交环境,减少维护成本,提高HPC集群的使用效率。

微信图片_20180111111127.jpg

3、摆脱繁琐复杂的命令上传操作,提供友好管理界面和及时报错提醒

     GRID-MASTER直接面向仿真应用工程人员,为其提供与后台计算资源和完善友好的作业提交管理界面,并实现了作业的多用户、多作业并发提交与管理。本系统不仅支持大规模计算,而且对前、后处理以及实时监控功能有非常好的支持。

微信图片_20180111135420.jpg

2014-02-13 17:13:33 tenfyguo 阅读数 1318
小结一下自己的思考,自己心目中的云和云计算的几个技术特点:
1,高度抽象的服务封装;
   个人觉得这个是最重要的,任何工作和架构,只有能够足够抽象化才能做到“不变应万变”,但这个也是最难的,需要对业务和需求的场景的深度和广度有
   非常深刻的理解,并且能够抽象建模。


2,基于资源池的调度;
   举一个简单的例子,如某个节点的机器坏了,可以直接从资源池中拿一台替换,并且是自动甚至是智能的,而无需去修好机器后再换上。 
   
3,按需获取;
4,弹性扩展:
   由于是基于高度抽象的服务,因此弹性扩展是一个延伸的特性了


5,低成本:
   云化的一个很重要的目的,在于资源复用的效率会更高,因此成本也会更低,举一个例子,如   


6,分布式:
   分布式是一个潜在的需求,从资源复用,全局调度,弹性扩展等要求都需要分布式的支持
   
7,安全性:
   云化后的服务和部署应该是已经内置了安全支持的了,对服务的使用者来说,无需过多关注这块的运营安全性,监控,调度,防攻击,智能流量切换等均是重要的能力。
2016-04-10 22:45:57 GH234505 阅读数 6000

  由于GPU目前在各行各业的广泛应用,无论是深度学习、大数据、云计算等都离不开GPU的并行加速,前阵子自学了Cuda-c编程,希望将来的研究工作能够用得上。
  Cuda系列总共有4篇,这里主要用于记录本人学习过程中的一些问题的思考和总结,及网上汇总摘录的别人的一些总结、看法等,并不适合新手入门。如有错误,欢迎各位指正。  

sm流处理器簇对blocks的调度策略

  在cuda中,GPU中的SM(GTX650M有2个sm处理器)被GPU调度器把线程块逐个分配到SM上,每个SM同时处理这些被分配的线程块block,但是每次每个时刻都只能处理一个warp线程束,由于有时会存在内存读取等操作导致等待,那么SM会转而处理其他的warp来掩盖这个延迟。并且这些warp不一定都是在同一个线程块block内的,另之所以每次同时处理多个block而不是只处理一个block并把该block内的线程个数设置成支持的最大的线程个数,一是可以允许其在支持不同线程个数的不同型号的显卡上都能处理相同的程序;二是由于gpu并行运算一般存在成千上万个线程,并且线程块个数远远大于SM,所以不会存在同一个SM内的线程块几乎同时执行完毕,而最终执行最后一个被调度的线程块而造成等待时间大于之前sm执行的时间所导致的效率低下。

附录1:

  GPU线程以网格(grid)的方式组织,而每个网格中又包含若干个线程块,在G80/GT200系列中,每一个线程块最多可包含512个线程,Fermi架构中每个线程块支持高达1536个线程。同一线程块中的众多线程拥有相同的指令地址,不仅能够并行执行,而且能够通过共享存储器(Shared memory)和栅栏(barrier)实现块内通信。这样,同一网格内的不同块之间存在不需要通信的粗粒度并行,而一个块内的线程之间又形成了允许通信的细粒度并行。这些就是CUDA的关键特性:线程按照粗粒度的线程块和细粒度的线程两个层次进行组织、在细粒度并行的层次通过共享存储器和栅栏同步实现通信,这就是CUDA的双层线程模型。
  在执行时,GPU的任务分配单元(global block scheduler)将网格分配到GPU芯片上。启动CUDA 内核时,需要将网格信息从CPU传输到GPU。任务分配单元根据这些信息将块分配到SM上。任务分配单元使用的是轮询策略:轮询查看SM是否还有足够的资源来执行新的块,如果有则给SM分配一个新的块,如果没有则查看下一个SM。决定能否分配的因素有:每个块使用的共享存储器数量,每个块使用的寄存器数量,以及其它的一些限制条件。任务分配单元在SM的任务分配中保持平衡,但是程序员可以通过更改块内线程数,每个线程使用的寄存器数和共享存储器数来隐式的控制,从而保证SM之间的任务均衡。任务以这种方式划分能够使程序获得了可扩展性:由于每个子问题都能在任意一个SM上运行,CUDA程序在核心数量不同的处理器上都能正常运行,这样就隐藏了硬件差异。
  对于程序员来说,他们需要将任务划分为互不相干的粗粒度子问题(最好是易并行计算),再将每个子问题划分为能够使用线程处理的问题。同一线程块中的线程开始于相同的指令地址,理论上能够以不同的分支执行。但实际上,在块内的分支因为SM构架的原因被大大限制了。内核函数实质上是以块为单位执行的。同一线程块中的线程需要SM中的共享存储器共享数据,因此它们必须在同一个SM中发射。线程块中的每一个线程被发射到一个SP上。任务分配单元可以为每个SM分配最多8个块。而SM中的线程调度单元又将分配到的块进行细分,将其中的线程组织成更小的结构,称为线程束(warp)。在CUDA中,warp对程序员来说是透明的,它的大小可能会随着硬件的发展发生变化,在当前版本的CUDA中,每个warp是由32个线程组成的。SM中一条指令的延迟最小为4个指令周期。8个SP采用了发射一次指令,执行4次的流水线结构。所以由32个线程组成的Warp是CUDA程序执行的最小单位,并且同一个warp是严格串行的,因此在warp内是无须同步的。在一个SM中可能同时有来自不同块的warp。当一个块中的warp在进行访存或者同步等高延迟操作时,另一个块可以占用SM中的计算资源。这样,在SM内就实现了简单的乱序执行。不同块之间的执行没有顺序,完全并行。无论是在一次只能处理一个线程块的GPU上,还是在一次能处理数十乃至上百个线程块的GPU上,这一模型都能很好的适用。

附录2:

硬件基本架构
  实际上在 nVidia 的 GPU 里,最基本的处理单元是所谓的 SP(Streaming Processor),而一颗 nVidia 的 GPU 里,会有非常多的 SP 可以同时做计算;而数个 SP 会在附加一些其他单元,一起组成一个 SM(Streaming Multiprocessor)。几个 SM 则会在组成所谓的 TPC(Texture Processing Clusters)。
  在 G80/G92 的架构下,总共会有 128 个 SP,以 8 个 SP 为一组,组成 16 个 SM,再以两个 SM 为一个 TPC,共分成 8 个 TPC 来运作。而在新一代的 GT200 里,SP 则是增加到 240 个,还是以 8 个 SP 组成一个 SM,但是改成以 3 个 SM 组成一个 TPC,共 10 组 TPC。下面则是提供了两种不同表示方式的示意图。(可参考《NVIDIA G92终极状态!!》、《NVIDIA D10U绘图核心》)

对应到 CUDA
  而在 CUDA 中,应该是没有 TPC 的那一层架构,而是只要根据 GPU 的 SM、SP 的数量和资源来调整就可以了。
  如果把 CUDA 的 Grid - Block - Thread 架构对应到实际的硬件上的话,会类似对应成 GPU - Streaming Multiprocessor - Streaming Processor;一整个 Grid 会直接丢给 GPU 来执行,而 Block 大致就是对应到 SM,thread 则大致对应到 SP。当然,这个讲法并不是很精确,只是一个简单的比喻而已。

SM 中的 Warp 和 Block
  CUDA 的 device 实际在执行的时候,会以 Block 为单位,把一个个的 block 分配给 SM 进行运算;而 block 中的 thread,又会以「warp」为单位,把 thread 来做分组计算。目前 CUDA 的 warp 大小都是 32,也就是 32 个 thread 会被群组成一个 warp 来一起执行;同一个 warp 里的 thread,会以不同的数据,执行同样的指令。此外,在 Compute Capability 1.2 的硬件中,还加入了 warp vote 的功能,可以快速的进行 warp 内的简单统计。
  基本上 warp 分组的动作是由 SM 自动进行的,会以连续的方式来做分组。比如说如果有一个 block 里有 128 个 thread 的话,就会被分成四组 warp,第 0-31 个 thread 会是 warp 1、32-63 是 warp 2、64-95 是 warp 3、96-127 是 warp 4。
  而如果 block 里面的 thread 数量不是 32 的倍数,那他会把剩下的 thread 独立成一个 warp;比如说 thread 数目是 66 的话,就会有三个 warp:0-31、32-63、64-65。由于最后一个 warp 里只剩下两个 thread,所以其实在计算时,就相当于浪费了 30 个 thread 的计算能力;这点是在设定 block 中 thread 数量一定要注意的事!
  一个 SM 一次只会执行一个 block 里的一个 warp,但是 SM 不见得会一次就把这个 warp 的所有指令都执行完;当遇到正在执行的 warp 需要等待的时候(例如存取 global memory 就会要等好一段时间),就切换到别的 warp 来继续做运算,藉此避免为了等待而浪费时间。所以理论上效率最好的状况,就是在 SM 中有够多的 warp 可以切换,让在执行的时候,不会有「所有 warp 都要等待的情形发生;因为当所有的 warp 都要等待时,就会变成 SM 无事可做的状况了~
  下图就是一个 warp 排程的例子。一开始是先执行 thread block 1 的 warp1,而当他执行到第六行指令的时候,因为需要等待,所以就会先切到 thread block 的 warp2 来执行;一直等到存取结束,且刚好有一个 warp 结束时,才继续执行 TB1 warp1 的第七行指令。

这里写图片描述

  实际上,warp 也是 CUDA 中,每一个 SM 执行的最小单位;如果 GPU 有 16 组 SM 的话,也就代表他真正在执行的 thread 数目会是 32x16 个。不过由于 CUDA 是要透过 warp 的切换来隐藏 thread 的延迟、等待,来达到大量平行化的目的,所以会用所谓的 active thread 这个名词来代表一个 SM 里同时可以处理的 thread 数目。
  而在 block 的方面,一个 SM 可以同时处理多个 thread block,当其中有 block 的所有 thread 都处理完后,他就会再去找其他还没处理的 block 来处理。假设有 16 个 SM、64 个 block、每个 SM 可以同时处理三个 block 的话,那一开始执行时,device 就会同时处理 48 个 block;而剩下的 16 个 block 则会等 SM 有处理完 block 后,再进到 SM 中处理,直到所有 block 都处理结束。
  为一个多处理器指定了一个或多个要执行的线程块时,它会将其分成warp块,并由SIMT单元进行调度。将块分割为warp的方法总是相同的,每个warp都包含连续的线程,递增线程索引,第一个warp中包含全局线程过索引0-31。每发出一条指令时,SIMT单元都会选择一个已准备好执行的warp块,并将指令发送到该warp块的活动线程。Warp块每次执行一条通用指令,因此在warp块的全部32个线程执行同一条路径时,可达到最高效率。如果一个warp块的线程通过独立于数据的条件分支而分散,warp块将连续执行所使用的各分支路径,而禁用未在此路径上的线程,完成所有路径时,线程重新汇聚到同一执行路径下,其执行时间为各时间总和。分支仅在warp块内出现,不同的warp块总是独立执行的–无论它们执行的是通用的代码路径还是彼此无关的代码路径。

建议的数值?
  在 Compute Capability 1.0/1.1 中,每个 SM 最多可以同时管理 768 个 thread(768 active threads)或 8 个 block(8 active blocks);而每一个 warp 的大小,则是 32 个 thread,也就是一个 SM 最多可以有 768 / 32 = 24 个 warp(24 active warps)。到了 Compute Capability 1.2 的话,则是 active warp 则是变为 32,所以 active thread 也增加到 1024。
  在这里,先以 Compute Capability 1.0/1.1 的数字来做计算。根据上面的数据,如果一个 block 里有 128 个 thread 的话,那一个 SM 可以容纳 6 个 block;如果一个 block 有 256 个 thread 的话,那 SM 就只能容纳 3 个 block。不过如果一个 block 只有 64 个 thread 的话,SM 可以容纳的 block 不会是 12 个,而是他本身的数量限制的 8 个。
  因此在 Compute Capability 1.0/1.1 的硬件上,决定 block 大小的时候,最好让里面的 thread 数目是 warp 数量(32)的倍数(可以的话,是 64 的倍数会更好);而在一个 SM 里,最好也要同时存在复数个 block。如果再希望能满足最多 24 个 warp 的情形下,block 里的 thread 数目似乎会是 96(一个 SM 中有 8 个 block)、128(一个 SM 中有 6 个 block)、192(一个 SM 中有 4 个 block)、256(一个 SM 中有 3 个 block) 这些数字了~
  Compute Capability 1.0/1.1 的硬件上,每个grid最多可以允许65535×65535个block。每个block最多可以允许512个thread,但是第三维上的最大值为64。而官方的建议则是一个 block 里至少要有 64 个 thread,192 或 256 个也是通常比较合适的数字(请参考 Programming Guide)。
  但是是否这些数字就是最合适的呢?其实也不尽然。因为实际上,一个 SM 可以允许的 block 数量,还要另外考虑到他所用到 SM 的资源:shared memory、registers 等。在 G80 中,每个 SM 有 16KB 的 shared memory 和 8192 个 register。而在同一个 SM 里的 block 和 thread,则要共享这些资源;如果资源不够多个 block 使用的话,那 CUDA 就会减少 Block 的量,来让资源够用。在这种情形下,也会因此让 SM 的 thread 数量变少,而不到最多的 768 个。
  比如说如果一个 thread 要用到 16 个 register 的话(在 kernel 中宣告的变量),那一个 SM 的 8192 个 register 实际上只能让 512 个 thread 来使用;而如果一个 thread 要用 32 个 register,那一个 SM 就只能有 256 个 thread 了~而 shared memory 由于是 thread block 共享的,因此变成是要看一个 block 要用多少的 shread memory、一个 SM 的 16KB 能分给多少个 block 了。
  所以虽然说当一个 SM 里的 thread 越多时,越能隐藏 latency,但是也会让每个 thread 能使用的资源更少。因此,这点也就是在优化时要做取舍的了。

没有更多推荐了,返回首页