本文介绍如何使用TFJob在ASK+ECI场景下,快速完成基于GPU的TensorFlow分布式训练任务。
1. 前提条件
已创建ACK Serverless集群。具体操作,请参见创建Serverless Kubernetes集群。
已通过kubectl连接Kubernetes集群。具体操作,请参见通过kubectl连接Kubernetes集群。
已创建容器镜像缓存。具体操作,请参见创建容器镜像缓存。
已创建NAS文件系统,并添加挂载点。在NAS文件系统控制台上创建文件系统,并添加挂载点。更多信息,请参见管理文件系统和管理挂载点。
2. 背景信息
我们知道,在AI训练/推理的场景下,往往需要大量的计算资源来对复杂的模型参数进行计算推理,因此在单台机器上的计算往往无法满足用户需要。于是机器学习框架逐渐由单机迁移到集群,如图所示,但是这样又引入了新的问题。分布式训练任务能利用数据中心所有服务器构成的资源池,让大量数据能分布在不同的服务器进行参数存储和训练,这无疑是分布式训练任务的优点。然而,这还不够,它还存在一些不足之处:
缺乏调度能力,需要用户手动配置和管理任务的计算资源。
集群规模大时,训练任务的管理很麻烦,要跟踪和管理每个任务的状态,需要在上层做大量开发。
训练时TensorFlow各个Task资源无法隔离,导致任务间因资源抢占互相影响。
随着云原生概念的不断发展,对于这种典型的AI训练/推理场景也逐渐衍生出一套完整的解决方案,基于Kubernetes架构对于分布式训练任务进行管理调度,主要有以下好处:
租户隔离,保证不同的用户能够互不干扰。
方便管理与扩展能力,通过简单的配置便可实现大规模集群的管理。
本文主要阐述基于Kubernetes+TFJob方式以实现对复杂的分布式tensorflow任务的训练。
TFJob,是Kubernetes中的一种用户定义资源类型。通过这个资源类型,仅通过中心化的集群配置,用户便可以在Kubernetes集群部署自己的分布式深度学习任务。
基于阿里云的容器服务平台,针对以上的问题,我们推荐您使用ASK+ECI的方案来运行您的分布式训练任务,同时该方案还具备以下优势:
按需付费,免运维,极致弹性。
镜像缓存功能加速Pod创建,训练任务启动快速。
3. 操作步骤
- 通过Kubeflow的Arena工具在Kubernetes集群中部署Tensorflow作业运行环境并安装TFJob Controller。
git clone https://github.com/kubeflow/arena.git
kubectl create ns arena-system
kubectl create -f arena/kubernetes-artifacts/jobmon/jobmon-role.yaml
kubectl create -f arena/kubernetes-artifacts/tf-operator/tf-crd.yaml
kubectl create -f arena/kubernetes-artifacts/tf-operator/tf-operator.yaml
您可以执行如下命令查看tfjob-operator是否安装成功。
kubectl get pods -n arena-system | grep tf-job-operator
如图所示,可以看到分布式tensorflow运行环境配置成功。
2.在ACK Serverless集群中部署CoreDNS服务。由于分布式系统需要pod节点间需要建立连接并通信,ACK Serverless集群默认可选安装CoreDNS服务,因此需要单独安装CoreDNS服务。找到组件管理-网络-CoreDNS,选择并进行安装。
如图所示,CoreDNS组件安装成功。
3.声明PV与PVC, 用于存储mnist训练所需要的数据。
apiVersion: v1
kind: PersistentVolume
metadata:
name: tf-mnist-nas
labels:
tfjob: tf-mnist-nas
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
storageClassName: nas
flexVolume:
driver: "alicloud/nas"
options:
mode: "755"
path: /training
server: 175dd4ad88-mae80.cn-beijing.nas.aliyuncs.com
vers: "4.0"
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: tf-mnist-nas
spec:
storageClassName: nas
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
selector:
matchLabels:
tfjob: tf-mnist-nas
4.提交分布式训练的TFJob。
apiVersion: kubeflow.org/v1
kind: TFJob
metadata:
name: tf-mnist-gpu
namespace: default
spec:
tfReplicaSpecs:
PS:
replicas: 1
template:
metadata:
annotations:
k8s.aliyun.com/eci-image-cache: 'true' # 开启镜像缓存自动匹配
spec:
containers:
- command:
- python
- /app/main.py
env:
- name: TEST_TMPDIR
value: /training
image: >-
registry.cn-beijing.aliyuncs.com/eci/tf-dist-mnist:cpu
imagePullPolicy: Always
name: tensorflow
volumeMounts:
- mountPath: /training
name: tf-mnist-nas
restartPolicy: OnFailure
volumes:
- name: tf-mnist-nas
persistentVolumeClaim:
claimName: tf-mnist-nas
MASTER:
replicas: 1
template:
metadata:
annotations:
k8s.aliyun.com/eci-image-cache: 'true' # 开启镜像缓存自动匹配
k8s.aliyun.com/eci-use-specs: ecs.gn7i-c8g1.2xlarge # 指定GPU规格
spec:
containers:
- command:
- python
- /app/main.py
env:
- name: TEST_TMPDIR
value: /training
image: >-
registry.cn-beijing.aliyuncs.com/eci/tf-dist-mnist:gpu
name: tensorflow
resources:
limits:
nvidia.com/gpu: 1
volumeMounts:
- mountPath: /training
name: tf-mnist-nas
restartPolicy: OnFailure
volumes:
- name: tf-mnist-nas
persistentVolumeClaim:
claimName: tf-mnist-nas
WORKER:
replicas: 1
template:
metadata:
annotations:
k8s.aliyun.com/eci-image-cache: 'true' # 开启镜像缓存自动匹配
k8s.aliyun.com/eci-use-specs: ecs.gn7i-c8g1.2xlarge # 指定GPU规格
spec:
containers:
- command:
- python
- /app/main.py
env:
- name: TEST_TMPDIR
value: /training
image: >-
registry.cn-beijing.aliyuncs.com/eci/tf-dist-mnist:gpu
imagePullPolicy: Always
name: tensorflow
resources:
limits:
nvidia.com/gpu: 1
volumeMounts:
- mountPath: /training
name: tf-mnist-nas
restartPolicy: OnFailure
volumes:
- name: tf-mnist-nas
persistentVolumeClaim:
claimName: tf-mnist-nas
5.查看TFJob运行状态及容器日志输出。
kubectl logs tf-mnist-gpu-master-0 --tail=150
6.部署tensorboard,查看训练效果。
说明
tensorboard是tensorflow自带的一个强大的可视化工具,也是一个Web应用程序套件。tensorboard通过运行一个本地服务器,来监听6006端口。在浏览器发出请求时,分析训练时记录的数据,绘制训练过程中的图像。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: tensorboard
name: tensorboard
spec:
replicas: 1
selector:
matchLabels:
app: tensorboard
template:
metadata:
labels:
app: tensorboard
spec:
volumes:
- name: tf-mnist-nas
persistentVolumeClaim:
claimName: tf-mnist-nas
containers:
- name: tensorboard
image: tensorflow/tensorflow:1.7.0
imagePullPolicy: Always
command:
- /usr/local/bin/tensorboard
args:
- --logdir
- /training/tensorflow/logs
volumeMounts:
- name: tf-mnist-nas
mountPath: "/training"
ports:
- containerPort: 6006
protocol: TCP
dnsPolicy: ClusterFirst
restartPolicy: Always
查看部署是否成功。
kubectl get pods| grep tensorboard
tensorboard创建成功后,通过kubectl port-forward命令进行访问。
kubectl port-forward tensorboard-cc746c797-98w2f 6006:6006
通过http://127.0.0.1:6006登录tensorboard,查看分布式训练效果。
7.通过tensorflow cnn benchmark对比不同worker数目带来训练效果的差异。
说明
tensorflow cnn benchmark提供了基于cnn的多个图像分类模型用于图像数据的分类,示例在parameter server架构下采用cnn中的resnet50模型对图像进行训练。
示例YAML如下。
apiVersion: kubeflow.org/v1
kind: TFJob
metadata:
name: tf-benchmarks-gpu
namespace: default
spec:
tfReplicaSpecs:
PS:
replicas: 1
template:
metadata:
annotations:
k8s.aliyun.com/eci-image-cache: 'true' # 开启镜像缓存自动匹配
spec:
containers:
- args:
- python
- tf_cnn_benchmarks.py
- '--batch_size=128'
- '--num_batches=100'
- '--model=resnet50'
- '--variable_update=parameter_server'
- '--flush_stdout=true'
- '--num_gpus=1'
- '--local_parameter_device=cpu'
- '--device=cpu'
- '--data_format=NHWC'
image: 'registry-vpc.cn-beijing.aliyuncs.com/eci/tf-benchmarks-cpu:1.0'
name: tensorflow
resources:
limits:
cpu: '16'
workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks
Worker:
replicas: 1
template:
metadata:
annotations:
k8s.aliyun.com/eci-image-cache: 'true' # 开启镜像缓存自动匹配
k8s.aliyun.com/eci-use-specs: ecs.gn7i-c8g1.2xlarge # 指定GPU规格创建ECI实例
spec:
containers:
- args:
- python
- tf_cnn_benchmarks.py
- '--batch_size=128'
- '--num_batches=100'
- '--model=resnet50'
- '--variable_update=parameter_server'
- '--flush_stdout=true'
- '--num_gpus=1'
- '--local_parameter_device=cpu'
- '--device=gpu'
- '--data_format=NHWC'
image: 'registry-vpc.cn-beijing.aliyuncs.com/eci/tf-benchmarks-gpu:1.0'
name: tensorflow
resources:
limits:
nvidia.com/gpu: 1 # 指定gpu资源
workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks
(1 )执行命令创建训练任务pod。
kubectl create -f tf-benchmarks-gpu.yaml
创建成功后执行如下命令,可查看pod运行状态。
kubectl get pods | grep tf-benchmarks-gpu
容器处于运行状态后,便开始执行训练任务,执行如下命令,可以看到对应容器的日志输出。
kubectl logs tf-benchmarks-gpu-worker-0
训练任务完成后,我们可以通过日志看到,我们此次基于resnet50模型训练性能为198.28(images/sec)。
(2)增加分布式worker数,采用多张gpu训练。
作为验证,我们修改worker副本数目,重新创建分布式训练任务,相当于在集群中增加worker实例为2个,采用多张gpu并行计算,相当于增加训练的batch_size,提高集群模型训练性能,对比日志输出得到如下结果。
由此可见,通过增加训练模型worker副本数,可以相应地提高分布式tensorflow模型训练的性能,因此可以通过水平扩展方式支持更大规模的AI训练任务。
4. Q&A
Q:master节点、ps节点、worker节点的作用分别是什么?
A:分布式任务整体遵循了PS架构,即参数放置在ps,而worker执行计算,我们其实可以把master也看作是一种worker,只不过在架构中负责会话初始化与资源调度。
Q:训练速度和什么参数有关,参数是越大越好么?
A:训练速度和batchSize、worker、ps、gpu数目等都相关,具体加速效果要视情况而定,在某些情况下加大参数可以获得相应的加速比,但是到达瓶颈后可能不会继续增加。