ML Atlas

06 · Sieci · 4 min czytania · Interaktywne · aktualizacja

Na czym polega propagacja wsteczna (backpropagation) w sieciach neuronowych?

W skrócie

Propagacja wsteczna liczy, jak strata zależy od każdej wagi sieci, przesyłając sygnał błędu od wyjścia do wejścia zgodnie z regułą łańcuchową.

Co to jest

Propagacja wsteczna (ang. backpropagation, w skrócie backprop) to algorytm obliczania gradientu funkcji straty względem wszystkich wag sieci neuronowej. Stosuje regułę łańcuchową warstwa po warstwie, od wyjścia do wejścia, i wykorzystuje wyniki pośrednie zapamiętane podczas przejścia w przód. Dzięki temu gradient milionów wag kosztuje tylko kilka razy więcej niż jedno przejście w przód.

Sama propagacja wsteczna niczego nie „uczy”. Odpowiada tylko na pytanie: o ile zmieniłaby się strata, gdyby tę konkretną wagę lekko zwiększyć? Uczeniem zajmuje się optymalizator, np. spadek gradientu, który na podstawie tej odpowiedzi przesuwa wagi w stronę mniejszej straty.

Intuicja: po przegranym meczu trener nie zmienia wszystkiego naraz. Ustala, kto i w jakim stopniu przyczynił się do wyniku: najpierw ostatnie podanie, potem zagranie, które do niego doprowadziło, i tak dalej wstecz. Propagacja wsteczna robi to samo z błędem, dzieląc „odpowiedzialność” między neurony proporcjonalnie do ich wpływu na wynik.

Mechanizm — dlaczego tak działa

Sieć to złożenie funkcji: strata L zależy od wyjścia y, y od sumy z ostatniej warstwy, z od aktywacji h warstwy ukrytej, a h od wag W₁. Reguła łańcuchowa mówi, że pochodne złożenia się mnożą: ∂L/∂W₁ = ∂L/∂y · ∂y/∂z · ∂z/∂h · ∂h/∂W₁. Propagacja wsteczna liczy ten iloczyn od lewej strony, czyli od straty, i każdy częściowy wynik wykorzystuje ponownie dla wszystkich wag niższej warstwy.

To ponowne użycie jest całym sekretem wydajności. Naiwna metoda, czyli lekkie zaburzenie każdej wagi i ponowne przejście w przód, wymaga tylu przejść, ile jest wag. Przy milionie wag to milion przejść. Propagacja wsteczna potrzebuje jednego przejścia w przód i jednego wstecz, bo sygnał błędu δ = ∂L/∂z dla danej warstwy jest liczony raz i rozsyłany do wszystkich jej wag: ∂L/∂W = δ · (wejście warstwy).

Przejście sygnału przez warstwę wstecz to dwie operacje. Mnożenie przez transponowaną macierz wag rozdziela błąd między neurony poprzedniej warstwy (δ_h = Wᵀ·δ). Mnożenie przez pochodną aktywacji f'(z) wycisza neurony, które w przejściu w przód były mało czułe. Dla sigmoidy f'(z) = σ(z)(1 − σ(z)) ≤ 0,25, więc w głębokiej sieci sygnał może słabnąć z warstwy na warstwę. To źródło zjawiska zanikającego gradientu. Dla ReLU pochodna wynosi 1 albo 0, co zmniejsza ten problem, ale tworzy ryzyko „martwych” neuronów.

Propagacja wsteczna jest szczególnym przypadkiem automatycznego różniczkowania w trybie odwrotnym. Współczesne biblioteki nie wymagają ręcznego wyprowadzania wzorów: zapisują graf operacji z przejścia w przód i automatycznie przechodzą go wstecz. Pomysł był odkrywany niezależnie kilka razy, a w uczeniu sieci spopularyzowała go praca Rumelharta, Hintona i Williamsa z 1986 roku.

Ograniczenie: gradient mówi tylko, jak zmienić wagi, żeby strata zmalała lokalnie, w nieskończenie małym otoczeniu. Nie gwarantuje znalezienia minimum globalnego ani dobrego uogólnienia. To zadanie optymalizatora, inicjalizacji i regularyzacji.

Na przykładzie

