Kubeflow实战系列: 利用TFJob运行分布式TensorFlow

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: TensorFlow作为现在最为流行的深度学习代码库,在数据科学家中间非常流行,特别是可以明显加速训练效率的分布式训练更是杀手级的特性。但是如何真正部署和运行大规模的分布式模型训练,却成了新的挑战。

介绍

本系列将介绍如何在阿里云容器服务上运行Kubeflow, 本文介绍如何使用TfJob运行分布式模型训练。

TensorFlow分布式训练和Kubernetes

TensorFlow作为现在最为流行的深度学习代码库,在数据科学家中间非常流行,特别是可以明显加速训练效率的分布式训练更是杀手级的特性。但是如何真正部署和运行大规模的分布式模型训练,却成了新的挑战。 实际分布式TensorFLow的使用者需要关心3件事情。

  1. 寻找足够运行训练的资源,通常一个分布式训练需要若干数量的worker(运算服务器)和ps(参数服务器),而这些运算成员都需要使用计算资源。
  2. 安装和配置支撑程序运算的软件和应用
  3. 根据分布式TensorFlow的设计,需要配置ClusterSpec。这个json格式的ClusterSpec是用来描述整个分布式训练集群的架构,比如需要使用两个worker和ps,ClusterSpec应该长成下面的样子,并且分布式训练中每个成员都需要利用这个ClusterSpec初始化tf.train.ClusterSpec对象,建立集群内部通信
cluster = tf.train.ClusterSpec({"worker": ["<VM_1>:2222",
                                           "<VM_2>:2222"],
                                "ps": ["<IP_VM_1>:2223",
                                       "<IP_VM_2>:2223"]})

其中第一件事情是Kubernetes资源调度非常擅长的事情,无论CPU和GPU调度,都是直接可以使用;而第二件事情是Docker擅长的,固化和可重复的操作保存到容器镜像。而自动化的构建ClusterSpecTFJob解决的问题,让用户通过简单的集中式配置,完成TensorFlow分布式集群拓扑的构建。

应该说烦恼了数据科学家很久的分布式训练问题,通过Kubernetes+TFJob的方案可以得到比较好的解决。

利用Kubernetes和TFJob部署分布式训练

  1. 修改TensorFlow分布式训练代码

之前在阿里云上小试TFJob一文中已经介绍了TFJob的定义,这里就不再赘述了。可以知道TFJob里有的角色类型为MASTER, WORKERPS

举个现实的例子,假设从事分布式训练的TFJob叫做distributed-mnist, 其中节点有1个MASTER, 2个WORKERS和2个PS,ClusterSpec对应的格式如下所示:

{  
    "master":[  
        "distributed-mnist-master-0:2222"
    ],
    "ps":[  
        "distributed-mnist-ps-0:2222",
        "distributed-mnist-ps-1:2222"
    ],
    "worker":[  
        "distributed-mnist-worker-0:2222",
        "distributed-mnist-worker-1:2222"
    ]
}

tf_operator的工作就是创建对应的5个Pod, 并且将环境变量TF_CONFIG传入到每个Pod中,TF_CONFIG包含三部分的内容,当前集群ClusterSpec, 该节点的角色类型,以及id。比如该Pod为worker0,它所收到的环境变量TF_CONFIG为:

{  
   "cluster":{  
      "master":[  
         "distributed-mnist-master-0:2222"
      ],
      "ps":[  
         "distributed-mnist-ps-0:2222"
      ],
      "worker":[  
         "distributed-mnist-worker-0:2222",
         "distributed-mnist-worker-1:2222"
      ]
   },
   "task":{  
      "type":"worker",
      "index":0
   },
   "environment":"cloud"
}

在这里,tf_operator负责将集群拓扑的发现和配置工作完成,免除了使用者的麻烦。对于使用者来说,他只需要在这里代码中使用通过获取环境变量TF_CONFIG中的上下文。

这意味着,用户需要根据和TFJob的规约修改分布式训练代码:

# 从环境变量TF_CONFIG中读取json格式的数据
tf_config_json = os.environ.get("TF_CONFIG", "{}")

# 反序列化成python对象
tf_config = json.loads(tf_config_json)

