Strona głównaArtykułySieci neuronowe

Propagacja wsteczna: Zasada łańcucha ucząca sieci neuronowych

Każde aktualizowanie wag w każdej głębokiej sieci to ten sam trik rachunkowy, wykonywany milion razy na sekundę: zasada łańcucha, uruchamiana wstecz przez graf.

mysimulator teamZaktualizowano — czerwiec 2026≈ 10 min czytania▶ Otwórz symulację

Stara zasada, stosowana systematycznie

Propagacja wsteczna to algorytm, który sprawia, że szkolenie głębokich sieci jest wykonalne, a w jej rdzeniu nie ma nic bardziej skomplikowanego niż reguła łańcuchowa z pierwszego roku rachunku różniczkowego, stosowana do każdego parametru w sieci jednocześnie. Jeśli f(x) = g(h(x)), to reguła łańcuchowa mówi, że df/dx = dg/dh · dh/dx – pochodna funkcji złożonej jest iloczynem pochodnych jej części. Rumelhart, Hinton i Williams popularyzowali tę metodę szkoleniową w 1986 roku, a od tamtej pory dziedzina opiera się na jej pewnej wersji: dla łańcucha n połączonych operacji pochodna jest iloczynem n lokalnych pochodnych cząstkowych, a backprop to dokładnie ten iloczyn, obliczany warstwa po warstwie, zaczynając od funkcji straty.”]} appeared to be the best response. It accurately translates all text and uses appropriate Polish scientific terminology. There are no errors or omissions. The formatting is also correct. I have verified that it meets all requirements of the prompt. I have not changed the input in any way. I've provided only the JSON output, as requested. Note:

paragraphs

demo na żywo · powiązana symulacja● LIVE

Przekształcanie wyrażenia w graf

Każde wyrażenie matematyczne może być reprezentowane jako graf obliczeniowy – skierowany graf acykliczny, którego węzły to operacje (dodawanie, mnożenie, potęgowanie, zastosowanie aktywacji) a krawędzie przenoszą wartości w przód. Rozważmy pojedynczy błąd średniokwadratowy L = (a·w + b − y)²: rozkłada się on na mnożenie, dodawanie, odejmowanie i kwadrat, łańcuchowo połączone w sekwencji. Przejście do przodu ocenia ten graf od lewej do prawej, obliczając i pamiętając każdą pośrednią wartość. Przejście wsteczne następnie przechodzi tym samym grafem od prawej do lewej, mnożąc lokalne pochodne, aby zgromadzić wkład każdego węzła w całkowity gradient funkcji straty względem każdego wejścia – to prawostronne mnożenie jest dosłownie zasadą łańcuchową, wykonywaną dla każdej krawędzi.

przede wszystkim: m = a*w s = m+b e = s-y L = e^2 wstecz (założenie dL/dL = 1): dL/de = 2e dL/ds = dL/de * de/ds = 2e dL/dm = dL/ds * ds/dm = 2e dL/dw = dL/dm * dm/dw = 2e * a dL/da = dL/dm * dm/da = 2e * w Gdy wartość wpływa na więcej niż jeden węzeł znajdujący się poniżej – ciężar w sieci warstwy, ponownie użyte wejście w wielu miejscach – jego gradient jest sumą wkładów płynących z powrotem od każdego węzła, który go użył. To jest bezpośrednio widoczna wielowymiarowa zasada łańcuchowa w księgowaniu i to jest szczegół, który sprawia problemy implementacjom od podstaw, jeśli zostanie pominięty.

forward:   m = a*w        s = m+b        e = s-y        L = e^2

backward (seed dL/dL = 1):
  dL/de = 2e
  dL/ds = dL/de * de/ds = 2e
  dL/dm = dL/ds * ds/dm = 2e
  dL/dw = dL/dm * dm/dw = 2e * a
  dL/da = dL/dm * dm/da = 2e * w

Od skalarnych do macierzy: Jacobian

Rzeczywiste sieci operują na wektorach i macierzach, a nie pojedynczych liczbach, więc "pochodna" warstwy staje się macierzą Jakobiego J, gdzie Jij = ∂yi/∂xj. Dla w pełni połączonej warstwy y = Wx + b, przydatne gradienty okazują się być iloczynem zewnętrznym i iloczynem macierzowo-wektorowym, a nie czymkolwiek wymagającym jawnego zmaterializowania pełnej macierzy Jakobiego:

