人工智能时代前沿技术社区

首页 > 人工智能 > 热点

当TensorFlow遇上Kubernetes ---中兴通讯人工智能计算平台的技术实践

现在,人工智能、AI已经成为互联网圈内出现频率最高的词汇了。而作为当下最流行的深度学习框架TensorFlow,也是被诸多技术人在各种场合频频提起。

作者:谭盼雨 | 2017-09-01 17:21:13 | 来源:飞马网

现在,人工智能、AI已经成为互联网圈内出现频率最高的词汇了。而作为当下最流行的深度学习框架TensorFlow,也是被诸多技术人在各种场合频频提起。

1.png

中兴高级系统架构师 刘光聪

来自中兴通信的刘光聪在飞马网的FMI人工智能大会上也提到了TensorFlow,他以中兴通讯人工智能计算平台的技术实践为例,详细为我们介绍了当TensorFlow遇上Kubernetes,需要注意的问题与地方。

刘光聪表示,TensorFlow整体就是一个C++,C++的一个维界把社会分成两层,上层是支持多语言的框架。TensorFlow可能面临的用户很多,但是主流的话应该是PYthon或者其他的语言,另外,刘光聪强调,PYthon也是目前TensorFlow提供最完整API的一种语言。

对于我们常说的前端和后端,这个前端可能是客户端,有很多很多高级API,也就是说前端实际上一种多语言的客户端;后端也是客户端,但其实是一个计算引擎。们把这个客户端称为一个客户端的代理,或者是叫C++的客户端,他其实是为了对接其他语言的各种接口。

后端,C++分了几个层,它的运行时,其实想完成两件事:

第一件事就是图控制。你这个图过来之后我怎么把这个图计算出来,分类出来,怎么优化,怎么分布,最高效的把这个图计算完成。

第二件事就是绘画的控制。一个用户,他面对计算的一个集群资源,它要通过一种通道,就是绘画取得这个计算,你用完之后把它关掉,我们把它简单的看成一个多租户的概念,多用户可以进去,控制计+算资源是独立的,这样的两个事儿。

而中间的计算,在TensorFlow抽象为一个OP,这是它的一个设计最本质的一个点。但是OP其实不计算,OP只是一种抽象计算。真正的计算是在设备上的实现,我们把它称为Kernol,也就是说它在CPU和GPU 上的实现可能不一样的。这样的话有了一层很复杂的Kernol的事项,TensorFlow最核心的计算一层都是在这儿,OP和Kernol之间的一层。

TensorFlow的设计原则

刘光聪告诉我们,TensorFlow的设计原则是很重要的。因为有这样的一个原则,你犯错的几率会降低。

第一个就是延迟计算。或者把它称为符号计算,延迟计算在分布式的计算的框架里面应该是通用的,包括spark也是一样的,它也是构造一个DAG,但是它不计算,直到最后一刻才开始计算。同样,TensorFlow也是一样的,首先把你的网络模型,先做一个抽象,变成一个图,学习模型和网络,和图之间是有抽象转换的。图构造好之后,用户把这个图扔给后端,后端开始执行,把它高效的完成,做出这个图。

第二个,OP是最小的计算单元。如果是单机多卡,在同一个进程内,设备之间需要通信,需要插入两个结点,在单进程,首先把这个范围缩小。但是这个单进程,他是在一个进程内,你还把它插入两个结点,一个SNED结点,一个RECV结点。SNED结点是Kernol实现的,最主要的是原设备和目标设备。

第三个就是设备的抽象。因为在不同的设备的扩展非常难,包括上一代系统,TensorFlow的上一代系统对于GPU加速很困难。我们现在做SPGA的加速或者其他硬件的加速。

第四个叫基于任务的抽象。我们在机器学习里面,有一个PS架构,而TensorFlow的PS实现基于Task,也就是说PS跟其他worker没有什么区别。

TensorFlow编程的模型

第一个就是计算图。图是一个DAG,就是一堆结点,规划怎么把计算抽象,怎么去完成这个计算。

第二个叫nameScope。NameScope就是给图打了一个层次划分,这样你再调试的时候很容易定位OP。

