Kurs: sieci neuronowe od środka · Lekcja 8 z 12 · 13 min
Przeuczenie w sieciach: dropout i wczesne zatrzymanie
W skrócie
Sieć zapamiętuje 299 cyfr treningowych bez błędu. Dropout i wczesne zatrzymanie mają to hamować. Ile dają i czemu mniejsza luka nie znaczy lepszej sieci?
Rozgrzewka Dwa pytania z kursu ML, na których ta lekcja się opiera. Minuta, a lekcji nie blokuje.
W kursie ML przeuczenie wyglądało tak: model zna dane treningowe lepiej niż nowe. Sieć ma tyle wag, że potrafi zapamiętać każdy przykład. Dwa najczęstsze hamulce w sieciach to dropout i wczesne zatrzymanie. Oba należą do regularyzacji: ograniczają dopasowanie do treningu w nadziei, że wynik na nowych danych wzrośnie. Ta nadzieja wymaga sprawdzenia.
Wybierz odpowiedź i pewność.
Odpowiedz, żeby odblokować lab.
Pokaż odpowiedź
Poprawna odpowiedź: Ok. 93,6%, czyli prawie tyle samo
93,6% przy p = 0,5: 1 cyfra więcej z 359. Przy jednym przebiegu treningu taka różnica niczego nie przesądza.
Spróbuj
- Lab startuje bez dropoutu: trening 100,0%, test 93,3%, luka 6,7 pkt proc. Klikaj kolejne p. Cel: po 30 epokach znajdź p z najmniejszą luką i sprawdź, co się stało z testem.
- Porównaj w tabeli kolumnę „test”. Między p = 0, 0,2 i 0,5 różnice to pojedyncze cyfry.
- Przesuń suwak epok w lewo. Zobacz, kiedy trening odrywa się od testu.
Pomysł w prostych słowach
Dropout w każdym kroku treningu wyłącza losowo ułamek p neuronów ukrytych. Za każdym razem uczy się więc trochę inna, cieńsza sieć. Żaden neuron nie może liczyć na to, że sąsiad zawsze będzie obecny, więc wiedza rozkłada się na wiele neuronów. Przy ocenie działają wszystkie.
Żeby sygnał w treningu i przy ocenie miał tę samą skalę, ocalałe neurony mnoży się w treningu przez 1/(1 − p). To odwrócony dropout: w kodzie średnia po wszystkich maskach daje dokładnie te same aktywacje co sieć bez dropoutu.
Dlaczego to działa
Sieć z 64 neuronami ukrytymi ma 2⁶⁴ możliwych masek. Dropout przypomina uczenie wielu cieńszych sieci ze wspólnymi wagami i uśrednianie ich przy ocenie. Uśrednienie wielu modeli zwykle uogólnia lepiej niż jeden, jak las losowy z kursu ML.
Dropout nie dodaje jednak informacji o cyfrach. Zmienia tylko to, jak sieć uczy się tych samych 299 przykładów. W labie najlepsze p daje 1 cyfrę więcej. Na pięciu startach wag najlepszy dropout wygrywa z brakiem dropoutu najwyżej o 4 cyfry z 359.
Wczesne zatrzymanie znasz z kursu ML (lekcja 3.6) i z rozgrzewki: przy 20% błędnych etykiet trening do 100 epok obniża test z 86,1% do 76,3%. Sieć zatrzymana po stracie walidacyjnej wraca do najlepszych wag. W sieciach działa to tak samo, bo to ten sam spadek gradientu, epoka po epoce.
Częsty błąd
Prawda czy fałsz: „Mniejsza luka między treningiem a testem oznacza lepszą sieć.” Fałsz. W labie p = 0,8 ma najmniejszą lukę: 3,7 pkt proc. zamiast 6,7. Test spadł jednak z 93,3% do 90,3%, czyli o 11 cyfr. Luka zmalała, bo trening spadł jeszcze bardziej, do 94,0%. Na pięciu startach wag p = 0,8 za każdym razem obniża i trening, i test. Ustawienie wybierasz po najlepszym wyniku na walidacji, nie po najmniejszej luce. W labie test gra rolę walidacji; w projekcie test zostaje na sam koniec.
Dla ciekawych
Luka nie zawsze rośnie z wielkością sieci. Bardzo duże sieci potrafią mieć 100% na treningu i mimo to dobrze uogólniać, a błąd testowy bywa niemonotoniczny względem liczby wag. To podwójne zejście, opisane w haśle Atlasu.
Quiz
Trzy pytania na sprawdzenie się. Wybierz odpowiedź albo rozwiń odpowiedź pod pytaniem. Z klawiatury: strzałki wybierają, Enter albo spacja zatwierdza.
Najważniejsze wnioski
- Dropout wyłącza w treningu losowe neurony, więc sieć nie może polegać na pojedynczych; przy ocenie działają wszystkie.
- Regularyzacja ma sens tylko wtedy, gdy poprawia walidację; tu najlepszy dropout to 1 cyfra więcej z 359.
- Mniejsza luka nie znaczy lepszej sieci: p = 0,8 zmniejsza lukę, obniżając obie trafności.
- Wczesne zatrzymanie działa w sieciach jak w kursie ML: wybierasz epokę po stracie walidacyjnej.
Głębiej: wzór, kod, praktyka
Matematyka
Odwrócony dropout dla neuronu i: m_i ~ Bernoulli(1 − p), h̃_i = m_i · h_i / (1 − p).
- Wartość oczekiwana:
E[h̃_i] = (1 − p) · h_i / (1 − p) = h_i, więc przy ocenie bierzemyhbez maski i bez skalowania. - Wariancja:
Var(h̃_i) = p / (1 − p) · h_i². Przy p = 0,5 toh_i², przy p = 0,8 już4 · h_i²: szum w treningu rośnie szybko z p. - Luka = trafność na treningu − trafność na teście. Regularyzacja zwykle ją zmniejsza, ale wybiera się maksimum trafności na walidacji.
- Wczesne zatrzymanie:
e = argmin_e L_val(e), a model wraca do wag z epokie.
W kodzie (Python)
Odwrócony dropout na 4 neuronach w numpy: jedna maska i średnia po wszystkich 16 maskach. Potem luka i test z wyników labu po 30 epokach:
import numpy as np
from itertools import product
# odwrócony dropout na 4 neuronach ukrytych: każdy wyłączony z prawdopodobieństwem p, ocalałe razy 1/(1-p)
h, p = np.array([0.8, 0.0, 1.5, 0.3]), 0.5
masks = np.array(list(product([0, 1], repeat=4))) # wszystkie 16 masek, każda równie prawdopodobna przy p = 0.5
outs = masks * h / (1 - p)
print("one mask (1, 0, 1, 0):", " ".join(f"{v:.2f}" for v in outs[10]))
print("mean over 16 masks: ", " ".join(f"{v:.2f}" for v in outs.mean(axis=0)))
print("without dropout: ", " ".join(f"{v:.2f}" for v in h))
# wyniki labu po 30 epokach: trafione cyfry z 299 treningowych i z 359 testowych
ps = np.array([0, 0.2, 0.5, 0.8])
train = np.array([299, 299, 298, 281]) / 299
test = np.array([335, 335, 336, 324]) / 359
gap = train - test
for q, g, t in zip(ps, gap, test):
print(f"p = {q:.1f}: gap {100 * g:3.1f} pp, test {100 * t:.1f}%")
print(f"smallest gap: p = {ps[gap.argmin()]:.1f}, best test: p = {ps[test.argmax()]:.1f}")
Wynik
one mask (1, 0, 1, 0): 1.60 0.00 3.00 0.00
mean over 16 masks: 0.80 0.00 1.50 0.30
without dropout: 0.80 0.00 1.50 0.30
p = 0.0: gap 6.7 pp, test 93.3%
p = 0.2: gap 6.7 pp, test 93.3%
p = 0.5: gap 6.1 pp, test 93.6%
p = 0.8: gap 3.7 pp, test 90.3%
smallest gap: p = 0.8, best test: p = 0.5
Jedna maska podwaja ocalałe aktywacje, ale średnio sygnał jest taki sam jak bez dropoutu. Najmniejsza luka i najlepszy test wskazują różne p. Uruchomione w numpy 2.1.3.
Pobierz notebook (.ipynb). Otwórz go w Jupyterze albo wgraj do Google Colab; brakujące dane pobierze sam.
Dla praktyka
- W PyTorch
nn.Dropout(p)działa tylko w trybiemodel.train(). Przed oceną wywołajmodel.eval(), inaczej wyniki są losowe i zaniżone. - Zacznij od małego p i patrz na walidację. Duże p, jak 0,8 w labie, częściej szkodzi niż pomaga.
- Przy wczesnym zatrzymaniu zapisuj wagi z najlepszej epoki (checkpoint) i ustaw cierpliwość większą niż drgania krzywej walidacyjnej.
- Dropout nie zastąpi danych. Przy małym zbiorze sprawdź najpierw, czy więcej przykładów albo prostsza sieć nie dają więcej.
Więcej w Atlasie
Hasła encyklopedii o pojęciach z tej lekcji: