MPI 训练 (MPIJob)

使用 MPI 进行训练的说明

本指南将引导您使用 MPI 进行训练。

MPI Operator,MPIJob,使得在 Kubernetes 上运行 allreduce 风格的分布式训练变得容易。请参阅这篇博文,了解 MPI Operator 及其行业应用。

注意:由于 Istio 自动 Sidecar 注入MPIJob 默认无法在用户命名空间中工作。为了使其运行,需要添加注解 sidecar.istio.io/inject: "false" 以禁用其对 MPIJob Pod 或命名空间的注入。要查看如何将此注解添加到 yaml 文件的示例,请参阅TFJob 文档

安装

您可以使用默认设置部署操作员,运行以下命令

git clone https://github.com/kubeflow/mpi-operator
cd mpi-operator
kubectl apply -f deploy/v2beta1/mpi-operator.yaml

或者,按照入门指南部署 Kubeflow。

Kubeflow 0.2.0 中引入了 MPI 支持的 Alpha 版本。您必须使用高于 0.2.0 版本的 Kubeflow。

您可以通过以下命令检查 MPI Job 自定义资源是否已安装

kubectl get crd

输出应包含 mpijobs.kubeflow.org,如下所示

NAME                                       AGE
...
mpijobs.kubeflow.org                       4d
...

如果未包含,您可以使用kustomize 如下添加

git clone https://github.com/kubeflow/mpi-operator
cd mpi-operator
kustomize build manifests/overlays/kubeflow | kubectl apply -f -

请注意,自 Kubernetes v1.14 起,kustomize 成为 kubectl 中的子命令,因此您也可以运行以下命令替代

自 Kubernetes v1.21 起,您可以使用

kubectl apply -k manifests/overlays/kubeflow
kubectl kustomize base | kubectl apply -f -

创建 MPI Job

您可以通过定义 MPIJob 配置文件来创建 MPI Job。参阅TensorFlow 基准测试示例配置文件,以启动多节点 TensorFlow 基准训练作业。您可以根据您的需求修改配置文件。

cat examples/v2beta1/tensorflow-benchmarks/tensorflow-benchmarks.yaml

部署 MPIJob 资源以开始训练

kubectl apply -f examples/v2beta1/tensorflow-benchmarks/tensorflow-benchmarks.yaml

调度策略

MPI Operator 支持Gang 调度。如果您想修改 PodGroup 参数,可以在以下配置

apiVersion: kubeflow.org/v2beta1
kind: MPIJob
metadata:
  name: tensorflow-benchmarks
spec:
  slotsPerWorker: 1
  runPolicy:
    cleanPodPolicy: Running
+   schedulingPolicy:
+     minAvailable: 10
+     queue: test-queue
+     minResources:
+       cpu: 3000m
+     priorityClass: high
+     scheduleTimeoutSeconds: 180
  mpiReplicaSpecs:
...

此外,这些字段将根据以下情况传递给 volcano 或 coscheduling 插件的 PodGroup

  • .spec.runPolicy.schedulingPolicy.minAvailable 定义了运行 PodGroup 的最小成员数,并被传递给 .spec.minMember。使用此字段时,必须确保应用程序支持弹性缩放(例如 Elastic Horovod)。
  • .spec.runPolicy.schedulingPolicy.queue 定义了为 PodGroup 分配资源的队列名称。但是,如果您使用 volcano 作为 Gang 调度器,则此值将传递给 .spec.queue
  • .spec.runPolicy.schedulingPolicy.minResources 定义了运行 PodGroup 的最小资源量,并被传递给 .spec.minResources
  • .spec.runPolicy.schedulingPolicy.priorityClass 定义了 PodGroup 的 PriorityClass。但是,如果您使用 volcano 作为 Gang 调度器,则此值将传递给 .spec.priorityClassName
  • .spec.runPolicy.schedulingPolicy.scheduleTimeutSeconds 定义了成员在运行 PodGroup 前的最大等待时间。但是,如果您使用 coscheduling 插件作为 Gang 调度器,则此值将传递给 .spec.scheduleTimeutSeconds

此外,如果您未设置这些字段,MPI Operator 将根据以下情况填充它们

volcano

  • .spec.runPolicy.schedulingPolicy.minAvailable:一个 launcher 和 workers 的数量。
  • .spec.runPolicy.schedulingPolicy.queue.spec.annotationsscheduling.volcano.sh/group-name 的值。
  • .spec.runPolicy.schedulingPolicy.minResources:未设置任何值。
  • .spec.runPolicy.schedulingPolicy.priorityClass:它使用 launcher 的 priorityClass。如果未设置 launcher 的 priorityClass,则使用 workers 的 priorityClass。

scheduler-plugins

  • .spec.runPolicy.schedulingPolicy.minAvailable:一个 launcher 和 workers 的数量。
  • .spec.runPolicy.schedulingPolicy.minResources:所有容器中定义的资源总量。但是,如果副本数(.spec.mpiReplicaSpecs[Launcher].replicas + .spec.mpiReplicaSpecs[Worker].replicas)大于 minMembers,它将根据 podSpec.priorityClassName 中的每个 priorityClass 设置重新排序副本,然后优先级低于 minMember 的资源将不会添加到 minResources 中。请注意,如果在重新排序副本时集群中不存在 podSpec.priorityClassName 中指定的 priorityClass,则不会考虑该 priorityClass。
  • .spec.runPolicy.schedulingPolicy.scheduleTimeutSeconds: 0

监控 MPI Job

创建 MPIJob 资源后,您应该能够看到根据指定 GPU 数量创建的 Pod。您还可以从状态部分监控 Job 状态。以下是 Job 成功完成时的示例输出。

kubectl get -o yaml mpijobs tensorflow-benchmarks
apiVersion: kubeflow.org/v2beta1
kind: MPIJob
metadata:
  creationTimestamp: "2019-07-09T22:15:51Z"
  generation: 1
  name: tensorflow-benchmarks
  namespace: default
  resourceVersion: "5645868"
  selfLink: /apis/kubeflow.org/v1alpha2/namespaces/default/mpijobs/tensorflow-benchmarks
  uid: 1c5b470f-a297-11e9-964d-88d7f67c6e6d
spec:
  runPolicy:
    cleanPodPolicy: Running
  mpiReplicaSpecs:
    Launcher:
      replicas: 1
      template:
        spec:
          containers:
          - command:
            - mpirun
            - --allow-run-as-root
            - -np
            - "2"
            - -bind-to
            - none
            - -map-by
            - slot
            - -x
            - NCCL_DEBUG=INFO
            - -x
            - LD_LIBRARY_PATH
            - -x
            - PATH
            - -mca
            - pml
            - ob1
            - -mca
            - btl
            - ^openib
            - python
            - scripts/tf_cnn_benchmarks/tf_cnn_benchmarks.py
            - --model=resnet101
            - --batch_size=64
            - --variable_update=horovod
            image: mpioperator/tensorflow-benchmarks:latest
            name: tensorflow-benchmarks
    Worker:
      replicas: 1
      template:
        spec:
          containers:
          - image: mpioperator/tensorflow-benchmarks:latest
            name: tensorflow-benchmarks
            resources:
              limits:
                nvidia.com/gpu: 2
  slotsPerWorker: 2
status:
  completionTime: "2019-07-09T22:17:06Z"
  conditions:
  - lastTransitionTime: "2019-07-09T22:15:51Z"
    lastUpdateTime: "2019-07-09T22:15:51Z"
    message: MPIJob default/tensorflow-benchmarks is created.
    reason: MPIJobCreated
    status: "True"
    type: Created
  - lastTransitionTime: "2019-07-09T22:15:54Z"
    lastUpdateTime: "2019-07-09T22:15:54Z"
    message: MPIJob default/tensorflow-benchmarks is running.
    reason: MPIJobRunning
    status: "False"
    type: Running
  - lastTransitionTime: "2019-07-09T22:17:06Z"
    lastUpdateTime: "2019-07-09T22:17:06Z"
    message: MPIJob default/tensorflow-benchmarks successfully completed.
    reason: MPIJobSucceeded
    status: "True"
    type: Succeeded
  replicaStatuses:
    Launcher:
      succeeded: 1
    Worker: {}
  startTime: "2019-07-09T22:15:51Z"

训练应运行 100 步,并在 GPU 集群上花费几分钟。您可以检查日志以查看训练进度。Job 启动后,从 launcher pod 访问日志

PODNAME=$(kubectl get pods -l mpi_job_name=tensorflow-benchmarks,mpi_role_type=launcher -o name)
kubectl logs -f ${PODNAME}
TensorFlow:  1.14
Model:       resnet101
Dataset:     imagenet (synthetic)
Mode:        training
SingleSess:  False
Batch size:  128 global
             64 per device
Num batches: 100
Num epochs:  0.01
Devices:     ['horovod/gpu:0', 'horovod/gpu:1']
NUMA bind:   False
Data format: NCHW
Optimizer:   sgd
Variables:   horovod

...

40	images/sec: 154.4 +/- 0.7 (jitter = 4.0)	8.280
40	images/sec: 154.4 +/- 0.7 (jitter = 4.1)	8.482
50	images/sec: 154.8 +/- 0.6 (jitter = 4.0)	8.397
50	images/sec: 154.8 +/- 0.6 (jitter = 4.2)	8.450
60	images/sec: 154.5 +/- 0.5 (jitter = 4.1)	8.321
60	images/sec: 154.5 +/- 0.5 (jitter = 4.4)	8.349
70	images/sec: 154.5 +/- 0.5 (jitter = 4.0)	8.433
70	images/sec: 154.5 +/- 0.5 (jitter = 4.4)	8.430
80	images/sec: 154.8 +/- 0.4 (jitter = 3.6)	8.199
80	images/sec: 154.8 +/- 0.4 (jitter = 3.8)	8.404
90	images/sec: 154.6 +/- 0.4 (jitter = 3.7)	8.418
90	images/sec: 154.6 +/- 0.4 (jitter = 3.6)	8.459
100	images/sec: 154.2 +/- 0.4 (jitter = 4.0)	8.372
100	images/sec: 154.2 +/- 0.4 (jitter = 4.0)	8.542
----------------------------------------------------------------
total images/sec: 308.27

有关使用 Intel MPI 的示例,请参阅

cat examples/pi/pi-intel.yaml

暴露的指标

指标名称指标类型描述标签
mpi_operator_jobs_created_total计数器统计创建的 MPI job 数量
mpi_operator_jobs_successful_total计数器统计成功的 MPI job 数量
mpi_operator_jobs_failed_total计数器统计失败的 MPI job 数量
mpi_operator_job_info测量仪关于 MPIJob 的信息launcher=<launcher-pod-name>
namespace=<job-namespace>

连接指标

通过kube-state-metrics,可以通过标签连接指标。例如 kube_pod_info * on(pod,namespace) group_left label_replace(mpi_operator_job_infos, "pod", "$0", "launcher", ".*")

Docker 镜像

每次发布时,我们都会将Dockerhub 上的 mpioperator Docker 镜像推送到 Dockerhub。您可以使用以下 Dockerfile 自行构建镜像

或者,您可以使用 make 构建镜像

make RELEASE_VERSION=dev IMAGE_NAME=registry.example.com/mpi-operator images

这将生成一个带有标签 registry.example.com/mpi-operator:dev 的镜像。

贡献

CONTRIBUTING 中了解更多。

反馈

本页面有帮助吗?


上次修改时间:2025 年 3 月 11 日:修复 MPIJob 的调度策略文档 (#4033) (fb10cda)