A Python loop
You write
Training API · Small models
SmolGym is post-training for small language models. Your Python script keeps the data, the reward, and the loss. We run sampling, the backward pass, and the optimizer. The API is compatible with the Tinker SDK. The models stay small, and custom weights are welcome.
SFTRLLoRACustom weights
A Python loop
You write
The GPUs
We run
Small, or yours
The model
Downloadable
The weights
You own the training loop. SmolGym owns the part that is annoying to run: loading the model, sampling it, computing gradients, and keeping the checkpoint. Your script can sit on a laptop.
forward_backward() and optim_step(), for the loss you sent.One reinforcement step is sample(), your_reward(),forward_backward(), then optim_step(). Supervised training uses the same loop without sample(). The calls match the Tinker SDK. SmolGym runs them for small models, and for models you bring.
training = service.create_lora_training_client(
base_model="rack/small", # or weights you uploaded
)
for step in range(n_steps):
sampling = training.save_weights_and_get_sampling_client()
responses = sampling.sample(prompts, params).result()
rewards = your_reward(responses)
training.forward_backward(batch, loss_fn="importance_sampling")
training.optim_step(AdamParams(learning_rate=1e-4))
training.save_state("run-1")sample()Draw completions from the weights you are training.
your_reward()Score them. The verifier, the sandbox, and the judge stay in your code.
forward_backward()Send the batch and the loss. We compute the gradients.
optim_step()Apply the update on the GPUs that hold the model.
save_state()Keep optimizer state, and download the weights when you want them.
Two copies of the weights sit on the GPUs. The sampler reads one, to generate. The trainer writes the other, when you call optim_step(). Sync copies the written weights onto the sampler, so the next sample() sees the update. Your script sends the loss. It does not hold W.
Uses the last synced W. Does not train.
optim_step() is the only place W changes.
Scores and sends the batch. W stays on the GPU.
Several runs can share the loaded base. The step writes the small matrices only.
Base · held
Adapter · written
Same step, larger write. Only when the whole model still fits the floor.
All of W · written
The loss is yours. The subtraction runs on the trainer.
A batch and a loss. No sampling. The script sends examples, we run forward_backward() and optim_step().
Sample, score, update. The reward can be an exact match, a test, a rubric, or a judge.
A pairwise loss, if that is the update you want. The loop is still yours.
An adapter on a small base. Several runs can share the loaded model.
Every parameter, when an adapter is not enough, and the model still fits the floor.
Multi-turn tools, code execution, a search sandbox. You run the episode. We call sample() each turn and train on the signal you send back.
| Rack | Custom | |
|---|---|---|
| Model | A small open model we host | Weights you upload |
| Fit | One training machine | The same machine |
| Update | LoRA, or the full model | LoRA, or the full model |
| After | Download the weights | Download the weights |
The API is compatible with the Tinker SDK. The floor is one machine. If the model fits it, or the weights are already yours, the loop runs here. Change the model by changing one string, or by uploading the weights.
Send the model, whether the loop is supervised or reinforcement, and what the reward checks. If it fits the floor, you get a session: your script, our GPUs, weights you can download.
Start a run