# 获取Cluster Spec
cluster_spec = tf_config.get("cluster", {})
cluster_spec_object = tf.train.ClusterSpec(cluster_spec)

# 获取角色类型和id, 比如这里的job_name 是 "worker" and task_id 是 0
task = tf_config.get("task", {})
job_name = task["type"]
task_id = task["index"]

# 创建TensorFlow Training Server对象
server_def = tf.train.ServerDef(
    cluster=cluster_spec_object.as_cluster_def(),
    protocol="grpc",
    job_name=job_name,
    task_index=task_id)
server = tf.train.Server(server_def)

# 如果job_name为ps,则调用server.join()
if job_name == 'ps':
    server.join()

# 检查当前进程是否是master, 如果是master,就需要负责创建session和保存summary。
is_chief = (job_name == 'master')


# 通常分布式训练的例子只有ps和worker两个角色,而在TFJob里增加了master这个角色,实际在分布式TensorFlow的编程模型并没有这个设计。而这需要使用TFJob的分布式代码里进行处理,不过这个处理并不复杂,只需要将master也看做worker_device的类型
with tf.device(tf.train.replica_device_setter(
    worker_device="/job:{0}/task:{1}".format(job_name,task_id),
    cluster=cluster_spec)):

具体代码可以参考示例代码

2. 在本例子中,将演示如何使用TFJob运行分布式训练,并且将训练结果和日志保存到NAS存储上,最后通过Tensorboard读取训练日志。

2.1 创建NAS数据卷,并且设置与当前Kubernetes集群的同一个具体vpc的挂载点。操作详见文档

2.2 在NAS上创建 /training的数据文件夹, 下载mnist训练所需要的数据

mkdir -p /nfs
mount -t nfs -o vers=4.0 xxxxxxx.cn-hangzhou.nas.aliyuncs.com:/ /nfs
mkdir -p /nfs/training
umount /nfs

2.3 创建NAS的PV, 以下为示例nas-dist-pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: kubeflow-dist-nas-mnist
  labels:
    tfjob: kubeflow-dist-nas-mnist
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  storageClassName: nas
  flexVolume:
    driver: "alicloud/nas"
    options:
      mode: "755"
      path: /training
      server: xxxxxxx.cn-hangzhou.nas.aliyuncs.com
      vers: "4.0"

将该模板保存到nas-dist-pv.yaml, 并且创建pv:

# kubectl create -f nas-dist-pv.yaml
persistentvolume "kubeflow-dist-nas-mnist" created

2.4 利用nas-dist-pvc.yaml创建PVC

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: kubeflow-dist-nas-mnist
spec:
  storageClassName: nas
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
  selector:
    matchLabels:
      tfjob: kubeflow-dist-nas-mnist

具体命令:

# kubectl create -f nas-dist-pvc.yaml
persistentvolumeclaim "kubeflow-dist-nas-mnist" created

2.5 创建TFJob

apiVersion: kubeflow.org/v1alpha1
kind: TFJob
metadata:
  name: mnist-simple-gpu-dist
spec:
  replicaSpecs:
    - replicas: 1 # 1 Master
      tfReplicaType: MASTER
      template:
        spec:
          containers:
            - image: registry.aliyuncs.com/tensorflow-samples/tf-mnist-distributed:gpu
              name: tensorflow
              env:
              - name: TEST_TMPDIR
                value: /training
              command: ["python", "/app/main.py"]
              resources:
                limits:
                  nvidia.com/gpu: 1
              volumeMounts:
              - name: kubeflow-dist-nas-mnist
                mountPath: "/training"
          volumes:
            - name: kubeflow-dist-nas-mnist
              persistentVolumeClaim:
                claimName: kubeflow-dist-nas-mnist
          restartPolicy: OnFailure
    - replicas: 1 # 1 or 2 Workers depends on how many gpus you have
      tfReplicaType: WORKER
      template:
        spec:
          containers:
          - image: registry.aliyuncs.com/tensorflow-samples/tf-mnist-distributed:gpu                        
            name: tensorflow
            env:
            - name: TEST_TMPDIR
              value: /training
            command: ["python", "/app/main.py"]
            imagePullPolicy: Always
            resources:
              limits:
                nvidia.com/gpu: 1
            volumeMounts:
              - name: kubeflow-dist-nas-mnist
                mountPath: "/training"
          volumes:
            - name: kubeflow-dist-nas-mnist
              persistentVolumeClaim:
                claimName: kubeflow-dist-nas-mnist
          restartPolicy: OnFailure
    - replicas: 1  # 1 Parameter server
      tfReplicaType: PS
      template:
        spec:
          containers:
          - image: registry.aliyuncs.com/tensorflow-samples/tf-mnist-distributed:cpu                      
            name: tensorflow
            command: ["python", "/app/main.py"]
            env:
            - name: TEST_TMPDIR
              value: /training
            imagePullPolicy: Always
            volumeMounts:
              - name: kubeflow-dist-nas-mnist
                mountPath: "/training"
          volumes:
            - name: kubeflow-dist-nas-mnist
              persistentVolumeClaim:
                claimName: kubeflow-dist-nas-mnist
          restartPolicy: OnFailure

将该模板保存到mnist-simple-gpu-dist.yaml, 并且创建分布式训练的TFJob:

# kubectl create -f mnist-simple-gpu-dist.yaml
tfjob "mnist-simple-gpu-dist" created

检查所有运行的Pod

# RUNTIMEID=$(kubectl get tfjob mnist-simple-gpu-dist -o=jsonpath='{.spec.RuntimeId}')
# kubectl get po -lruntime_id=$RUNTIMEID
NAME                                        READY     STATUS    RESTARTS   AGE
mnist-simple-gpu-dist-master-z5z4-0-ipy0s   1/1       Running   0          31s
mnist-simple-gpu-dist-ps-z5z4-0-3nzpa       1/1       Running   0          31s
mnist-simple-gpu-dist-worker-z5z4-0-zm0zm   1/1       Running   0          31s

查看master的日志,可以看到ClusterSpec已经成功的构建出来了

# kubectl logs -l runtime_id=$RUNTIMEID,job_type=MASTER

2018-06-10 09:31:55.342689: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1105] Found device 0 with properties:
name: Tesla P100-PCIE-16GB major: 6 minor: 0 memoryClockRate(GHz): 1.3285
pciBusID: 0000:00:08.0
totalMemory: 15.89GiB freeMemory: 15.60GiB
2018-06-10 09:31:55.342724: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1195] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Tesla P100-PCIE-16GB, pci bus id: 0000:00:08.0, compute capability: 6.0)
2018-06-10 09:31:55.805747: I tensorflow/core/distributed_runtime/rpc/grpc_channel.cc:215] Initialize GrpcChannelCache for job master -> {0 -> localhost:2222}
2018-06-10 09:31:55.805786: I tensorflow/core/distributed_runtime/rpc/grpc_channel.cc:215] Initialize GrpcChannelCache for job ps -> {0 -> mnist-simple-gpu-dist-ps-m5yi-0:2222}
2018-06-10 09:31:55.805794: I tensorflow/core/distributed_runtime/rpc/grpc_channel.cc:215] Initialize GrpcChannelCache for job worker -> {0 -> mnist-simple-gpu-dist-worker-m5yi-0:2222}
2018-06-10 09:31:55.807119: I tensorflow/core/distributed_runtime/rpc/grpc_server_lib.cc:324] Started server with target: grpc://localhost:2222
...

Accuracy at step 900: 0.9709
Accuracy at step 910: 0.971
Accuracy at step 920: 0.9735
Accuracy at step 930: 0.9716
Accuracy at step 940: 0.972
Accuracy at step 950: 0.9697
Accuracy at step 960: 0.9718
Accuracy at step 970: 0.9738
Accuracy at step 980: 0.9725
Accuracy at step 990: 0.9724
Adding run metadata for 999

2.6 部署TensorBoard,并且查看训练效果

为了更方便 TensorFlow 程序的理解、调试与优化,可以用 TensorBoard 来观察 TensorFlow 训练效果,理解训练框架和优化算法, 而TensorBoard通过读取TensorFlow的事件日志获取运行时的信息。

在之前的分布式训练样例中已经记录了事件日志,并且保存到文件events.out.tfevents*

