simulate_for_sbi and simulate_in_batches seeded through seed_all_backends, which
also sets torch.backends.cudnn.deterministic and clears benchmark. Both flags are
global to the process, so simulating switched convolutional training running later
in the same session onto deterministic cuDNN algorithms.
The seeding moves to seed_random_states in sbi/utils/sbiutils.py, and
seed_all_backends calls it before setting the two flags, which keeps its behavior
for the autouse fixture in tests/conftest.py and for existing callers. The
simulation paths, including the simulator_seeded closures used with num_workers >
1, call seed_random_states instead.
Seeding itself is unchanged: with seed=None the seed is still drawn from the torch
random state, so an upstream torch.manual_seed keeps reproducing a
simulate_for_sbi(seed=None) call, and the per-batch seeds are drawn from the same
state as before.
Fixes sbi-dev#2159
What does this PR do?
simulate_for_sbiandsimulate_in_batchesseed the random states withseed_all_backends, which also setstorch.backends.cudnn.deterministic = Trueandtorch.backends.cudnn.benchmark = False. Those are global to the process, so one call toa simulation helper switched the rest of the session to deterministic cuDNN algorithms and
could slow down later training of convolutional embedding nets.
This separates the two concerns.
seed_random_statesdraws the seed and seedsrandom,numpy, torch and torch.cuda.
seed_all_backendsis now that call plus the two cuDNN lines,so its behavior is unchanged for the autouse fixture in
tests/conftest.pyand for thetest call sites. The simulation paths use
seed_random_states.Seeding itself does not change: with
seed=Nonethe seed is still drawn from PyTorch'srandom state, so an upstream
torch.manual_seedkeeps reproducing asimulate_for_sbi(seed=None)call, and the per-batch seeds used whennum_workers > 1aredrawn from the same state as before.
Does this close any issues?
Fixes #2159
Anything else we should know?
seed_all_backends. I used a second function instead: acall like
seed_all_backends(seed, deterministic_cudnn=False)reads as a contradiction,and this way
seed_all_backendskeeps exactly its current meaning for the people who dowant bit-reproducible convolutions. Say the word if you would rather have the flag.
simulator_seededclosures. That PR is still open, so this onetargets
main; I will rebase once feat: parallel simulation with simulate_from_theta and parallelize_simulator #1738 lands to keep the two in sync.seed_random_statesinsbi/utils/__init__.py, matchingseed_all_backends, which is imported fromsbi.utils.sbiutilsby the tests that useit. No public API is added or changed.
seed_all_backendsare the only place the package touches cuDNN, and nonotebook or page in
docs/mentions it, so there is nothing else to update.simulate_for_sbicall to quietly maketheir convolutional training deterministic now gets the torch default, and has to call
seed_all_backends(seed)or set the flags themselves. That is the point of the issue, butit is still a behavior change worth a line in the release notes.
How I checked it:
The repro from the issue (
simulate_for_sbi(lambda t: t, BoxUniform(...), 5)then printingtorch.backends.cudnn.deterministic) printsTrueonmainandFalsehere.test_simulating_leaves_cudnn_flagsfails onmainfor bothseed=Noneandseed=42and passes with the change. The fixture sets
deterministic=False, benchmark=Truebeforethe call on purpose: at the all-
Falsedefault a test cannot tell "left alone" from"set to False", so it would pass without the fix.
num_workers > 1the seeded simulator runs in a worker process, whose flags theparent cannot see, so that call site is covered by the direct
seed_random_statestestrather than by pretending the end-to-end test observes it.
simulate_for_sbiatnum_workers1 and 2 andsimulate_in_batchesatnum_workers=2return identicalxforseed=42across twocalls, and
seed=Noneis still reproduced by an upstreamtorch.manual_seed(0).slow.pytest -n auto -m "not slow and not gpu"gives 7180 passed, 25 skipped, 116 xfailed in 5:31, andruff,pyright sbiandpre-commit run --all-filespass.I used Claude to explore the code, sanity-check the plan and draft this
patch and its tests, and verified the behavior locally as described above.
Checklist
uv run pytest -n auto -m "not slow and not gpu"passes.uv run pre-commit run --all-filespasses (ruff and formatting).uv run pyright sbipasses.with
pytest.mark.slow.