Skip to content

Commit becbf01

Browse files
committed
Add RL tutorial and run script for GPT-OSS 20B on Multi-Host TPUs
1 parent 989abc6 commit becbf01

3 files changed

Lines changed: 337 additions & 0 deletions

File tree

docs/tutorials/post_training_index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ MaxText was co-designed with key Google led innovations to provide a unified pos
3737
- [RL on Single-Host TPUs](./posttraining/rl.md)
3838
- [RL on Multi-Host TPUs](./posttraining/rl_on_multi_host.md)
3939
- [RL with Qwen3-30b-a3b-base](./posttraining/rl_qwen3_30b.md)
40+
- [RL with GPT-OSS 20B](./posttraining/rl_gptoss_20b.md)
4041

4142
## Step by step RL
4243

@@ -75,6 +76,7 @@ posttraining/dpo.md
7576
posttraining/rl.md
7677
posttraining/rl_on_multi_host.md
7778
posttraining/rl_qwen3_30b.md
79+
posttraining/rl_gptoss_20b.md
7880
posttraining/knowledge_distillation.md
7981
posttraining/lora.md
8082
posttraining/lora_on_multi_host.md
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
<!--
2+
Copyright 2023-2026 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+
https://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+
17+
# Reinforcement Learning with GPT-OSS 20B on Multi-Host TPUs
18+
19+
This tutorial provides step-by-step instructions for setting up the environment
20+
and training the GPT-OSS 20B model on the [GSM8K dataset](https://huggingface.co/datasets/openai/gsm8k) on an Viperfish GKE cluster with `v5p-64` nodes.
21+
22+
## Prerequisites
23+
24+
Before starting, ensure you have:
25+
26+
- Access to a Google Cloud Project with TPU quotas.
27+
- A Hugging Face account with an access token for downloading models.
28+
- Permissions for Google Artifact Registry (Artifact Registry Writer role).
29+
- Prerequisites for XPK installed (follow [official documentation](https://github.com/AI-Hypercomputer/xpk/blob/main/docs/installation.md#1-prerequisites)).
30+
- A Pathways-ready GKE cluster (see [create GKE cluster](https://docs.cloud.google.com/ai-hypercomputer/docs/workloads/pathways-on-cloud/create-gke-cluster)).
31+
- **Docker** installed and configured for sudoless use. Follow the steps to [configure sudoless Docker](https://docs.docker.com/engine/install/linux-postinstall/).
32+
33+
## Build and Upload MaxText Docker Image
34+
35+
For instructions on building and uploading the MaxText Docker image with post-training dependencies, please refer to the [official documentation](../../build_maxtext.md).
36+
37+
## Setup Environment Variables
38+
39+
Set up the following environment variables to configure your training run. Replace
40+
placeholders with your actual values.
41+
42+
```bash
43+
# Your GCP project ID.
44+
# If you've already set it in your local config, you can retrieve it via:
45+
# gcloud config get-value project
46+
export PROJECT_ID=<PROJECT_ID>
47+
48+
# The name of your GKE cluster.
49+
export CLUSTER_NAME=<CLUSTER_NAME>
50+
51+
# The GCP location of your GKE cluster.
52+
export ZONE=<ZONE> # e.g., 'us-central1' or 'us-central1-a'
53+
54+
# Use a GCS bucket you own to store logs and checkpoints.
55+
export BASE_OUTPUT_DIRECTORY=<GCS_BUCKET> # e.g., gs://my-bucket/maxtext-runs
56+
57+
# The Docker image you pushed in the previous step
58+
export CLOUD_IMAGE_NAME=<IMAGE_NAME>
59+
export DOCKER_IMAGE="gcr.io/${PROJECT_ID?}/${CLOUD_IMAGE_NAME?}"
60+
```
61+
62+
## Clone MaxText Repository
63+
64+
If you haven't already, clone the MaxText repository to your local machine:
65+
66+
```bash
67+
git clone https://github.com/AI-Hypercomputer/maxtext.git
68+
cd maxtext
69+
```
70+
71+
## Authenticate with Hugging Face
72+
73+
To download the `gpt-oss-20b` model checkpoint from Hugging Face, you need to authenticate using your Hugging Face account credentials. Run the following command and follow the prompts to log in:
74+
75+
```bash
76+
hf auth login
77+
```
78+
79+
## Get Your MaxText Compatible Model Checkpoint
80+
81+
### Option 1: Using an existing MaxText checkpoint
82+
83+
If you already have a MaxText-compatible model checkpoint, simply set the
84+
following environment variable and move on to the next section.
85+
86+
```bash
87+
export MAXTEXT_CKPT_PATH=<CKPT_PATH> # e.g., gs://my-bucket/my-model-checkpoint/0/items
88+
```
89+
90+
### Option 2: Converting from a Hugging Face checkpoint
91+
92+
> **Note:** Converting the 20B model requires approximately 40 GB of free disk space to download its safetensors. Please verify you have sufficient space before running the conversion.
93+
94+
```bash
95+
# Create and activate a virtual environment
96+
uv venv --python 3.12 --seed tpu_venv
97+
source tpu_venv/bin/activate
98+
uv pip install -e .[tpu] --resolution=lowest
99+
100+
# Install torch for conversion
101+
python3 -m pip install torch --index-url https://download.pytorch.org/whl/cpu
102+
103+
# Download Hugging Face weights to a local directory
104+
huggingface-cli download openai/gpt-oss-20b --local-dir ./gpt-oss-20b-hf
105+
106+
# Set up the MaxText checkpoint path environment variable where the converted checkpoint will be saved
107+
export MAXTEXT_CKPT_PATH="${BASE_OUTPUT_DIRECTORY}/checkpoints/gpt-oss-20b-converted/0/items"
108+
109+
# Run the conversion script to convert the Hugging Face checkpoint to MaxText format
110+
python3 -m maxtext.checkpoint_conversion.standalone_scripts.convert_gpt_oss_ckpt \
111+
--base-model-path ./gpt-oss-20b-hf \
112+
--maxtext-model-path ${MAXTEXT_CKPT_PATH} \
113+
--model-size gpt-oss-20b \
114+
--use-ocdbt=False --use-zarr3=False
115+
116+
# Deactivate the virtual environment
117+
deactivate
118+
rm -rf tpu_venv
119+
```
120+
121+
## Run RL Workload
122+
123+
### Submit your workload
124+
125+
```bash
126+
# Create and activate a virtual environment
127+
uv venv --python 3.12 --seed runner_venv
128+
source runner_venv/bin/activate
129+
uv pip install -e .[runner] --resolution=lowest
130+
131+
# Run the RL training script on your cluster
132+
bash scripts/run_gptoss_20b_rl.sh
133+
134+
# Deactivate the virtual environment
135+
deactivate
136+
rm -rf runner_venv
137+
```
138+
139+
### Monitor your workload
140+
141+
To monitor your job's progress, you can use `kubectl` to check the `Jobset` status and stream logs directly from the pods.
142+
143+
```bash
144+
kubectl get jobset -n default ${WORKLOAD_NAME}
145+
146+
# List pods to find the specific name
147+
kubectl get pods | grep ${WORKLOAD_NAME}
148+
149+
# stream the logs from the running pod (replace <POD_NAME> with the name you found)
150+
kubectl logs -f <POD_NAME>
151+
```
152+
153+
Alternatively, after running the bash script, you will also get a link to the Google Cloud Console to view your workload logs. Follow the link to view logs and monitor your workload's progress in the Cloud Console.
154+
155+
### Monitor RL Metrics
156+
157+
During RL training, you can monitor key metrics to track model convergence, reward trends, and hardware performance.
158+
159+
To enable Tunix-managed metrics measurement, set `enable_tunix_perf_metrics` to `true` in `src/maxtext/configs/post_train/rl.yml`. Note that this flag is already set to `True` by default in the [scripts/run_gptoss_20b_rl.sh](../../../scripts/run_gptoss_20b_rl.sh) script for this tutorial workload. When enabled, Tunix automatically collects and uploads these metrics to TensorBoard.
160+
161+
For a complete list of collected metrics, see the [Tunix Metrics Documentation](https://tunix.readthedocs.io/en/latest/metrics.html). Key metrics to monitor include:
162+
163+
- **Model Quality & Reward Metrics:**
164+
- `rewards/mean`: The average reward across the batch (crucial for tracking learning progress).
165+
- `score/mean`: The average raw score from the reward model before applying the KL penalty.
166+
- **Rollout & Generation Metrics:**
167+
- `rollout_time`: How long each rollout step takes.
168+
- `completions/mean_length`: The average token length of generated completions.
169+
- `actor_dequeue_time`: The time spent waiting for data from the rollout workers (relevant when async rollout is enabled).
170+
- **Performance & Efficiency Metrics:**
171+
- `step_time_sec`: The execution time for a single training step.
172+
173+
## Convert Checkpoint to Hugging Face Format
174+
175+
After training, you may want to convert your MaxText checkpoint back to Hugging Face format. Use the following command to perform the conversion:
176+
177+
```bash
178+
# Create and activate a virtual environment
179+
uv venv --python 3.12 --seed tpu_venv
180+
source tpu_venv/bin/activate
181+
uv pip install -e .[tpu] --resolution=lowest
182+
183+
# Install torch for conversion
184+
python3 -m pip install torch --index-url https://download.pytorch.org/whl/cpu
185+
186+
# Define the output path for the converted checkpoint
187+
export HF_CKPT_OUTPUT_DIR="${BASE_OUTPUT_DIRECTORY}/checkpoints/gpt-oss-20b-hf-converted"
188+
189+
# Run the conversion script to convert the MaxText checkpoint back to Hugging Face format
190+
python3 -m maxtext.checkpoint_conversion.to_huggingface \
191+
src/maxtext/configs/base.yml \
192+
model_name=gpt-oss-20b \
193+
load_parameters_path="${MAXTEXT_CKPT_PATH}" \
194+
base_output_directory="${HF_CKPT_OUTPUT_DIR}" \
195+
scan_layers=True \
196+
weight_dtype=bfloat16 hardware=cpu skip_jax_distributed_system=True
197+
198+
# Deactivate the virtual environment
199+
deactivate
200+
rm -rf tpu_venv
201+
```

scripts/run_gptoss_20b_rl.sh

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
#!/bin/bash
2+
3+
# This script launches a Reinforcement Learning (RL) training workload for the
4+
# GPT-OSS 20B model on a GKE cluster using XPK.
5+
6+
set -e
7+
8+
# --- Environment Setup ---
9+
if ! pip show xpk &> /dev/null; then
10+
echo "xpk not found in the environment. Please install it by running:"
11+
echo "uv pip install -e .[runner] --resolution=lowest"
12+
exit 1
13+
fi
14+
15+
# --- Environment Variables ---
16+
export PROJECT_ID="${PROJECT_ID:-}" # GCP project ID where the Ironwood cluster is deployed
17+
export CLUSTER_NAME="${CLUSTER_NAME:-}" # Name of your Ironwood cluster
18+
export ZONE="${ZONE:-}" # Zone where your Ironwood cluster is deployed
19+
export BASE_OUTPUT_DIRECTORY="${BASE_OUTPUT_DIRECTORY:-}" # GCS bucket path for outputs (e.g., gs://my-bucket/outputs)
20+
export DOCKER_IMAGE="${DOCKER_IMAGE:-}" # Full path to the Docker image you pushed (e.g., gcr.io/my-project/my-image:tag)
21+
export MAXTEXT_CKPT_PATH="${MAXTEXT_CKPT_PATH:-}" # GCS path of the MaxText checkpoint you want to fine-tune from (e.g., gs://my-bucket/checkpoints/maxtext-ckpt)
22+
export TPU_TYPE="v5p-64"
23+
export WORKLOAD_NAME="rl-$(date +%Y%m%d-%H%M)"
24+
25+
# --- Variable Validation ---
26+
if [ -z "$PROJECT_ID" ]; then
27+
echo "Error: PROJECT_ID is not set. Please set it in the script or as an environment variable."
28+
exit 1
29+
fi
30+
if [ -z "$CLUSTER_NAME" ]; then
31+
echo "Error: CLUSTER_NAME is not set. Please set it in the script or as an environment variable."
32+
exit 1
33+
fi
34+
if [ -z "$ZONE" ]; then
35+
echo "Error: ZONE is not set. Please set it in the script or as an environment variable."
36+
exit 1
37+
fi
38+
if [ -z "$BASE_OUTPUT_DIRECTORY" ]; then
39+
echo "Error: BASE_OUTPUT_DIRECTORY is not set. Please set it in the script or as an environment variable."
40+
exit 1
41+
fi
42+
if [ -z "$DOCKER_IMAGE" ]; then
43+
echo "Error: DOCKER_IMAGE is not set. Please set it in the script or as an environment variable."
44+
exit 1
45+
fi
46+
47+
if [ -z "$MAXTEXT_CKPT_PATH" ]; then
48+
echo "MAXTEXT_CKPT_PATH is not set. Please set it in the script or as an environment variable."
49+
exit 1
50+
fi
51+
52+
# XLA Flags
53+
XLA_FLAGS="--xla_tpu_dvfs_p_state=7 \
54+
--xla_tpu_scoped_vmem_limit_kib=65536 \
55+
--xla_tpu_num_sparse_cores_for_gather_offloading=1 \
56+
--xla_tpu_bf16_emission_mode=NATIVE_EMISSION \
57+
--xla_tpu_enable_sparse_core_reduce_scatter_v2=true \
58+
--xla_tpu_enable_sparse_core_collective_offload_all_gather=true \
59+
--xla_tpu_enable_sparse_core_collective_offload_2d_all_gather=true \
60+
--xla_tpu_use_tc_device_shape_on_sc=True \
61+
--xla_sc_disable_megacore_partitioning=True \
62+
--xla_tpu_enable_async_collective_fusion_fuse_all_gather=false \
63+
--xla_enable_async_all_gather=true \
64+
--xla_tpu_prefer_async_allgather_to_allreduce=true \
65+
--xla_tpu_enable_sparse_core_collective_offload_all_reduce=true \
66+
--xla_tpu_enable_sparse_core_collective_offload_reduce_scatter=true \
67+
--xla_tpu_enable_sparse_core_collective_offload_3d_all_gather=true \
68+
--xla_tpu_use_single_sparse_core_for_all_gather_offload=true \
69+
--xla_tpu_enable_concurrent_sparse_core_offloading=true \
70+
--xla_tpu_enable_offloading_gather_to_sparsecore=true \
71+
--xla_tpu_sparse_core_all_gather_latency_multiplier=1 \
72+
--xla_tpu_sparse_core_reduce_scatter_latency_multiplier=3 \
73+
--xla_tpu_enable_sparse_core_collective_aggregator=true \
74+
--xla_tpu_enable_latency_hiding_layer_scheduler=true \
75+
--xla_tpu_scheduler_percent_shared_memory_limit=150 \
76+
--xla_tpu_enable_layer_scheduler_for_dependent_collectives=true \
77+
--xla_tpu_enable_sparse_core_collective_offload_nd_reduce_scatter=true \
78+
--xla_tpu_pcie_bandwidth_multiplier=0.03 \
79+
--xla_tpu_enable_sparse_core_offload_queuing_in_lhs=true \
80+
--xla_tpu_enable_multi_compute_overlap_in_layer_scheduler=false \
81+
--xla_tpu_enable_3d_reduce_scatter_decomposer=false"
82+
83+
MAXTEXT_COMMAND="MODEL_IMPL_TYPE=flax_nnx \
84+
GRPC_ENABLE_FORK_SUPPORT=0 \
85+
JAX_RANDOM_WEIGHTS=1 \
86+
VLLM_ENABLE_V1_MULTIPROCESSING=0 \
87+
SKIP_JAX_PRECOMPILE=1 \
88+
NEW_MODEL_DESIGN=0 \
89+
TPU_MIN_LOG_LEVEL=0 \
90+
TF_CPP_MIN_LOG_LEVEL=0 \
91+
TPU_STDERR_LOG_LEVEL=0 \
92+
JAX_PLATFORMS=proxy,cpu \
93+
JAX_BACKEND_TARGET=grpc://127.0.0.1:29000 \
94+
ENABLE_PATHWAYS_PERSISTENCE=1 \
95+
python3 -m maxtext.trainers.post_train.rl.train_rl src/maxtext/configs/post_train/rl.yml \
96+
model_name=gpt-oss-20b \
97+
tokenizer_path=unsloth/gpt-oss-20b-BF16 \
98+
load_parameters_path=${MAXTEXT_CKPT_PATH} \
99+
run_name=${WORKLOAD_NAME} \
100+
base_output_directory=${BASE_OUTPUT_DIRECTORY} \
101+
checkpoint_storage_use_ocdbt=False \
102+
checkpoint_storage_use_zarr3=False \
103+
rollout_data_parallelism=2 \
104+
rollout_tensor_parallelism=8 \
105+
hbm_utilization_vllm=0.8 \
106+
batch_size=8 profiler=xplane \
107+
profiler_steps=2 \
108+
num_batches=500 \
109+
base_emb_dim=2880 \
110+
vocab_size=201088 \
111+
batch_size=16 \
112+
train_micro_batch_size=16 \
113+
rollout_micro_batch_size=16 \
114+
enable_dp_attention=False \
115+
async_scheduling=True \
116+
chips_per_vm=4 \
117+
chat_template_path=maxtext/examples/chat_templates/gpt_oss_rl.json \
118+
enable_tunix_perf_metrics=True \
119+
"
120+
121+
# Workload Creation
122+
xpk workload create-pathways \
123+
--cluster=$CLUSTER_NAME \
124+
--project=$PROJECT_ID \
125+
--zone=$ZONE \
126+
--priority=medium \
127+
--max-restarts=0 \
128+
--tpu-type=$TPU_TYPE \
129+
--num-slices=1 \
130+
--docker-image="${DOCKER_IMAGE}" \
131+
--workload="${WORKLOAD_NAME}" \
132+
--custom-pathways-proxy-server-args='${XLA_FLAGS}' \
133+
--command="${MAXTEXT_COMMAND}"
134+

0 commit comments

Comments
 (0)