# tree
.
└── tensorflow
    ├── input_data
    │   ├── t10k-images-idx3-ubyte.gz
    │   ├── t10k-labels-idx1-ubyte.gz
    │   ├── train-images-idx3-ubyte.gz
    │   └── train-labels-idx1-ubyte.gz
    └── logs
        ├── checkpoint
        ├── events.out.tfevents.1528760350.mnist-simple-gpu-dist-master-fziz-0-74je9
        ├── graph.pbtxt
        ├── model.ckpt-0.data-00000-of-00001
        ├── model.ckpt-0.index
        ├── model.ckpt-0.meta
        ├── test
        │   ├── events.out.tfevents.1528760351.mnist-simple-gpu-dist-master-fziz-0-74je9
        │   └── events.out.tfevents.1528760356.mnist-simple-gpu-dist-worker-fziz-0-9mvsd
        └── train
            ├── events.out.tfevents.1528760350.mnist-simple-gpu-dist-master-fziz-0-74je9
            └── events.out.tfevents.1528760355.mnist-simple-gpu-dist-worker-fziz-0-9mvsd

5 directories, 14 files

在Kubernetes部署TensorBoard, 并且指定之前训练的NAS存储

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: tensorboard
  name: tensorboard
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tensorboard
  template:
    metadata:
      labels:
        app: tensorboard
    spec:
      volumes:
      - name: kubeflow-dist-nas-mnist
        persistentVolumeClaim:
            claimName: kubeflow-dist-nas-mnist
      containers:
      - name: tensorboard
        image: tensorflow/tensorflow:1.7.0
        imagePullPolicy: Always
        command:
         - /usr/local/bin/tensorboard
        args:
        - --logdir
        - /training/tensorflow/logs
        volumeMounts:
        - name: kubeflow-dist-nas-mnist
          mountPath: "/training"
        ports:
        - containerPort: 6006
          protocol: TCP
      dnsPolicy: ClusterFirst
      restartPolicy: Always

将该模板保存到tensorboard.yaml, 并且创建tensorboard:

# kubectl create -f tensorboard.yaml
deployment "tensorboard" created

TensorBoard创建成功后,通过kubectl port-forward命令进行访问

PODNAME=$(kubectl get pod -l app=tensorboard -o jsonpath='{.items[0].metadata.name}')
kubectl port-forward ${PODNAME} 6006:6006

通过http://127.0.0.1:6006登录TensorBoard,查看分布式训练的模型和效果:

tensorboard-0.jpg

tensorboard-1.jpg

总结