第三个是设备。就是TensorFlow对一些优化的时候,程序员要把这个OP特定的放在GPU上这样一些特定的约束。

OP就是图里边的一个结点,OPDef是原数据,odeDef实际是一种用户指定的数据。比如OPDef定义为属性的名字,而odeDef把这些属性名给设计了池。

绘画是另外一个最重要的概念---Variable,其实你在写ts.Variable的时候,并不是说你就得到一个OP,其实你得到的是一个字图,这个字图其实有三个部分构成。第一部分叫做叫初始值,第二个是初始化器,第三个是快照。

2.png

所有的初始化器都用了一个NoOp来做的,NoOp和这两个初始化器,它是用控制器把他俩连在一块的。理论上两个初始化器可以并行跑,否则发挥不出来TensorFlow高强度,高并发的优势,不幸的是它并发不出来,原因是W和V之间产生了依赖。所以导致这个计算引擎首先会去执行W的初始化器,完了之后把值拿出来,去赋给W,这就是你要去设计一个图的时候。

其次就是Python,TensorFlow这边生命周期非常简单,这个目标就是对应marst的抵制,去取得计算资源,或者取得一堆CPU或者GPU的的计算资源,第二是迭代,执行N次,每一次我们把它称之为一次stup,你需要把数据的输入告诉他,输出就反过来。你用完之后需要把它close掉,是因为在后端把资源释放掉。

C++这边也是很简单的对应过去的生命周期,但是生命周期有点不一样,表达方式不一样:

▲ 第一个,他需要Client的多态的构建,后端他需要区分本地模式的运行模式,可能是分布式的,可能是基于RDMA的分布式的特殊的实现。

▲ 第二步你需要把图发过来,我不希望图弄好之后,我每一次跑step,都需要把图传一遍,效率太低了。

▲ 第三步就是真正的迭代跑,不停的sessionrun,然后每次跑出来一个loss,然后去跟进W,再跑第二轮Step,直到你的模型设立了,sessionrun close掉。

TensorFlow的运行

刘光聪告诉我们,TensorFlow的运行,主要通过三个方面来讲:

* 第一运行模式。

* 第二创建绘画。

* 第三迭代执行。

而TensorFlow两种最基本的模式是:

3.png

一、本地的模式。本地的模式其实就是在进程内,就是Client和Master之间,它是通过一个session取得了Master的计算服务,把图发给Master,Master对这个图进行剪枝优化,然后分解,然后把子图部署在这个worker的各个设备里边去,有可能CPU1跑一个子图,CPU0再跑一个图,GPN再跑另外一个子图,一个大图最终被多个设备并发的跑。但是这样有一个问题,因为图之间,子图之间可能会产生数据的依赖,这样的话,很可能GPU0跑完了,等着GPU1的数据,GPU1还在跑,GPU0就浪费了计算资源。刘光聪表示,这正是他们最大的挑战。

4.png

二、分布式模型。其实跨进程,包括Client、Master在不同的进程,也可能是Client、Master在相同进程内,但是worker和worker之间在不同的进程。一般说来Client、Master在同一个进程,Master和worker之间也可能在一个进程的空间内,worker和worker之间,不可能在一个进程内,而Master和worker之间可能,不管怎么样都可以灵活的部署,反正是分布式,他的执行和绑定也是一样的。指定一个Master的地址,把图扔在Master上,但是和本地的模式相比多了一层Master要把这个图平均的分给这些worker,而刚才本地是只要把图平均的分给设备就好了。因为我们这个worker,比如说有单机四卡,或者四个GPU,我这个图最多可以发给4个GDP,让他们并发的跑,这样大图平均的分个多个worker,这个也不能这么说,如果你做数据并发的话,每个worker之间跑的都是一个图,这是一模一样的图,只不过跑的是不同的数据。

分布式模型是经典的MasterClient的模式,它与普通的Master,Client模式不同的是在worker和worker之间,它有数据的交换,而普通的Master和Client之间,worker应该是独立的。而正是TensorFlow把worker和worker之间产生了一种数据的依赖。

5.png

第一步、要创建一个绘画。(如图)这是客户端,这我们掉了一个tf.Session,经过一个C API、然后变成C++这边,C++这边其实有session反回来。所以Python对C++那边的,是直接持有C++句柄。

