该文章出自于ADDOPS团队,是关于如何在K8S上玩转tensorflow的主题,该文章深入浅出的给我们介绍了当前tensorflow的现状和架构特点等,然后介绍了让tensorflow如何基于k8s快速落地,让大家都能简单的上手tensorflow,整体文章脉络清晰,内容适度,所以希望能给大家带来启发。
PS:丰富的一线技术、多元化的表现形式,尽在“
HULK一线技术杂谈
”,点关注哦!
前言
Tensorflow作为深度学习领域逐渐成熟的项目,以其支持多种开发语言,支持多种异构平台,提供强大的算法模型,被越来越多的开发者使用。但在使用的过程中,尤其是GPU集群的时候,我们或多或少将面临以下问题:
-
资源隔离。Tensorflow(以下简称tf)中并没有租户的概念,何如在集群中建立租户的概念,做到资源的有效隔离成为比较重要的问题;
-
缺乏GPU调度。tf通过指定GPU的编号来实现GPU的调度,这样容易造成集群的GPU负载不均衡;
-
进程遗留问题。tf的分布式模式ps服务器会出现tf进程遗留问题;
-
训练的数据分发以及训练模型保存,都需要人工介入;
-
训练日志保存、查看不方便;
因此,我们需要一个集群调度和管理系统,可以解决GPU调度、资源隔离、统一的作业管理和跟踪等问题。
目前,社区中有多种开源项目可以解决类似的问题,比如yarn,kubernetes。yarn是hadoop生态中的资源管理系统,而kubernetes(以下简称k8s)作为Google开源的容器集群管理系统,在tf1.6版本加入GPU管理后,已经成为很好的tf任务的统一调度和管理系统。
下文是我们公司在tensorflow on kubernetes方面的实践经验。
设计目标
我们将tensorflow引入k8s,可以利用其本身的机制解决资源隔离,GPU调度以及进程遗留的问题。除此之外,我们还需要面临下面问题的挑战:
为了解决上面的问题,我们开发了tensorflow on kubernetes系统。
架构
tensorflow on kubernetes包含三个主要的部分,分别是client、task和autospec模块。client模块负责接收用户创建任务的请求,并将任务发送给task模块。task模块根据任务的类型(单机模式和分布式模式)来确定接下来的流程:
如果type选择的是single(单机模式),对应的是tf中的单机任务,则按照按照用户提交的配额来启动container并完成最终的任务;
如果type选择的是distribute(分布式模式),对应的是tf的分布式任务,则按照分布式模式来执行任务。需要注意的是,在分布式模式中会涉及到生成clusterspec信息,autospec模块负责自动生成clusterspec信息,减少人工干预。
下面是tensorflow on kubernetes的架构图:
接下来将对三个模块进行重点介绍。
client模块
tshell
在容器中执行任务的时候,我们可以通过三种方式获取执行任务的代码和训练需要的数据:
-
将代码和数据做成新的镜像;
-
将代码和数据通过卷的形式挂载到容器中;
-
从存储系统中获取代码和数据;
前两种方式不太适合用户经常修改代码的场景,最后一种场景可以解决修改代码的问题,但是它也有下拉代码和数据需要时间的缺点。综合考虑后,我们采取第三种方式。
我们做了一个tshell客户端,方便用户将代码和程序进行打包和上传。比如给自己的任务起名字叫cifar10-multigpu,将代码打包放到code下面,将训练数据放到data下面。
最后打包成cifar10-multigpu.tar.gz并上传到s3后,就可以提交任务。
提交任务
在提交任务的时候,需要指定提前预估一下执行任务需要的配额:cpu核数、内存大小以及gpu个数(默认不提供),当然也可以按照我们提供的初始配额来调度任务。
比如,按照下面格式来将配额信息、s3地址信息以及执行模式填好后,执行send_task.py我们就可以提交一次任务。