利用tf-operator可以解决分布式训练的问题,简化数据科学家进行分布式训练工作。同时使用Tensorboard查看训练效果, 再利用NAS或者OSS来存放数据和模型,这样一方面有效的重用训练数据和保存实验结果,另外一方面也是为模型预测的发布做准备。如何把模型训练,验证,预测串联起来构成机器学习的工作流(workflow), 也是Kubeflow的核心价值,我们在后面的文章中也会进行介绍。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
2月前
|
数据管理 API 调度
鸿蒙HarmonyOS应用开发 | 探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力
HarmonyOS Next 是华为新一代操作系统,专注于分布式技术的深度应用与生态融合。本文通过技术特点、应用场景及实战案例,全面解析其核心技术架构与开发流程。重点介绍分布式软总线2.0、数据管理、任务调度等升级特性,并提供基于 ArkTS 的原生开发支持。通过开发跨设备协同音乐播放应用,展示分布式能力的实际应用,涵盖项目配置、主界面设计、分布式服务实现及部署调试步骤。此外,深入分析分布式数据同步原理、任务调度优化及常见问题解决方案,帮助开发者掌握 HarmonyOS Next 的核心技术和实战技巧。
263 76
鸿蒙HarmonyOS应用开发 | 探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力
|
6天前
|
人工智能 Kubernetes 异构计算
大道至简-基于ACK的Deepseek满血版分布式推理部署实战
本教程演示如何在ACK中多机分布式部署DeepSeek R1满血版。
|
28天前
|
存储 缓存 Java
Java中的分布式缓存与Memcached集成实战
通过在Java项目中集成Memcached,可以显著提升系统的性能和响应速度。合理的缓存策略、分布式架构设计和异常处理机制是实现高效缓存的关键。希望本文提供的实战示例和优化建议能够帮助开发者更好地应用Memcached,实现高性能的分布式缓存解决方案。
39 9
|
2月前
|
物联网 调度 vr&ar
鸿蒙HarmonyOS应用开发 |鸿蒙技术分享HarmonyOS Next 深度解析:分布式能力与跨设备协作实战
鸿蒙技术分享:HarmonyOS Next 深度解析 随着万物互联时代的到来,华为发布的 HarmonyOS Next 在技术架构和生态体验上实现了重大升级。本文从技术架构、生态优势和开发实践三方面深入探讨其特点,并通过跨设备笔记应用实战案例,展示其强大的分布式能力和多设备协作功能。核心亮点包括新一代微内核架构、统一开发语言 ArkTS 和多模态交互支持。开发者可借助 DevEco Studio 4.0 快速上手,体验高效、灵活的开发过程。 239个字符
243 13
鸿蒙HarmonyOS应用开发 |鸿蒙技术分享HarmonyOS Next 深度解析:分布式能力与跨设备协作实战
|
2月前
|
NoSQL Java Redis
秒杀抢购场景下实战JVM级别锁与分布式锁
在电商系统中,秒杀抢购活动是一种常见的营销手段。它通过设定极低的价格和有限的商品数量,吸引大量用户在特定时间点抢购,从而迅速增加销量、提升品牌曝光度和用户活跃度。然而,这种活动也对系统的性能和稳定性提出了极高的要求。特别是在秒杀开始的瞬间,系统需要处理海量的并发请求,同时确保数据的准确性和一致性。 为了解决这些问题,系统开发者们引入了锁机制。锁机制是一种用于控制对共享资源的并发访问的技术,它能够确保在同一时间只有一个进程或线程能够操作某个资源,从而避免数据不一致或冲突。在秒杀抢购场景下,锁机制显得尤为重要,它能够保证商品库存的扣减操作是原子性的,避免出现超卖或数据不一致的情况。
88 10
|
4月前
|
NoSQL Java Redis
开发实战:使用Redisson实现分布式延时消息,订单30分钟关闭的另外一种实现!
本文详细介绍了 Redisson 延迟队列(DelayedQueue)的实现原理,包括基本使用、内部数据结构、基本流程、发送和获取延时消息以及初始化延时队列等内容。文章通过代码示例和流程图,逐步解析了延迟消息的发送、接收及处理机制,帮助读者深入了解 Redisson 延迟队列的工作原理。
|
5月前
|
分布式计算 资源调度 Hadoop
在YARN集群上运行部署MapReduce分布式计算框架
主要介绍了如何在YARN集群上配置和运行MapReduce分布式计算框架,包括准备数据、运行MapReduce任务、查看任务日志,并启动HistoryServer服务以便于日志查看。
96 0
|
2月前
|
机器学习/深度学习 人工智能 算法
猫狗宠物识别系统Python+TensorFlow+人工智能+深度学习+卷积网络算法
宠物识别系统使用Python和TensorFlow搭建卷积神经网络,基于37种常见猫狗数据集训练高精度模型,并保存为h5格式。通过Django框架搭建Web平台,用户上传宠物图片即可识别其名称,提供便捷的宠物识别服务。
357 55
|
3月前
|
机器学习/深度学习 数据采集 数据可视化
TensorFlow,一款由谷歌开发的开源深度学习框架,详细讲解了使用 TensorFlow 构建深度学习模型的步骤
本文介绍了 TensorFlow,一款由谷歌开发的开源深度学习框架,详细讲解了使用 TensorFlow 构建深度学习模型的步骤,包括数据准备、模型定义、损失函数与优化器选择、模型训练与评估、模型保存与部署,并展示了构建全连接神经网络的具体示例。此外,还探讨了 TensorFlow 的高级特性,如自动微分、模型可视化和分布式训练,以及其在未来的发展前景。
366 5
|
3月前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
垃圾识别分类系统。本系统采用Python作为主要编程语言,通过收集了5种常见的垃圾数据集('塑料', '玻璃', '纸张', '纸板', '金属'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对图像数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。然后使用Django搭建Web网页端可视化操作界面,实现用户在网页端上传一张垃圾图片识别其名称。
142 0
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络