במדריך הזה נסביר איך לתזמן סביבת אימון מבוזרת ללמידת חיזוק ב-Google Kubernetes Engine (GKE). אתם משתמשים ב-Ray ובמסגרת verl (Volcano Engine Reinforcement Learning) כדי להגדיר סביבת אימון מבוזרת לצורך כוונון עדין של מודל Qwen2.5-32B-Instruct במערך הנתונים GSM8K.
המדריך הזה מתמקד בצינור עיבוד נתונים לאימון של אופטימיזציה של מדיניות יחסית לקבוצה (GRPO) ב-GKE עם Ray ו-verl. GRPO הוא אלגוריתם ללמידה חיזוקית שנועד לשפר את יכולת ההסקה של מודל. האלגוריתם הזה חוסך בזיכרון ומפשט את תהליך הלמידה באמצעות חיזוקים (RL) על ידי ביטול ה-Critic, או מודל הערך, ושימוש בחישוב יחסי שמבוסס על קבוצה במקום זאת.
המדריך הזה הוא נקודת התחלה טובה אם אתם צריכים להגדיר סביבת אימון מבוזרת שבה הנתונים, משקלי המודל ומנוע האימון מופרדים כדי לשפר את היעילות.
המדריך הזה תומך בארכיטקטורות ה-GPU הבאות:
- צמתים של GPU מבוססי Intel או AMD: הגדרה ושינוי קנה מידה באמצעות NVIDIA B200 או H200 GPUs, באמצעות הקצאת משאבים דינמית (DRA) של GKE לנתיב Autopilot.
- צמתים מבוססי Arm A4X (GB200): הגדרה והרחבה באמצעות NVIDIA GB200 Grace Blackwell Superchips, באמצעות הקצאת משאבים דינמית (DRA) של GKE ו-Multi-Node NVLink (IMEX).
רקע
בקטעים הבאים מופיעה סקירה כללית קצרה של המושגים שבהם נעשה שימוש במדריך הזה.
למידת חיזוקים (RL)
ב-RL, המודלים לומדים מתוך ניסיון, מחקר ומשוב, ולא מתוך חיקוי סטטי. במהלך האימון המקדים, המודל לומד מה לומר, ובמהלך הלמידה ממשוב אנושי (RLHF), הוא לומד איך להיות מועיל, בטוח והגיוני. RL משמש כגשר בין מודל בסיסי לבין מודל מכוונן לשימוש במקרה שימוש ספציפי.
אופטימיזציה יחסית של מדיניות קבוצתית (GRPO)
GRPO, אלגוריתם שזכה לפופולריות בזכות DeepSeek, מציע חלופה חסכונית בזיכרון ל-Proximal Policy Optimization (PPO) להתאמת LLM, על ידי הסרת מודל ה-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.
לפני שמתחילים
- נכנסים לחשבון Google Cloud . אנחנו ממליצים למשתמשים חדשים ב- Google Cloud ליצור חשבון כדי שיוכלו להעריך את הביצועים של המוצרים שלנו בתרחישים מהעולם האמיתי. לקוחות חדשים מקבלים בחינם גם קרדיט בשווי 300$ להרצה, לבדיקה ולפריסה של עומסי העבודה.
-
התקינו את ה-CLI של Google Cloud.
-
אם אתם משתמשים בספק זהויות חיצוני (IdP), קודם אתם צריכים להיכנס ל-CLI של gcloud באמצעות המאגר המאוחד לניהול זהויות.
-
כדי לאתחל את ה-CLI של gcloud, הריצו את הפקודה הבאה:
gcloud init -
יוצרים או בוחרים Google Cloud פרויקט.
תפקידים שנדרשים כדי לבחור או ליצור פרויקט
- Select a project: כדי לבחור פרויקט לא צריך תפקיד IAM ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
-
יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד Project Creator (
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). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד 'אדמין בממשק Service Usage' (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 ספציפי – אפשר לבחור כל פרויקט שקיבלתם בו תפקיד.
-
יצירת פרויקט: כדי ליצור פרויקט, צריך את התפקיד Project Creator (
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). אחרת, תוכלו לקבל את ההרשאה הזו דרך התפקיד 'אדמין בממשק Service Usage' (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 Superchips), ל-A4 (B200 GPUs) או ל-A3 Ultra (H200 GPUs). למידע נוסף, קראו את המאמרים תכנון מכסת GPU ומכסת GPU.
- מוודאים שיש לכם הזמנת קיבולת פעילה לסוג המכונה של ה-GPU. מידע נוסף זמין במאמר בנושא שריון קיבולת דרך צוות התמיכה בחשבון.
- כדי להגדיר את A4X (GB200), צריך לוודא שHelm מותקן.
הכנת הסביבה
במדריך הזה משתמשים ב-Cloud Shell.
עוברים אל Google Cloud המסוף.
בחלק העליון של Google Cloud חלון המסוף, לוחצים על הלחצן Activate Cloud Shell.
מגדירים את משתני הסביבה:
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. -
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 Superchips), use
a4x-highgpu-4g. - ל-A4 (יחידות GPU מסוג B200), צריך להשתמש בגרסה
a4-highgpu-8gואילך. - ל-A3 Ultra (יחידות GPU מדגם H200), צריך להשתמש ב-
a3-ultragpu-8gואילך.
- A4X (GB200 Superchips), use
-
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
טייס אוטומטי
הקטע הזה נדרש רק עבור מעבדי GKE Standard A4 ו-A3 Ultra GPU.
אם אתם משתמשים ב-Autopilot, דלגו על הקטע הזה ועברו ישירות אל יצירת אשכול GKE. GKE מקצה באופן אוטומטי את רשתות ה-VPC ורשתות המשנה הנדרשות, ומשתמש ב-DRANET מנוהל של GKE כדי להקצות את המשאבים האלה ל-Pods. לא צריך ליצור ידנית תשתית רשת.
רגילה
יוצרים רשת VPC לממשק gVNIC:
יוצרים רשת VPC ל-RDMA:
יוצרים את 8 רשתות המשנה של RDMA עבור 8 יחידות ה-GPU:
A4X
הקטע הזה נדרש רק עבור מעבדי GKE Standard A4 ו-A3 Ultra GPU.
אם אתם משתמשים ביחידות GPU מסוג A4X (GB200), דלגו על הקטע הזה ועברו ישירות אל יצירת אשכול GKE. במכשירי GPU מסוג A4X (GB200) או ב-Autopilot, GKE יוצר את הרשתות באופן אוטומטי כשמאגר הצמתים משתמש בautoפרופיל רשת של מאיץ. התוכנית Cluster Toolkit מאפשרת את הפרופיל הזה באמצעות הדגל enable_dranet:true.
יצירת אשכול GKE
יוצרים אשכול GKE שמתאים לארכיטקטורת ה-GPU:
A4 ו-A3 Ultra
בוחרים את מצב אשכול GKE שבו רוצים להשתמש:
טייס אוטומטי
יצירת אשכול Autopilot:
מקבלים פרטי כניסה לאשכול:
רגילה
יצירת אשכול רגיל:
מקבלים פרטי כניסה לאשכול:
יוצרים את מאגר הצמתים של ה-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}מוודאים שהאשכול חושף כרטיסי רשת של 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:
אחרי שהסטטוס של
data-prep-jobPod משתנה ל-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 (ההורדה הזו דורשת כ-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, שמורכב מ-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 של עובדים יהיה
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, לוחצים על תצוגה מקדימה באינטרנט, בוחרים באפשרות שינוי יציאה ומזינים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, לוחצים על תצוגה מקדימה באינטרנט, בוחרים באפשרות שינוי יציאה ומזינים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}