במדריך הזה נסביר איך לתזמר סביבת אימון מבוזרת ללמידה מחוזקת ב-Google Kubernetes Engine (GKE). אתם משתמשים ב-Ray וב-framework של verl (Volcano Engine Reinforcement Learning) כדי להגדיר סביבת אימון מבוזרת לכוונון של מודל Qwen2.5-32B-Instruct במערך הנתונים GSM8K.
המדריך הזה מתמקד בצינור עיבוד נתונים לאימון של אופטימיזציה של מדיניות יחסית לקבוצה (GRPO) ב-GKE עם Ray ו-verl. GRPO הוא אלגוריתם למידה חיזוקית שנועד לשפר את יכולת החשיבה של המודל. האלגוריתם הזה חוסך בזיכרון ומפשט את תהליך הלמידה באמצעות חיזוקים (RL) על ידי ביטול ה-Critic, או מודל הערך, ושימוש בחישוב יחסי שמבוסס על קבוצה במקום זאת.
המדריך הזה הוא נקודת התחלה טובה אם אתם צריכים להגדיר סביבת אימון מבוזרת שבה הנתונים, משקלי המודל ומנוע האימון מופרדים כדי לשפר את היעילות.
המדריך הזה תומך בארכיטקטורות הבאות של GPU:
- צומתי GPU שמבוססים על Intel או AMD: הגדרה ושינוי קנה מידה באמצעות מעבדי GPU מסוג NVIDIA B200 או H200, באמצעות הקצאת משאבים דינמית (DRA) של GKE לנתיב Autopilot.
- צמתים מבוססי Arm A4X (GB200): הגדרה והרחבה באמצעות NVIDIA GB200 Grace Blackwell Superchips, באמצעות הקצאת משאבים דינמית (DRA) של GKE ו-Multi-Node NVLink (IMEX).
רקע
בקטעים הבאים מופיעה סקירה כללית קצרה של המושגים שבהם משתמשים במדריך הזה.
למידת חיזוק (RL)
במקום חיקוי סטטי, RL מלמד מודלים באמצעות ניסיון, חקירה ומשוב. במהלך האימון המקדים, המודל לומד מה לומר, ובמהלך הלמידה ממשוב אנושי (RLHF), הוא לומד איך להיות מועיל, בטוח והגיוני. למידה מחוזקת משמשת כגשר בין מודל בסיס לבין מודל שעבר כוונון לתרחיש שימוש ספציפי.
מידע נוסף זמין במאמר מהי למידת חיזוק?
אופטימיזציה של מדיניות יחסית לקבוצה (GRPO)
GRPO, אלגוריתם שפותח על ידי DeepSeek, מציע חלופה יעילה מבחינת זיכרון ל-Proximal Policy Optimization (PPO) להתאמה של LLM על ידי הסרת המודל של Critic. במקום רשת Critic, GRPO יוצר קבוצה של תשובות לאותה הנחיה ומשתמש בתגמול הממוצע של הקבוצה הזו כבסיס להשוואה.
מידע נוסף זמין במאמר בנושא GRPO.
Volcano Engine Reinforcement Learning (verl)
verl הוא פריימוורק עם ביצועים גבוהים שמיועד לטפל בדפוסי הזיכרון והמחשוב המורכבים של RL שמבוסס על LLM.
מידע נוסף זמין במאמר בנושא verl.
מטרות
במדריך הזה מוסבר איך להגדיר למידת חיזוק ב-GKE באמצעות verl, על ידי ביצוע השלבים הבאים:
- מגדירים אשכול GKE עם A4X (GB200 Superchips), A4 (B200 GPUs) או A3 Ultra (H200 GPUs).
- מגדירים את KubeRay לניהול אשכול Ray מבוזר.
- משתמשים ב-Cloud Storage FUSE כדי לטעון קטגוריה של Cloud Storage בכל הצמתים.
- מריצים משימת אימון של GRPO באמצעות verl כדי להתאים את מודל Qwen2.5-32B-Instruct למערך הנתונים GSM8K.
לפני שמתחילים
- במדריך הזה משתמשים ב-Cloud Shell, שכולל את Google Cloud CLI ואת
kubectlמותקנים מראש. אם אתם לא משתמשים ב-Cloud Shell, אתם צריכים להתקין ולהפעיל את Google Cloud CLI, וגם להתקין אתkubectl.
- נכנסים לחשבון Google Cloud . אנחנו ממליצים למשתמשים חדשים ב- Google Cloud ליצור חשבון כדי שיוכלו להעריך את הביצועים של המוצרים שלנו בתרחישים מהעולם האמיתי. לקוחות חדשים מקבלים בחינם גם קרדיט בשווי 300$ להרצה, לבדיקה ולפריסה של עומסי העבודה.
-
התקינו את ה-CLI של Google Cloud.
-
אם אתם משתמשים בספק זהויות חיצוני (IdP), קודם אתם צריכים להיכנס ל-CLI של gcloud באמצעות המאגר המאוחד לניהול זהויות.
-
כדי לאתחל את ה-CLI של gcloud, הריצו את הפקודה הבאה:
gcloud init -
יוצרים או בוחרים Google Cloud פרויקט.
התפקידים שנדרשים כדי לבחור או ליצור פרויקט
- Select a project: כדי לבחור פרויקט לא צריך תפקיד IAM ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
-
יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד "יצירת פרויקטים" (
roles/resourcemanager.projectCreator), שכולל את ההרשאהresourcemanager.projects.create. איך מקצים תפקידים
-
יוצרים 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. אם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד "בעלים" (roles/owner). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד "אדמין בממשק 'שימוש בשירות'" (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידיםgcloud services enable container.googleapis.com
storage.googleapis.com compute.googleapis.com -
התקינו את ה-CLI של Google Cloud.
-
אם אתם משתמשים בספק זהויות חיצוני (IdP), קודם אתם צריכים להיכנס ל-CLI של gcloud באמצעות המאגר המאוחד לניהול זהויות.
-
כדי לאתחל את ה-CLI של gcloud, הריצו את הפקודה הבאה:
gcloud init -
יוצרים או בוחרים Google Cloud פרויקט.
התפקידים שנדרשים כדי לבחור או ליצור פרויקט
- Select a project: כדי לבחור פרויקט לא צריך תפקיד IAM ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
-
יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד "יצירת פרויקטים" (
roles/resourcemanager.projectCreator), שכולל את ההרשאהresourcemanager.projects.create. איך מקצים תפקידים
-
יוצרים 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. אם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד "בעלים" (roles/owner). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד "אדמין בממשק 'שימוש בשירות'" (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידיםgcloud services enable container.googleapis.com
storage.googleapis.com compute.googleapis.com -
מעניקים תפקידים לחשבון המשתמש. מריצים את הפקודה הבאה לכל אחד מהתפקידים הבאים ב-IAM:
roles/container.admin, roles/iam.serviceAccountAdmin, roles/storage.admin, roles/iam.serviceAccountUsergcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE
מחליפים את מה שכתוב בשדות הבאים:
-
PROJECT_ID: מזהה הפרויקט. -
USER_IDENTIFIER: המזהה של חשבון המשתמש . לדוגמה,myemail@example.com. -
ROLE: תפקיד ה-IAM שאתם מקצים לחשבון המשתמש.
-
- אם אין לכם חשבון ב-Hugging Face, יוצרים חשבון.
- מוודאים שיש לכם טוקן של Hugging Face.
- מוודאים שיש לפרויקט מכסה מספיקה ל-A4X (שבבי GB200 Superchip), ל-A4 (מעבדי GPU מסוג B200) או ל-A3 Ultra (מעבדי GPU מסוג H200). למידע נוסף, קראו את המאמרים תכנון מכסת GPU ומכסת GPU.
- מוודאים שיש לכם הזמנת קיבולת פעילה לסוג המכונה של ה-GPU. מידע נוסף זמין במאמר שריון קיבולת באמצעות צוות ניהול החשבון.
- כדי להגדיר את A4X (GB200), ודאו ש-Helm מותקן.
הכנת הסביבה
במדריך הזה משתמשים ב-Cloud Shell.
עוברים אל Google Cloud המסוף.
בחלק העליון של חלון המסוף, לוחצים על הכפתור Activate Cloud Shell. Google Cloud
מגדירים את משתני הסביבה:
A4 ו-A3 Ultra
טייס אוטומטי
רגילה
A4X
export PROJECT_ID=$(gcloud config get project) export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)") export CONTROL_PLANE_REGION=YOUR_REGION export NODE_ZONE=YOUR_ZONE export CLUSTER_NAME=YOUR_CLUSTER_NAME export KSA_NAME=YOUR_KSA_NAME export GS_BUCKET=YOUR_GCS_BUCKET-${PROJECT_ID} export NAMESPACE=default export GPU_TYPE=YOUR_GPU_TYPE export MACHINE_TYPE=YOUR_MACINE_TYPE export RESERVATION=YOUR_RESERVATION_NAME export HF_TOKEN=YOUR_HF_TOKEN # A4X (GB200 Superchips) only variables export NUM_GPU_NODES=4 export VERL_IMAGE=verlai/verl:vllm023.aarch64.dev1 export VERL_REF=ddbcdb7מחליפים את הערכים הבאים:
-
YOUR_REGION: האזור ב-Compute Engine למישור הבקרה של אשכול GKE. -
YOUR_ZONE: האזור שבו הצמתים מוזמנים. למידע נוסף, ראו זמינות של GPU. -
YOUR_CLUSTER_NAME: השם של אשכול GKE. השם צריך להיות באורך של עד 40 תווים, והוא יכול לכלול תווים אלפאנומריים קטנים ומקפים. -
YOUR_KSA_NAME: השם של חשבון השירות ב-Kubernetes. -
YOUR_GCS_BUCKET: שם הבסיס של הקטגוריה ב-Cloud Storage. אין צורך לציין את הקידומתgs://. -
YOUR_GPU_TYPE: המאיץ שהזמנתם בהזמנת הקיבולת של Compute Engine. הערך חייב להיות אחד מהערכים הבאים:-
nvidia-gb200: A4X (GB200 Superchips) -
nvidia-b200: A4 (יחידות GPU מסוג B200) -
nvidia-h200-141gb: A3 Ultra (מעבדי GPU מדגם H200)
-
-
YOUR_MACHINE_TYPE: סוג המכונה שבה משתמשים:- ב-A4X (שבבי GB200 Superchip), משתמשים ב-
a4x-highgpu-4g. - ל-A4 (יחידות GPU מסוג B200), צריך להשתמש בגרסה
a4-highgpu-8gואילך. - ב-A3 Ultra (מעבדי GPU מסוג H200), צריך להשתמש בגרסה
a3-ultragpu-8gואילך.
- ב-A4X (שבבי GB200 Superchip), משתמשים ב-
-
YOUR_CPU_MACHINE_TYPE: סוג המכונה של Compute Engine עבור מאגר הצמתים שמוגדר כברירת מחדל ל-CPU. משתמשים בhighmemסוג מכונה עם לפחות 16 מעבדים וירטואליים שנתמך באזור של האשכול, כמוn4-highmem-16אוn2d-highmem-16. YOUR_RESERVATION_NAME: השם של הזמנת הקיבולת.-
YOUR_HF_TOKEN: האסימון שלכם ב-Hugging Face. - כשמגדירים את הסביבה באשכולות GKE Standard, משתמשים במשתנים הבאים:
-
YOUR_GVNIC_NAME(רק ב-A4 או ב-A3 Ultra): הקידומת של שם הרשת של gVNIC. אפשר להשתמש בכל קידומת שרוצים. -
YOUR_RDMA_NAME(רק ב-A4 או ב-A3 Ultra): הקידומת של רשת הגישה הישירה לזיכרון מרחוק (RDMA). אפשר להשתמש בכל קידומת שרוצים.
-
-
משכפלים את המאגר לדוגמה:
בהמשך המדריך, תוכלו לעיין בעותק שלכם של מאגר הדוגמאות כדי למצוא את הקבצים הספציפיים שאתם צריכים לבדוק או להחיל.
עוברים לספריית העבודה של מצב GKE שנבחר:
A4 ו-A3 Ultra
טייס אוטומטי
רגילה
A4X
אין צורך לשנות את הספרייה. אתם יכולים לעבור ישירות לקטע הבא.
הגדרת התשתית
בקטע הזה יוצרים רשתות VPC רגילות ואת אשכול GKE.
יצירת רשת RDMA ורשתות משנה (GKE Standard – A4 ו-A3 Ultra בלבד)
A4 ו-A3 Ultra
טייס אוטומטי
הקטע הזה רלוונטי רק ל-GPU מסוג GKE Standard A4 ו-A3 Ultra.
אם אתם משתמשים ב-Autopilot, דלגו על החלק הזה ועברו ישירות ליצירת אשכול GKE. GKE מקצה באופן אוטומטי את רשתות ה-VPC ורשתות המשנה הנדרשות, ומשתמש ב-DRANET שמנוהל על ידי GKE כדי להקצות את המשאבים האלה לפודים. לא צריך ליצור ידנית תשתית רשת.
רגילה
יוצרים רשת VPC לממשק gVNIC:
יוצרים רשת VPC ל-RDMA:
יוצרים את 8 רשתות המשנה של RDMA עבור 8 יחידות ה-GPU:
A4X
הקטע הזה רלוונטי רק ל-GPU מסוג GKE Standard A4 ו-A3 Ultra.
אם אתם משתמשים ביחידות GPU מסוג A4X (GB200), דלגו על הקטע הזה ועברו ישירות אל יצירת אשכול GKE. במכשירי GPU מסוג A4X (GB200) או ב-Autopilot, GKE יוצר את הרשתות באופן אוטומטי כשמאגר הצמתים משתמש בautoפרופיל רשת של מאיץ. התוכנית Cluster Toolkit מאפשרת את הפרופיל הזה באמצעות הדגל enable_dranet:true.
יצירת אשכול GKE
יוצרים אשכול GKE שמתאים לארכיטקטורת ה-GPU:
A4 ו-A3 Ultra
בוחרים את מצב אשכול GKE שבו רוצים להשתמש:
טייס אוטומטי
יוצרים אשכול Autopilot:
מקבלים את פרטי הכניסה לאשכול:
רגילה
יצירת אשכול Standard:
מקבלים את פרטי הכניסה לאשכול:
יוצרים את מאגר הצמתים של ה-GPU. מאגרי הצמתים האלה משתמשים בהזמנה שלכם כדי להבטיח זמינות. מתחילים עם שני צמתים:
מתקינים את NCCL RDMA installer שמשמש לאשכולות רגילים:
A4X
יוצרים אשכול GKE ומאגר צמתים באמצעות תוכנית ה-Cluster Toolkit
gke-a4x. התוכנית מקצה את אשכול GKE, כולל מאגר הצמתים של A4X שקשור להזמנה, רשתות המאיצים (gVNIC אחד נוסף וארבע מסילות RDMA) ומנהל ההתקן המנוהל של DRANET שחושף את כרטיסי ה-NIC של CX-7 כמכשירי DRA.משתמשים בהוראות הפריסה של התוכנית כדי להגדיר את הפרמטרים (כמו
PROJECT_ID,CONTROL_PLANE_REGION,NODE_ZONE, הזמנה ו-NUM_GPU_NODES), ואז פורסים את האשכול. לחלופין, אפשר לפעול לפי המדריך ליצירת אשכול GKE ב-A4X כדי ליצור אשכול באופן ידני.- מקבלים את פרטי הכניסה לאשכול:
gcloud container clusters get-credentials ${CLUSTER_NAME} --location=${CONTROL_PLANE_REGION}מוודאים שהאשכול חושף את כרטיסי ה-NIC של ה-RDMA דרך DRA:
kubectl get deviceclassesהפלט חייב לכלול את
mrdma.google.com.מוודאים שצמתי A4X קיימים:
kubectl get nodes -l cloud.google.com/gke-accelerator=nvidia-gb200מתקינים את הפלאגין gIB NCCL (גרסת A4X):
kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/gpudirect-rdma/nccl-rdma-installer-a4x.yamlמתקינים את הדרייבר NVIDIA DRA, שמספק ערוצי
ComputeDomain(IMEX) ל-NVLink מרובה צמתים: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מתקינים את מפעיל 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}}"
הגדרת מיפוי רשת (GKE Standard – A4 ו-A3 Ultra בלבד)
A4 ו-A3 Ultra
טייס אוטומטי
השלב הזה נדרש להגדרות GPU ב-GKE Standard (רק A4 ו-A3 Ultra). אם אתם משתמשים ב-A4X (GB200), GKE מנהל את ממשקי הרשת באופן אוטומטי, ולכן אפשר לדלג על הקטע הזה.
רגילה
בודקים את המניפסט של
network-mapping.yaml:מחילים את המניפסט:
A4X
השלב הזה נדרש להגדרות של GPU ב-GKE Standard (רק ל-A4 ול-A3 Ultra). אם אתם משתמשים ב-A4X (GB200), GKE מנהל את ממשקי הרשת באופן אוטומטי, ולכן אפשר לדלג על הקטע הזה.
הכנת הנתונים והאחסון
הגדרת משאבים של Cloud Storage ו-Kubernetes:
יוצרים קטגוריה של Cloud Storage:
יוצרים חשבון שירות של Kubernetes (KSA) ומקשרים אותו לדלי:
יוצרים את ה-Secret עבור Hugging Face:
בודקים את המניפסט
gcsfuse-storage.yaml:מחילים את המניפסט:
הגדרת DRANET
מגדירים את DRANET:
A4 ו-A3 Ultra
טייס אוטומטי
יוצרים את מניפסט ComputeClass:
מחילים את
computeclass-dranet.yamlהמניפסט (שנוצר בשלב הקודם) ואתresourceclaim-dranet.yamlהמניפסט (שנכלל במאגר הדוגמאות):
רגילה
אין צורך להגדיר את DRANET. אפשר להמשיך ישירות לקטע הבא.
A4X
DRANET מוגדר על ידי Cluster Toolkit. אפשר להמשיך ישירות לקטע הבא.
הכנת המודל והנתונים
מאכלסים את הקטגוריה של Cloud Storage במשקלי המודל ובמערכי הנתונים. אפשר להריץ את הפקודות האלה באופן מקומי או ב-Pod של GKE כדי לאכלס את הדלי:
A4 ו-A3 Ultra
טייס אוטומטי
בודקים את המניפסט
data-prep-job.yaml, שמגדיר את משימת הכנת הנתונים:מפעילים את המשימה:
בודקים את הסטטוס של ה-Pod:
אחרי שה-Pod של
data-prep-jobמגיע לסטטוסRunning, מקישים על Control+C כדי להפסיק את הצפייה.עוקבים אחרי העבודה:
הפקודה
kubectl logsמחזירה פלט מינימלי או ללא פלט עד שה-Pod מגיע לסטטוסRunning.
רגילה
בודקים את המניפסט
data-prep-job.yaml, שמגדיר את המשימה להכנת הנתונים:הפעלת המשימה:
מעקב אחרי העבודה:
A4X
משכפלים את מאגר 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/gsm8kמורידים את המודל Qwen2.5-32B-Instruct באמצעות Hugging Face CLI (ההורדה הזו דורשת כ-66GB של מקום בכונן):
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, שמורכב מ-Pod ראשי אחד של המערכת ומכמה Pods של עובדים שמגובים ב-GPU.
A4 ו-A3 Ultra
בוחרים את מצב האשכול של GKE שבו השתמשתם כדי ליצור את האשכול:
טייס אוטומטי
בודקים את עומס העבודה של RayCluster:
מפעילים את RayCluster:
רגילה
בודקים את עומס העבודה של RayCluster:
מחילים את RayCluster:
A4X
יוצרים את RDMA
ResourceClaimTemplateואת NVIDIAComputeDomain. כל פוד של עובד GPU תופס ארבעה כרטיסי רשת של RDMA (כל המסילות של הצומת שלו) וערוץ 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.yamlפורסים את RayCluster. ה-Pod של Ray head פועל בצומת A4X בלי לבקש GPU (כי התמונה היא רק
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-pvcמחילים את מניפסט RayCluster:
envsubst < ray-cluster-a4x.yaml | kubectl apply -f -מחכים עד ש-Pod ראשי אחד וארבעה Pods של Worker יהיו במצב
Running:kubectl get pods -w
הפעלת משימת ה-GRPO
מגדירים ושולחים את משימת האימון של למידת חיזוק:
A4 ו-A3 Ultra
בוחרים את מצב האשכול של GKE שבו השתמשתם כדי ליצור את האשכול:
טייס אוטומטי
מגדירים את Ray Client:
משחזרים את שירות Ray Head:
מגדירים העברה ליציאה אחרת אל צומת לוח הבקרה של Ray. התהליך פועל ברקע, כך שאפשר להמשיך להריץ פקודות באותו סשן של מסוף.
כדי לעצור את הלולאה של העברת היציאה, משתמשים בפקודה
kill ${PF_LOOP_PID}.בודקים את המניפסט של
runtime-env.yaml:אם אתם משתמשים במעבדי GPU מסוג H200, אתם צריכים לשנות את הערך של משתנה הסביבה
NCCL_CONF_FILEל-/usr/local/gib/configs/nccl.a3u.conf.הקובץ הזה משמש את לקוח Ray. אין צורך להחיל את המניפסט הזה על האשכול.
שולחים את המשימה באמצעות הפקודה
ray job submit:עוקבים אחרי היומנים של משימת האימון ובודקים אם המדד
critic/score/meanעולה, מה שמצביע על כך שהמודל לומד:- מרכז הבקרה של Ray:
- פותחים את
http://localhost:8265בדפדפן. אם אתם משתמשים ב-Cloud Shell, לוחצים על Web Preview, בוחרים באפשרות Change port ומזינים את הערך8265. - עוברים לכרטיסייה משרות.
- לוחצים על מזהה המשרה.
- מסננים את היומנים לפי מילת המפתח
criticכדי לבדוק אתcritic/score/mean.
- פותחים את
טרמינל: מכיוון שהעבודה נשלחת באופן אסינכרוני עם הדגל
--no-wait, מריצים את הפקודה הבאה כדי להזרים את יומני העבודה בטרמינל:
- מרכז הבקרה של Ray:
אחרי שהאימון מסתיים, מוודאים שנקודות הבדיקה של המודל נשמרו בקטגוריה של Cloud Storage, על ידי הצגת תוכן הספרייה:
אפשר גם לראות את נקודות הבדיקה במסוף Google Cloud : עוברים אל Cloud Storage > Buckets, בוחרים באפשרות
YOUR_GCS_BUCKETופותחים את התיקייהverl/checkpoints.
רגילה
מגדירים את Ray Client:
משחזרים את שירות Ray Head:
מגדירים העברה ליציאה אחרת אל צומת לוח הבקרה של Ray. התהליך פועל ברקע, כך שאפשר להמשיך להריץ פקודות באותו סשן של מסוף.
כדי לעצור את לולאת העברת הפורטים, משתמשים בפקודה
kill ${PF_PID}.בודקים את המניפסט
runtime-env.yaml:אם משתמשים במעבדי GPU מסוג H200, משנים את הערך של משתנה הסביבה
NCCL_TUNER_CONFIG_PATHל-/usr/local/gib/configs/tuner_config_a3u.txtpb.הקובץ הזה משמש את לקוח Ray. אין צורך להחיל את המניפסט הזה על האשכול.
שולחים את המשימה:
עוקבים אחרי היומנים של משימת האימון ומחפשים את המדד
critic/score/meanשעולה, מה שמצביע על כך שהמודל לומד:- מרכז הבקרה של Ray:
- פותחים את
http://localhost:8265בדפדפן. אם אתם משתמשים ב-Cloud Shell, לוחצים על Web Preview, בוחרים באפשרות Change port ומזינים את הערך8265. - עוברים לכרטיסייה משרות.
- לוחצים על מזהה המשרה.
- מסננים את היומנים לפי מילת המפתח
criticכדי לבדוק את המדדcritic/score/mean.
- פותחים את
פלט המסוף: מכיוון שהמשימה נשלחת באופן אסינכרוני עם הדגל
--no-wait, צריך להעביר בסטרימינג את יומני המשימה בטרמינל באמצעות הפקודה הבאה:
- מרכז הבקרה של Ray:
אחרי שהאימון מסתיים, כדי לוודא שנקודות הבדיקה של המודל נשמרו בקטגוריה שלכם ב-Cloud Storage, מריצים את הפקודה הבאה כדי להציג את התוכן של הספרייה:
אפשר גם לראות את נקודות הבדיקה במסוף Google Cloud : עוברים אל Cloud Storage > Buckets, בוחרים באפשרות
YOUR_GCS_BUCKETופותחים את התיקייהverl/checkpoints.
A4X
מאחזרים את שם ה-Pod של Ray head:
export HEAD_POD=$(kubectl get pod -n ${NAMESPACE} -l ray.io/node-type=head -o jsonpath='{.items[0].metadata.name}')מגדירים את קובץ סביבת זמן הריצה של Ray ישירות ב-Pod הראשי:
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'שולחים את משימת האימון של GRPO על ידי הרצתה ב-Pod הראשי של Ray:
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):kubectl exec ${HEAD_POD} -c ray-head -- ray job logs <var>JOB_ID</var> --followהחלפה של
JOB_ID. כדי לוודא ש-NVLink בין צמתים פעיל, מחפשים שורות NCCL ביומנים שמכילים את הערךvia P2P/MNNVL.
הסרת המשאבים
כדי להימנע מצבירת חיובים, מוחקים את המשאבים:
A4 ו-A3 Ultra
טייס אוטומטי
אם הלולאה של העברת היציאות עדיין פועלת בסשן ברקע, צריך לסיים אותה:
מוחקים את אשכול Ray:
מוחקים את Cloud Storage FUSE:
מוחקים את המשאבים של DRANET:
מוחקים את הקטגוריה של Cloud Storage:
מוחקים את אשכול GKE:
רגילה
אם הלולאה של העברת היציאה עדיין פועלת בסשן ברקע, צריך לסיים אותה:
מוחקים את אשכול Ray:
מחיקת Cloud Storage FUSE:
מוחקים את הקטגוריה של Cloud Storage:
מוחקים את אשכול ה-GKE:
מחיקת רשתות ה-VPC ותת-הרשתות:
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}