Ce tutoriel vous explique comment exécuter des charges de travail PyTorch distribuées et affiner un modèle Gemma 4 sur des tranches Cloud TPU multi-hôtes dans Google Kubernetes Engine (GKE) à l'aide de Ray Core, Ray Train, PyTorch Fully Sharded Data Parallel (FSDP2) et TorchTPU.
Ce tutoriel s'adresse aux ingénieurs en machine learning (ML), aux administrateurs et opérateurs de plate-forme, ainsi qu'aux spécialistes des données et de l'IA qui souhaitent orchestrer des charges de travail d'entraînement PyTorch distribuées sur des tranches de TPU multi-hôtes dans Kubernetes. Pour en savoir plus sur les rôles courants et les exemples de tâches que nous citons dans le contenu Google Cloud , consultez Rôles utilisateur et tâches courantes de GKE.
Avant de commencer ce tutoriel, assurez-vous de connaître les éléments suivants :
- À propos des modes de fonctionnement de GKE
- À propos des TPU dans GKE
- Pools de nœuds de tranche TPU multi-hôtes
- À propos de Ray sur GKE
Arrière-plan
Cette section décrit les principales technologies utilisées dans ce tutoriel.
TPU
Les Tensor Processing Units (TPU) sont des accélérateurs conçus sur mesure par Google pour les charges de travail de machine learning. Ce tutoriel est compatible avec les TPU Trillium (v6e) et Ironwood (TPU7x). Dans une tranche de TPU multi-hôte, plusieurs hôtes TPU communiquent directement via un réseau d'interconnexion entre puces (ICI) à haut débit. Cela fournit la mémoire à haut débit (HBM) agrégée et la communication collective à faible latence requises pour entraîner des modèles qui dépassent la capacité de mémoire d'une seule puce ou d'un seul hôte TPU.
TorchTPU
TorchTPU est un backend PyTorch Open Source pour Cloud TPU, développé en collaboration par Google et Meta. Avec TorchTPU, vous pouvez exécuter des modèles PyTorch existants sur du matériel TPU avec un minimum de modifications du code, et faire évoluer les charges de travail d'entraînement et d'inférence d'une seule puce à des pods TPU multitranches grâce au compilateur XLA (Accelerated Linear Algebra). TorchTPU utilise un modèle d'exécution à un processus par appareil sur le réseau ICI de TPU et est compatible avec les API PyTorch standards, y compris l'exécution eager, torch.compile, torch.distributed, DeviceMesh, DTensor et Fully Sharded Data Parallel (FSDP2).
KubeRay et Ray sur TPU
KubeRay est un opérateur Kubernetes permettant de déployer et de gérer des applications Ray. L'activation du module complémentaire Ray sur GKE déploie l'opérateur KubeRay géré et le webhook TPU KubeRay. Lorsque KubeRay crée des pods de nœuds de calcul qui demandent des ressources google.com/tpu, le webhook configure automatiquement les noms d'hôte des pods, le service sans adresse IP et les variables d'environnement TPU requises pour la coordination multi-hôte.
Ray détecte la topologie TPU sur chaque nœud au démarrage et planifie les charges de travail distribuées sur les tranches TPU. Vous pouvez orchestrer des charges de travail TorchTPU distribuées à deux niveaux :
- Ray Core fournit des groupes d'emplacements tenant compte de la topologie et une planification des acteurs pour les boucles d'exécution distribuées personnalisées, telles que le calcul tensoriel parallèle ou les pipelines d'apprentissage par renforcement (RL).
- Ray Train fournit un entraînement géré distribué en parallèle des données et en parallèle des modèles, y compris PyTorch Distributed Data Parallel (DDP), PyTorch FSDP2 et JAX SPMD (single program, multiple data), avec des points de contrôle intégrés et une récupération automatique après défaillance.
Objectifs
Ce tutoriel vous explique comment effectuer les tâches suivantes :
- Créez un cluster GKE en mode Autopilot ou Standard sur TPU Trillium (v6e) ou Ironwood (TPU7x).
- Créez une image de conteneur qui superpose les bibliothèques d'entraînement Ray et Hugging Face sur l'image de base TorchTPU.
- Déployez une ressource personnalisée RayCluster pour provisionner les nœuds principaux et les nœuds de calcul TPU.
- Exécutez un calcul distribué de tenseurs parallèles avec PyTorch
DeviceMeshetDTensorsur une tranche TPU à l'aide de Ray Core. - Affinez un modèle Gemma 4 avec PyTorch FSDP2 sur une tranche de TPU multi-hôte à l'aide de Ray Train.
Coûts
Dans ce tutoriel, vous utilisez les composants facturables suivants de Google Cloud :
Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût.
Une fois que vous avez terminé les tâches décrites dans ce tutoriel, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.
Avant de commencer
Avant de commencer, effectuez les tâches suivantes :
- Activez l'API Artifact Registry, l'API Cloud Storage et l'API Google Kubernetes Engine. Activer les API
- Si vous souhaitez utiliser la Google Cloud CLI pour cette tâche, installez puis initialisez la gcloud CLI. Si vous avez déjà installé la gcloud CLI, obtenez la dernière version en exécutant la commande
gcloud components update. Il est possible que les versions antérieures de la gcloud CLI ne permettent pas d'exécuter les commandes de ce document.
- Vérifiez que votre projet dispose d'un quota suffisant pour la capacité TPU Trillium (v6e) ou Ironwood (TPU7x) dans la zone sélectionnée. Pour en savoir plus, consultez Quotas Cloud TPU.
- Assurez-vous que votre compte dispose des rôles IAM suivants :
- Administrateur Kubernetes Engine (
roles/container.admin) - Administrateur Artifact Registry (
roles/artifactregistry.admin) - Administrateur de l'espace de stockage (
roles/storage.admin)
- Administrateur Kubernetes Engine (
Préparer votre environnement
Dans ce tutoriel, vous utilisez Cloud Shell pour gérer les ressources hébergées sur Google Cloud. Cloud Shell est préinstallé avec les logiciels dont vous avez besoin pour ce tutoriel, y compris kubectl, docker, python3 et la CLI gcloud.
Pour configurer votre environnement avec Cloud Shell, procédez comme suit :
Dans la console Google Cloud , lancez une session Cloud Shell en cliquant sur
Activer Cloud Shell dans la consoleGoogle Cloud . Une session s'ouvre dans le volet inférieur de la console Google Cloud .
Clonez le dépôt
kubernetes-engine-sampleset accédez au répertoire de l'exemple pour ce tutoriel :git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git cd kubernetes-engine-samples/ai-ml/gke-ray/raytrain/torchtpuCréez et activez un environnement virtuel Python local avec la CLI Ray installée :
python3 -m venv ~/ray-env source ~/ray-env/bin/activate pip install "ray[default]==2.58.0"Pour télécharger les pondérations du modèle Gemma 4, acceptez le contrat de licence Google sur Hugging Face :
- Accédez à la page du modèle Gemma 4 sur Hugging Face.
- Connectez-vous et acceptez les conditions de licence en cliquant sur Accepter et accéder au dépôt.
- Dans les paramètres de votre compte Hugging Face, générez un jeton d'accès utilisateur avec des autorisations
Read.
Définissez les variables d'environnement pour votre projet Google Cloud , votre cluster, votre bucket Cloud Storage et votre jeton Hugging Face :
export PROJECT_ID=PROJECT_ID export CLUSTER_NAME=CLUSTER_NAME export REGION=REGION export ZONE=ZONE export ARTIFACT_REGISTRY=ARTIFACT_REGISTRY export BUCKET_NAME=BUCKET_NAME export HF_TOKEN=HF_TOKEN export IMAGE_URI=${REGION}-docker.pkg.dev/${PROJECT_ID}/${ARTIFACT_REGISTRY}/ray-torchtpu:latest gcloud config set project ${PROJECT_ID}Remplacez les éléments suivants :
PROJECT_ID: ID de votre projet Google Cloud .CLUSTER_NAME: nom de votre cluster GKE, par exempleray-torchtpu-cluster.REGION: région où se trouvent votre dépôt Artifact Registry, votre bucket Cloud Storage et votre capacité TPU.ZONE: zone dans laquelle votre capacité de TPU est disponible. Pour connaître les régions et zones disponibles par version de TPU, consultez Régions et zones TPU.ARTIFACT_REGISTRY: nom de votre dépôt Docker Artifact Registry, par exempleray-torchtpu.BUCKET_NAME: nom de votre bucket Cloud Storage pour stocker les points de contrôle Ray Train, par exemplePROJECT_ID-ray-torchtpu.HF_TOKEN: votre jeton d'accès Hugging Face.
Créer un cluster GKE
Vous pouvez exécuter des charges de travail d'entraînement TorchTPU distribuées dans un cluster GKE Autopilot ou Standard avec le module complémentaire Ray Operator géré activé.
Créez votre cluster GKE et configurez les identifiants pour l'outil de ligne de commande
kubectl:Autopilot
Créez un cluster GKE Autopilot régional avec le module complémentaire de l'opérateur Ray activé :
gcloud container clusters create-auto ${CLUSTER_NAME} \ --project=${PROJECT_ID} \ --region=${REGION} \ --cluster-version=1.36 \ --enable-ray-operatorLorsque vous déploierez la ressource personnalisée RayCluster lors d'une étape ultérieure, GKE Autopilot provisionnera automatiquement le nœud principal du processeur et la tranche TPU multi-hôte qui correspondent à vos requêtes de ressources de pod et à vos sélecteurs de nœuds.
Configurez l'outil de ligne de commande
kubectlpour communiquer avec votre cluster :gcloud container clusters get-credentials ${CLUSTER_NAME} \ --project=${PROJECT_ID} \ --region=${REGION}
Standard
Créez un cluster GKE Standard zonal avec un pool de nœuds de processeur pour héberger le pod de tête Ray, le streaming d'images, GKE Dataplane V2 et la fédération d'identité de charge de travail pour GKE activés :
gcloud container clusters create ${CLUSTER_NAME} \ --project=${PROJECT_ID} \ --zone=${ZONE} \ --cluster-version=1.36 \ --machine-type=n2-standard-8 \ --num-nodes=1 \ --addons=RayOperator \ --enable-image-streaming \ --enable-dataplane-v2 \ --workload-pool=${PROJECT_ID}.svc.id.googConfigurez l'outil de ligne de commande
kubectlpour communiquer avec votre cluster :gcloud container clusters get-credentials ${CLUSTER_NAME} \ --project=${PROJECT_ID} \ --zone=${ZONE}Créez un pool de nœuds de tranche TPU multi-hôte de 16 appareils avec une topologie
4x4sur quatre hôtes sur TPU Trillium (v6e) ou une topologie2x2x2sur deux hôtes sur Ironwood (TPU7x) :Trillium (v6e)
gcloud container node-pools create tpu-multi-host-pool \ --project=${PROJECT_ID} \ --cluster=${CLUSTER_NAME} \ --zone=${ZONE} \ --machine-type=ct6e-standard-4t \ --tpu-topology=4x4 \ --num-nodes=4Ironwood (TPU7x)
gcloud container node-pools create tpu-multi-host-pool \ --project=${PROJECT_ID} \ --cluster=${CLUSTER_NAME} \ --zone=${ZONE} \ --machine-type=tpu7x-standard-4t \ --tpu-topology=2x2x2 \ --num-nodes=2
Créez un bucket Cloud Storage pour stocker les points de contrôle Ray Train partagés entre les nœuds TPU multi-hôtes et accordez à la ressource de compte de service Kubernetes
defaultl'accès au bucket :gcloud storage buckets create gs://${BUCKET_NAME} --location=${REGION} PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)") gcloud storage buckets add-iam-policy-binding gs://${BUCKET_NAME} \ --member="principal://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/global/workloadIdentityPools/${PROJECT_ID}.svc.id.goog/subject/ns/default/sa/default" \ --role="roles/storage.objectAdmin"Créez un secret Kubernetes avec votre jeton d'accès Hugging Face afin que les pods Ray puissent télécharger les pondérations Gemma 4 protégées :
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HF_TOKEN}
Créer l'image de conteneur
Créez une image de conteneur qui installe Ray et les bibliothèques d'entraînement Hugging Face sur l'image de base TorchTPU prédéfinie, qui inclut TorchTPU et la bibliothèque libtpu.
Créez un dépôt Docker Artifact Registry et configurez l'authentification Docker :
gcloud artifacts repositories create ${ARTIFACT_REGISTRY} \ --repository-format=docker \ --location=${REGION} gcloud auth configure-docker ${REGION}-docker.pkg.dev,us-docker.pkg.devInspectez le fichier
Dockerfiledans le répertoire de l'exemple :L'entraînement sur une seule tranche avec la classe Ray
TorchTraineret la planification par chiplet sur Ironwood (TPU7x) nécessitent Ray version 2.58.0 ou ultérieure, et l'ajustement de Gemma 4 nécessite la bibliothèquetransformersversion 5.5.0 ou ultérieure.Créez et transférez l'image vers Artifact Registry :
docker build -t ${IMAGE_URI} . docker push ${IMAGE_URI}
Déployer la ressource personnalisée RayCluster
Déployez une ressource personnalisée RayCluster qui provisionne un pod principal de processeur, un volume /dev/shm en mémoire pour le magasin d'objets en mémoire partagée Ray et un groupe de nœuds de calcul TPU multi-hôtes.
Examinez le fichier manifeste RayCluster pour votre version de TPU dans l'exemple de dépôt :
Trillium (v6e)
Ironwood (TPU7x)
Sur Ironwood (TPU7x), chaque puce physique contient deux chiplets, ce qui fournit huit cœurs TPU logiques par hôte à quatre puces. Le fichier manifeste définit la valeur du champ
TPUsur"8"dans la sectionresourceset définit la variable d'environnementRAY_TPU_RESOURCE_PER_CHIPsur"2"pour annoncer et planifier huit ressourcesTPUlogiques par hôte.Appliquez le fichier manifeste pour créer la ressource personnalisée RayCluster :
Trillium (v6e)
envsubst < ray-cluster.tpu-v6e-multihost.yaml | kubectl apply -f -Ironwood (TPU7x)
envsubst < ray-cluster.tpu-v7x-multihost.yaml | kubectl apply -f -Attendez que le pod principal RayCluster et tous les pods de nœuds de calcul TPU atteignent l'état
Running:kubectl get pods -l ray.io/cluster=ray-torchtpu-clusterLe résultat ressemble à ce qui suit :
Trillium (v6e)
NAME READY STATUS RESTARTS AGE ray-torchtpu-cluster-head-pdpk6 1/1 Running 0 2m30s ray-torchtpu-cluster-v6e-16-worker-brwpc 1/1 Running 0 2m30s ray-torchtpu-cluster-v6e-16-worker-dx4w7 1/1 Running 0 2m30s ray-torchtpu-cluster-v6e-16-worker-h4d4w 1/1 Running 0 2m30s ray-torchtpu-cluster-v6e-16-worker-t2g24 1/1 Running 0 2m30sIronwood (TPU7x)
NAME READY STATUS RESTARTS AGE ray-torchtpu-cluster-head-k9x2m 1/1 Running 0 2m30s ray-torchtpu-cluster-tpu7x-16-worker-7cwpq 1/1 Running 0 2m30s ray-torchtpu-cluster-tpu7x-16-worker-m98r9 1/1 Running 0 2m30sInspectez les variables d'environnement sur l'un des pods de nœuds de calcul pour vérifier que le webhook TPU KubeRay a injecté les variables de coordination TPU multi-hôte et de topologie TorchTPU :
kubectl get pods -l ray.io/node-type=worker \ -o=jsonpath='{range .items[0].spec.containers[0].env[*]}{.name}={.value}{"\n"}{end}' \ | grep -E "TPU_WORKER_ID|TPU_WORKER_HOSTNAMES|TPU_NAME|TORCH_TPU_TOPOLOGY|TORCH_TPU_SLICEBUILDER_ADDRESSES"Le résultat ressemble à ce qui suit :
Trillium (v6e)
TPU_WORKER_HOSTNAMES=v6e-16-0-0.ray-torchtpu-cluster-headless,v6e-16-0-1.ray-torchtpu-cluster-headless,v6e-16-0-2.ray-torchtpu-cluster-headless,v6e-16-0-3.ray-torchtpu-cluster-headless TORCH_TPU_TOPOLOGY=4,4,1 TORCH_TPU_SLICEBUILDER_ADDRESSES=v6e-16-0-0.ray-torchtpu-cluster-headless:8471,v6e-16-0-0.ray-torchtpu-cluster-headless:8472,v6e-16-0-0.ray-torchtpu-cluster-headless:8473,v6e-16-0-0.ray-torchtpu-cluster-headless:8474,v6e-16-0-1.ray-torchtpu-cluster-headless:8471,v6e-16-0-1.ray-torchtpu-cluster-headless:8472,v6e-16-0-1.ray-torchtpu-cluster-headless:8473,v6e-16-0-1.ray-torchtpu-cluster-headless:8474,v6e-16-0-2.ray-torchtpu-cluster-headless:8471,v6e-16-0-2.ray-torchtpu-cluster-headless:8472,v6e-16-0-2.ray-torchtpu-cluster-headless:8473,v6e-16-0-2.ray-torchtpu-cluster-headless:8474,v6e-16-0-3.ray-torchtpu-cluster-headless:8471,v6e-16-0-3.ray-torchtpu-cluster-headless:8472,v6e-16-0-3.ray-torchtpu-cluster-headless:8473,v6e-16-0-3.ray-torchtpu-cluster-headless:8474 TPU_WORKER_ID=3 TPU_NAME=v6e-16-0Ironwood (TPU7x)
TPU_WORKER_HOSTNAMES=tpu7x-16-0-0.ray-torchtpu-cluster-headless,tpu7x-16-0-1.ray-torchtpu-cluster-headless TORCH_TPU_TOPOLOGY=2,2,2,2 TORCH_TPU_SLICEBUILDER_ADDRESSES=tpu7x-16-0-0.ray-torchtpu-cluster-headless:8471,tpu7x-16-0-0.ray-torchtpu-cluster-headless:8472,tpu7x-16-0-0.ray-torchtpu-cluster-headless:8473,tpu7x-16-0-0.ray-torchtpu-cluster-headless:8474,tpu7x-16-0-0.ray-torchtpu-cluster-headless:8475,tpu7x-16-0-0.ray-torchtpu-cluster-headless:8476,tpu7x-16-0-0.ray-torchtpu-cluster-headless:8477,tpu7x-16-0-0.ray-torchtpu-cluster-headless:8478,tpu7x-16-0-1.ray-torchtpu-cluster-headless:8471,tpu7x-16-0-1.ray-torchtpu-cluster-headless:8472,tpu7x-16-0-1.ray-torchtpu-cluster-headless:8473,tpu7x-16-0-1.ray-torchtpu-cluster-headless:8474,tpu7x-16-0-1.ray-torchtpu-cluster-headless:8475,tpu7x-16-0-1.ray-torchtpu-cluster-headless:8476,tpu7x-16-0-1.ray-torchtpu-cluster-headless:8477,tpu7x-16-0-1.ray-torchtpu-cluster-headless:8478 TPU_WORKER_ID=1 TPU_NAME=tpu7x-16-0Établissez une session de transfert de port vers le service principal Ray :
kubectl port-forward svc/ray-torchtpu-cluster-head-svc 8265:8265 >/dev/null 2>&1 &Vous pouvez inspecter les nœuds de calcul TPU et leurs libellés
ray.io/tpu-*détectés automatiquement dans l'onglet Cluster du tableau de bord Ray.
Exécuter le parallélisme de tenseur distribué avec Ray Core
Ray Core fournit la fonction slice_placement_group dans le module ray.util.tpu pour réserver une tranche de TPU multi-hôte intacte et la classe PlacementGroupSchedulingStrategy pour planifier un acteur Ray par appareil TPU logique sur la tranche.
Examinez le script
ray_core_collectives.pydans l'exemple de dépôt :Le script exécute le parallélisme Tensor distribué sur la tranche TPU en trois étapes :
- La fonction
slice_placement_groupréserve une tranche de TPU de 16 appareils et planifie un acteurTorchTPUSliceWorkersur chaque appareil TPU. - Chaque acteur calcule son rang global à partir de son index d'hôte et de l'ID de l'appareil local, puis initialise le groupe de processus
tpu_dist. - Les fonctions
init_device_meshetparallelize_modulesegmentent les couches de feed-forward sur les 16 appareils TPU, vérifient le résultat par rapport à une référence de processeur sur un seul appareil et exécutent un collectifall_reducesur ICI.
- La fonction
Envoyez le job Ray Core pour votre version de TPU :
Trillium (v6e)
ray job submit \ --address http://localhost:8265 \ --working-dir . \ --runtime-env-json '{"excludes": ["ray-env", ".git", "*.whl"]}' \ -- python3 ray_core_collectives.py --topology=4x4 --accelerator-type=TPU-V6EIronwood (TPU7x)
ray job submit \ --address http://localhost:8265 \ --working-dir . \ --runtime-env-json '{"excludes": ["ray-env", ".git", "*.whl"]}' \ -- python3 ray_core_collectives.py --topology=2x2x2 --accelerator-type=TPU-V7XLe résultat ressemble à ce qui suit :
Trillium (v6e)
Rank 0 (worker_id=0, local_rank=0, ip=10.72.3.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 1 (worker_id=0, local_rank=1, ip=10.72.3.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 2 (worker_id=0, local_rank=2, ip=10.72.3.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 3 (worker_id=0, local_rank=3, ip=10.72.3.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 4 (worker_id=1, local_rank=0, ip=10.72.14.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 5 (worker_id=1, local_rank=1, ip=10.72.14.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 6 (worker_id=1, local_rank=2, ip=10.72.14.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 7 (worker_id=1, local_rank=3, ip=10.72.14.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 8 (worker_id=2, local_rank=0, ip=10.72.7.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 9 (worker_id=2, local_rank=1, ip=10.72.7.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 10 (worker_id=2, local_rank=2, ip=10.72.7.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 11 (worker_id=2, local_rank=3, ip=10.72.7.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 12 (worker_id=3, local_rank=0, ip=10.72.6.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 13 (worker_id=3, local_rank=1, ip=10.72.6.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 14 (worker_id=3, local_rank=2, ip=10.72.6.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 15 (worker_id=3, local_rank=3, ip=10.72.6.20): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] All 16 TorchTPU ranks verified DTensor TP parity (max_abs_diff=0.002470) and all_reduce sum = 136.0 ------------------------------------------ Job 'raysubmit_HFTkKrjSnfza3ZFD' succeeded ------------------------------------------Ironwood (TPU7x)
Rank 0 (worker_id=0, local_rank=0, ip=172.16.14.6): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 1 (worker_id=0, local_rank=1, ip=172.16.14.6): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 2 (worker_id=0, local_rank=2, ip=172.16.14.6): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 3 (worker_id=0, local_rank=3, ip=172.16.14.6): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 4 (worker_id=0, local_rank=4, ip=172.16.14.6): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 5 (worker_id=0, local_rank=5, ip=172.16.14.6): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 6 (worker_id=0, local_rank=6, ip=172.16.14.6): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 7 (worker_id=0, local_rank=7, ip=172.16.14.6): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 8 (worker_id=1, local_rank=0, ip=172.16.15.7): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 9 (worker_id=1, local_rank=1, ip=172.16.15.7): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 10 (worker_id=1, local_rank=2, ip=172.16.15.7): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 11 (worker_id=1, local_rank=3, ip=172.16.15.7): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 12 (worker_id=1, local_rank=4, ip=172.16.15.7): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 13 (worker_id=1, local_rank=5, ip=172.16.15.7): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 14 (worker_id=1, local_rank=6, ip=172.16.15.7): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] Rank 15 (worker_id=1, local_rank=7, ip=172.16.15.7): all_reduce_sum=[136.0, 136.0, 136.0, 136.0] All 16 TorchTPU ranks verified DTensor TP parity (max_abs_diff=0.002470) and all_reduce sum = 136.0 ------------------------------------------ Job 'raysubmit_MrJbAe3hvARBcBN2' succeeded ------------------------------------------
Affiner un modèle Gemma 4 avec Ray Train et PyTorch FSDP2
La classe TorchTrainer de Ray Train automatise la réservation de tranches TPU, l'emplacement des nœuds de calcul et l'initialisation de torch.distributed sur une tranche TPU multi-hôte.
Examinez le script
ray_train_llm_finetune.pydans l'exemple de dépôt, qui affine le modèlegoogle/gemma-4-E2B-itsur l'ensemble de données d'instructionsdatabricks/databricks-dolly-15k:Le script configure la classe
TorchTraineravec les composants suivants :- La classe
ScalingConfigconfigure la topologie des nœuds de calcul distribués pour le job d'entraînement. La définition des paramètresuse_tpu=True,num_workers=16,topologyetaccelerator_typeréserve une tranche de TPU de 16 appareils et planifie un nœud de calcul par cœur de TPU. - La classe
TorchConfigconfigure le groupe de processustorch.distributedsur les nœuds de calcul. La définition du paramètrebackend="tpu_dist"connecte les 16 workers sur le réseau TPU ICI avant l'exécution de la fonctiontrain_func. - La fonction
create_dataloadertélécharge et tokenise l'ensemble de données d'instructions, regroupe les séquences de jetons avec un objet PyTorchDataLoaderet appelle la fonctionray.train.torch.prepare_data_loaderpour que chaque nœud de calcul reçoive un segment disjoint de chaque lot global sur l'appareil TPU qui lui est attribué. - La fonction
train_funccharge le modèle avec une précisionbfloat16et appelle la fonction PyTorch FSDP2fully_shardsur chaque bloc de propagation avant et sur le modèle racine pour segmenter les paramètres, les gradients et les états de l'optimiseur sur les 16 cœurs de TPU. - La classe
Checkpointet la fonctionray.train.reportcollectent le dictionnaire d'état complet du modèle au rang 0 à la fin de chaque epoch et importent le point de contrôle dans votre bucket Cloud Storage.
- La classe
Envoyez le job d'affinage
TorchTrainerFSDP2 pour votre version de TPU :Trillium (v6e)
ray job submit \ --address http://localhost:8265 \ --working-dir . \ --runtime-env-json '{"excludes": ["ray-env", ".git", "*.whl"]}' \ -- python3 ray_train_llm_finetune.py \ --topology=4x4 \ --accelerator-type=TPU-V6E \ --storage-path=gs://${BUCKET_NAME}/ray_train_torchtpuIronwood (TPU7x)
ray job submit \ --address http://localhost:8265 \ --working-dir . \ --runtime-env-json '{"excludes": ["ray-env", ".git", "*.whl"]}' \ -- python3 ray_train_llm_finetune.py \ --topology=2x2x2 \ --accelerator-type=TPU-V7X \ --storage-path=gs://${BUCKET_NAME}/ray_train_torchtpuLe résultat ressemble à ce qui suit :
Trillium (v6e)
Starting Ray Train FSDP2 SFT job: model=google/gemma-4-E2B-it, topology=4x4, accelerator_type=TPU-V6E, num_workers=16 (TrainController pid=5407) Attempting to start training worker group of size 16 with the following resources: [{'TPU': 1, 'accelerator_type:TPU-V6E': 0.001}] * 16 (RayTrainWorker pid=19733, ip=10.72.3.20) Setting up process group for: env:// [rank=0, world_size=16] (RayTrainWorker pid=19733, ip=10.72.3.20) Epoch 1/3 | loss=3.1402 | epoch_time=28.17s | tokens/s=18613.5 (RayTrainWorker pid=19733, ip=10.72.3.20) Checkpoint successfully created at: Checkpoint(filesystem=gcs, path=my-project-ray-torchtpu/ray_train_torchtpu/torchtpu_gemma4_fsdp2_sft_1791864427/checkpoint_2026-10-13_04-08-10.762175) (RayTrainWorker pid=19733, ip=10.72.3.20) Epoch 2/3 | loss=2.3318 | epoch_time=26.07s | tokens/s=20112.8 (RayTrainWorker pid=19733, ip=10.72.3.20) Checkpoint successfully created at: Checkpoint(filesystem=gcs, path=my-project-ray-torchtpu/ray_train_torchtpu/torchtpu_gemma4_fsdp2_sft_1791864427/checkpoint_2026-10-13_04-10-02.548088) (RayTrainWorker pid=19733, ip=10.72.3.20) Epoch 3/3 | loss=2.2050 | epoch_time=25.52s | tokens/s=20545.2 (RayTrainWorker pid=19733, ip=10.72.3.20) Checkpoint successfully created at: Checkpoint(filesystem=gcs, path=my-project-ray-torchtpu/ray_train_torchtpu/torchtpu_gemma4_fsdp2_sft_1791864427/checkpoint_2026-10-13_04-11-48.701853) Training completed! Final metrics: {'epoch': 3, 'loss': 2.205, 'epoch_time_s': 25.52, 'tokens_per_s': 20545.2} Saved checkpoint: Checkpoint(filesystem=gcs, path=my-project-ray-torchtpu/ray_train_torchtpu/torchtpu_gemma4_fsdp2_sft_1791864427/checkpoint_2026-10-13_04-11-48.701853) ------------------------------------------ Job 'raysubmit_zbm4pnFZitA1YECA' succeeded ------------------------------------------Ironwood (TPU7x)
Starting Ray Train FSDP2 SFT job: model=google/gemma-4-E2B-it, topology=2x2x2, accelerator_type=TPU-V7X, num_workers=16 (TrainController pid=1162) Attempting to start training worker group of size 16 with the following resources: [{'TPU': 1, 'accelerator_type:TPU-V7X': 0.001}] * 16 (RayTrainWorker pid=257, ip=172.16.26.6) Setting up process group for: env:// [rank=0, world_size=16] (RayTrainWorker pid=257, ip=172.16.26.6) Epoch 1/3 | loss=3.1407 | epoch_time=26.28s | tokens/s=19953.3 (RayTrainWorker pid=257, ip=172.16.26.6) Checkpoint successfully created at: Checkpoint(filesystem=gcs, path=my-project-ray-torchtpu/ray_train_torchtpu/torchtpu_gemma4_fsdp2_sft_1791867004/checkpoint_2026-10-13_04-52-00.026930) (RayTrainWorker pid=257, ip=172.16.26.6) Epoch 2/3 | loss=2.3235 | epoch_time=16.68s | tokens/s=31429.9 (RayTrainWorker pid=257, ip=172.16.26.6) Checkpoint successfully created at: Checkpoint(filesystem=gcs, path=my-project-ray-torchtpu/ray_train_torchtpu/torchtpu_gemma4_fsdp2_sft_1791867004/checkpoint_2026-10-13_04-53-33.533341) (RayTrainWorker pid=257, ip=172.16.26.6) Epoch 3/3 | loss=2.1964 | epoch_time=16.98s | tokens/s=30884.6 (RayTrainWorker pid=257, ip=172.16.26.6) Checkpoint successfully created at: Checkpoint(filesystem=gcs, path=my-project-ray-torchtpu/ray_train_torchtpu/torchtpu_gemma4_fsdp2_sft_1791867004/checkpoint_2026-10-13_04-55-01.508219) Training completed! Final metrics: {'epoch': 3, 'loss': 2.1964, 'epoch_time_s': 16.98, 'tokens_per_s': 30884.6} Saved checkpoint: Checkpoint(filesystem=gcs, path=my-project-ray-torchtpu/ray_train_torchtpu/torchtpu_gemma4_fsdp2_sft_1791867004/checkpoint_2026-10-13_04-55-01.508219) ------------------------------------------ Job 'raysubmit_zSNnCXhHkwKiSmJh' succeeded ------------------------------------------Le résultat de l'entraînement affiche les éléments suivants :
- L'epoch 1 inclut la compilation initiale du graphe XLA. Les époques 2 et 3 réutilisent les exécutables mis en cache de
/dev/shm/torch_tpu_cache, atteignant plus de 20 000 jetons par seconde sur TPU Trillium (v6e) et 31 000 jetons par seconde sur Ironwood (TPU7x). - La perte d'entropie croisée globale synchronisée sur les 16 rangs de nœuds de calcul FSDP2 diminue de 3,14 à l'époque 1 à 2,20 à l'époque 3 sur les trois époques de réglage sur l'ensemble de données d'instructions
databricks/databricks-dolly-15k. - À la fin de chaque époque, le rang 0 rassemble le dictionnaire d'état complet du modèle et importe le point de contrôle dans votre bucket Cloud Storage, en conservant le point de contrôle avec la perte la plus faible, comme configuré dans l'objet
CheckpointConfig(num_to_keep=1, checkpoint_score_attribute="loss", checkpoint_score_order="min").
- L'epoch 1 inclut la compilation initiale du graphe XLA. Les époques 2 et 3 réutilisent les exécutables mis en cache de
Observer les performances des charges de travail
Pour surveiller l'utilisation des TensorCores TPU, l'utilisation de la mémoire HBM et les métriques du cluster Ray dans Cloud Monitoring, consultez Collecter et afficher les journaux et les métriques des clusters Ray sur GKE et Afficher les métriques TPU sur le tableau de bord Ray.
Accéder au tableau de bord Ray
Pour inspecter l'état de vos acteurs Ray, de vos groupes d'emplacement et de vos jobs d'entraînement dans le tableau de bord Ray intégré, procédez comme suit :
Si le transfert de port vers le service principal Ray n'est pas déjà en cours d'exécution, démarrez-le en arrière-plan :
kubectl port-forward svc/ray-torchtpu-cluster-head-svc 8265:8265 >/dev/null 2>&1 &Dans Cloud Shell, cliquez sur
Aperçu sur le Web et sélectionnez Prévisualiser sur le port 8265, ou ouvrez
http://localhost:8265dans votre navigateur local.Cliquez sur les onglets Jobs (Jobs), Cluster et Metrics (Métriques) pour inspecter les journaux des nœuds de calcul, l'état du groupe d'emplacement, les étiquettes des nœuds TPU et le graphique TPU Utilization by Node (Utilisation des TPU par nœud).
Effectuer un nettoyage
Pour éviter que les ressources utilisées dans ce tutoriel ne soient facturées sur votre compte Google Cloud , supprimez la ressource personnalisée RayCluster, le cluster GKE, le bucket Cloud Storage et le dépôt Artifact Registry :
Arrêtez le processus de transfert de port en arrière-plan, puis supprimez la ressource personnalisée RayCluster et le secret Kubernetes :
pkill -f "kubectl port-forward" || true kubectl delete raycluster ray-torchtpu-cluster kubectl delete secret hf-secret --ignore-not-foundSupprimez le cluster GKE :
Autopilot
gcloud container clusters delete ${CLUSTER_NAME} \ --region=${REGION}Standard
gcloud container clusters delete ${CLUSTER_NAME} \ --zone=${ZONE}Supprimez le bucket Cloud Storage et son contenu de point de contrôle :
gcloud storage rm --recursive gs://${BUCKET_NAME}Supprimez le dépôt Artifact Registry :
gcloud artifacts repositories delete ${ARTIFACT_REGISTRY} \ --location=${REGION}
Étapes suivantes
- En savoir plus sur PyTorch sur Cloud TPU
- Consultez la documentation TorchTPU.
- Découvrez comment diffuser des LLM sur des TPU multi-hôtes avec Ray et TorchTPU.
- Découvrez comment optimiser l'entraînement de l'IA sur les TPU avec DWS et Kueue.
- Consultez À propos des TPU dans GKE.
- Consultez la documentation de Ray Train.