Zum Inhalt springen
Menü der Dokumentation

Seeds und Determinismus in Forschungscode

Eine zufallsbasierte Analyse kann bei zwei Läufen zwei verschiedene Zahlen liefern. Setzen Sie Seeds im Code, machen Sie sie konfigurierbar und dokumentieren Sie verbleibende Schwankungen.

Zuletzt aktualisiert

In Ihrem Bericht

Bereich
Execution
Prüfung
Determinism & Reproducible Randomness

Warum das wichtig ist

Train/Test-Splits, Gewichtsinitialisierung, Bootstrap-Resampling, Embeddings und MCMC ziehen Zufallszahlen. Ohne festgehaltenen Seed kann niemand bei einem leicht abweichenden Ergebnis Rauschen von einem Fehler unterscheiden. Seeds zu notieren ist Regel 6 der Ten Simple Rules for Reproducible Computational Research.

Seeds reichen nicht immer: Die Reproduzierbarkeitshinweise von PyTorch warnen, dass Ergebnisse zwischen Releases und Plattformen sowie zwischen CPU und GPU abweichen können, selbst mit identischen Seeds.

So sieht gute Praxis aus

  • Ein Seed, nahe dem Einstiegspunkt gesetzt und an alles weitergereicht, was Zufallszahlen zieht: Pythons random, NumPy, PyTorch, scikit-learn und Data-Loader-Worker.
  • Der Seed wird mit jedem Ergebnis gespeichert und lässt sich über Kommandozeile oder Konfigurationsdatei ändern.
  • Notebooks sowie R-Markdown- und Quarto-Berichte setzen den Seed in der ersten Zelle oder im ersten Chunk.
  • Parallele Jobs nutzen eigene reproduzierbare Zufallsströme, etwa future.seed = TRUE in R.
  • Schwankungen zwischen Läufen, etwa durch GPU-Kernel, stehen mit typischer Größenordnung im README.

So beheben Sie es

Python und PyTorch. Lesen Sie den Seed von der Kommandozeile und setzen Sie alle Generatoren an einer Stelle, auch für Data-Loader-Worker:

python
import argparse, random
import numpy as np
import torch

parser = argparse.ArgumentParser()
parser.add_argument("--seed", type=int, default=0)
args = parser.parse_args()

random.seed(args.seed)
np.random.seed(args.seed)
torch.manual_seed(args.seed)
torch.use_deterministic_algorithms(True)  # error on nondeterministic ops

def seed_worker(worker_id):
    worker_seed = torch.initial_seed() % 2**32
    np.random.seed(worker_seed)
    random.seed(worker_seed)

g = torch.Generator()
g.manual_seed(args.seed)
loader = torch.utils.data.DataLoader(
    dataset, num_workers=4,
    worker_init_fn=seed_worker, generator=g,
)

Auf GPUs braucht der deterministische Modus weitere Einstellungen, aufgeführt in den Hinweisen von PyTorch. Übergeben Sie in scikit-learn random_state=args.seed an jeden Schätzer und Splitter.

R. Setzen Sie den Seed einmal am Anfang. Für parallelen Code liefert future.seed = TRUE dieselben Zufallszahlen, unabhängig von der Zahl der Worker:

R
args <- commandArgs(trailingOnly = TRUE)
seed <- if (length(args) > 0) as.integer(args[1]) else 42L
set.seed(seed)

library(future.apply)
future::plan(future::multisession, workers = 4)
boot <- future_lapply(1:1000, function(i) mean(sample(x, replace = TRUE)),
                      future.seed = TRUE)

Diese Prüfung für Ihr Repository

Jede Analyse liefert Befunde zu dieser Prüfung, mit Dateiverweisen und Korrekturvorschlägen.