Skip to content

Add LLaMA 3.1 405B 256-GPU FP8-MX pretraining recipe on GKE A4X (NeMo 26.06.01) #recipebot - #284

Open
leonardchan wants to merge 1 commit into
AI-Hypercomputer:leoch/a4x-llama31-405b-256gpus-fp8mx-nemo2606from
leonardchan:leoch/a4x-llama31-405b-256gpus-fp8mx-nemo2606
Open

leonardchan wants to merge 1 commit into
AI-Hypercomputer:leoch/a4x-llama31-405b-256gpus-fp8mx-nemo2606from
leonardchan:leoch/a4x-llama31-405b-256gpus-fp8mx-nemo2606

Conversation

@leonardchan

Copy link
Copy Markdown
Collaborator

Adds the verified 256-GPU LLaMA 3.1 405B FP8-MX pretraining recipe for GKE A4X (NVIDIA GB200 NVL72) using NeMo 26.06.01 and Megatron-Bridge.

Benchmark & Performance Highlights

  • Measured Throughput: 1,984.25 MODEL_TFLOP/s/GPU
  • NVIDIA DGX-B200 Target: 1,976.00 MODEL_TFLOP/s/GPU
  • % Reached (GCP / NVIDIA Roofline): 100.42%
  • Steady-State Step Latency: 62.53s / step
  • Model FLOPs Utilization (MFU): 44.09% MFU
  • uBench Run ID: `megatron_bridge_training-nemo2606/llama31_405b_256gpus_fp8mx_seq8192_gbs1536-2026-08-20_091758-1f6d19dc-857d-466b-9988-d66662832c96`

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a pretraining recipe for LLaMA 3.1 405B on A4X GKE Node Pools using NVIDIA Megatron-Bridge and NeMo. The review feedback identifies several critical issues: the NCCL tuner configuration is set for the wrong platform (A3U instead of A4X); the Helm installation instructions in the README are missing a required file parameter; the launcher script contains hardcoded GPU and node counts, unconditionally overwrites the Hugging Face token, ignores parsed configuration overrides, and lacks safety checks for empty artifact directories; the Helm templates lack guards for null GCS mount values; and cloning the repository at runtime across 64 nodes simultaneously risks GitHub rate limiting.


# Overriding NCCL_SOCKET_IFNAME definition
export NCCL_SOCKET_IFNAME="eth0,eth1"
export NCCL_TUNER_CONFIG_PATH=/usr/local/gib/configs/tuner_config_a3u.txtpb

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The NCCL tuner config path is set to tuner_config_a3u.txtpb, which is for the A3U (H100) platform. Since this recipe is specifically for A4X (GB200 NVL72), it should use the A4 tuner config (tuner_config_a4.txtpb) to ensure optimal network performance and correct topology tuning.

                export NCCL_TUNER_CONFIG_PATH=/usr/local/gib/configs/tuner_config_a4.txtpb

Comment on lines +74 to +80
helm install llama31-405b-256gpus-fp8mx . \
--set queue=${KUEUE_NAME} \
--set volumes.gcsMounts[0].bucketName=${GCS_BUCKET} \
--set volumes.gcsMounts[0].mountPath=/runtime-logs \
--set workload.envs[0].name=ARTIFACT_DIR \
--set workload.envs[0].value=/runtime-logs/llama31-405b-256gpus-fp8mx/artifacts
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The helm install command is missing --set-file workload_launcher=launcher.sh. Without this, the chart will deploy the default "No workload launcher specified" script and fail immediately.

Suggested change
helm install llama31-405b-256gpus-fp8mx . \
--set queue=${KUEUE_NAME} \
--set volumes.gcsMounts[0].bucketName=${GCS_BUCKET} \
--set volumes.gcsMounts[0].mountPath=/runtime-logs \
--set workload.envs[0].name=ARTIFACT_DIR \
--set workload.envs[0].value=/runtime-logs/llama31-405b-256gpus-fp8mx/artifacts
```
helm install llama31-405b-256gpus-fp8mx . \
--set queue=${KUEUE_NAME} \
--set-file workload_launcher=launcher.sh \
--set volumes.gcsMounts[0].bucketName=${GCS_BUCKET} \
--set volumes.gcsMounts[0].mountPath=/runtime-logs \
--set workload.envs[0].name=ARTIFACT_DIR \
--set workload.envs[0].value=/runtime-logs/llama31-405b-256gpus-fp8mx/artifacts

@@ -0,0 +1,169 @@
export HF_TOKEN=<YOUR_HF_TOKEN>

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This line unconditionally overwrites HF_TOKEN with the literal string <YOUR_HF_TOKEN>, which prevents users from securely passing their Hugging Face token via Kubernetes Secrets or standard environment variables. It should use a default value expansion instead.

Suggested change
export HF_TOKEN=<YOUR_HF_TOKEN>
export HF_TOKEN="${HF_TOKEN:-<YOUR_HF_TOKEN>}"

Comment on lines +154 to +155
--nproc-per-node="4" \
--nnodes="64" \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The GPU and node counts are hardcoded in the torchrun command. They should use the environment variables GPUS_PER_NODE and NNODES provided by the JobSet to allow dynamic scaling and customization via Helm values.

Suggested change
--nproc-per-node="4" \
--nnodes="64" \
--nproc-per-node="${GPUS_PER_NODE:-4}" \
--nnodes="${NNODES:-64}" \

Comment on lines +129 to +130
--num_gpus 256 \
--gpus_per_node 4 \

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The GPU and node counts are hardcoded in the Python script arguments. They should use the environment variables WORLD_SIZE and GPUS_PER_NODE provided by the JobSet to allow dynamic scaling and customization via Helm values.

Suggested change
--num_gpus 256 \
--gpus_per_node 4 \
--num_gpus \$WORLD_SIZE \
--gpus_per_node \$GPUS_PER_NODE \

Comment on lines +142 to +143
logger.log_throughput=True \
train.manual_gc_interval=100

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The script parses command-line arguments into config_overrides but never actually passes them to the Python training script (run_script.py). This means any configuration overrides provided by the user will be silently ignored. You should append ${config_overrides} to the Python command.

Suggested change
logger.log_throughput=True \
train.manual_gc_interval=100
logger.log_throughput=True \
train.manual_gc_interval=100 \
${config_overrides}

Comment on lines +162 to +167
if [[ "$JOB_COMPLETION_INDEX" == "0" ]]; then
mkdir -p "${ARTIFACT_DIR}"
cp -r "${explicit_log_dir}"/* "${ARTIFACT_DIR}/"
env > "${ARTIFACT_DIR}/environ.txt"
ls "${ARTIFACT_DIR}"
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If ARTIFACT_DIR is empty or null, mkdir -p will fail, and the subsequent cp command will attempt to copy log files to the root directory (/), which can cause permission errors or unintended file overwrites. Adding a check to ensure ARTIFACT_DIR is non-empty before proceeding is highly recommended.

Suggested change
if [[ "$JOB_COMPLETION_INDEX" == "0" ]]; then
mkdir -p "${ARTIFACT_DIR}"
cp -r "${explicit_log_dir}"/* "${ARTIFACT_DIR}/"
env > "${ARTIFACT_DIR}/environ.txt"
ls "${ARTIFACT_DIR}"
fi
if [[ "$JOB_COMPLETION_INDEX" == "0" && -n "${ARTIFACT_DIR}" ]]; then
mkdir -p "${ARTIFACT_DIR}"
cp -r "${explicit_log_dir}"/* "${ARTIFACT_DIR}/"
env > "${ARTIFACT_DIR}/environ.txt"
ls "${ARTIFACT_DIR}"
fi

Comment on lines +177 to +186
{{- range $gcs := $root.Values.volumes.gcsMounts }}
- name: "{{ $gcs.bucketName }}"
csi:
driver: gcsfuse.csi.storage.gke.io
volumeAttributes:
bucketName: "{{ $gcs.bucketName }}"
{{- if $gcs.mountOptions }}
mountOptions: "{{ $gcs.mountOptions }}"
{{- end }}
{{- end}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The gcsMounts loop is evaluated even if gcsVolumes is false or if bucketName is null, which can cause Helm rendering errors or invalid Kubernetes manifests. It should be guarded with {{- if $gcs.bucketName }}.

            {{- range $gcs := $root.Values.volumes.gcsMounts }}
            {{- if $gcs.bucketName }}
            - name: "{{ $gcs.bucketName }}"
              csi:
                driver: gcsfuse.csi.storage.gke.io
                volumeAttributes:
                  bucketName: "{{ $gcs.bucketName }}"
                  {{- if $gcs.mountOptions }}
                  mountOptions: "{{ $gcs.mountOptions }}"
                  {{- end }}
            {{- end }}
            {{- end}}

Comment on lines +347 to +350
{{- range $gcs := $root.Values.volumes.gcsMounts }}
- name: "{{ $gcs.bucketName }}"
mountPath: "{{ $gcs.mountPath }}"
{{- end }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The gcsMounts volumeMounts loop is evaluated even if gcsVolumes is false or if bucketName is null, which can cause Helm rendering errors or invalid Kubernetes manifests. It should be guarded with {{- if $gcs.bucketName }}.

                {{- range $gcs := $root.Values.volumes.gcsMounts }}
                {{- if $gcs.bucketName }}
                - name: "{{ $gcs.bucketName }}"
                  mountPath: "{{ $gcs.mountPath }}"
                {{- end }}
                {{- end }}

Comment on lines +101 to +106
cd /opt
rm -rf Megatron-Bridge
git clone https://github.com/NVIDIA-NeMo/Megatron-Bridge.git
cd Megatron-Bridge
git checkout fcbb6031103d0ca845c1a54d4fee55ecfcca17b6
git submodule update --init --recursive

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Cloning the Megatron-Bridge repository at runtime on all 64 nodes simultaneously can trigger GitHub rate limits, leading to connection resets and job failures. It is highly recommended to pre-bake this repository into the container image or use a shared volume. If runtime cloning is necessary, consider adding a retry loop or cloning with --depth 1 where possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant