The core loop
For each prompt in a batch:- Sample
rollouts_per_promptcompletions from the current policy - Score every completion with your reward function
- Compute advantage:
(reward - group_mean) / (group_std + epsilon) - Update policy to make above-average completions more likely (bounded by KL distance from the reference model)
Hyperparameters
Every field of the GRPO hyperparameters, with defaults:LoRA and QLoRA
By default Veri full-finetunes the base model. To train low-rank adapters instead, setlora_rank (and optionally lora_alpha). For QLoRA, also set load_in_4bit: the base loads in 4-bit (NF4) and you train adapters on top, which cuts VRAM roughly 4x and lets larger models fit on a single GPU.
LoRA (16-bit base, multi-GPU capable):
load_in_4bit requires lora_rank: the 4-bit base is frozen, so training happens in the adapters. QLoRA runs on a single GPU today; for multi-GPU, use 16-bit LoRA (lora_rank without load_in_4bit). Adapters target the attention and MLP projections (q/k/v/o, gate/up/down).artifact_type: "adapter" on GET /v1/training_jobs/{id}/model), and Veri also keeps the merged weights (adapter merged into the base model, merged_files on the same call). A LoRA job deploys like a full fine-tune (veri deploy <job_id>, or source="training_job" in the API) and is served from the merged weights; saving it to your model library saves the merged weights too, and artifact="adapter" saves the adapter alone for multi-adapter fleets. To publish either artifact to Hugging Face, see Hugging Face.
Picking values
For first runs, change two things:max_response_length: drop to512if you’re hitting OOM, raise to4096for tasks that need long outputs (reasoning, code)max_steps: set to50to100for smoke tests, then raise it for the real run (omitting it means 100 steps)
learning_rate=1e-6for full finetuning; with LoRA, a LoRA-scale rate such as2e-5rollouts_per_prompt=8: sweet spot for advantage signal vs. compute. Drop to4only if you’re cost-constrainedkl_coef: leave it unset (0.0, no reference model). If outputs drift into incoherence, set0.001to0.01
Common failure modes
Policy collapse:entropy → 0, model produces identical outputs for every prompt. Cause: KL coefficient too low, learning rate too high, or reward function gives the same score to too many completions. Lower learning_rate, raise kl_coef.
Reward hacking — Reward goes up, but outputs become weird (gaming the reward function rather than solving the task). Tighten the reward — add format checks, length penalties, or a frontier judge as a sanity scorer.
Length explosion: completions/mean_length grows toward max_response_length without reward improving. Add a length penalty to the reward, or drop max_response_length.
Reading the metrics
Pull metrics withGET /v1/training_jobs/{id}/metrics (or the dashboard if you’re integrated with W&B):
Sample hyperparameter blocks
Smoke test (small model on one L4, LoRA):When NOT to use GRPO
If your model can’t follow the format you want yet (e.g. won’t wrap answers in<answer> tags), do an SFT pass first to teach the structure, then GRPO to reinforce correctness. RL works better when the policy already has non-zero probability of producing the right shape.
Where to go next
Reward functions
Design rewards GRPO can actually optimize against.
Datasets
Get training data into Veri.
Submit a job
Wire it all into
training_jobs.create.
