Skip to content

Commit 38ce7e2

Browse files
authored
Merge pull request #197 from weikuo0506/weikuo-llama3-70b-h200-recipe
Add Llama 3 70B 64gpus BF16 recipe for A3Ultra #recipebot
2 parents 55d825c + d93f5a2 commit 38ce7e2

8 files changed

Lines changed: 770 additions & 0 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
apiVersion: v2
16+
name: a3u_jobset_workload
17+
description: a3u_jobset_workload
18+
type: application
19+
version: 0.1.0
20+
appVersion: "1.16.0"
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<!-- mdformat global-off -->
2+
# Pretrain llama3-70b workloads on a3ultra GKE Node pools with Nvidia Megatron-Bridge Framework
3+
4+
This recipe outlines the steps for running a llama3-70b pretraining
5+
workload on [a3ultra GKE Node pools](https://cloud.google.com/kubernetes-engine) by using the
6+
[Megatron-Bridge pretraining workload](https://github.com/NVIDIA-NeMo/Megatron-Bridge).
7+
8+
## Orchestration and deployment tools
9+
10+
For this recipe, the following setup is used:
11+
12+
- Orchestration - [Google Kubernetes Engine (GKE)](https://cloud.google.com/kubernetes-engine)
13+
- Pretraining job configuration and deployment - A Helm chart is used to
14+
configure and deploy the [Kubernetes Jobset](https://kubernetes.io/blog/2025/03/23/introducing-jobset) resource which manages the execution of the
15+
[Megatron-Bridge pretraining workload](https://github.com/NVIDIA-NeMo/Megatron-Bridge).
16+
17+
## Test environment
18+
19+
This recipe has been optimized for and tested with the following configuration:
20+
21+
- GKE cluster
22+
Please follow Cluster Toolkit [instructions](https://github.com/GoogleCloudPlatform/cluster-toolkit/)
23+
to create your a3ultra GKE cluster.
24+
25+
## Training dataset
26+
27+
This recipe uses a mock pretraining dataset provided by the Megatron-Bridge framework.
28+
29+
## Docker container image
30+
31+
This recipe uses the following docker images:
32+
33+
- `nvcr.io/nvidia/nemo:26.02`
34+
- `us-docker.pkg.dev/gce-ai-infra/gpudirect-gib/nccl-plugin-gib:v1.1.0`
35+
36+
## Run the recipe
37+
38+
From your client workstation, complete the following steps:
39+
40+
### Configure environment settings
41+
42+
Set the environment variables to match your environment:
43+
44+
```bash
45+
export PROJECT_ID=<PROJECT_ID>
46+
export CLUSTER_REGION=<CLUSTER_REGION>
47+
export CLUSTER_NAME=<CLUSTER_NAME>
48+
export GCS_BUCKET=<GCS_BUCKET> # Note: path should not be prefixed with gs://
49+
export KUEUE_NAME=<KUEUE_NAME>
50+
export HF_TOKEN=<YOUR_HF_TOKEN>
51+
```
52+
53+
Replace the following values:
54+
55+
- `<PROJECT_ID>`: your Google Cloud project ID.
56+
- `<CLUSTER_REGION>`: the region where your cluster is located.
57+
- `<CLUSTER_NAME>`: the name of your GKE cluster.
58+
- `<GCS_BUCKET>`: the name of your Cloud Storage bucket. Don't include the `gs://` prefix.
59+
- `<KUEUE_NAME>`: the name of the Kueue local queue. The default queue created by the cluster toolkit is `a3ultra`. Make sure to verify the name of the local queue in your cluster.
60+
- `<YOUR_HF_TOKEN>`: Your HuggingFace token.
61+
62+
Set the default project:
63+
64+
```bash
65+
gcloud config set project $PROJECT_ID
66+
```
67+
68+
### Get the recipe
69+
70+
Clone the `gpu-recipes` repository and set a reference to the recipe folder.
71+
72+
```
73+
git clone https://github.com/ai-hypercomputer/gpu-recipes.git
74+
cd gpu-recipes
75+
export REPO_ROOT=`git rev-parse --show-toplevel`
76+
export RECIPE_ROOT=$REPO_ROOT/training/a3ultra/llama3_70b/megatron-bridge-gke/nemo2602/64gpus-bf16-seq8192-gbs256/recipe
77+
cd $RECIPE_ROOT
78+
```
79+
80+
### Get cluster credentials
81+
82+
```
83+
gcloud container clusters get-credentials $CLUSTER_NAME --region $CLUSTER_REGION
84+
```
85+
86+
### Configure and submit a pretraining job
87+
88+
#### Using 8 node (64 gpus) bf16 precision
89+
To execute the job with the default settings, run the following command from
90+
your client:
91+
92+
```bash
93+
cd $RECIPE_ROOT
94+
export WORKLOAD_NAME=$USER-a3ultra-llama3-70b-8node
95+
helm install $WORKLOAD_NAME . -f values.yaml \
96+
--set-file workload_launcher=launcher.sh \
97+
--set workload.image=nvcr.io/nvidia/nemo:26.02 \
98+
--set volumes.gcsMounts[0].bucketName=${GCS_BUCKET} \
99+
--set volumes.gcsMounts[0].mountPath=/job-logs \
100+
--set workload.envs[0].value=/job-logs/$WORKLOAD_NAME \
101+
--set queue=${KUEUE_NAME}
102+
```
103+
104+
**Examples**
105+
106+
- To set the number of training steps to 100, run the following command from
107+
your client:
108+
109+
```bash
110+
cd $RECIPE_ROOT
111+
export WORKLOAD_NAME=$USER-a3ultra-llama3-70b-8node
112+
helm install $WORKLOAD_NAME . -f values.yaml \
113+
--set-file workload_launcher=launcher.sh \
114+
--set workload.image=nvcr.io/nvidia/nemo:26.02 \
115+
--set volumes.gcsMounts[0].bucketName=${GCS_BUCKET} \
116+
--set volumes.gcsMounts[0].mountPath=/job-logs \
117+
--set workload.envs[0].value=/job-logs/$WORKLOAD_NAME \
118+
--set queue=${KUEUE_NAME} \
119+
--set workload.arguments[0]="trainer.max_steps=100"
120+
```
121+
122+
### Monitor the job
123+
124+
To check the status of pods in your job, run the following command:
125+
126+
```
127+
kubectl get pods | grep $USER-a3ultra-llama3-70b-8node
128+
```
129+
130+
Replace the following:
131+
132+
- JOB_NAME_PREFIX - your job name prefix. For example $USER-a3ultra-llama3-70b-8node.
133+
134+
To get the logs for one of the pods, run the following command:
135+
136+
```
137+
kubectl logs POD_NAME
138+
```
139+
140+
Information about the training job's progress, including crucial details such as
141+
loss, step count, and step time, is generated by the rank 0 process.
142+
This process runs on the pod whose name begins with
143+
`JOB_NAME_PREFIX-workload-0-0`.
144+
For example: `$USER-a3ultra-llama3-70b-8node-workload-0-0-s9zrv`.
145+
146+
### Uninstall the Helm release
147+
148+
You can delete the job and other resources created by the Helm chart. To
149+
uninstall Helm, run the following command from your client:
150+
151+
```bash
152+
helm uninstall $USER-a3ultra-llama3-70b-8node
153+
```
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
usage()
2+
{
3+
cat << EOF
4+
usage: bash ./launcher.sh [config-override [config-override ...]]
5+
config-override (Optional) A NeMo configuration override. E.g. trainer.max_steps=10000.
6+
EOF
7+
}
8+
9+
parse_args() {
10+
while [[ "$1" != "" ]]; do
11+
case $(grep -o "=" <<< "$1" | wc -l) in
12+
1 )
13+
config_overrides+=("$1")
14+
;;
15+
* )
16+
echo "Invalid config override: $1"
17+
usage
18+
exit 1
19+
esac
20+
shift
21+
done
22+
config_overrides="${config_overrides[*]}"
23+
}
24+
25+
config_overrides=()
26+
parse_args "$@"
27+
28+
if [[ -z "${config_overrides[*]}" ]]; then
29+
echo "No NeMo config overrides specified"
30+
else
31+
echo "NeMo config overrides:"
32+
echo " ${config_overrides}"
33+
fi
34+
35+
export LD_LIBRARY_PATH="/usr/local/cuda/compat/lib:$NCCL_PLUGIN_PATH:$LD_LIBRARY_PATH"
36+
ldconfig "$LD_LIBRARY_PATH"
37+
echo "Added $LD_LIBRARY_PATH to ldconfig:"
38+
ldconfig -p | grep libcuda | sed 's/^/ /'
39+
echo ""
40+
41+
if [[ -n "${EXPLICIT_LOG_DIR}" ]]; then
42+
explicit_log_dir="${EXPLICIT_LOG_DIR}"
43+
else
44+
explicit_log_dir="workload_logs"
45+
fi
46+
47+
# Ensure explicit_log_dir is an absolute path before any cd commands
48+
if [[ "$explicit_log_dir" != /* ]]; then
49+
explicit_log_dir="${PWD}/${explicit_log_dir}"
50+
fi
51+
echo "Logging to ${explicit_log_dir}"
52+
53+
if [[ -n "${TOKENIZER_PATH}" ]]; then
54+
echo "Getting tokenizer files"
55+
cp "${TOKENIZER_PATH}"/* .
56+
echo ""
57+
fi
58+
59+
echo "Launching Torch distributed on the node rank $JOB_COMPLETION_INDEX out of $NNODES nodes"
60+
61+
pip install git+https://github.com/NVIDIA/dllogger#egg=dllogger
62+
63+
# Create the nsys directory.
64+
mkdir -p "${explicit_log_dir}/nsys"
65+
66+
# Collect diagnostics to a single line
67+
kv="\"kernel_version\": \"$(uname --kernel-release)\""
68+
if command -v nvidia-smi &> /dev/null; then
69+
cuda_v=$(nvidia-smi -q -x | grep -Po '(?<=<cuda_version>).*(?=</cuda_version>)' || true)
70+
driver_v=$(nvidia-smi -q -x | grep -Po '(?<=<driver_version>).*(?=</driver_version>)' || true)
71+
vbios_v=$(nvidia-smi -q -x | grep -Po '(?<=<vbios_version>).*(?=</vbios_version>)' | head -n1 || true)
72+
kv="${kv}, \"cuda_version\": \"${cuda_v}\""
73+
kv="${kv}, \"driver_version\": \"${driver_v}\""
74+
kv="${kv}, \"vbios_version\": \"${vbios_v}\""
75+
fi
76+
echo "VERSION_DIAGNOSTICS: {${kv}}"
77+
78+
79+
export HF_TOKEN=YOUR_HF_TOKEN
80+
81+
cd /opt
82+
rm -rf Megatron-Bridge
83+
git clone https://github.com/NVIDIA-NeMo/Megatron-Bridge.git
84+
cd Megatron-Bridge
85+
git checkout f7a9428f301fa17ac374d5e7166a63b0aa4771af
86+
git submodule update --init --recursive
87+
sed -i -e '/pretrain(config=recipe/i \ recipe.dist.distributed_timeout_minutes = 10' scripts/performance/run_script.py
88+
ls
89+
90+
91+
92+
worker_command=$(cat <<- EOM
93+
if [ "\$RANK" -eq "0" ]; then
94+
echo "Worker 0 is stalling for a few seconds.." ;
95+
sleep 3 ;
96+
echo "The detected environment within worker rank 0 is:" ;
97+
env | sed 's/^/ /' ;
98+
fi ;
99+
100+
cd /opt/Megatron-Bridge ;
101+
102+
numactl \
103+
--cpunodebind=\$((LOCAL_RANK/4)) \
104+
--membind=\$((LOCAL_RANK/4)) nsys profile \
105+
-t nvtx,cuda \
106+
--cuda-event-trace=false \
107+
--sample=none \
108+
--capture-range=cudaProfilerApi \
109+
--capture-range-end=stop \
110+
--kill none \
111+
-o "${explicit_log_dir}/$JOB_IDENTIFIER/rank-\$RANK" \
112+
--force-overwrite true \
113+
--session-new "nsys-\$RANDOM-\$RANK" \
114+
nice -10 \
115+
python scripts/performance/run_script.py \
116+
--gpu h100 \
117+
--model_family_name llama \
118+
--model_recipe_name llama3_70b \
119+
--num_gpus 64 \
120+
--gpus_per_node 8 \
121+
--compute_dtype bf16 \
122+
--global_batch_size 256 \
123+
--micro_batch_size 1 \
124+
--seq_length 8192 \
125+
--tensor_model_parallel_size 4 \
126+
--pipeline_model_parallel_size 8 \
127+
--context_parallel_size 1 \
128+
--virtual_pipeline_model_parallel_size 5 \
129+
--use_megatron_fsdp False \
130+
--max_steps 50 \
131+
132+
EOM
133+
)
134+
135+
echo "$worker_command" > worker_command.sh
136+
chmod 777 worker_command.sh
137+
138+
torchrun \
139+
--nproc-per-node="8" \
140+
--nnodes="8" \
141+
--node_rank="${JOB_COMPLETION_INDEX}" \
142+
--rdzv_id="${JOB_IDENTIFIER}" \
143+
--master_addr="${MASTER_ADDR}" \
144+
--master_port="${MASTER_PORT}" \
145+
--no-python bash worker_command.sh
146+
147+
148+
if [[ "$JOB_COMPLETION_INDEX" == "0" ]]; then
149+
mkdir -p "${ARTIFACT_DIR}"
150+
cp -r "${explicit_log_dir}"/* "${ARTIFACT_DIR}/"
151+
env > "${ARTIFACT_DIR}/environ.txt"
152+
ls "${ARTIFACT_DIR}"
153+
fi
154+
echo "Training completed"
155+
echo "Pod on $(hostname --fqdn) is exiting"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# yamllint disable
2+
# Copyright 2025 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
{{- if .Values.workload.configFile }}
17+
apiVersion: v1
18+
kind: ConfigMap
19+
metadata:
20+
name: "{{ .Release.Name }}-config"
21+
data:
22+
workload-configuration: |-
23+
{{- if .Values.workload_config }}
24+
{{ .Values.workload_config | nindent 4 }}
25+
{{- else }}
26+
{{ "config: null" | nindent 4 }}
27+
{{- end }}
28+
{{- end }}

0 commit comments

Comments
 (0)