MPI 训练 (MPIJob)
本指南将引导您使用 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.annotations
中scheduling.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 中了解更多。