VPC環境で利用できます。
ML expert Platformは、モデル学習のための様々なフレームワークの Jobを提供します。
kubectlを利用したモデル学習では、最も一般的な形態である単一ノード学習(Job)、分散ノード学習(PytorchJob)について説明します。
単一ノード学習の場合、Jobの使用をお勧めします。
PytorchJobを使用する場合、分散ノード学習のための機能により Masterや Workerの形式でリリース・管理されるため、リソースを無駄に消費する可能性があります。
単一ノード学習(Job)を実行する
学習のための Kubernetes Jobの定義は、以下のユースケースのように作成できます。
- 高性能ストレージをマウントして使用する場合、学習イメージ内の UIDおよび GIDは500に設定する必要があります。
- Podの
securityContextにfsGroupを設定しないでください。fsGroupが設定されると、Kubernetesがマウントされたボリューム内のすべてのファイルの所有権を再帰的に変更します。そのため、大容量のデータが保存された高性能ストレージの場合は、Podの初期化時間が大幅に長くなる可能性があります。
# job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: mnist
namespace: p-{projectName}
spec:
backoffLimit: 1
template:
metadata:
annotations:
sidecar.istio.io/inject: "false"
spec:
restartPolicy: Never
containers:
- name: main
image: { 学習イメージ (e.g.example.com/mnist:latest ) } # NVIDIA Base イメージに基づいて作成された学習コード
imagePullPolicy: Always
resources:
limits:
memory: "8Gi"
cpu: "4"
nvidia.com/gpu: "1"
command: ["python"]
args:
- /opt/mnist/src/mnist.py
- --checkpoint_path
- /opt/mnist/checkpoints/mnist.pt
- --log_path
- /opt/mnist/log
- --data_path
- /opt/mnist/data
- --download_data
kubectl apply -f job.yaml
batch/mnist created
外部コンテナレジストリを使用する
コンテナレジストリに Secret情報が必要な場合は、Container Secretを作成するを参照し、作成できます。
作成された Secretは、以下のように使用できます。
...
spec:
imagePullSecrets:
- name: my-harbor-secret # 事前に作成した Docker Credential Secretの名前
...
既存の Volumeを使用する
Volumesを通じて作成された Volumeは、以下のように使用できます。
...
spec:
containers:
- name: main
...
volumeMounts:
- mountPath: /data
name: mnist-data # 下部の spec.volumesに記載した名前
volumes:
- name: mnist-data
persistentVolumeClaim:
claimName: mnist-data # Volumesを通じて作成された PVCの名前
...
Jobのライフサイクル
Jobが終了した場合、一定時間コンテナのログおよびステータスを保持するため、削除されずにリストに残ります。
リストに残せる Jobの最大数には制限があるため、TTLを使用してライフサイクルを管理します。詳細は、Kubernetes Job API文書をご参照ください。
Job作成時に Time To Live(TTL)を任意に設定できます。TTLは Jobが完了(成功・失敗)した後に有効となり、設定したTTLが経過すると Jobおよび Jobに属する Podがすべて自動的に削除されます。
以下は、3週間の TTLを適用した例です。
apiVersion: batch/v1
kind: Job
metadata:
name: mnist
namespace: p-{projectName}
spec:
ttlSecondsAfterFinished: 1814400 # TTLを直接設定するフィールド(単位: sec)
分散ノード学習(PytorchJob)を実行する
PyTorchJobを利用すると、以下のようなメリットがあります。
- 作成されたコンテナ specを基に Masterおよび Worker Podを適切に作成します。
- PyTorchの分散学習に一般的に必要な環境変数(i.e., WORLD_SIZE, RANK、MASTER_ADDRなど)を自動的に設定します。
- 学習に使われる Podが相互通信できるよう、K8s Serviceを自動的に作成します。Masterは
<pytorch-job-name>-master-0、Workerは<pytorch-job-name>-worker-<idx>などの名前でアクセスできます。 - 必要に応じて、Elastic Policy を使用するを通じて torchrunで使用するパラメータを環境変数として作成します(
--nnodes、--nproc-per-node、--rdzv-endpointなど)。
PytorchJobを作成する
Pytorchで分散学習する際は、torchrun(Elastic Launch)の使用をお勧めします。また、torchrunを使用する際は、マスター Podを別途指定しません。Torch Elasticでは、マスターノードのロールを果たす RANK=0の Podが、実行中に変更されることがあります。
spec.elasticPolicy- torchrun関連の設定です。ここで指定した設定は、環境変数として渡されます。詳細は、Elastic Policy を使用するをご参照ください。spec.runPolicy- PyTorchJobの実行および終了後の処理に関するパラメータを指定できます。詳細は、Run Policy を使用するをご参照ください。spec.pytorchReplicaSpecs.Worker- 分散学習を実行する Worker Podに関する設定です。
- 学習を行うコンテナの名前(e.g.
spec.pytorchReplicaSpecs.Worker.template.spec.containers[*].name)は、必ずpytorchにします。 - 円滑な分散学習のために、Istio Sidecarが Injectされないように
spec.pytorchReplicaSpecs.Worker.template.metadata.annotationsにsidecar.istio.io/inject: "false"が自動的に設定されます。当該 annotationが設定されない場合、RuntimeError: Connection reset by peerなどのノード間通信にエラーが発生します。 - 高性能ストレージをマウントして使用する場合、学習イメージ内の UIDおよび GIDは500に設定する必要があります。
- Podの
securityContextにfsGroupを設定しないでください。fsGroupが設定されると、Kubernetesがマウントされたボリューム内のすべてのファイルの所有権を再帰的に変更します。そのため、大容量のデータが保存された高性能ストレージの場合は、Podの初期化時間が大幅に長くなる可能性があります。
学習のための PytorchJobの定義は、以下のユースケースのように作成できます。
# pytorchjob.yaml
apiVersion: kubeflow.org/v1
kind: PyTorchJob
metadata:
name: pytorch-mnist-dist-nccl
namespace: p-{ projectName } # プロジェクトに該当する Kubernetes Namespace名
spec:
pytorchReplicaSpecs:
Worker:
replicas: 2
restartPolicy: OnFailure
template:
metadata:
annotations:
sidecar.istio.io/inject: "false" # 自動的に設定される(省略可能)
spec:
nodeSelector:
mlx.navercorp.com/zone: { 提供された GPU Zone名 } # GPU Resourcesで確認できる Zone名
containers:
- name: pytorch # PyTorchJobの container名は必ず pytorchに設定
image: examples.com/pytorch-mnist-dist:23.03-py3
imagePullPolicy: Always
command: ["bash", "-c"]
args:
- >
torchrun --nnodes ${PET_NNODES} --nproc_per_node ${PET_NPROC_PER_NODE} --rdzv_id ${PET_RDZV_ID} --rdzv_backend ${PET_RDZV_BACKEND} --rdzv_endpoint ${PET_RDZV_ENDPOINT}
/opt/mnist/src/mnist.py --checkpoint_path /data/checkpoints/mnist.pt --log_path /data/logs --data_path /data/dataset
env:
- name: NCCL_DEBUG
value: INFO
- name: GLOO_SOCKET_FAMILY
value: AF_INET
securityContext: # Infinibandを使用するための securityContextが必要です。
capabilities:
add: ["IPC_LOCK"]
# shared memory
volumeMounts:
- mountPath: /dev/shm
name: shared-memory
volumes:
- emptyDir:
medium: Memory
name: shared-memory
kubectl apply -f pytorchjob.yaml
pytorchjob.kubeflow.org/pytorch-elastic-mnist-nccl created
Elastic Policy を使用する
torchrun を使用するために、elasticPolicy を作成します。
...
spec:
...
elasticPolicy:
rdzvId: mnist
rdzvBackend: c10d
minReplicas: 2
maxReplicas: 2
nProcPerNode: 8
...
elasticPolicy 各フィールド値を基に PyTorchJob に使用される環境変数が設定されます。環境変数は、 torchrun のパラメータを設定する際に使用できます。torchrun で使用するパラメータなどに関する詳細は、公式ドキュメントをご参照ください。
elasticPolicy フィールド |
対応環境変数 | 関係 torchrun パラメータ |
説明 |
|---|---|---|---|
rdzvId |
PET_RDZV_ID |
--rdzv-id |
ランデブー用 Job ID |
rdzvBackend |
PET_RDZV_BACKEND |
--rdzv-backend |
ランデブーバックエンド(i.e.、c10d) |
minReplicas, maxReplicas |
PET_NNODES |
--nnodes |
ノード数 |
nProcPerNode |
PET_NPROC_PER_NODE |
--nproc-per-node |
ノードごとの GPU数 |
maxRestarts |
PET_MAX_RESTARTS |
--max-restarts |
最大再起動回数 |
Run Policy を使用する
torchrunを使用するために runPolicyを作成します。
...
spec:
runPolicy:
cleanPodPolicy: None
ttlSecondsAfterFinished: 1814400 # TTLを直接設定するフィールド(単位: sec)
...
spec.runPolicyには PyTorchJob の実行およびまとめに関するパラメータを指定できます。指定しない場合、デフォルト値を使用します。spec.runPolicy下位に指定できるパラメータは、次の通りです。(参考資料: Kubeflow Trainer API Reference v1.9)
cleanPodPolicy-PytorchJobが完了した後、Podをどのようにまとめるかを決めます。- デフォルト値:
None None: Job完了後も Podを削除しないため、後ほどログを確認する際役に立ちます。All: Job完了後にすべての Podを削除します。Runningは Job完了後に実行中の Podを削除します。特別な場合を除き、使用しません。
- デフォルト値:
ttlSecondsAfterFinished- Job完了後、何秒後に Jobを削除するかを決めます。activeDeadlineSeconds- Jobの最大実行時間です。指定した時間が経過した後は、失敗として処理されます。設定されていない場合、jobの実行時間に制限はありません。backoffLimit- Jobが失敗した場合の最大再実行回数です。
Infiniband を使用する
- 別途の RDMAリソースの設定(request/limit)は必要ありません
- GPU Zoneの情報は、使用可能な GPU Zone情報の照会をご参照ください。
InfiniBandネットワークで接続されたノードで分散学習を実行すると、ノード間通信を高速化できます。
前のセクションで示したユースケースを InfiniBand環境に適用するには、追加すべき定義がいくつかありますが、以下のように要約できます。
- InfiniBandネットワークが構成された区域の名前を Annotationで定義します(i.e.、
mlx.navercorp.com/zone=ai-infra) - InfiniBandを使用するために
IPC_LOCKcapabilityをsecurityContextに追加します。 - 分散学習を支援するための Shared Memoryを
volumesに設定します。
Infinibandを使用するためには、以下のように設定できます。
...
metadata:
annotations:
mlx.navercorp.com/zone="ai-infra"
...
spec:
...
pytorchReplicaSpecs:
Worker:
template:
containers:
- name: pytorch
securityContext: # Infinibandを使用するための securityContextが必要です。
capabilities:
add: ["IPC_LOCK"]
# shared memory
volumeMounts:
- mountPath: /dev/shm
name: shared-memory
volumes:
- emptyDir:
medium: Memory
name: shared-memory
...
PytorchJobデバッグ
PytorchJob使用時に問題が発生し、デバッグが必要な場合は、以下のように環境変数値を設定することで、必要な情報をログに出力できます。
NCCL_DEBUG: NCCLと関連デバッグTORCH_DISTRIBUTED_DEBUG、TORCH_CPP_LOG_LEVEL: 分散学習に対するデバッグ; 詳細は、PyTorch公式ドキュメントをご参照ください。
デバッグのために、以下のように使用できます。
...
spec:
...
pytorchReplicaSpecs:
Worker:
template:
containers:
- name: pytorch
...
env:
- name: NCCL_DEBUG
value: "INFO"
- name: TORCH_DISTRIBUTED_DEBUG
value: "DETAIL"
- name: TORCH_CPP_LOG_LEVEL
value: "INFO"
...
外部コンテナレジストリを使用する
コンテナレジストリに Secret情報が必要な場合は、Container Secretを作成するを参照し、作成できます。
作成された Secretは、以下のように使用できます。
...
spec:
...
pytorchReplicaSpecs:
Worker:
template:
containers:
- name: pytorch
imagePullSecrets:
- name: my-harbor-secret # 事前に作成した Docker Credential Secretの名前
...
既存の Volumeを使用する
Volumesを通じて作成された Volumeは、以下のように使用できます。
...
spec:
...
pytorchReplicaSpecs:
Worker:
template:
containers:
- name: pytorch
volumeMounts:
- mountPath: /data
name: mnist-data # 下部の spec.volumesに記載した名前
volumes:
- name: mnist-data
persistentVolumeClaim:
claimName: mnist-data # Volumesを通じて作成された PVCの名前
...
PytorchJobのステータスを確認
kubectl get、kubectl describe を利用して PyTorchJob のステータスを確認できます。
kubectl get pytorchjob pytorch-elastic-mnist-nccl
NAME STATE AGE
pytorch-elastic-mnist-nccl Running 12s
kubectl describe pytorchjob pytorch-elastic-mnist-nccl
Status:
Completion Time: 2024-11-22T09:16:58Z
Conditions:
Last Transition Time: 2024-11-22T09:15:43Z
Last Update Time: 2024-11-22T09:15:43Z
Message: PyTorchJob pytorch-elastic-mnist-nccl is created.
Reason: PyTorchJobCreated
Status: True
Type: Created
Last Transition Time: 2024-11-22T09:15:48Z
Last Update Time: 2024-11-22T09:15:48Z
Message: PyTorchJob nb12706/pytorch-elastic-mnist-nccl is running.
Reason: PyTorchJobRunning
Status: False
Type: Running
Last Transition Time: 2024-11-22T09:16:58Z
Last Update Time: 2024-11-22T09:16:58Z
Message: PyTorchJob nb12706/pytorch-elastic-mnist-nccl successfully completed.
Reason: PyTorchJobSucceeded
Status: True
Type: Succeeded
Last Reconcile Time: 2024-11-22T09:15:43Z
Replica Statuses:
Worker:
Selector: training.kubeflow.org/job-name=pytorch-elastic-mnist-nccl,training.kubeflow.org/operator-name=pytorchjob-controller,training.kubeflow.org/replica-type=worker
Succeeded: 2
Start Time: 2024-11-22T09:15:44Z
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreatePod 4m21s pytorchjob-controller Created pod: pytorch-elastic-mnist-nccl-worker-0
Normal SuccessfulCreatePod 4m21s pytorchjob-controller Created pod: pytorch-elastic-mnist-nccl-worker-1
Normal SuccessfulCreateService 4m21s pytorchjob-controller Created service: pytorch-elastic-mnist-nccl-worker-0
Normal SuccessfulCreateService 4m21s pytorchjob-controller Created service: pytorch-elastic-mnist-nccl-worker-1
Normal ExitedWithCode 3m7s (x3 over 3m8s) pytorchjob-controller Pod: nb12706.pytorch-elastic-mnist-nccl-worker-1 exited with code 0
Normal ExitedWithCode 3m7s (x2 over 3m8s) pytorchjob-controller Pod: nb12706.pytorch-elastic-mnist-nccl-worker-0 exited with code 0
Normal PyTorchJobSucceeded 3m7s pytorchjob-controller PyTorchJob nb12706/pytorch-elastic-mnist-nccl successfully completed.
Normal JobTerminated 3m6s (x4 over 3m7s) pytorchjob-controller Job has been terminated. Deleting PodGroup
Normal SuccessfulDeletePodGroup 3m6s (x4 over 3m7s) pytorchjob-controller Deleted PodGroup: pytorch-elastic-mnist-nccl
学習 Podが正しく作成されない場合、以下のように Eventsを通じて原因を把握できます。
kubectl describe pytorchjob pytorch-elastic-mnist-nccl
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedCreatePod 47m (x3 over 103m) pytorchjob-controller Error creating: Pods "job-worker-1" is forbidden: exceeded quota: normal-quota, requested: requests.nvidia.com/gpu=1, used: requests.nvidia.com/gpu=2, limited: requests.nvidia.com/gpu=2
分散学習時の注意点
MLXPで分散学習を行う際の注意点についてご案内します。
NVIDIA Driverと互換性のある CUDAバージョンを使用
CUDA Runtimeバージョンは、ノードにインストールされた NVIDIA Driverと互換性がある必要があります。CUDA Runtimeが要求する最小 Driverバージョンを満たしていない場合、CUDAの初期化エラーまたはランタイムエラーが発生し、学習タスクが正常に実行されないことがあります。
IPv6が使用できない場合は GLOO_SOCKET_FAMILY=INETを設定
GLOOはノード間のステータス確認および Rank管理のために、頻繁に TCP接続を作成します。IPv6を使用できない環境で大規模学習を実行する場合、接続を試行するたびに IPv6接続が先に試行された後に失敗し、その後IPv4で再試行されます。このような二重の試行が繰り返されると、ファイルディスクリプタの枯渇などのリソース問題が発生し、結果として学習が中断される可能性があります。
このような問題を防ぐために GLOO_SOCKET_FAMILY=AF_INET 環境変数を設定し、IPv4のみ使用するように構成することをお勧めします。
GLOOで IPv4を強制するには、以下のように設定できます。
...
spec:
...
pytorchReplicaSpecs:
Worker:
template:
containers:
- name: pytorch
...
env:
- name: GLOO_SOCKET_FAMILY
value: AF_INET
...
PyTorchJob名の長さ制限(推奨)
PyTorchJob名は Kubernetesリソース(Pod、Serviceなど)作成時に接頭語として使用されるため、50文字以内で設定することをお勧めします。50文字を超えると、派生リソース名が長さ制限を超えて作成に失敗したり、worker indexパースに問題が発生したりします。
Shared Memory設定時に memory limitの設定を削除
Shared Memory(/dev/shm)は容量制限を設けないか、十分に大きなサイズに設定することをお勧めします。/dev/shmが足りないと、DataLoaderのマルチプロセス workerが異常終了する可能性があり、NCCLの通信性能低下につながる恐れがあります。
Memory limitを削除した Shared Memory設定の例は、次の通りです。
...
spec:
...
pytorchReplicaSpecs:
Worker:
template:
containers:
- name: pytorch
# shared memory
volumeMounts:
- mountPath: /dev/shm
name: shared-memory
volumes:
- emptyDir:
medium: Memory
name: shared-memory