במדריך הזה נסביר איך להריץ עומסי עבודה מבוזרים של PyTorch ולכוונן מודל Gemma 4 בפרוסות Cloud TPU בכמה מארחים ב-Google Kubernetes Engine (GKE) באמצעות Ray Core, Ray Train, PyTorch Fully Sharded Data Parallel (FSDP2) ו-TorchTPU.
המדריך הזה מיועד למהנדסי למידת מכונה (ML), לאדמינים ולמפעילי פלטפורמות ולמומחי נתונים ו-AI שרוצים לתזמר עומסי עבודה מבוזרים של אימון PyTorch בפרוסות TPU עם כמה מארחים ב-Kubernetes. למידע נוסף על תפקידים נפוצים ומשימות לדוגמה שמוזכרות בתוכן של Google Cloud , קראו את המאמר תפקידים ומשימות נפוצים של משתמשי GKE.
לפני שמתחילים את המדריך, חשוב לוודא שאתם מכירים את הנושאים הבאים:
- מידע על מצבי ההפעלה של GKE
- מידע על יחידות TPU ב-GKE
- מאגרי צמתים של פרוסות TPU עם כמה מארחים
- מידע על Ray ב-GKE
רקע
בקטע הזה מתוארות הטכנולוגיות העיקריות שבהן משתמשים במדריך הזה.
יחידות TPU
יחידות Tensor Processing Unit (TPU) הן מאיצים ש-Google פיתחה בהתאמה אישית לעומסי עבודה של למידת מכונה. המדריך הזה תומך גם ב-TPU Trillium (v6e) וגם ב-Ironwood (TPU7x). בפרוסת TPU עם כמה מארחים, כמה מארחי TPU מתקשרים ישירות דרך רשת Inter-Chip Interconnect (ICI) במהירות גבוהה, ומספקים את הזיכרון המצטבר ברוחב פס גבוה (HBM) ואת התקשורת הקולקטיבית עם זמן אחזור קצר שנדרשים לאימון מודלים שחורגים מקיבולת הזיכרון של שבב יחיד או של מארח TPU יחיד.
TorchTPU
TorchTPU הוא קצה עורפי של PyTorch בקוד פתוח ל-Cloud TPU, שפותח בשיתוף פעולה בין Google לבין Meta. בעזרת TorchTPU, אתם יכולים להריץ מודלים קיימים של PyTorch על חומרת TPU עם שינויים מינימליים בקוד, ולהרחיב את עומסי העבודה של האימון וההסקה משבב יחיד למארזי TPU Pod עם כמה פרוסות באמצעות מהדר Accelerated Linear Algebra (XLA). TorchTPU משתמש במודל הפעלה של תהליך אחד לכל מכשיר ברשת TPU ICI, ותומך בממשקי API סטנדרטיים של PyTorch, כולל ביצוע מיידי, torch.compile, torch.distributed, DeviceMesh, DTensor ו-Fully Sharded Data Parallel (FSDP2).
KubeRay ו-Ray ב-TPU
KubeRay הוא אופרטור של Kubernetes לפריסה ולניהול של אפליקציות Ray. כשמפעילים את התוסף Ray on GKE, נפרסים מפעיל KubeRay המנוהל וה-webhook של KubeRay TPU. כש-KubeRay יוצר Pods של Worker שמבקשים משאבי google.com/tpu, ה-webhook מגדיר באופן אוטומטי את שמות המארחים של ה-Pod, את השירות ללא ממשק משתמש ואת משתני הסביבה של ה-TPU שנדרשים לתיאום בין כמה מארחים.
Ray מזהה את הטופולוגיה של ה-TPU בכל צומת בזמן ההפעלה, ומתזמן עומסי עבודה מבוזרים בפרוסות TPU. אתם יכולים לתזמר עומסי עבודה מבוזרים של TorchTPU בשתי רמות:
- Ray Core מספק קבוצות מיקום (placement groups) עם מודעות לטופולוגיה ותזמון שחקנים ללולאות ביצוע מבוזרות בהתאמה אישית, כמו חישוב מקבילי של טנזורים או צינורות עיבוד נתונים של למידת חיזוק (RL).
- Ray Train מספק אימון מנוהל של מודלים ונתונים במקביל, כולל PyTorch Distributed Data Parallel (DDP), PyTorch FSDP2 ו-JAX single program, multiple data (SPMD), עם נקודות ביקורת מובנות ושחזור אוטומטי במקרה של כשל.
מטרות
במדריך הזה מוסבר איך:
- יוצרים אשכול GKE במצב Autopilot או Standard ב-TPU Trillium (v6e) או Ironwood (TPU7x).
- יוצרים קובץ אימג' של קונטיינר שמוסיף שכבות של ספריות אימון של Ray ו-Hugging Face מעל קובץ האימג' הבסיסי של TorchTPU.
- פורסים משאב בהתאמה אישית של RayCluster כדי להקצות את צומת ה-head ואת צומתי העובדים של ה-TPU.
- הפעלת חישוב מבוזר של טנזור מקביל באמצעות PyTorch
DeviceMeshו-DTensorבפרוסת TPU באמצעות Ray Core. - כוונון עדין של מודל Gemma 4 באמצעות PyTorch FSDP2 בפרוסת TPU עם כמה מארחים באמצעות Ray Train.
עלויות
במדריך הזה משתמשים ברכיבים הבאים של Google Cloud, והשימוש בהם כרוך בתשלום:
כדי להעריך את העלויות בהתאם לשימוש הצפוי, אתם יכולים להשתמש במחשבון העלויות.
כדי להימנע מחיובים נוספים אחרי שסיימתם את המשימות שמתוארות במדריך הזה, אתם יכולים למחוק את המשאבים שיצרתם. מידע נוסף זמין בקטע הסרת המשאבים.
לפני שמתחילים
לפני שמתחילים, חשוב לוודא שביצעתם את המשימות הבאות:
- מפעילים את Artifact Registry API, את Cloud Storage API ואת Google Kubernetes Engine API. הפעלת ממשקי ה-API
- כדי להשתמש ב-Google Cloud CLI למשימה הזו, מתקינים ואז מאתחלים את ה-CLI של gcloud. אם כבר התקנתם את ה-CLI של gcloud, הריצו את הפקודה
gcloud components updateכדי לקבל את הגרסה העדכנית. יכול להיות שבגרסאות קודמות של ה-CLI של gcloud אי אפשר להריץ את הפקודות שבמסמך הזה.
- מוודאים שיש לפרויקט מכסה מספיקה לקיבולת של TPU Trillium (v6e) או Ironwood (TPU7x) באזור שנבחר. מידע נוסף זמין במאמר מכסות של Cloud TPU.
- מוודאים שלחשבון שלכם יש את התפקידים הבאים ב-IAM:
- אדמין ב-Kubernetes Engine (
roles/container.admin) - אדמין ב-Artifact Registry (
roles/artifactregistry.admin) - אדמין באחסון (
roles/storage.admin)
- אדמין ב-Kubernetes Engine (
הכנת הסביבה
במדריך הזה תשתמשו ב-Cloud Shell כדי לנהל משאבים שמתארחים ב- Google Cloud. ב-Cloud Shell מותקנת מראש התוכנה שדרושה למדריך הזה, כולל kubectl, docker, python3 ו-gcloud CLI.
כדי להגדיר את הסביבה באמצעות Cloud Shell:
במסוף Google Cloud , לוחצים על
Activate Cloud Shell במסוףGoogle Cloud כדי להפעיל סשן של Cloud Shell. הפעולה הזו מפעילה סשן בחלונית התחתונה של מסוף Google Cloud .
משכפלים את המאגר
kubernetes-engine-samplesועוברים לספריית הדוגמאות של המדריך הזה:git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git cd kubernetes-engine-samples/ai-ml/gke-ray/raytrain/torchtpuיוצרים ומפעילים סביבה וירטואלית מקומית של Python עם Ray CLI מותקן:
python3 -m venv ~/ray-env source ~/ray-env/bin/activate pip install "ray[default]==2.58.0"כדי להוריד את משקלי המודל של Gemma 4, צריך לאשר את הסכם הרישיון של Google ב-Hugging Face:
- עוברים אל דף המודל של Gemma 4 ב-Hugging Face.
- נכנסים לחשבון ומאשרים את תנאי הרישיון בלחיצה על Agree and access repository.
- בהגדרות החשבון ב-Hugging Face, יוצרים טוקן גישה למשתמש עם הרשאות
Read.
מגדירים את משתני הסביבה של הפרויקט, האשכול, הקטגוריה של Cloud Storage והאסימון של Hugging Face ב- Google Cloud :
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}מחליפים את מה שכתוב בשדות הבאים:
-
PROJECT_ID: מזהה הפרויקט ב- Google Cloud . -
CLUSTER_NAME: השם של אשכול GKE, למשלray-torchtpu-cluster. -
REGION: האזור שבו נמצאים המאגר של Artifact Registry, הקטגוריה של Cloud Storage והקיבולת של ה-TPU. -
ZONE: האזור שבו קיבולת ה-TPU זמינה. במאמר אזורים ותחומים של TPU מפורטים האזורים והתחומים שזמינים לכל גרסת TPU. ARTIFACT_REGISTRY: השם של מאגר Docker ב-Artifact Registry, למשלray-torchtpu.-
BUCKET_NAME: השם של הקטגוריה ב-Cloud Storage שבה מאוחסנות נקודות הביקורת של Ray Train, למשלPROJECT_ID-ray-torchtpu. -
HF_TOKEN: טוקן הגישה ל-Hugging Face.
-
יצירת אשכול GKE
אתם יכולים להריץ עומסי עבודה מבוזרים של אימון TorchTPU באשכול GKE Autopilot או Standard, כשהתוסף המנוהל Ray operator מופעל.
יוצרים את אשכול GKE ומגדירים את פרטי הכניסה לכלי שורת הפקודה
kubectl:טייס אוטומטי
יוצרים אשכול GKE Autopilot אזורי עם תוסף Ray operator מופעל:
gcloud container clusters create-auto ${CLUSTER_NAME} \ --project=${PROJECT_ID} \ --region=${REGION} \ --cluster-version=1.36 \ --enable-ray-operatorכשפורסים את המשאב בהתאמה אישית של RayCluster בשלב מאוחר יותר, GKE Autopilot מקצה באופן אוטומטי את צומת ה-CPU הראשי ואת פרוסת ה-TPU עם כמה מארחים שתואמים לבקשות המשאבים של Pod ולבוררי הצמתים.
מגדירים את כלי שורת הפקודה
kubectlכדי לתקשר עם האשכול:gcloud container clusters get-credentials ${CLUSTER_NAME} \ --project=${PROJECT_ID} \ --region=${REGION}
רגילה
יוצרים אשכול GKE Standard אזורי עם מאגר צומתי CPU לאירוח ה-Pod הראשי של Ray, עם הזרמת תמונות, GKE Dataplane V2 ואיחוד זהויות של עומסי עבודה ל-GKE:
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.googמגדירים את כלי שורת הפקודה
kubectlכדי לתקשר עם האשכול:gcloud container clusters get-credentials ${CLUSTER_NAME} \ --project=${PROJECT_ID} \ --zone=${ZONE}יוצרים מאגר של פרוסות TPU עם מספר מארחים ו-16 מכשירים, עם טופולוגיית
4x4בארבעה מארחים ב-TPU Trillium (v6e) או טופולוגיית2x2x2בשני מארחים ב-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
יוצרים קטגוריה של Cloud Storage כדי לאחסן נקודות בקרה משותפות של Ray Train בצומתי TPU עם כמה מארחים, ונותנים למשאב
defaultKubernetes ServiceAccount גישה לקטגוריה: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"יוצרים Kubernetes Secret עם טוקן הגישה של Hugging Face כדי ש-Ray Pods יוכלו להוריד את המשקלים של Gemma 4:
kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HF_TOKEN}
יצירת קובץ האימג' של הקונטיינר
יוצרים קובץ אימג' של קונטיינר שמתקין את Ray ואת ספריות האימון של Hugging Face על גבי קובץ האימג' הבסיסי של TorchTPU, שכולל את TorchTPU ואת הספרייה libtpu.
יוצרים מאגר Docker ב-Artifact Registry ומגדירים את האימות של Docker:
gcloud artifacts repositories create ${ARTIFACT_REGISTRY} \ --repository-format=docker \ --location=${REGION} gcloud auth configure-docker ${REGION}-docker.pkg.dev,us-docker.pkg.devבודקים את
Dockerfileבספרייה לדוגמה:כדי לאמן פרוסה אחת עם המחלקה
TorchTrainerשל Ray ולתזמן לכל צ'יפלט ב-Ironwood (TPU7x), צריך את Ray בגרסה 2.58.0 ואילך. כדי לבצע כוונון עדין של Gemma 4, צריך את הספרייהtransformersבגרסה 5.5.0 ואילך.יוצרים את קובץ האימג' ומעבירים אותו בדחיפה ל-Artifact Registry:
docker build -t ${IMAGE_URI} . docker push ${IMAGE_URI}
פריסת המשאב בהתאמה אישית של RayCluster
פורסים משאב בהתאמה אישית של RayCluster שמקצה Pod ראשי של מעבד (CPU), נפח /dev/shm בזיכרון למאגר האובייקטים של הזיכרון המשותף של Ray וקבוצת וורקרים של TPU עם כמה מארחים.
בודקים את המניפסט של RayCluster לגרסת ה-TPU במאגר לדוגמה:
Trillium (v6e)
Ironwood (TPU7x)
ב-Ironwood (TPU7x), כל שבב פיזי מכיל שני צ'יפלטים, שמספקים שמונה ליבות TPU לוגיות לכל מארח עם ארבעה שבבים. המניפסט מגדיר את הערך של השדה
TPUל-"8"בקטעresources, ומגדיר את משתנה הסביבהRAY_TPU_RESOURCE_PER_CHIPל-"2"כדי לפרסם ולתזמן שמונה משאביTPUלוגיים לכל מארח.מחילים את המניפסט כדי ליצור את המשאב בהתאמה אישית של 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 -מחכים עד שה-Pod הראשי של RayCluster וכל ה-Pods של TPU worker יגיעו למצב
Running:kubectl get pods -l ray.io/cluster=ray-torchtpu-clusterהפלט אמור להיראות כך:
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 2m30sבודקים את משתני הסביבה באחד מה-Pods של ה-workers כדי לוודא שה-webhook של KubeRay TPU החדיר את משתני התיאום של ה-TPU עם כמה מארחים ואת משתני הטופולוגיה של 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"הפלט אמור להיראות כך:
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מגדירים סשן של העברה ליציאה אחרת לשירות הראשי של Ray:
kubectl port-forward svc/ray-torchtpu-cluster-head-svc 8265:8265 >/dev/null 2>&1 &אפשר לבדוק את צומתי העובדים של ה-TPU ואת התוויות של
ray.io/tpu-*שזוהו באופן אוטומטי בכרטיסייה Cluster ב-Ray Dashboard.
הפעלת מקביליות מבוזרת של טנזורים באמצעות Ray Core
Ray Core מספק את הפונקציה slice_placement_group במודול ray.util.tpu כדי להקצות פרוסת TPU שלמה עם כמה מארחים, ואת המחלקה PlacementGroupSchedulingStrategy כדי לתזמן שחקן Ray אחד לכל מכשיר TPU לוגי בפרוסה.
בודקים את הסקריפט
ray_core_collectives.pyבמאגר לדוגמה:הסקריפט מריץ מקביליות טנזור מבוזרת בפרוסת ה-TPU בשלושה שלבים:
- הפונקציה
slice_placement_groupשומרת פרוסת TPU של 16 מכשירים ומתזמנת שחקןTorchTPUSliceWorkerאחד בכל מכשיר TPU. - כל שחקן מחשב את הדירוג הגלובלי שלו לפי אינדקס המארח ומזהה המכשיר המקומי, ואז מאתחל את קבוצת התהליכים של
tpu_dist. - הפונקציות
init_device_meshו-parallelize_moduleמפצלות את שכבות ה-feed-forward בין כל 16 מכשירי ה-TPU, מאמתות את הפלט מול קובץ עזר של מעבד במכשיר אחד ומריצותall_reduceקולקטיבי ב-ICI.
- הפונקציה
שולחים את המשימה של Ray Core לגרסת ה-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-V7Xהפלט אמור להיראות כך:
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 ------------------------------------------
כוונון עדין של מודל Gemma 4 באמצעות Ray Train ו-PyTorch FSDP2
הכיתה TorchTrainer של Ray Train הופכת את ההזמנה של פרוסת TPU, את מיקום ה-worker ואת האתחול של torch.distributed לאוטומטיים בפרוסת TPU עם כמה מארחים.
בודקים את הסקריפט
ray_train_llm_finetune.pyבמאגר לדוגמה, שמבצע כוונון עדין של המודלgoogle/gemma-4-E2B-itבמערך הנתונים של ההוראותdatabricks/databricks-dolly-15k:הסקריפט מגדיר את המחלקה
TorchTrainerעם הרכיבים הבאים:- הכיתה
ScalingConfigמגדירה את טופולוגיית ה-worker המבוזרת למשימת האימון. הגדרת הפרמטריםuse_tpu=True,num_workers=16,topologyו-accelerator_typeשומרת פרוסת TPU של 16 מכשירים ומתזמנת וורקר אחד לכל ליבת TPU. - הכיתה
TorchConfigמגדירה את קבוצת התהליכיםtorch.distributedבכל ה-workers. הגדרת הפרמטרbackend="tpu_dist"מחברת את כל 16 ה-workers דרך רשת ה-TPU ICI לפני שהפונקציהtrain_funcפועלת. - הפונקציה
create_dataloaderמורידה את מערך הנתונים של ההוראות ומבצעת לו טוקניזציה, יוצרת אצוות של רצפי הטוקנים באמצעות אובייקטDataLoaderשל PyTorch, וקוראת לפונקציהray.train.torch.prepare_data_loaderכדי שכל worker יקבל חלק נפרד מכל אצווה גלובלית במכשיר ה-TPU שהוקצה לו. - הפונקציה
train_funcטוענת את המודל ברמת הדיוקbfloat16וקוראת לפונקציהfully_shardשל PyTorch FSDP2 בכל בלוק של feed-forward ובמודל הבסיס כדי לחלק את הפרמטרים, הגרדיאנטים ומצבי האופטימיזציה בין כל 16 ליבות ה-TPU. - הכיתה
Checkpointוהפונקציהray.train.reportאוספות את מילון המצבים המלא של המודל בדירוג 0 בסוף כל תקופה, ומעלות את נקודת הבדיקה לקטגוריה של Cloud Storage.
- הכיתה
שולחים את משימת הכוונון העדין של
TorchTrainerFSDP2 לגרסת ה-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_torchtpuהפלט אמור להיראות כך:
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 ------------------------------------------פלט האימון מציג את הפרטים הבאים:
- תקופה 1 כוללת הידור ראשוני של תרשים XLA. בתקופות 2 ו-3 נעשה שימוש חוזר בקובצי ההפעלה שנשמרו במטמון מ-
/dev/shm/torch_tpu_cache, והן מגיעות ליותר מ-20,000 טוקנים לשנייה ב-TPU Trillium (v6e) ול-31,000 טוקנים לשנייה ב-Ironwood (TPU7x). - האובדן הגלובלי של אנטרופיה צולבת, שמסונכרן בין כל 16 הדרגות של ה-worker ב-FSDP2, יורד מ-3.14 בתקופה 1 ל-2.20 בתקופה 3, בשלוש תקופות הכוונון בקבוצת הנתונים של ההוראות ב-
databricks/databricks-dolly-15k. - בסוף כל תקופה, דירוג 0 אוסף את מילון המצבים המלא של המודל ומעלה את נקודת הבדיקה לקטגוריה של Cloud Storage, תוך שמירה על נקודת הבדיקה עם האובדן הנמוך ביותר, כפי שהוגדר באובייקט
CheckpointConfig(num_to_keep=1, checkpoint_score_attribute="loss", checkpoint_score_order="min").
- תקופה 1 כוללת הידור ראשוני של תרשים XLA. בתקופות 2 ו-3 נעשה שימוש חוזר בקובצי ההפעלה שנשמרו במטמון מ-
בדיקת הביצועים של עומסי העבודה
כדי לעקוב אחרי השימוש ב-TPU TensorCore, ב-HBM ובמדדים של אשכול Ray ב-Cloud Monitoring, קראו את המאמרים איסוף והצגה של יומנים ומדדים של אשכולות Ray ב-GKE והצגת מדדי TPU במרכז הבקרה של Ray.
גישה ללוח הבקרה של Ray
כדי לבדוק את הסטטוס של השחקנים, קבוצות המיקום ומשימות האימון של Ray במרכז הבקרה המובנה של Ray:
אם העברה ליציאה אחרת לשירות הראשי של Ray עדיין לא פועלת, מפעילים אותה ברקע:
kubectl port-forward svc/ray-torchtpu-cluster-head-svc 8265:8265 >/dev/null 2>&1 &ב-Cloud Shell, לוחצים על
Web Preview ובוחרים באפשרות Preview on port 8265, או פותחים את
http://localhost:8265בדפדפן המקומי.לוחצים על הכרטיסיות Jobs, Cluster ו-Metrics כדי לבדוק את יומני ה-worker, את המצב של קבוצת המיקום, את התוויות של צומת ה-TPU ואת התרשים TPU Utilization by Node.
הסרת המשאבים
כדי להימנע מחיובים בחשבון Google Cloud על המשאבים שבהם השתמשתם במדריך הזה, אתם צריכים למחוק את המשאב המותאם אישית של RayCluster, את אשכול GKE, את הקטגוריה של Cloud Storage ואת המאגר של Artifact Registry:
עוצרים את תהליך העברת היציאה ברקע ומוחקים את המשאב בהתאמה אישית של RayCluster ואת הסוד של Kubernetes:
pkill -f "kubectl port-forward" || true kubectl delete raycluster ray-torchtpu-cluster kubectl delete secret hf-secret --ignore-not-foundמוחקים את אשכול ה-GKE:
טייס אוטומטי
gcloud container clusters delete ${CLUSTER_NAME} \ --region=${REGION}רגילה
gcloud container clusters delete ${CLUSTER_NAME} \ --zone=${ZONE}מוחקים את הקטגוריה של Cloud Storage ואת התוכן של נקודת הבדיקה:
gcloud storage rm --recursive gs://${BUCKET_NAME}מוחקים את המאגר ב-Artifact Registry:
gcloud artifacts repositories delete ${ARTIFACT_REGISTRY} \ --location=${REGION}
המאמרים הבאים
- מידע נוסף על PyTorch ב-Cloud TPU
- למסמכי התיעוד של TorchTPU
- איך מפעילים מודלים גדולים של שפה (LLM) במארחים מרובים של TPU באמצעות Ray ו-TorchTPU
- איך לבצע אופטימיזציה של אימון AI ב-TPU באמצעות DWS ו-Kueue
- מידע על יחידות TPU ב-GKE
- למסמכי התיעוד של Ray Train