ML Atlas

Kurs: sieci neuronowe od środka · Lekcja 7 z 12 · 14 min

Głęboka sieć: gdy sygnał nie dociera

W skrócie

Więcej warstw nie znaczy mocniejsza sieć. Bez właściwej budowy sygnał błędu gaśnie, zanim dotrze do pierwszych warstw. Cztery lekarstwa naprawiają to od środka.

Rozgrzewka Dwa pytania z kursu ML, na których ta lekcja się opiera. Minuta, a lekcji nie blokuje.
Z kursu ML, lekcja 1.6: Spadek gradientu: nauka małymi krokami Co gradient mówi algorytmowi w każdym kroku?

Pokaż odpowiedź

Poprawna odpowiedź: W którą stronę i jak stromo rośnie strata w bieżącym punkcie

Gradient wskazuje w górę, więc krok w przeciwną stronę obniża stratę, ale opisuje tylko najbliższe otoczenie bieżącego punktu.

Z kursu ML, lekcja 7.1: Sieci neuronowe: wiele prostych elementów razem Dlaczego sieć neuronowa potrzebuje funkcji aktywacji?

Pokaż odpowiedź

Poprawna odpowiedź: Bo bez niej kilka warstw działa jak jedna ważona suma i rysuje prostą

Aktywacja zagina sygnał; bez zgięć kolejne warstwy nie dodają nic ponad jeden model liniowy.

W lekcji 5 gradient płynął od straty do wag i w każdym węźle mnożył się przez lokalną pochodną. W jednym neuronie to kilka mnożeń. W sieci z 10 warstwami gradient pierwszej warstwy to iloczyn pochodnych wszystkich warstw nad nią. Jeśli każda z tych liczb jest mniejsza od 1, iloczyn maleje wykładniczo. To zanikający gradient: pierwsze warstwy prawie się nie uczą, choć reszta sieci jest gotowa.

Przewidź, potem sprawdź Sieć z 10 warstwami ukrytymi po 16 neuronów z tanh, bez skrótów, uczy się 5 epok na cyfrach. Ta sama sieć z 2 warstwami trafia 79,7%. Jaką trafność na teście będzie mieć sieć z 10 warstwami?
Jak bardzo jesteś pewny(-a)?

Eksperyment

Ten interaktywny eksperyment działa w przeglądarce z włączonym JavaScriptem. Tekst wokół opisuje, co w nim widać. W eksperymencie: Przy 10 warstwach po 16 neuronów (tanh, bez normalizacji) zwykła sieć ma tuż po starcie gradient warstwy 1 równy 1,4·10⁻³ i po 5 epokach zostaje na 10,3% (poziom zgadywania), a ta sama sieć ze skrótami ma gradient 1,65 i osiąga 94,4%.

Pokaż odpowiedź

Poprawna odpowiedź: Ok. 10%, czyli zgadywanie

10,3%, czyli poziom zgadywania. Tuż po losowaniu wag gradient wag warstwy 1 ma normę 1,4·10⁻³. Ta sama sieć ze skrótami ma gradient 1,65 i po 5 epokach trafia 94,4%.

Spróbuj

  • Lab startuje z 10 warstwami bez skrótów: 10,3%. Włącz to, co pozwala tej sieci się uczyć. To cel labu.
  • Na górnym wykresie porównaj sygnał wsteczny w warstwie 1 i w ostatniej. Bez skrótów linia opada w stronę wejścia, ze skrótami nie.
  • Przesuń suwak na 2 warstwy, potem na 6 i 8. Zwykła sieć traci trafność z każdą warstwą: 79,7%, 28,1%, 13,6%.
  • Ustaw 20 warstw: gradient warstwy 1 zwykłej sieci spada do 5,7·10⁻⁶.

Pomysł w prostych słowach

Wyobraź sobie głuchy telefon przez 10 osób, z których każda mówi ciszej niż usłyszała. Na końcu nikt nic nie słyszy. Tak działa droga wstecz w głębokiej sieci bez skrótów. W labie każda warstwa mnoży sygnał wsteczny średnio przez ok. 0,56. Bierze się to z małych wag na starcie i z pochodnej tanh, która nie przekracza 1.

Po 10 warstwach do pierwszej warstwy dociera mniej niż 1% sygnału, który dostała ostatnia warstwa ukryta. Pierwsza warstwa dostaje prawie zerowy gradient, więc jej wagi stoją. Zostają losowe, a reszta sieci próbuje rozpoznawać cyfry z losowego przekształcenia pikseli. Sieć się nie uczy, choć niczego jej nie brakuje poza drogą dla sygnału.

Dlaczego to działa

