このチュートリアルでは、Google Kubernetes Engine(GKE)で強化学習用の分散トレーニング環境をオーケストレートする方法について説明します。Ray と verl(Volcano Engine Reinforcement Learning)フレームワークを使用して、分散トレーニング環境を設定し、GSM8K データセットで Qwen2.5-32B-Instruct モデルをファインチューニングします。
このチュートリアルでは、Ray と verl を使用した GKE でのグループ相対ポリシー最適化(GRPO)トレーニング パイプラインに焦点を当てます。GRPO は、モデルの推論能力を向上させるように設計された強化学習アルゴリズムです。このメモリ効率の高いアルゴリズムは、Critic(値モデル)を排除し、相対グループベースの計算を使用することで、強化学習(RL)プロセスを簡素化します。
このチュートリアルは、効率性を高めるためにデータ、モデルの重み、トレーニング エンジンを分離する分散トレーニング環境を設定する必要がある場合に適しています。
このチュートリアルは、次の GPU アーキテクチャをサポートしています。
- Intel または AMD ベースの GPU ノード: NVIDIA B200 または H200 GPU を使用して設定し、スケーリングします。
- Arm ベースの A4X(GB200)ノード: NVIDIA GB200 Grace Blackwell Superchip を使用して設定とスケーリングを行い、GKE 動的リソース割り当て(DRA)とマルチノード NVLink(IMEX)を使用します。
背景
以降のセクションでは、このチュートリアルで使用するコンセプトの概要を説明します。
強化学習(RL)
RL は、静的な模倣ではなく、経験、探索、フィードバックを通じてモデルを学習させます。事前トレーニングではモデルに何を言うかを教えますが、人間からのフィードバックを用いた強化学習(RLHF)では、有用性、安全性、論理性を教えます。RL は、ベースモデルと特殊なユースケースのファインチューニング済みモデルの橋渡し役として機能します。
詳細については、強化学習とはをご覧ください。
グループ相対ポリシーの最適化(GRPO)
DeepSeek によって普及したアルゴリズムである GRPO は、Critic モデルを削除することで、LLM アライメント用の Proximal Policy Optimization(PPO)に代わるメモリ効率の高い方法を提供します。Critic ネットワークの代わりに、GRPO は同じプロンプトに対する一連のレスポンスを生成し、そのグループの平均報酬をベースラインとして使用します。
詳細については、GRPO をご覧ください。
Volcano Engine Reinforcement Learning(verl)
verl は、LLM ベースの RL の複雑なメモリとコンピューティング パターンを処理するように設計された高性能フレームワークです。
詳細については、verl をご覧ください。
目標
このチュートリアルでは、次の手順に沿って verl を使用して GKE で強化学習を設定する方法について説明します。
- A4X(GB200 Superchip)、A4(B200 GPU)、A3 Ultra(H200 GPU)を使用して GKE クラスタを設定します。
- 分散 Ray クラスタを管理するように KubeRay を構成します。
- Cloud Storage FUSE を使用して、すべてのノードに Cloud Storage バケットをマウントします。
- verl を使用して GRPO トレーニング ジョブを実行し、Qwen2.5-32B-Instruct モデルを GSM8K データセットに合わせます。
始める前に
- Google Cloud アカウントにログインします。 Google Cloudを初めて使用する場合は、 アカウントを作成して、実際のシナリオでの Google プロダクトのパフォーマンスを評価してください。新規のお客様には、ワークロードの実行、テスト、デプロイができる無料クレジット $300 分を差し上げます。
-
Google Cloud CLI をインストールします。
-
外部 ID プロバイダ(IdP)を使用している場合は、まず連携 ID を使用して gcloud CLI にログインする必要があります。
-
gcloud CLI を初期化するには、次のコマンドを実行します。
gcloud init -
Google Cloud プロジェクトを作成または選択します。
プロジェクトの選択または作成に必要なロール
- プロジェクトを選択する: プロジェクトの選択に特定の IAM ロールは必要ありません。ロールが付与されているプロジェクトであれば、どのプロジェクトでも選択できます。
-
プロジェクトを作成する: プロジェクトを作成するには、
resourcemanager.projects.create権限を含むプロジェクト作成者ロール(roles/resourcemanager.projectCreator)が必要です。詳しくは、ロールを付与する方法をご覧ください。
-
Google Cloud プロジェクトを作成します。
gcloud projects create PROJECT_ID
PROJECT_IDは、作成する Google Cloud プロジェクトの名前に置き換えます。 -
作成した Google Cloud プロジェクトを選択します。
gcloud config set project PROJECT_ID
PROJECT_IDは、 Google Cloud プロジェクトの名前に置き換えます。
必要な API を有効にします。
API を有効にするために必要なロール
API を有効にするには、
serviceusage.services.enable権限を含む Service Usage 管理者 IAM ロール(roles/serviceusage.serviceUsageAdmin)が必要です。詳しくは、ロールを付与する方法をご覧ください。gcloud services enable container.googleapis.com
storage.googleapis.com compute.googleapis.com -
Google Cloud CLI をインストールします。
-
外部 ID プロバイダ(IdP)を使用している場合は、まず連携 ID を使用して gcloud CLI にログインする必要があります。
-
gcloud CLI を初期化するには、次のコマンドを実行します。
gcloud init -
Google Cloud プロジェクトを作成または選択します。
プロジェクトの選択または作成に必要なロール
- プロジェクトを選択する: プロジェクトの選択に特定の IAM ロールは必要ありません。ロールが付与されているプロジェクトであれば、どのプロジェクトでも選択できます。
-
プロジェクトを作成する: プロジェクトを作成するには、
resourcemanager.projects.create権限を含むプロジェクト作成者ロール(roles/resourcemanager.projectCreator)が必要です。詳しくは、ロールを付与する方法をご覧ください。
-
Google Cloud プロジェクトを作成します。
gcloud projects create PROJECT_ID
PROJECT_IDは、作成する Google Cloud プロジェクトの名前に置き換えます。 -
作成した Google Cloud プロジェクトを選択します。
gcloud config set project PROJECT_ID
PROJECT_IDは、 Google Cloud プロジェクトの名前に置き換えます。
必要な API を有効にします。
API を有効にするために必要なロール
API を有効にするには、
serviceusage.services.enable権限を含む Service Usage 管理者 IAM ロール(roles/serviceusage.serviceUsageAdmin)が必要です。詳しくは、ロールを付与する方法をご覧ください。gcloud services enable container.googleapis.com
storage.googleapis.com compute.googleapis.com -
ユーザー アカウントにロールを付与します。次の IAM ロールごとに次のコマンドを 1 回実行します。
roles/container.admin, roles/iam.serviceAccountAdmin, roles/storage.admingcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE
次のように置き換えます。
PROJECT_ID: プロジェクト ID。USER_IDENTIFIER: ユーザー アカウントの識別子。例:myemail@example.comROLE: ユーザー アカウントに付与する IAM ロール。
- Hugging Face アカウントを作成します(まだ作成していない場合)。
- Hugging Face トークンがあることを確認します。
- プロジェクトに A4X(GB200 Superchips)、A4(B200 GPU)、A3 Ultra(H200 GPU)に十分な割り当てがあることを確認します。詳細については、GPU 割り当てを計画すると GPU 割り当てをご覧ください。
- GPU マシンタイプのアクティブな容量予約があることを確認します。詳細については、アカウント チームを通じて容量を予約するをご覧ください。
- A4X(GB200)の設定では、Helm がインストールされていることを確認してください。
環境を準備する
このチュートリアルでは、Cloud Shell を使用します。
Google Cloud コンソールに移動します。
Google Cloud コンソール ウィンドウの上部にある [Cloud Shell をアクティブにする] ボタンをクリックします。
環境変数を設定します。
export PROJECT_ID=$(gcloud config get project) export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)") export CONTROL_PLANE_REGION=CONTROL_PLANE_REGION export NODE_ZONE=NODE_ZONE export CLUSTER_NAME=CLUSTER_NAME export KSA_NAME=KSA_NAME export GS_BUCKET=BUCKET_NAME-${PROJECT_ID} export NAMESPACE=default export GPU_TYPE=GPU_TYPE export MACHINE_TYPE=MACHINE_TYPE export RESERVATION=RESERVATION export HF_TOKEN=YOUR_HUGGING_FACE_TOKEN # A4 (B200 GPUs) or A3 Ultra (H200 GPUs) only variables export GVNIC_NETWORK_PREFIX=YGVNIC_NAME export RDMA_NETWORK_PREFIX=RDMA_NAME # A4X (GB200 Superchips) only variables export NUM_GPU_NODES=4 export VERL_IMAGE=verlai/verl:vllm023.aarch64.dev1 export VERL_REF=ddbcdb7次の値を置き換えます。
CONTROL_PLANE_REGION: GKE クラスタ コントロール プレーンの Compute Engine リージョン。NODE_ZONE: ノードが予約されているゾーン。詳細については、GPU の可用性をご覧ください。CLUSTER_NAME: GKE クラスタの名前。KSA_NAME: Kubernetes サービス アカウントの名前。BUCKET_NAME: Cloud Storage バケットのベース名。gs://プレフィックスを指定する必要はありません。GPU_TYPE: Compute Engine の容量予約で予約したアクセラレータ。次のいずれかの値を指定する必要があります。nvidia-gb200: A4X(GB200 Superchip)nvidia-b200: A4(B200 GPU)nvidia-h200-141gb: A3 Ultra(H200 GPU)
MACHINE_TYPE: 使用するマシンのタイプ:- A4X(GB200 Superchip)の場合は、
a4x-highgpu-4gを使用します。 - A4(B200 GPU)の場合は、
a4-highgpu-8g以降を使用します。 - A3 Ultra(H200 GPU)の場合は、
a3-ultragpu-8g以降を使用します。
- A4X(GB200 Superchip)の場合は、
RESERVATION: 容量予約の名前。YOUR_HUGGING_FACE_TOKEN: Hugging Face トークン。GVNIC_NAME(A4 または A3 Ultra のみ): gVNIC ネットワーク名の接頭辞。任意の接頭辞を使用できます。RDMA_NAME(A4 または A3 Ultra のみ): リモート ダイレクト メモリ アクセス(RDMA)ネットワークの接頭辞。任意の接頭辞を使用できます。
インフラストラクチャを設定する
このセクションでは、標準の VPC ネットワークと GKE クラスタを作成します。
RDMA ネットワークとサブネットを作成する(A4 と A3 Ultra のみ)
このセクションは、A4 GPU と A3 Ultra GPU のみに必要です。
A4X(GB200)GPU を使用する場合は、このセクションをスキップして、GKE クラスタを作成するに直接進みます。A4X(GB200)GPU の場合、ノードプールが auto アクセラレータ ネットワーク プロファイルを使用すると、GKE はネットワークを自動的に作成します。Cluster Toolkit ブループリントは、enable_dranet:true フラグを使用してこのプロファイルを有効にします。
gVNIC インターフェース用の VPC ネットワークを作成します。
gcloud compute networks create ${GVNIC_NETWORK_PREFIX}-net \ --subnet-mode=custom \ --project=${PROJECT_ID} gcloud compute networks subnets create ${GVNIC_NETWORK_PREFIX}-sub \ --network=${GVNIC_NETWORK_PREFIX}-net \ --region=${CONTROL_PLANE_REGION} \ --range=192.168.0.0/24 gcloud compute firewall-rules create ${GVNIC_NETWORK_PREFIX}-internal \ --network=${GVNIC_NETWORK_PREFIX}-net \ --action=ALLOW \ --rules=tcp:0-65535,udp:0-65535,icmp \ --source-ranges=192.168.0.0/168 個の GPU 用に 8 個のサブネットを持つ RDMA 用の VPC ネットワークとサブネットを作成します。
gcloud beta compute networks create ${RDMA_NETWORK_PREFIX}-net \ --network-profile=${NODE_ZONE}-vpc-roce \ --subnet-mode=custom for N in $(seq 0 7); do gcloud compute networks subnets create ${RDMA_NETWORK_PREFIX}-sub-$N \ --network=${RDMA_NETWORK_PREFIX}-net \ --region=${CONTROL_PLANE_REGION} \ --range=192.168.$((N+1)).0/24 & done waitサンプル リポジトリのクローンを作成します。
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git cd kubernetes-engine-samples作業ディレクトリに移動します。
cd ai-ml/verl-on-gke
GKE クラスタを作成する
GPU アーキテクチャに対応する GKE クラスタを作成します。
A4 と A3 Ultra
使用する GKE クラスタモードを選択します。
Autopilot
Autopilot クラスタを作成します。
gcloud container clusters create-auto ${CLUSTER_NAME} \ --location=${CONTROL_PLANE_REGION} \ --enable-multi-networking \ --enable-ray-operatorクラスタの認証情報を取得します。
gcloud container clusters get-credentials ${CLUSTER_NAME} \ --location=${CONTROL_PLANE_REGION}Autopilot 用の NCCL RDMA インストーラをインストールします。
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/refs/heads/master/gpudirect-rdma/nccl-rdma-installer-autopilot.yaml
標準
Standard クラスタを作成します。
gcloud container clusters create ${CLUSTER_NAME} \ --location=${CONTROL_PLANE_REGION} \ --enable-dataplane-v2 \ --workload-pool=${PROJECT_ID}.svc.id.goog \ --enable-ip-alias \ --enable-multi-networking \ --addons=RayOperator,GcsFuseCsiDriver \ --machine-type=c2-standard-16 \ --num-nodes=1 \ --min-nodes=1 \ --max-nodes=5 \ --enable-autoscalingクラスタの認証情報を取得します。
gcloud container clusters get-credentials ${CLUSTER_NAME} --location=${CONTROL_PLANE_REGION}GPU ノードプールを作成します。これらのノードプールは、予約を使用して可用性を確保します。2 つのノードから始めます。
gcloud container node-pools create gpu-pool \ --cluster=${CLUSTER_NAME} \ --location=${CONTROL_PLANE_REGION} \ --node-locations=${NODE_ZONE} \ --machine-type=${MACHINE_TYPE} \ --accelerator=type=${GPU_TYPE},count=8,gpu-driver-version=DEFAULT \ --reservation-affinity=specific \ --reservation=${RESERVATION} \ --enable-autoscaling \ --num-nodes=2 \ --total-max-nodes=10 \ --additional-node-network=network=${GVNIC_NETWORK_PREFIX}-net,subnetwork=${GVNIC_NETWORK_PREFIX}-sub \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-0 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-1 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-2 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-3 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-4 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-5 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-6 \ --additional-node-network=network=${RDMA_NETWORK_PREFIX}-net,subnetwork=${RDMA_NETWORK_PREFIX}-sub-7Standard クラスタで使用される NCCL RDMA インストーラをインストールします。
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/refs/heads/master/gpudirect-rdma/nccl-rdma-installer.yaml
A4X
Cluster Toolkit
gke-a4xブループリントを使用して、GKE クラスタとノードプールを作成します。ブループリントは、予約にバインドされた A4X ノードプール、アクセラレータ ネットワーク(1 つの追加の gVNIC と 4 つの RDMA レール)、CX-7 NIC を DRA デバイスとして公開するマネージド DRANET ドライバなど、GKE クラスタをプロビジョニングします。ブループリントのデプロイ手順に沿って、パラメータ(
PROJECT_ID、CONTROL_PLANE_REGION、NODE_ZONE、予約、NUM_GPU_NODESなど)を構成し、クラスタをデプロイします。または、A4X GKE クラスタ作成ガイドに沿って、クラスタを手動で作成することもできます。クラスタの認証情報を取得します。
gcloud container clusters get-credentials ${CLUSTER_NAME} --location=${CONTROL_PLANE_REGION}クラスタが DRA を介して RDMA NIC を公開していることを確認します。
kubectl get deviceclasses出力には
mrdma.google.comが含まれている必要があります。A4X ノードが存在することを確認します。
kubectl get nodes -l cloud.google.com/gke-accelerator=nvidia-gb200gIB NCCL プラグイン(A4X バリアント)をインストールします。
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/gpudirect-rdma/nccl-rdma-installer-a4x.yamlマルチノード NVLink 用の
ComputeDomain(IMEX)チャネルを提供する NVIDIA DRA ドライバをインストールします。helm repo add nvidia https://helm.ngc.nvidia.com/nvidia && helm repo update kubectl create namespace nvidia-dra-driver-gpu kubectl apply -f - <<EOF apiVersion: v1 kind: ResourceQuota metadata: name: nvidia-dra-driver-gpu-quota namespace: nvidia-dra-driver-gpu spec: hard: pods: "$((2 * NUM_GPU_NODES + 1))" scopeSelector: matchExpressions: - operator: In scopeName: PriorityClass values: - system-node-critical - system-cluster-critical EOF helm upgrade --install nvidia-dra-driver-gpu nvidia/nvidia-dra-driver-gpu \ --version=25.3.1 --namespace nvidia-dra-driver-gpu \ --set nvidiaDriverRoot=/home/kubernetes/bin/nvidia \ --set resources.gpus.enabled=false \ --set kubeletPlugin.tolerations[0].key=nvidia.com/gpu \ --set kubeletPlugin.tolerations[0].operator=Exists \ --set kubeletPlugin.tolerations[1].key=kubernetes.io/arch \ --set kubeletPlugin.tolerations[1].operator=Existsワークロード Namespace にスコープ設定された KubeRay オペレーターをインストールします。
kubectl create namespace ${NAMESPACE} helm repo add kuberay https://ray-project.github.io/kuberay-helm/ && helm repo update helm upgrade --install kuberay-operator kuberay/kuberay-operator \ --namespace ${NAMESPACE} \ --set singleNamespaceInstall=true --set "watchNamespace={${NAMESPACE}}"
ネットワーク マッピングを構成する(A4 と A3 Ultra のみ)
この手順は、標準 GPU の設定(A4 と A3 Ultra のみ)に必要です。A4X(GB200)を使用する場合、GKE がネットワーク インターフェースを自動的に管理するため、このセクションはスキップしてください。
マニフェスト
network-mapping.yamlを調べます。次のようにマニフェストを適用します。
envsubst < network-mapping.yaml > network-mapping-updated.yaml kubectl apply -f network-mapping-updated.yaml
データとストレージを準備する
Cloud Storage と Kubernetes のリソースを構成します。
Cloud Storage バケットを作成します。
gcloud storage buckets create gs://${GS_BUCKET} \ --location=${CONTROL_PLANE_REGION} \ --enable-hierarchical-namespace \ --uniform-bucket-level-accessKubernetes サービス アカウント(KSA)を作成し、バケットにバインドします。
kubectl create serviceaccount ${KSA_NAME} --namespace ${NAMESPACE} gcloud storage buckets add-iam-policy-binding gs://${GS_BUCKET} \ --member "principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/${NAMESPACE}/sa/${KSA_NAME}" \ --role "roles/storage.objectUser"Hugging Face の Secret を作成します。
kubectl create secret generic hf-secret --from-literal=hf_api_token=${HF_TOKEN}マニフェスト
gcsfuse-storage.yamlを調べます。次のようにマニフェストを適用します。
envsubst < gcsfuse-storage.yaml > gcsfuse-storage-updated.yaml kubectl apply -f gcsfuse-storage-updated.yaml
モデルとデータを準備する
モデルの重みとデータセットを使用して Cloud Storage バケットにデータを入力します。これらのコマンドをローカルまたは GKE Pod で実行して、バケットにデータを入力できます。
verl リポジトリをクローンし、仮想環境を準備して GSM8K データセットを処理します。
git clone https://github.com/volcengine/verl.git git -C verl checkout ${VERL_REF} VENV_DIR=.venv python3 -m venv $VENV_DIR source $VENV_DIR/bin/activate pip install verl python verl/examples/data_preprocess/gsm8k.py --local_save_dir ~/data/gsm8kHugging Face CLI を使用して Qwen2.5-32B-Instruct モデルをダウンロードします(これには約 66 GB のディスク容量が必要です)。
hf download Qwen/Qwen2.5-32B-Instruct --local-dir Qwen2.5-32B-Instructモデル、データ、verl コードを Cloud Storage バケットにアップロードします。
gcloud storage cp --recursive verl gs://${GS_BUCKET}/verl gcloud storage cp --recursive Qwen2.5-32B-Instruct gs://${GS_BUCKET}/Qwen2.5-32B-Instruct gcloud storage cp --recursive ~/data/gsm8k/* gs://${GS_BUCKET}/gsm8k/
RayCluster カスタム リソースをデプロイする
RayCluster カスタム リソースをデプロイします。これは、1 つのシステム ヘッド Pod と複数の GPU バックアップ ワーカー Pod で構成されます。
A4 と A3 Ultra
クラスタの作成に使用した GKE クラスタモードを選択します。
Autopilot
RayCluster をデプロイします。次のコードを
ray-cluster-auto.yamlに保存します。RayCluster を適用します。
envsubst < ray-cluster-auto.yaml > ray-cluster-auto-updated.yaml kubectl apply -f ray-cluster-auto-updated.yaml
標準
RayCluster をデプロイします。次の構成を
ray-cluster-standard.yamlに保存します。RayCluster を適用します。
envsubst < ray-cluster-standard.yaml > ray-cluster-updated.yaml kubectl apply -f ray-cluster-updated.yaml
A4X
RDMA
ResourceClaimTemplateと NVIDIAComputeDomainを作成します。各 GPU ワーカー Pod は、4 つの RDMA NIC(ノードのすべてのレール)と 1 つの IMEX チャネルを要求します。次のマニフェストをcompute-domain-a4x.yamlに保存します。apiVersion: resource.k8s.io/v1 kind: ResourceClaimTemplate metadata: name: verl-rdma-nic namespace: ${NAMESPACE} spec: spec: devices: requests: - name: nic exactly: deviceClassName: mrdma.google.com allocationMode: ExactCount count: 1 --- apiVersion: resource.nvidia.com/v1beta1 kind: ComputeDomain metadata: name: verl-compute-domain namespace: ${NAMESPACE} spec: numNodes: ${NUM_GPU_NODES} channel: resourceClaimTemplate: name: verl-compute-domain-channel次のようにマニフェストを適用します。
kubectl apply -f compute-domain-a4x.yamlRayCluster をデプロイします。Ray ヘッド Pod は、GPU をリクエストせずに A4X ノードで実行されます(イメージは
arm64のみであるため)。次の構成をray-cluster-a4x.yamlに保存します。apiVersion: ray.io/v1 kind: RayCluster metadata: name: gb200-ray-cluster namespace: ${NAMESPACE} spec: rayVersion: '2.49.0' headGroupSpec: rayStartParams: dashboard-host: '0.0.0.0' num-cpus: "0" template: metadata: annotations: gke-gcsfuse/volumes: "true" spec: serviceAccountName: ${KSA_NAME} nodeSelector: cloud.google.com/gke-accelerator: nvidia-gb200 tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule - key: kubernetes.io/arch operator: Exists effect: NoSchedule containers: - name: ray-head image: ${VERL_IMAGE} lifecycle: postStart: exec: command: - /bin/bash - -c - pip3 install --quiet TransferQueue==0.1.8 ports: - containerPort: 6379 name: gcs-server - containerPort: 8265 name: dashboard - containerPort: 10001 name: client resources: limits: cpu: "12" memory: 32Gi ephemeral-storage: 20Gi requests: cpu: "12" memory: 32Gi ephemeral-storage: 20Gi volumeMounts: - mountPath: /tmp/ray name: ray-logs - name: training-bucket-vol mountPath: /data volumes: - name: ray-logs emptyDir: {} - name: training-bucket-vol persistentVolumeClaim: claimName: training-bucket-pvc workerGroupSpecs: - replicas: ${NUM_GPU_NODES} minReplicas: ${NUM_GPU_NODES} maxReplicas: ${NUM_GPU_NODES} groupName: gpu-group rayStartParams: num-cpus: "120" template: metadata: annotations: gke-gcsfuse/volumes: "true" spec: serviceAccountName: ${KSA_NAME} nodeSelector: cloud.google.com/gke-accelerator: nvidia-gb200 affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: ray.io/group: gpu-group topologyKey: kubernetes.io/hostname tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule - key: kubernetes.io/arch operator: Exists effect: NoSchedule containers: - name: ray-worker image: ${VERL_IMAGE} lifecycle: postStart: exec: command: - /bin/bash - -c - pip3 install --quiet TransferQueue==0.1.8 env: - name: LD_LIBRARY_PATH value: /usr/local/nvidia/lib64 resources: limits: cpu: "120" memory: 600Gi nvidia.com/gpu: "4" ephemeral-storage: 500Gi requests: cpu: "120" memory: 600Gi nvidia.com/gpu: "4" ephemeral-storage: 500Gi claims: - name: rdma-nic-0 - name: rdma-nic-1 - name: rdma-nic-2 - name: rdma-nic-3 - name: compute-domain-channel volumeMounts: - name: nvidia mountPath: /usr/local/nvidia - name: gib mountPath: /usr/local/gib - name: shared-memory mountPath: /dev/shm - name: ray-tmp-storage mountPath: /tmp - name: training-bucket-vol mountPath: /data resourceClaims: - name: rdma-nic-0 resourceClaimTemplateName: verl-rdma-nic - name: rdma-nic-1 resourceClaimTemplateName: verl-rdma-nic - name: rdma-nic-2 resourceClaimTemplateName: verl-rdma-nic - name: rdma-nic-3 resourceClaimTemplateName: verl-rdma-nic - name: compute-domain-channel resourceClaimTemplateName: verl-compute-domain-channel volumes: - name: gib hostPath: path: /home/kubernetes/bin/gib - name: nvidia hostPath: path: /home/kubernetes/bin/nvidia - name: shared-memory emptyDir: medium: Memory sizeLimit: 200Gi - name: ray-tmp-storage emptyDir: {} - name: training-bucket-vol persistentVolumeClaim: claimName: training-bucket-pvcRayCluster マニフェストを適用します。
envsubst < ray-cluster-a4x.yaml | kubectl apply -f -1 つのヘッド Pod と 4 つのワーカー Pod が
Running状態になるまで待ちます。kubectl get pods -w
GRPO ジョブを起動する
強化学習トレーニング ジョブを構成して送信します。
A4 と A3 Ultra
Ray ダッシュボード ノードへのポート転送を設定します。このコマンドは実行中、ターミナルをブロックするため、別のターミナル ウィンドウを使用してください。Ctrl+C キーを押して停止します。
kubectl port-forward svc/b200-ray-cluster-head-svc 8265:8265マニフェスト
runtime-env.yamlを調べます。H200 GPU を使用する場合は、
NCCL_TUNER_CONFIG_PATHを/usr/local/gib/configs/tuner_config_a3u.txtpbに変更します。このファイルは Ray クライアントで使用されます。このマニフェストをクラスタに適用する必要はありません。
ray job submitを使用して Job を送信します。ray job submit \ --address "http://localhost:8265" \ --runtime-env runtime-env.yaml \ -- \ bash -c " cd /data/verl && PYTHONUNBUFFERED=1 python3 -m verl.trainer.main_ppo \ data.train_files=/data/gsm8k/train.parquet \ data.val_files=/data/gsm8k/test.parquet \ data.train_batch_size=256 \ data.max_prompt_length=512 \ data.max_response_length=512 \ actor_rollout_ref.model.path=/data/Qwen2.5-32B-Instruct \ actor_rollout_ref.actor.optim.lr=1e-5 \ actor_rollout_ref.actor.ppo_mini_batch_size=256 \ actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu=64 \ actor_rollout_ref.rollout.name=vllm \ actor_rollout_ref.rollout.log_prob_micro_batch_size_per_gpu=8 \ actor_rollout_ref.rollout.tensor_model_parallel_size=8 \ actor_rollout_ref.rollout.gpu_memory_utilization=0.6 \ actor_rollout_ref.ref.log_prob_micro_batch_size_per_gpu=4 \ actor_rollout_ref.actor.strategy=fsdp2 \ algorithm.kl_ctrl.kl_coef=0.001 \ trainer.logger=console \ trainer.val_before_train=False \ trainer.n_gpus_per_node=8 \ trainer.nnodes=2 \ trainer.save_freq=10 \ trainer.test_freq=10 \ trainer.default_local_dir=/data/verl/checkpoints \ algorithm.adv_estimator=grpo \ actor_rollout_ref.rollout.n=8 \ trainer.total_epochs=2"Ray ダッシュボードまたはコンソール出力でログをモニタリングします。
critic/score/meanが増加していることを確認します。これは学習を示しています。トレーニングが完了すると、トレーニング済みモデルのチェックポイントが
gs://$GS_BUCKET/verl/checkpointsに保存されます。
A4X
Ray ヘッド Pod の名前を取得します。
export HEAD_POD=$(kubectl get pod -n ${NAMESPACE} -l ray.io/node-type=head -o jsonpath='{.items[0].metadata.name}')ヘッド Pod で Ray ランタイム環境ファイルを直接構成します。
kubectl exec ${HEAD_POD} -c ray-head -- bash -c 'mkdir -p /tmp/submit && cat > /tmp/submit/runtime-env.yaml <<EOF working_dir: "." env_vars: PYTHONPATH: "/data/verl" LD_LIBRARY_PATH: "/usr/local/nvidia/lib64:/usr/local/gib/lib64" NCCL_DEBUG: "INFO" NCCL_ENV_PLUGIN: "gcp" HF_HOME: "/data/huggingface_cache" GLOO_SOCKET_IFNAME: "eth0" EOF'Ray ヘッド Pod で実行して GRPO トレーニング ジョブを送信します。
kubectl exec ${HEAD_POD} -c ray-head -- bash -c 'cd /tmp/submit && \ ray job submit --runtime-env runtime-env.yaml --no-wait -- \ python3 -m verl.trainer.main_ppo \ algorithm.adv_estimator=grpo \ data.train_files=/data/gsm8k/train.parquet \ data.val_files=/data/gsm8k/test.parquet \ data.train_batch_size=256 \ data.max_prompt_length=512 \ data.max_response_length=512 \ actor_rollout_ref.model.path=/data/Qwen2.5-32B-Instruct \ actor_rollout_ref.actor.optim.lr=1e-5 \ actor_rollout_ref.actor.ppo_mini_batch_size=64 \ actor_rollout_ref.actor.ppo_micro_batch_size_per_gpu=8 \ actor_rollout_ref.actor.use_kl_loss=True \ actor_rollout_ref.actor.strategy=fsdp2 \ actor_rollout_ref.rollout.name=vllm \ actor_rollout_ref.rollout.tensor_model_parallel_size=4 \ actor_rollout_ref.rollout.gpu_memory_utilization=0.6 \ actor_rollout_ref.rollout.n=8 \ actor_rollout_ref.rollout.log_prob_micro_batch_size_per_gpu=16 \ actor_rollout_ref.ref.log_prob_micro_batch_size_per_gpu=16 \ algorithm.kl_ctrl.kl_coef=0.001 \ trainer.logger=console \ trainer.n_gpus_per_node=4 \ trainer.nnodes=4 \ trainer.save_freq=10 \ trainer.test_freq=10 \ trainer.total_epochs=2 \ trainer.default_local_dir=/data/verl/checkpoints'ジョブログをモニタリングします(
ray job submitから返された一意の ID を使用)。kubectl exec ${HEAD_POD} -c ray-head -- ray job logs <var>JOB_ID</var> --followJOB_IDには、via P2P/MNNVLを含むログで NCCL 行を探して、クロスノード NVLink がアクティブであることを確認します。
クリーンアップ
課金されないようにするには、リソースを削除します。
A4 と A3 Ultra
kubectl delete raycluster b200-ray-cluster
gcloud container clusters delete ${CLUSTER_NAME} --location=${CONTROL_PLANE_REGION}
gcloud storage rm -r gs://${GS_BUCKET}
A4X
kubectl delete raycluster gb200-ray-cluster
kubectl delete computedomain verl-compute-domain
gcloud storage rm -r gs://${GS_BUCKET}
gcloud container clusters delete ${CLUSTER_NAME} --location=${CONTROL_PLANE_REGION}