Sieć 2-2-1 z sigmoidą i entropią krzyżową, ta sama co w haśle o przejściu w przód: x = (1; 0,5), wagi ukryte (0,5; −0,3) i (0,2; 0,8), wagi wyjścia (1; −1), cel t = 1. Przejście w przód dało h = (0,587; 0,646), y = 0,485 i stratę L = 0,723. Dla sigmoidy z entropią krzyżową sygnał błędu na wyjściu jest wyjątkowo prosty: δ = y − t = −0,515. Gradient wag wyjścia to δ·h = (−0,302; −0,332). Ujemny znak oznacza, że zwiększenie tych wag zmniejszy stratę.

Błąd wraca do warstwy ukrytej: δ·w = (−0,515; +0,515), pomnożone przez pochodne sigmoidy h(1 − h) = (0,242; 0,229), daje δ_h = (−0,125; 0,118). Gradient wagi z x₁ do pierwszego neuronu to −0,125·1 = −0,125. Sprawdzenie różnicą skończoną (zaburzenie wagi o 10⁻⁶) daje −0,1248268, czyli tę samą wartość z dokładnością do siedmiu miejsc po przecinku. Jeden krok spadku gradientu ze współczynnikiem uczenia 0,5 podnosi wyjście z 0,485 do 0,613, a stratę obniża z 0,723 do 0,490.

Ta ilustracja działa w przeglądarce z włączonym JavaScriptem: graf obliczeń jednego neuronu L = (σ(w₁x₁ + w₂x₂ + b) − y)² liczony krok po kroku: najpierw wartości w przód, potem gradienty wstecz z regułą łańcuchową; przy w₁ = 0,5 wychodzi ∂L/∂w₁ = −0,255, tyle samo co z różnicy skończonej.

W praktyce

  • PyTorch: loss.backward() wykonuje propagację wsteczną i dopisuje gradienty do param.grad; przed każdym krokiem wywołaj optimizer.zero_grad(), bo gradienty się sumują.
  • Sprawdzanie gradientu: torch.autograd.gradcheck porównuje gradient analityczny z różnicą skończoną. Własną implementację zawsze weryfikuj w ten sposób, najlepiej w float64.
  • Gdy gradienty eksplodują (strata nan), stosuj przycinanie: torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0).
  • Do monitorowania wypisuj normę gradientu każdej warstwy; normy rzędu 10⁻⁸ w pierwszych warstwach to sygnał zanikającego gradientu.
  • scikit-learn robi to wszystko wewnątrz MLPClassifier.fit; dostęp do gradientów jest możliwy dopiero w bibliotekach takich jak PyTorch czy JAX.

Najczęstsze pytania

Czy propagacja wsteczna to to samo co spadek gradientu?
Nie. Propagacja wsteczna oblicza gradient, a spadek gradientu (lub Adam, SGD z momentem) go wykorzystuje do zmiany wag. Można liczyć gradient propagacją wsteczną i użyć go w zupełnie innym algorytmie optymalizacji.
Czy mózg uczy się propagacją wsteczną?
Nie wiadomo, a dosłowna wersja jest mało prawdopodobna, bo wymagałaby przesyłania błędu dokładnie tymi samymi połączeniami w drugą stronę. Neuronaukowcy badają biologicznie wiarygodne przybliżenia, ale to wciąż otwarte pytanie.
Dlaczego trzeba zapamiętywać aktywacje z przejścia w przód?
Wzory na gradient zawierają wartości z przejścia w przód: wejście warstwy (do gradientu wag) i pochodną aktywacji w danym punkcie. Dlatego trening zużywa dużo więcej pamięci niż predykcja. Technika *gradient checkpointing* oszczędza pamięć kosztem ponownego liczenia części aktywacji.

Źródła

  • Rumelhart D. E., Hinton G. E., Williams R. J., „Learning representations by back-propagating errors”, Nature 323, 1986, s. 533–536.
  • Goodfellow I., Bengio Y., Courville A., „Deep Learning”, MIT Press, 2016, podrozdz. 6.5 „Back-Propagation and Other Differentiation Algorithms”.
  • Bishop C. M., „Pattern Recognition and Machine Learning”, Springer, 2006, podrozdz. 5.3 „Error Backpropagation”.
  • Baydin A. G., Pearlmutter B. A., Radul A. A., Siskind J. M., „Automatic differentiation in machine learning: a survey”, Journal of Machine Learning Research 18(153), 2018, s. 1–43.
  • Dokumentacja PyTorch, „A Gentle Introduction to torch.autograd”: https://pytorch.org/tutorials/beginner/blitz/autograd_tutorial.html

Zobacz też