Lekarstwa są cztery i każde łamie ten iloczyn w innym miejscu.

  1. ReLU zamiast sigmoidy i tanh. Pochodna sigmoidy nie przekracza 0,25, więc same pochodne 20 warstw dają razem czynnik najwyżej 0,25 do potęgi 20. Przy małych wagach, jak na starcie, gradient traci jeszcze więcej. Duże wagi mogą to zrównoważyć, ale łatwo wtedy o wybuchający gradient albo nasycenie sigmoidy. Pochodna ReLU dla dodatnich wejść wynosi 1.
  2. Inicjalizacja He. ReLU zeruje mniej więcej połowę wejść, więc wagi muszą być odpowiednio większe, żeby sygnał nie słabł. W widżecie zanikającego gradientu 20 warstw sigmoidy z inicjalizacją Xaviera daje stosunek gradientu pierwszej warstwy do ostatniej 2,4·10⁻¹³, a ReLU z He 2,19.
  3. Normalizacja (BatchNorm, LayerNorm) po każdej warstwie sprowadza sygnał w przód do stałej skali, więc on nie gaśnie ani nie rośnie. Gradientom w tył zwykle też pomaga, choć tego nie gwarantuje.
  4. Skróty: warstwa liczy h + F(h) zamiast F(h). Pochodna to 1 + ∂F/∂h, więc nawet gdy ∂F/∂h jest małe, gradient przechodzi przez jedynkę bez strat. W labie gradient warstwy 1 rośnie dzięki skrótom ponad 1000 razy.

Nowoczesne głębokie sieci, w tym transformery, łączą skróty z normalizacją. Bez tych dwóch trudno byłoby wytrenować dziesiątki warstw.

Częsty błąd

Prawda czy fałsz: „Głęboka sieć, która się nie uczy, potrzebuje więcej danych albo więcej epok.” Fałsz. Tu sygnał błędu nie dociera do pierwszych warstw już tuż po losowaniu wag, zanim zobaczą jakiekolwiek dane. Więcej epok prawie nie pomaga. Zwykła sieć z 10 warstwami uczona 20 epok zamiast 5, na pięciu startach wag, ani razu nie przekracza 25%. Ta sama sieć ze skrótami po 5 epokach przekracza 90% na każdym z tych startów. Pomaga zmiana budowy: skróty, ReLU, inicjalizacja, normalizacja.

Quiz

Trzy pytania na sprawdzenie się. Wybierz odpowiedź albo rozwiń odpowiedź pod pytaniem. Z klawiatury: strzałki wybierają, Enter albo spacja zatwierdza.

1. Dlaczego w sieci z 10 warstwami tanh pierwsza warstwa prawie się nie uczy?
Pokaż odpowiedź

Poprawna odpowiedź: Bo jej gradient to iloczyn pochodnych 10 warstw, a każda liczba jest mniejsza od 1

W labie każda warstwa mnoży sygnał wsteczny średnio przez ok. 0,56; w pierwszej warstwie zostaje mniej niż 1% sygnału z ostatniej.

2. Co robi skrót w warstwie h + F(h)?
Pokaż odpowiedź

Poprawna odpowiedź: Daje gradientowi drogę bez strat: pochodna to 1 + ∂F/∂h

Nawet gdy ∂F/∂h jest małe, jedynka przenosi gradient do wcześniejszych warstw.

3. Dlaczego z ReLU używa się inicjalizacji He, a nie Xaviera?
Pokaż odpowiedź

Poprawna odpowiedź: Bo ReLU zeruje mniej więcej połowę wejść, a He daje wagom dwa razy większą wariancję, żeby sygnał nie słabł

Przy Xavierze sygnał przez ReLU traci połowę wariancji na warstwę; He to wyrównuje.

Najważniejsze wnioski

  • Gradient pierwszej warstwy to iloczyn pochodnych wszystkich warstw nad nią; liczby mniejsze od 1 dają iloczyn bliski zera.
  • Głęboka sieć bez właściwej budowy uczy się gorzej niż płytka, bo jej pierwsze warstwy stoją.
  • Cztery lekarstwa: ReLU, inicjalizacja He, normalizacja i skróty.
  • Więcej epok nie naprawi sygnału, który nie dociera; pomaga zmiana budowy.

Głębiej: wzór, kod, praktyka

Matematyka

Sieć bez skrótów: h_{k+1} = tanh(W_k·h_k + b_k). Reguła łańcuchowa: ∂L/∂h_1 = J_1ᵀ·J_2ᵀ· … ·J_{n}ᵀ · ∂L/∂h_{n+1}, gdzie J_k = diag(tanh′(z_k))·W_k.

  • Jeśli każdy czynnik zmniejsza normę c < 1 razy, po n warstwach zostaje cⁿ; w labie c ≈ 0,56.
  • Pochodna sigmoidy ≤ 0,25, więc iloczyn samych pochodnych 20 warstw to najwyżej 0,25²⁰. Cały czynnik zawiera jeszcze wagi W_k. W łańcuchu jednej liczby z wagami |w| ≤ 1 jest jeszcze mniejszy; duże wagi mogą go podnieść ponad 1: 10 warstw z wagą 6 i biasem −3 daje 57,7.
  • Wariancja sygnału przez warstwę ReLU o n wejściach: Var(h_{k+1}) ≈ n · Var(w) / 2 · Var(h_k). Xavier (Var(w) = 2/(n_in + n_out)) daje przy n_in = n_out czynnik 1/2, He (Var(w) = 2/n) czynnik 1.
  • Skrót: h_{k+1} = h_k + F(h_k), więc ∂h_{k+1}/∂h_k = I + ∂F/∂h_k.
W kodzie (Python)

Skalarny szkic zanikającego gradientu w numpy: jeden sygnał przez 10 warstw z tanh, z jednym wzmocnieniem w na każdej warstwie. Do tego granica dla pochodnych sigmoidy, trzy łańcuchy sigmoid z różnymi wagami i wariancja sygnału przy Xavierze i He:

import numpy as np

# jeden sygnał przez 10 warstw: zwykła h <- tanh(w*h), ze skrótem h <- h + tanh(w*h)
w, depth = 0.58, 10  # 0.58 ≈ sqrt(1/3): typowe wzmocnienie warstwy po inicjalizacji jak w PyTorch
for name, skip in [("plain", False), ("residual", True)]:
    h, grad = 1.0, 1.0
    for _ in range(depth):
        local = w * (1 - np.tanh(w * h) ** 2)   # pochodna tanh(w*h) po h
        grad *= 1 + local if skip else local    # reguła łańcuchowa: mnożymy lokalne pochodne
        h = h + np.tanh(w * h) if skip else np.tanh(w * h)
    print(f"{name:8s}: signal {h:.3g}, gradient dh10/dh0 = {grad:.3g}")

# pochodne sigmoidy dają razem najwyżej 0.25 ** 20; cały gradient mnoży się jeszcze przez wagi
print(f"sigmoid, 20 layers: derivative factor at most x{0.25 ** 20:.2g}")
sigmoid = lambda z: 1 / (1 + np.exp(-z))
for w, b in [(1, 0), (6, -3), (6, 0)]:  # 10 warstw h <- sigmoid(w*h + b), start h = 0.5
    h, grad = 0.5, 1.0
    for _ in range(10):
        s = sigmoid(w * h + b)
        grad *= w * s * (1 - s)                 # waga razy pochodna sigmoidy
        h = s
    print(f"sigmoid, 10 layers, w={w}, b={b}: dh10/dh0 = {grad:.3g}, signal {h:.3g}")

# wariancja sygnału w 20 warstwach ReLU po 32 neurony: ReLU zeruje połowę, więc warstwa mnoży ją przez n * var_w / 2
n = 32
for name, var_w in [("Xavier", 2 / (n + n)), ("He", 2 / n)]:
    print(f"{name:6s}: x{n * var_w / 2:.2f} per layer, x{(n * var_w / 2) ** 20:.2g} after 20 layers")

Wynik

plain   : signal 0.00371, gradient dh10/dh0 = 0.00274
residual: signal 10, gradient dh10/dh0 = 2.31
sigmoid, 20 layers: derivative factor at most x9.1e-13
sigmoid, 10 layers, w=1, b=0: dh10/dh0 = 3.48e-07, signal 0.659
sigmoid, 10 layers, w=6, b=-3: dh10/dh0 = 57.7, signal 0.5
sigmoid, 10 layers, w=6, b=0: dh10/dh0 = 1.39e-17, signal 0.997
Xavier: x0.50 per layer, x9.5e-07 after 20 layers
He    : x1.00 per layer, x1 after 20 layers

Szkic na jednej liczbie daje ten sam rząd wielkości co prawdziwa sieć w labie: gradient warstwy 1 bez skrótów rzędu 10⁻³, ze skrótami powyżej 1. Ze skrótem sygnał w przód rośnie, bo każda warstwa coś do niego dodaje. Dlatego w praktyce skróty idą w parze z normalizacją. Granica 0,25²⁰ dotyczy samych pochodnych. Łańcuch sigmoid z wagą 1 traci jeszcze więcej niż 0,25¹⁰. Z wagą 6 i biasem −3 sygnał siedzi w środku sigmoidy i gradient rośnie 57,7 razy. Z wagą 6 bez biasu sigmoida się nasyca i zostaje 1,4·10⁻¹⁷. Uruchomione w numpy 2.1.3.

Dla praktyka
  • Głęboka sieć uczy się gorzej niż płytsza? Najpierw sprawdź normy gradientów warstw na pierwszej paczce, jak w labie. Spadek o rzędy wielkości w stronę wejścia to zanikający gradient.
  • Standardowy zestaw: ReLU albo GELU, inicjalizacja He (w PyTorch kaiming_normal_), normalizacja i skróty omijające co jedną lub dwie warstwy.
  • Gradient rosnący w stronę wejścia to odwrotny kłopot, wybuchający gradient. Pomaga przycinanie normy gradientu i mniejszy krok.
  • Zanim dodasz warstwy, sprawdź, czy płytsza sieć już nie wystarcza. Głębokość pomaga dopiero wtedy, gdy sygnał ma którędy płynąć.

Więcej w Atlasie

Hasła encyklopedii o pojęciach z tej lekcji: