ML Atlas

10 · Praktyka · 3 min czytania · aktualizacja

Jak zapewnić powtarzalność wyników w uczeniu maszynowym?

W skrócie

Powtarzalność to możliwość odtworzenia wyniku: te same dane, kod, wersje bibliotek i ziarna losowości, a także raport rozrzutu wyniku między ziarnami.

Co to jest

Powtarzalność (reproducibility) eksperymentu ML oznacza, że ktoś inny — albo ty za pół roku — uruchamiając ten sam kod na tych samych danych dostanie ten sam wynik. W szerszym sensie oznacza też, że wniosek („model B jest lepszy od A”) przetrwa zmianę rzeczy, które nie powinny mieć znaczenia: ziarna losowości, kolejności danych, sprzętu.

Te dwa poziomy warto odróżniać. Pierwszy to inżynieria: ustalone ziarna, zamrożone wersje, zapisane dane. Drugi to statystyka: nawet idealnie odtwarzalny wynik może być przypadkiem jednego szczęśliwego ziarna. Wynik, który znika przy innym random_state, był odtwarzalny, ale nieprawdziwy.

Mechanizm — dlaczego tak działa

Losowość jest w ML wszędzie: podział na zbiory i foldy, tasowanie mini-batchy, inicjalizacja wag, losowanie cech i próbek w lasach, dropout, augmentacja. Każde z tych źródeł zmienia wynik o trochę, a „trochę” bywa tej samej wielkości co różnica, którą chcemy zgłosić. Ustalenie ziarna zamraża jedną konkretną realizację tej losowości — nie usuwa jej wpływu, tylko go ukrywa.

Do tego dochodzą źródła mniej oczywiste. Wersja biblioteki może zmienić domyślny hiperparametr albo algorytm. Obliczenia równoległe na GPU sumują liczby zmiennoprzecinkowe w różnej kolejności, a dodawanie zmiennoprzecinkowe nie jest łączne, więc wyniki różnią się na ostatnich bitach — w długim treningu sieci te różnice potrafią urosnąć. Dane „z bazy” zmieniają się między uruchomieniami, jeśli nie zostały zapisane w konkretnej wersji.

Stąd dwie strategie. Inżynierska: zapisz wszystko, co wpływa na wynik — ziarna, wersje pakietów (plik z zamrożonymi wersjami, kontener), skrót lub wersję danych, konfigurację, commit kodu. Statystyczna: powtórz eksperyment dla kilku ziaren i kilku podziałów, a zgłaszaj średnią i rozrzut. Różnica między modelami jest wiarygodna dopiero wtedy, gdy jest wyraźnie większa niż rozrzut każdego z nich.

Uwaga na pułapkę: wybieranie najlepszego ziarna to też strojenie hiperparametru, tylko bezwartościowego. Taki wynik jest obciążony w górę dokładnie tak samo jak wybór najlepszego z wielu modeli na jednym zbiorze walidacyjnym.

Na przykładzie

Titanic, las losowy ze 100 drzewami, 5-krotna walidacja krzyżowa. Przy ustalonym podziale na foldy i 10 różnych ziarnach modelu wynik waha się od 80,7% do 81,6% (odchylenie standardowe 0,3 punktu procentowego). Przy ustalonym ziarnie modelu i 10 różnych ziarnach podziału na foldy: od 80,1% do 82,6% (odchylenie 0,7 punktu). Losowość podziału danych waży tu więcej niż losowość samego modelu.

Jeszcze wyraźniej widać to przy pojedynczym podziale 80/20. Ta sama regresja logistyczna, oceniana na 179 pasażerach odłożonych z 10 różnymi ziarnami, osiąga od 78,8% do 84,4% — rozpiętość 5,6 punktu. Ktoś, kto porównuje dwa modele na jednym takim podziale, może z powodzeniem „udowodnić” dowolną kolejność.

Dane: Titanic

W praktyce

  • Ustaw random_state w każdym losowym obiekcie scikit-learn (train_test_split, KFold(shuffle=True), modele), a w PyTorch torch.manual_seed, numpy.random.seed, random.seed.
  • Dla pełnego determinizmu w PyTorch: torch.use_deterministic_algorithms(True) i torch.backends.cudnn.benchmark = False — kosztem szybkości.
  • Zapisuj wersje: pip freeze > requirements.txt lub plik lock, najlepiej kontener; dane wersjonuj (skrót pliku, DVC, snapshot).
  • Raportuj średnią ± odchylenie z co najmniej 3–5 ziaren lub z RepeatedStratifiedKFold, nie pojedynczy przebieg.
  • Porównując modele, używaj tych samych foldów dla obu — różnice parami są mniej zaszumione niż wyniki osobno.
  • Typowy błąd: ustawione jedno ziarno globalne i przekonanie, że wynik jest „pewny”.

Najczęstsze pytania

Ustawiłem ziarno, a wyniki na GPU i tak się różnią. Dlaczego?
Część operacji na GPU (np. niektóre sploty i sumowania atomowe) jest niedeterministyczna, bo kolejność dodawania liczb zmiennoprzecinkowych zależy od harmonogramu wątków. PyTorch pozwala wymusić wersje deterministyczne, ale nie dla każdej operacji i zwykle wolniej.
Ile ziaren wystarczy?
Do szybkiej orientacji 3–5, do publikacji lub ważnej decyzji więcej, zależnie od rozrzutu. Ważniejsze od liczby jest porównanie: jeśli rozrzut między ziarnami jest tej samej wielkości co różnica między modelami, potrzeba więcej powtórzeń albo więcej danych, a nie lepszego ziarna.
Czy powtarzalność to to samo co replikowalność?
Terminologia nie jest jednolita. Często „odtwarzalność” oznacza ten sam wynik z tym samym kodem i danymi, a „replikację” — ten sam wniosek przy niezależnej implementacji lub nowych danych. Druga jest mocniejszym testem prawdziwości wyniku.

Źródła

  • Pineau J. i in. „Improving Reproducibility in Machine Learning Research (A Report from the NeurIPS 2019 Reproducibility Program)”, Journal of Machine Learning Research 22, 2021.
  • Henderson P. i in. „Deep Reinforcement Learning that Matters”, AAAI 2018.
  • Bouthillier X., Laurent C., Vincent P. „Unreproducible Research is Reproducible”, ICML 2019.
  • Dokumentacja PyTorch: „Reproducibility”, https://pytorch.org/docs/stable/notes/randomness.html
  • Dokumentacja scikit-learn: „Controlling randomness”, https://scikit-learn.org/stable/common_pitfalls.html

Zobacz też