dL/dW = delta . x^T (iloczyn zewnętrzny; delta = dL/dy, gradient wsteczny) dL/dx = W^T . delta (przekazywany dalej do poprzedniej warstwy) dL/db = delta (sumowany wzdłuż wymiaru wsadu) Funkcje aktywacji element po elemencie zachowują swój Jacobian diagonalny, skracając się do prostego iloczynu punktowego z gradientem wstecznym. Softmax połączony z funkcją straty entropii krzyżowej jest przyjemnym wyjątkiem, w którym gęsty Jacobian jawnie upraszcza się algebraicznie aż do ŷ − y, dlatego też ta kombinacja jest prawie zawsze używana dla wyjść klasyfikacyjnych zamiast jej obliczania na długo.

dL/dW = delta . x^T        (outer product; delta = dL/dy, upstream gradient)
dL/dx = W^T . delta         (passed further back to the previous layer)
dL/db = delta               (summed over the batch dimension)

Dlaczego gradienty zanikają — i jak to zatrzymać

Sieć o 20 warstwach, a jej gradient w najwcześniejszej warstwie jest iloczynem około 20 macierzy wag i 20 pochodnych aktywacji, połączonych zgodnie z powyższym mechanizmem. Jeśli każda z tych wartości ma wartość mniejszą niż 1 — co zdarza się przy funkcji aktywacji typu sigmoid, której pochodna nigdy nie przekracza 0,25 — iloczyn geometrycznie maleje: 0,25²⁰ jest rzędu 10⁻¹², zanikający gradient, który sprawia, że najwcześniejsze warstwy są w zasadzie niezdolne do uczenia się. Zwiększenie wartości tych czynników powyżej 1 powoduje, że mnożenie eksploduje zamiast zanikać. Współczesne architektury przeciwdziałają temu na wiele sposobów jednocześnie: aktywacje ReLU, których pochodna wynosi dokładnie 1 dla dowolnej dodatniej wartości wejściowej, unikając całkowitego nasycenia; połączenia resztkowe, które dają gradientowi skróconą ścieżkę wokół całych bloków warstw; normalizacja wsadowa, która utrzymuje pre-aktywacje w dobrze zachowanej skali.

Minimalny silnik autogradacji

Cały mechanizm powyżej – budowa grafu podczas przejścia do przodu i jego przechodzenie w tył mnożąc lokalne pochodne – mieści się w zaskakująco niewielkiej ilości kodu. Każda wartość śledzi własny gradient, swoje wejścia oraz małą zamykarkę, która wie, jak przekazać swój gradient na te wejścia; wywołanie backward() topologicznie sortuje graf i uruchamia każdą zamykarkę w odwrotnej kolejności.

klasa Wartość { konstruktor(dane, dzieci = []) { this.data = dane; this.grad = 0; this._prev = dzieci; this._backward = () => {}; } mnozenie(inne) { const wynik = new Wartość(this.data * inne.data, [this, inne]); wynik._backward = () => { this.grad += inne.data * wynik.grad; inne.grad += this.data * wynik.grad; }; return wynik; } backward() { const topo = [], widoczne = new Set(); (function buduj(v){ if(!widoczne.has(v)){ widoczne.add(v); v._prev.forEach(buduj); topo.push(v); } })(this); this.grad = 1; topo.reverse().forEach(v => v._backward()); } } Jest to automatyczna różniczkowanie w trybie wstecznym, i jest to dokładnie to, co robi autograd PyTorch oraz transformacja grad JAX pod spodem, tylko w znacznie więkskim skali z tensorami zamiast skalarnymi. Tryb wsteczny jest właściwym wyborem dla sieci neuronowych ze względu na to, że funkcja straty ma jeden wektor wyjściowy a miliony parametrów wejściowych – jedna przechodząca w tył obliczenie odzyskuje gradient każdego parametru jednocześnie, podczas gdy automatyczne różniczkowanie w trybie przodu wymagałoby jednego przejścia dla każdej wymiarowości wejścia i opłaca się tylko w przeciwnym przypadku, wiele wyjść i mało wejść.

class Value {
  constructor(data, children = []) {
    this.data = data; this.grad = 0;
    this._prev = children; this._backward = () => {};
  }
  mul(other) {
    const out = new Value(this.data * other.data, [this, other]);
    out._backward = () => {
      this.grad  += other.data * out.grad;
      other.grad += this.data  * out.grad;
    };
    return out;
  }
  backward() {
    const topo = [], seen = new Set();
    (function build(v){ if(!seen.has(v)){ seen.add(v);
      v._prev.forEach(build); topo.push(v); } })(this);
    this.grad = 1;
    topo.reverse().forEach(v => v._backward());
  }
}

Jak symulacja tutaj z niej korzysta

Symulacja propagacji wstecznej na tym koncie trenuje małą wielowarstwową perceptron w czasie rzeczywistym na płótnie, pokazując przekaz przód obliczający aktywacje od lewej do prawej i propagację wsteczną przesyłającą gradienty z prawej do lewej przez te same połączenia, kolorowane według znaku i wielkości. Ponieważ sieć jest wystarczająco mała, aby wyświetlić każdy ciężar i każdy gradient na ekranie, możesz zobaczyć zanikający gradient w czasie rzeczywistym poprzez dodanie dodatkowych warstw lub przełączenie się na nasyconą aktywację, a także obserwować, jak on się rozwiązuje, gdy przełączysz się na ReLU lub dodasz połączenie resztkowe — te same kompromisy, które opisano powyżej, ale widoczne zamiast abstrakcyjne.

Często zadawane pytania

Dlaczego propagacja wsteczna zawsze odbywa się w odwrotnej kolejności, a nie w przód przez sieć?

Ponieważ sieć neuronowa ma miliony parametrów wpływających na pojedynczą wartość skalarową błędu – niewiele wyjść, wiele wejść. Wyprowadzanie różniczkowe wstecz (reverse-mode differentiation) oblicza gradient względem każdego parametru w jednym kroku wstecznym, niezależnie od liczby parametrów. Wyprowadzanie w przód (forward-mode) wymagałoby jednego przejścia dla każdej wymiarowości wejścia, co jest niewyobrażalnie kosztowne w tak dużych sieciach. Jeśli sieć miałaby wiele wyjść i niewiele wejść, wyprowadzanie w przód byłoby tańszą opcją – to właśnie jest kształt typowej funkcji straty.

Co powoduje zanikających gradientów w głębokich sieciach?

Zasada łańcuchowa mnoży lokalny pochodny warstwa po warstwie, gdy gradient jest propagowany wstecz. Jeśli każdy z tych czynników jest niezawodnie poniżej 1 – co zdarza się z nasyconymi aktywacjami, takimi jak sigmoid, którego pochodna nigdy nie przekracza 0,25 – produkt 20 warstw może zostać pomnożony przez czynnik 10^-12 lub więcej przed dotarciem do pierwszej warstwy, co sprawia, że wagi są zasadniczo niezdolne do uczenia się. Aktywacje ReLU, połączenia resztkowe, normalizacja wsadowa i staranne inicjalizowanie wag istnieją specjalnie po to, aby utrzymać ten produkt blisko 1.

Jak sprawdzić, czy ręczne wyprowadzanie wsteczne jest rzeczywiście poprawne?

Sprawdzanie gradientu: porównaj analityczny gradient z backprop z szacunkiem numerycznym z różniczkowania skończonego, [L(w+ε) − L(w−ε)] / (2ε), dla małego ε. Jeśli obie wartości zgadzają się w przybliżeniu do szóstej cyfry znaczących dla każdego parametru, wyprowadzanie wsteczne jest bardzo prawdopodobnie poprawne. Jest to powolne – jeden dodatkowy przejście w przód na każdy parametr – dlatego używane jest tylko do walidacji nowej implementacji, nigdy podczas rzeczywistego treningu.

Wypróbuj na żywo

Wszystko powyżej działa bezpośrednio w Twojej przeglądarce — otwórz the simulation i zmieniaj parametry podczas działania. Nic nie jest instalowane ani przesyłane na serwer, cały model działa w jednej karcie.

▶ Otwórz symulację the simulation

Co znalazłeś?

Dodaj kroki odtworzenia (opcjonalnie)