Skip to main content
Group relative policy optimization (GRPO) is a reinforcement learning (RL) method that trains a model from a reward signal instead of example responses. The model generates several answers to each prompt, a reward function scores them, and the update favors the answers that beat their group’s average. Use it when you can check whether an output is right but can’t write the ideal output yourself, as with math, code, or tool calls. In this tutorial, you train a model on the GSM8K grade-school math dataset with a ready-made recipe from the post-training cookbook. An exact-match reward checks each final answer against the reference. By the end, you have a trained model registered in your project and know what each step of the training loop does. Training runs for 200 steps and takes about 4 hours. The model resource costs about $56 per hour, about $200 for the run, and bills per GPU-minute from the moment it’s ready until the recipe stops it. Make sure your credit balance covers the run.

Requirements

Before you begin, make sure you have:
  • Python 3.11 or later and uv.
  • A Together AI account with a credit balance of at least $100, the minimum for creating a model resource. See Pricing.
  • Your API key exported as TOGETHER_API_KEY. Get one from API keys in the Together AI console.
  • A Weights & Biases API key exported as WANDB_API_KEY. Most cookbook recipes log to Weights & Biases, including the one in this quickstart. To run without an account, export WANDB_MODE=offline instead.
  • Optionally, a Hugging Face token exported as HF_TOKEN for gated models or datasets.

Step 1: Clone the cookbook

Clone the cookbook and install its dependencies, including the Together Python SDK:

Step 2: Review the recipe

Open recipes/grpo/gsm8k.py:
recipes/grpo/gsm8k.py
GSM8K reference answers end with #### <number>, and the prompt asks the model to end its solution the same way. The dataset’s reward function reads the number after #### in each completion, falling back to a \boxed{} answer, and returns 1.0 if it matches the reference and 0.0 otherwise. A completion with neither marker scores 0.0, even when it states the right number. The other key settings in the recipe: Under the hood, each step of train_single_turn samples group_size completions per prompt, scores them, and computes each completion’s advantage relative to its group. It then runs forward_backward with the GRPO loss, optim_step, and weights_sync, so the next step samples from the updated model. How post-training runs GRPO explains each piece.

Step 3: Run training

The recipe provisions a model resource with one generator replica, waits for it to become ready, and then prints a few lines per step. You should see output like this:
The bracketed prefix on each step line, [3f8b2c7d], is the first eight characters of the session ID.

Step 4: Monitor the run

The step log and the grpo-gsm8k project in Weights & Biases report the same metrics. On a first run, watch these: The loss line is a poor progress signal for GRPO, so track accuracy instead. Monitoring covers the other metrics and how to act on them.

Step 5: Retrieve the trained model

When training finishes, the recipe saves a final inference checkpoint and prints its ID:
To download the weights, retrieve the session and pass the ID of its final inference checkpoint to download_checkpoint. The session ID is in the run’s manifest.json and on the Session ready line of the training output. The merged variant is the full model, about 72 GB for Qwen3.6 35B A3B, so check your free disk space first:
To serve the model on Together AI instead, see Deploy a checkpoint.
You trained a model with GRPO, watched it learn, and retrieved the result.

Confirm the resource stopped

The recipe stops the session and the model resource when it exits, so billing has already ended. If the run was interrupted, the resource may still be billing, or it may not be ready yet and start billing once it is. This script finds your resources that are waiting for capacity (PENDING), starting up (CREATING), or ready (READY), and stops each one:
created_by="me" limits the list to resources you created, so the script leaves other people’s resources in a shared project alone. force=True also stops any session that’s still attached. Without it, the API refuses to stop a resource while a session is active. If you have other runs in progress, the script stops their resources too. To stop only this run’s resource, pass the ID from the [model-resources:<id>] created line in the run’s output to client.post_training.model_resources.stop("your_resource_id", force=True). You can also stop resources from the Model resources tab under Post-training in the console. Manage model resources covers stopping, idle timers, and what a resource costs while it runs.

Next steps

Reinforcement learning with GRPO

Group size, clipping, dynamic sampling, overlong handling, and async training.

Reward functions

Bring your own dataset and reward to the GSM8K loop.

Concepts

How work splits between your code and Together AI GPUs, and the model resources, sessions, and checkpoints behind each run.

Deploy a checkpoint

Deploy the trained model on dedicated model inference.