Seeds and reproducibility
Until v0.73.0 there was no way to set a seed at all. Every run trained at 42, the framework default, and the only variation between two runs of one config was row ordering plus whatever the GPU did differently that day.
That matters more than it sounds, because a project that reports "arm A beat arm B by 0.006" needs to know what one arm does against itself. Without a seed knob, the natural spread was missing its largest source, and every measurement quoted against it was weaker than it looked.
The two keys
training:
seed: 1234 # weight init of new parameters, data order, dropout
data_seed: 99 # optional: vary data order while holding init fixedBoth are config keys, not CLI flags. There is no --seed.
- Both default to unset, not to 42. That is deliberate rather than tidy: an unset seed has to reproduce two different historical defaults, 42 for the trainer and 0 for the multipack sampler, and defaulting the field to 42 would have silently re-ordered every existing multipack run.
- An unset
seedresolves to 42; an unsetdata_seedstays unset. The fields are optional precisely so the trainer can tell "unset" from "explicitly 42". - Bounds are 0 to 2^32 - 1. Zero is legitimate. A YAML
trueis refused by name rather than coerced to 1. data_seedneeds a recent enoughaccelerate.
What changed in v0.73.1, and what did not
In v0.73.0 the seed reached the supervised trainer and nothing else. A seeded GRPO or DPO run was accepted, trained at 42, and said nothing. Seventeen of eighteen task wrappers ignored it. Replicates that differed only in their seed were the same run.
It now reaches every wrapper, and it is applied before the model loads, because the adapter's own initialisation is drawn before the trainer's seeding used to happen.
The values a run trains at are unchanged. What changed is when they arrive. An unseeded run's adapter and classification-head initialisation used to vary from process to process; it is now deterministic at 42.
What a seed does not buy you
This is the part worth reading before you design an experiment on top of it.
- It is not a determinism guarantee. For bit-exact reruns you also need PyTorch's deterministic-algorithms switch, and Soup does not set that for you.
- A resident 4-bit run is still not bit-reproducible from a seed. This is diagnosed and not fixed in the source. Never treat a resident quantised arm as reproducible.
- A streamed run is bit-reproducible: five runs, one adapter hash, zero movement on every behavioural suite. That asymmetry is real and is why the streamed arm is the control.
- The
mlxbackend reads neither field. It now says so, in its existing "MLX backend ignores" line. That is a warning rather than a rejection, because a config that is valid on transformers should not become unloadable by switching backend. Seeding MLX for real needs a separate generator and is separate work. - The multipack sampler still takes 0.
Why the ship gate cares
The consequence is concrete, and it is the reason this page sits next to the release notes rather than in a corner.
Three runs of one unchanged resident configuration moved two behavioural suites by 0.375 and 0.269, against a regression threshold of 0.05. Five of seven suites could cross the line on a re-run that changed nothing at all.
Two separate things follow, and they compose:
- Set a seed, so a replicate is a replicate.
- Measure what your instrument can resolve before you call a delta real. That is
soup ship --noise-floor, added in v0.73.2, and it exists because greedy decoding is not deterministic on a GPU either.
Neither one alone is enough. A seed removes a source of variation you control; the noise floor sizes the one you do not.
See also
- v0.73.1: the free GPU tier — where the seed reached the rest of the trainers.
- v0.73.2: the release gate — where the instrument got measured.
- v0.73.0 Borrowed Hardware — where the seed keys first shipped.
- The ship gate — the verdict these numbers feed.
Soup is free and Apache-2.0. If it saved you a training run, starring the repo costs nothing and helps most. You can also fund the GPU time behind the work a 4 GB laptop cannot reach.