6.png

第二步、就是Client到Master,他要把这个图发到Master过去,也就是说Master可以提供多用户的接入,你有多个Client可以接到我的Master上,我每个Master可以对应你一个MasterSession,这个MasterSession才是真正的资源的抽象。

如果客户端忘记把Master session close掉,Python代码异常或者C++这边又把资源泄露掉了,那怎么做呢?刘光聪告诉我们,这个时候不要慌,写个GC,看一下这个Session饱不饱和,如果长时间不饱和绝对是有问题的,就可以直接把计算资源回收了。

第三步、接下来要跑Session run。其实sessionrun在Master这边要做两个东西,第一个动作就是按Past分解,把这个图分给各个worker;第二个是把这个图剪枝了。接下来,把这些Patation注册在worker上去,每一个Patation对应一个Worker,把它注册过去,这就是第二级分解。这个做完之后,它就开始跑了,通知各个worker,并发跑,worker收到之后,单独一个worker收到之后,他也通知各个divese并发跑,这样的话,Worker之间并发,divese之间并发,所以TensorFlow是高效的并发事项。

TensorFlow典型场景应用

关于TensorFlow在训练的典型的场景下的应用,刘光聪从三个方面为我们做了分享:

* 第一、计算梯度。喜欢用代码交流,

* 第二、应用梯度。不是真正自计算,它只是构造了计算替代的一个图。

* 第三、工作流。

7.png

Runstep的构成就是正像图输出loss,反向图输出一堆W的梯度,到了更新子图,把反向图计算出来那一堆,每一个X上的梯度做下面那个更新,这样的话,X就被更新了,X更新完之后,StepOP是最后那个,你训练完成一次step你要计数一下,这个计数器非常有用。刘光聪表示,这是典型的在大规模的数据分布下的一个TensorFlow的工作流,因为你不支持前项和后项,很可能把样本数据捞进来。

中兴的TensorFlow容器化实践

8.png

刘光聪给我们透露,中心在实践过程中做了TensorFlow的容器化。希望做一个TensorFlow的一个高性能的计算的集群,使用的是英伟达的GPU服务器的一个集群和docker,在一个容器里面应试多个GPU,通过K8s来做容器的一个集群的资源的调度,我们在每个训练的推理过程当中,会创建多个pod,当然我们目前做的pod,对应一个docker容器。

为了去做一个容器化的集群的资源调度的时候,原来的K8s不太支持,我们做了一个扩展,首先在K8s做一些拓展。其次是尽量要跨node,node之间,要跨IP。

第二尽量的让GPU之间有 by 。其次不要产生碎片,让一些新的用户进来,利用起来这个资源,这个算法应该是非常复杂的。

第三个是,我们增加了RDMA,我们在K8snode上,K8s的能力,那些node上具有K8s这样一个能力的。

第四个,我们能板合,在某些产品下我们性能是能提升的。

以下是刘光聪现场与粉丝的Q&A:

Q:训练好一个模型,怎么与现有的系统进行集成?

A::这是另外的一个方向,训练和推理,你说的是推理,你出来之后这个模型怎么发布出去?目前,没有放到这一块,我们目前是支持云端的发布和PC的发布,还有另外就是,在中端的发布,就是手机平板上的发布,TensorFlow有一套机制,就是在线的发布,就是离线和在线的发布。有一个最重要的问题,就是一堆W和W对应的数据,那个实际就是代表的模型,那个模型就是一陀数据,拿着那个数据就可以做你的APP的发布,就是模型的发布。

Q:TensorFlow训练的时候,同步和异步两种训练方式有何特点?

A::这是两种不同的分布式训练的方法。异步就是各个worker之间各自算各自的,但是会出现抖动,同步的话,可能要均匀一点,不会出现剧烈的抖动,但是缺点就是,有可能有的结点会慢,那几个跑的贼快,那个慢,大家都慢了,是不是?所以各有优缺点,理论上应该是同步模型得到理论支撑,但是异步模型没有一个很好的理论。但是社区里面特别喜欢混合,达到一定时间再跑,这种混合的方式。

【责任编辑:谭盼雨】