在K8S集群上进行分布式训练

MindSpore Operator 是遵循Kubernetes的Operator模式(基于CRD-Custom Resource Definition功能),实现的在Kubernetes上进行分布式训练的插件。其中,MindSpore Operator在CRD中定义了Scheduler、PS、Worker三种角色,用户只需通过简单的YAML文件配置,就可以轻松地在K8S上使用MindSpore进行分布式训练。MindSpore Operator的代码仓详见:ms-operator

安装

安装方法可以有以下三种:

  1. 使用YAML直接安装

    kubectl apply -f deploy/v1/ms-operator.yaml
    

    安装后:

    使用kubectl get pods --all-namespaces,即可看到namespace为ms-operator-system的部署任务。

    使用kubectl describe pod ms-operator-controller-manager-xxx-xxx -n ms-operator-system,可查看pod的详细信息。

  2. 使用make deploy安装

    make deploy IMG=swr.cn-south-1.myhuaweicloud.com/mindspore/ms-operator:latest
    
  3. 本地调试环境

    make run
    

样例

当前ms-operator支持普通单Worker训练、PS模式的单Worker训练以及自动并行(例如数据并行、模型并行等)的Scheduler、Worker启动。

config/samples/中有运行样例。以数据并行的Scheduler、Worker启动为例,其中数据集和网络脚本需提前准备:

kubectl apply -f config/samples/ms_wide_deep_dataparallel.yaml

使用kubectl get all -o wide即可看到集群中启动的Scheduler和Worker,以及Scheduler对应的Service。

开发指南

核心代码

pkg/apis/v1/msjob_types.go中为MSJob的CRD定义。

pkg/controllers/v1/msjob_controller.go中为MSJob controller的核心逻辑。

镜像制作、上传

如需修改ms-operator代码并制作上传镜像,可参考以下命令:

make docker-build IMG={image_name}:{tag}
docker push {image_name}:{tag}

YAML文件配置说明

以自研组网的数据并行为例,介绍MSJob的YAML配置,如runPolicysuccessPolicy、各个角色数量、mindspore镜像、文件挂载等,用户需根据自己的实际需要进行配置。

apiVersion: mindspore.gitee.com/v1
kind: MSJob  # ms-operator自定的CRD类型,为MSJob
metadata:
  name: ms-widedeep-dataparallel  # 任务名
spec:
  runPolicy: # RunPolicy 封装了分布式训练作业的各种运行时策略,例如如何清理资源以及作业可以保持活动多长时间。
    cleanPodPolicy: None   # All/Running/None
  successPolicy: AllWorkers # 将MSJob标记为success的条件,默认为空,代表使用默认规则(单worker执行完毕即表示成功)
  msReplicaSpecs:
    Scheduler:
      replicas: 1  # Scheduler数量
      restartPolicy: Never  # 重启策略 Always,OnFailure,Never
      template:
        spec:
          volumes: # 文件挂载,如数据集、网络脚本等
            - name: script-data
              hostPath:
                path: /absolute_path
          containers:
            - name: mindspore # 各个角色中必须有且只有一个mindspore名字的container,可配置containerPort来调整默认端口号(2222),需设置端口name为 msjob-port
              image: mindspore-image-name:tag # mindspore镜像
              imagePullPolicy: IfNotPresent
              command: # 容器启动后的执行命令
                - /bin/bash
                - -c
                - python -s /absolute_path/train_and_eval_distribute.py --device_target="GPU" --epochs=1 --data_path=/absolute_path/criteo_mindrecord  --batch_size=16000
              volumeMounts:
                - mountPath: /absolute_path
                  name: script-data
              env:  # 可配置环境变量
                - name: GLOG_v
                  value: "1"
    Worker:
      replicas: 4 # Worker数量
      restartPolicy: Never
      template:
        spec:
          volumes:
            - name: script-data
              hostPath:
                path: /absolute_path
          containers:
            - name: mindspore
              image: mindspore-image-name:tag # mindspore镜像
              imagePullPolicy: IfNotPresent
              command:
                - /bin/bash
                - -c
                - python -s /absolute_path/train_and_eval_distribute.py --device_target="GPU" --epochs=1 --data_path=/absolute_path/criteo_mindrecord --batch_size=16000
              volumeMounts:
                - mountPath: /absolute_path
                  name: script-data
              env:
                - name: GLOG_v
                  value: "1"
              resources: # 资源限制配置
                limits:
                  nvidia.com/gpu: 1

常见问题

  • 镜像构建过程中若发现gcr.io/distroless/static无法拉取,可参考issue

  • 安装部署过程中发现gcr.io/kubebuilder/kube-rbac-proxy无法拉取,参考issue

  • 当在GPU中通过k8s调起任务,且需要使用NVIDIA显卡时,需要安装k8s device plugin、nvidia-docker2等环境。

  • YAML文件配置项中不要使用下划线。

  • 当k8s出现阻塞但是通过pod日志无法明确原因时,通过kubectl logs $(kubectl get statefulset,pods -o wide --all -namespaces|grep ms-operator-system|awk-F""'{print$2}') -n ms-operator-system查看pod创建过程的日志。

  • 通过pod执行任务,默认会在启动的容器根目录下执行,生成的相关文件都会存放在根目录下,但是如果映射路径只是根目录下的某个目录,那生成的文件不会映射保存到宿主机,建议在正式执行任务之前切换路径到指定目录下,便于保存任务执行过程中产生的文件。

  • 容灾场景下,如果出现bindIP failed,确认是不是上次训练生成持久化文件未做清理。

  • 不建议在YAML中直接重定向日志文件,如果需要重定向,请区分不同pod的重定向日志文件名。

  • Device上存在残留进程或者有其他进程的时候,可能会因为无法申请全部资源导致pod处于Pending状态,建议用户设置超时策略,避免始终被阻塞。