Poradniki
Poradniki · 12 min czytania · 25 lipca 2026

Jak zbudować silnik propagacji wstecznej od zera - przewodnik

Grafika ilustrująca: Jak zbudować silnik propagacji wstecznej od zera - przewodnik

Źródło: Link

Andrej Karpathy, jeden z najbardziej rozpoznawalnych naukowców w świecie deep learningu, powiedział kiedyś: "Jeśli nie rozumiesz backpropagation, nie rozumiesz neural networks". Miał rację. Większość kursów AI pokazuje Ci gotowe biblioteki, nie to, co dzieje się pod maską.

Zbudujesz teraz własny silnik propagacji wstecznej. Od zera. Bez PyTorcha, bez TensorFlow - tylko Python i matematyka na poziomie liceum. Dopiero wtedy zrozumiesz, jak naprawdę działają sieci neuronowe w GPT-5, Claude czy Gemini.

Zanim zaczniesz - co musisz wiedzieć

Ten poradnik wymaga:

  • Podstawowej znajomości Pythona (zmienne, funkcje, klasy)
  • Matematyki na poziomie liceum (pochodne, funkcje)
  • Jupyter Notebook lub dowolne środowisko Python
  • Około 2-3 godzin czasu na przejście przez wszystkie kroki

Nie musisz być programistą. Nie musisz znać zaawansowanej matematyki. Jeśli potrafisz obliczyć pochodną funkcji kwadratowej - wystarczy.

Graf obliczeniowy - podstawa każdego silnika autograd
Graf obliczeniowy - podstawa każdego silnika autograd

Czym jest propagacja wsteczna i dlaczego o nią chodzi

Propagacja wsteczna to algorytm, który pozwala sieci neuronowej "uczyć się" - czyli dostosowywać swoje wagi, żeby poprawiać wyniki. Działa w dwóch krokach:

  1. Forward pass - przepychasz dane przez sieć i liczysz wynik (np. "ten obraz to kot z prawdopodobieństwem 73%")
  2. Backward pass - liczysz, jak bardzo każda waga wpłynęła na błąd, i korygujесz ją w odpowiednią stronę

Kluczowe pojęcie: gradient. To matematyczna miara "jak bardzo zmiana wagi X wpłynie na błąd końcowy". Jeśli gradient wagi wynosi -0.5, zwiększenie tej wagi o 0.1 zmniejszy błąd o ~0.05.

Problem? Sieć neuronowa to setki tysięcy (często miliardy) wag połączonych w skomplikowany graf operacji matematycznych. Liczenie gradientów ręcznie dla każdej wagi to koszmar. Dlatego potrzebujesz autograd - silnika, który robi to automatycznie.

Micrograd - minimalistyczny silnik autograd

Micrograd to biblioteka stworzona przez Andreja Karpathy'ego, która implementuje backpropagation w ~150 liniach kodu. Nie ma w niej tensorów, GPU ani optymalizacji - tylko czysty mechanizm propagacji wstecznej.

Dzięki temu widzisz dokładnie, co się dzieje. Każda operacja (dodawanie, mnożenie, potęgowanie) buduje graf obliczeniowy. Każdy węzeł grafu wie, jak obliczyć swój gradient. Na końcu wywołujesz .backward() i gradienty płyną wstecz - od wyniku do wejść.

Krok 1: Zbuduj klasę Value - kontener na liczby z gradientami

Otwierasz nowy plik Python lub notebook. Zaczynasz od klasy Value - to opakowanie na zwykłą liczbę, które będzie pamiętać, skąd ta liczba pochodzi i jak obliczyć jej gradient.

class Value:
 def __init__(self, data):
 self.data = data
 self.grad = 0.0
 self._backward = lambda: None
 self._prev = set()

Co tu się dzieje:

  • self.data - faktyczna wartość liczbowa (np. 2.5)
  • self.grad - gradient tej wartości (na razie 0.0)
  • self._backward - funkcja, która obliczy gradienty rodziców (na razie pusta)
  • self._prev - zbiór wartości, z których powstała ta wartość (rodzice w grafie)

Teraz dodajesz podstawowe operacje matematyczne. Zaczynasz od dodawania:

def __add__(self, other):
 other = other if isinstance(other, Value) else Value(other)
 out = Value(self.data + other.data)
 out._prev = {self, other}
 
 def _backward():
 self.grad += out.grad
 other.grad += out.grad
 out._backward = _backward
 
 return out

Teraz możesz pisać a = Value(2); b = Value(3); c = a + b i c.data będzie wynosić 5. Co ważniejsze - c pamięta, że powstało z a i b, i wie, jak obliczyć ich gradienty.

Operacja dodawania buduje węzeł w grafie obliczeniowym
Operacja dodawania buduje węzeł w grafie obliczeniowym

Dlaczego gradient dodawania to po prostu 1.0

Matematyka: jeśli c = a + b, to pochodna c po a wynosi 1.0 (zmiana a o 1 zmienia c o 1). Dlatego w funkcji _backward po prostu przekazujesz gradient c do a i b bez zmian.

Operator += zamiast = jest kluczowy - ta sama wartość może być użyta w wielu miejscach grafu, więc jej gradient to suma wszystkich wpływów.

Krok 2: Dodaj mnożenie, potęgowanie i inne operacje

Dodajesz mnożenie analogicznie:

def __mul__(self, other):
 other = other if isinstance(other, Value) else Value(other)
 out = Value(self.data * other.data)
 out._prev = {self, other}
 
 def _backward():
 self.grad += other.data * out.grad
 other.grad += self.data * out.grad
 out._backward = _backward
 
 return out

Tutaj matematyka jest ciekawsza: jeśli c = a * b, to pochodna c po a wynosi b, a po b wynosi a. Dlatego gradient a to b.data * out.grad.

Potęgowanie:

def __pow__(self, other):
 assert isinstance(other, (int, float))
 out = Value(self.data ** other)
 out._prev = {self}
 
 def _backward():
 self.grad += other * (self.data ** (other - 1)) * out.grad
 out._backward = _backward
 
 return out

Tutaj używasz reguły potęgowania: pochodna x^n to n * x^(n-1).

Funkcja aktywacji - ReLU

Dodajesz najprostszą funkcję aktywacji - ReLU (Rectified Linear Unit). Zwraca wartość jeśli jest dodatnia, zero w przeciwnym razie:

def relu(self):
 out = Value(0 if self.data < 0 else self.data)
 out._prev = {self}
 
 def _backward():
 self.grad += (out.data > 0) * out.grad
 out._backward = _backward
 
 return out

Gradient ReLU to 1.0 jeśli wartość była dodatnia, 0.0 w przeciwnym razie. Proste, skuteczne - to właśnie ReLU napędza większość nowoczesnych sieci neuronowych.

Krok 3: Zaimplementuj backward pass - topologiczne sortowanie

Masz już operacje, które budują graf. Teraz potrzebujesz funkcji backward(), która przejdzie przez cały graf od końca do początku i obliczy wszystkie gradienty.

Problem: nie możesz wywołać _backward() w losowej kolejności. Musisz zacząć od wyniku końcowego i iść wstecz, upewniając się, że gradient każdego węzła jest obliczony zanim obliczysz gradienty jego rodziców.

Rozwiązanie: sortowanie topologiczne grafu.

def backward(self):
 topo = []
 visited = set()
 
 def build_topo(v):
 if v not in visited:
 visited.add(v)
 for child in v._prev:
 build_topo(child)
 topo.append(v)
 
 build_topo(self)
 
 self.grad = 1.0
 for node in reversed(topo):
 node._backward()

Co tu się dzieje:

  1. Funkcja build_topo rekurencyjnie przechodzi przez graf i buduje listę węzłów w kolejności topologicznej
  2. Ustawiasz gradient wyniku końcowego na 1.0 ("jak bardzo zmiana wyniku wpływa na wynik? Oczywiście 1.0")
  3. Idziesz przez listę od tyłu i wywołujesz _backward() każdego węzła

Teraz możesz zrobić:

a = Value(2.0)
b = Value(-3.0)
c = Value(10.0)
e = a * b
d = e + c
f = d.relu()
f.backward()

print(a.grad) # Gradient 'a' względem 'f'
print(b.grad) # Gradient 'b' względem 'f'

I dostaniesz dokładne wartości gradientów - automatycznie, bez ręcznego liczenia pochodnych.

Backward pass - gradienty płyną od wyniku do wejść
Backward pass - gradienty płyną od wyniku do wejść

Krok 4: Zbuduj neuron - podstawowy blok sieci

Masz silnik autograd. Teraz budujesz na nim neuron - podstawową jednostkę sieci neuronowej.

Neuron to funkcja, która:

  1. Bierze n wejść
  2. Mnoży każde wejście przez wagę
  3. Dodaje bias (przesunięcie)
  4. Przepuszcza przez funkcję aktywacji
import random

class Neuron:
 def __init__(self, nin):
 self.w = [Value(random.uniform(-1, 1)) for _ in range(nin)]
 self.b = Value(random.uniform(-1, 1))
 
 def __call__(self, x):
 act = sum((wi * xi for wi, xi in zip(self.w, x)), self.b)
 out = act.relu()
 return out
 
 def parameters(self):
 return self.w + [self.b]

Teraz możesz stworzyć neuron z 3 wejściami i przepuścić przez niego dane:

n = Neuron(3)
x = [Value(2.0), Value(0.0), Value(-1.5)]
output = n(x)
print(output.data) # Wynik neuronu

Warstwa i sieć neuronowa

Warstwa to zbiór neuronów działających równolegle:

class Layer:
 def __init__(self, nin, nout):
 self.neurons = [Neuron(nin) for _ in range(nout)]
 
 def __call__(self, x):
 outs = [n(x) for n in self.neurons]
 return outs[0] if len(outs) == 1 else outs
 
 def parameters(self):
 return [p for neuron in self.neurons for p in neuron.parameters()]

Sieć to stos warstw:

class MLP:
 def __init__(self, nin, nouts):
 sz = [nin] + nouts
 self.layers = [Layer(sz[i], sz[i+1]) for i in range(len(nouts))]
 
 def __call__(self, x):
 for layer in self.layers:
 x = layer(x)
 return x
 
 def parameters(self):
 return [p for layer in self.layers for p in layer.parameters()]

Teraz możesz zbudować sieć 3-4-4-1 (3 wejścia, dwie warstwy ukryte po 4 neurony, 1 wyjście):

model = MLP(3, [4, 4, 1])
print(len(model.parameters())) # Liczba wag w sieci

Krok 5: Wytrenuj sieć - pętla uczenia

Masz sieć. Masz autograd. Teraz uczysz sieć na prostym zbiorze danych.

Tworzysz zbiór treningowy - 4 przykłady wejść i oczekiwanych wyjść:

xs = [
 [2.0, 3.0, -1.0],
 [3.0, -1.0, 0.5],
 [0.5, 1.0, 1.0],
 [1.0, 1.0, -1.0]
]
ys = [1.0, -1.0, -1.0, 1.0] # Oczekiwane wyniki

Pętla uczenia:

for k in range(100): # 100 epok
 # Forward pass
 ypred = [model(x) for x in xs]
 loss = sum((yout - ygt)**2 for ygt, yout in zip(ys, ypred))
 
 # Backward pass
 for p in model.parameters():
 p.grad = 0.0 # Zeruj gradienty
 loss.backward()
 
 # Update wag
 for p in model.parameters():
 p.data += -0.05 * p.grad # Learning rate = 0.05
 
 if k % 10 == 0:
 print(f"Epoka {k}, Loss: {loss.data}")

Co tu się dzieje:

  1. Forward pass - przepychasz wszystkie przykłady przez sieć i liczysz błąd (loss) jako sumę kwadratów różnic między przewidywaniami a prawdą
  2. Zerowanie gradientów - ważne! Gradienty się akumulują, więc musisz je wyzerować przed każdym backward pass
  3. Backward pass - wywołujesz loss.backward() i wszystkie gradienty są obliczane automatycznie
  4. Update wag - odejmujesz od każdej wagi jej gradient pomnożony przez learning rate (0.05)

Po 100 epokach loss powinien spaść z ~4-5 do ~0.01. Sieć nauczyła się mapowania wejść na wyjścia.

Loss spada w miarę treningu - sieć uczy się
Loss spada w miarę treningu - sieć uczy się

Krok 6: Przetestuj sieć na nowych danych

Teraz sprawdzasz, czy sieć naprawdę nauczyła się wzorca, czy tylko "zakuła" przykłady treningowe:

test_x = [2.5, 2.0, -0.5]
test_output = model(test_x)
print(f"Przewidywanie: {test_output.data}")

Jeśli sieć jest dobrze wytrenowana, wynik powinien być bliski 1.0 (testowe wejście jest podobne do pierwszego przykładu treningowego).

Co dalej - gdzie ten mechanizm jest używany

To, co właśnie zbudowałeś, to dokładnie ten sam mechanizm, który napędza:

  • PyTorch (biblioteka torch.autograd)
  • TensorFlow (biblioteka tf.GradientTape)
  • JAX (biblioteka jax.grad)

Różnica? Skala. Produkcyjne biblioteki operują na tensorach (wielowymiarowych tablicach), używają GPU do równoległych obliczeń i mają setki optymalizacji. Rdzeń - graf obliczeniowy i propagacja wsteczna - jest identyczny.

Jeśli chcesz zgłębić temat, naturalnym krokiem jest nauka PyTorcha. Teraz rozumiesz, co dzieje się pod maską loss.backward() - to daje Ci przewagę nad 90% osób, które tylko kopiują kod z tutoriali.

Jeśli interesuje Cię, jak to wygląda w praktyce z prawdziwymi danymi, sprawdź przewodnik po pracy z danymi w Pythonie - tam pokazuję, jak przygotować dane do treningu modeli AI.

Najczęstsze pułapki i jak ich unikać

Podczas budowania własnego silnika autograd łatwo o błędy. Oto trzy najczęstsze:

1. Zapominasz zerować gradienty przed backward pass

Gradienty się akumulują. Jeśli nie wyzerujesz ich przed każdym backward(), będą rosnąć w nieskończoność i sieć nigdy się nie nauczy. Zawsze rób:

for p in model.parameters():
 p.grad = 0.0
loss.backward()

2. Używasz = zamiast += w funkcjach _backward

Jeśli ta sama wartość jest użyta w wielu miejscach grafu, jej gradient to suma wszystkich wpływów. Dlatego piszesz self.grad += out.grad, nie self.grad = out.grad.

3. Zbyt duży learning rate

Jeśli loss eksploduje zamiast spadać, prawdopodobnie learning rate jest za duży. Zacznij od 0.01-0.05 i eksperymentuj. Za mały learning rate = wolne uczenie, za duży = chaos.

Więcej o tym, jak dobierać hiperparametry i debugować modele, znajdziesz w przewodniku po debugowaniu modeli AI.

Chcesz to ogarnąć w praktyce?

Zbudowanie własnego silnika autograd to jedno. Żeby naprawdę wykorzystać AI w pracy - potrzebujesz systematycznej wiedzy. Na darmowym webinarze na żywo pokazuję krok po kroku, jak oszczędzać 10 godzin tygodniowo dzięki AI - bez wiedzy technicznej.

Zapisz się na darmowy webinar →

Wolisz uczyć się we własnym tempie? Sprawdź kurs AI Evolution

Najczęstsze pytania

Czy muszę znać zaawansowaną matematykę, żeby zbudować własny silnik autograd?

Nie. Wystarczy matematyka na poziomie liceum - pochodne podstawowych funkcji (potęga, suma, iloczyn). Jeśli pamiętasz, że pochodna x² to 2x, dasz radę. Reszta to logika programowania - budowanie grafu i przechodzenie przez niego w odpowiedniej kolejności.

Dlaczego gradient się akumuluje zamiast nadpisywać?

Ta sama wartość może być użyta w wielu miejscach grafu obliczeniowego. Jeśli a wpływa na wynik przez dwie różne ścieżki, jej gradient to suma wpływów z obu ścieżek. Dlatego używasz += zamiast = w funkcjach _backward.

Czy ten mechanizm jest taki sam jak w PyTorch i TensorFlow?

Tak, rdzeń jest identyczny - graf obliczeniowy i propagacja wsteczna. Różnica to skala i optymalizacje: produkcyjne biblioteki operują na tensorach (wielowymiarowych tablicach), używają GPU i mają setki optymalizacji wydajnościowych. Fundamentalny mechanizm - ten, który właśnie zbudowałeś - jest ten sam.

Co powinienem zrobić po zbudowaniu micrograd?

Naturalnym krokiem jest nauka PyTorcha lub TensorFlow. Teraz rozumiesz, co dzieje się pod maską, więc będziesz uczyć się 10x szybciej. Możesz też rozbudować micrograd o obsługę tensorów, więcej funkcji aktywacji (sigmoid, tanh) lub optymalizatory (Adam, RMSprop). Jeśli interesuje Cię praktyczne zastosowanie, sprawdź przewodnik po budowaniu agentów AI.

Jak długo trwa nauka propagacji wstecznej od podstaw?

Przejście przez ten poradnik i zbudowanie działającego silnika to 2-3 godziny. Pełne zrozumienie mechanizmu - kilka dni eksperymentowania z różnymi architekturami i zbiorami danych. Jeśli poświęcisz ten czas, będziesz rozumieć sieci neuronowe lepiej niż 90% osób, które tylko kopiują kod z tutoriali.

Podsumowanie - co właśnie zbudowałeś

Masz teraz działający silnik propagacji wstecznej. Od zera. Rozumiesz, jak graf obliczeniowy buduje się podczas forward pass, jak gradienty płyną wstecz podczas backward pass i jak sieć neuronowa uczy się minimalizując loss.

To nie jest wiedza teoretyczna. To fundament, na którym stoją GPT-5, Claude, Gemini i każdy inny model deep learningowy. Różnica między Tobą a kimś, kto tylko używa gotowych bibliotek? Ty wiesz, co dzieje się pod maską. To daje Ci przewagę.

Jeden krok na start: Otwórz notebook, skopiuj kod klasy Value z kroku 1 i zbuduj prosty graf obliczeniowy - dwa wejścia, jedno dodawanie, jedno mnożenie. Wywołaj backward() i wypisz gradienty. Zobaczysz, że to działa. To będzie Twój pierwszy krok do zrozumienia, jak naprawdę działają sieci neuronowe.

Na podstawie: Andrej Karpathy - Neural Networks: Zero to Hero (materiał edukacyjny)

Informacje o artykule

Darmowy AI Starter Kit

10 gotowych promptów do codziennej pracy + 5 narzędzi + plan na pierwszy tydzień. PDF, 4 strony konkretu.

Udostępnij:
Nie przegap nowych artykułów - dodaj SukcesAI do swoich źródeł w wyszukiwarce Google.
Dodaj do preferowanych źródeł
Jan Gajos

Ekspert AI & Founder, AI Evolution

Pasjonat sztucznej inteligencji, który od 18 lat działa z sukcesem biznesowo i szkoleniowo. Wprowadzam AI do swoich firm oraz codziennego życia. Fascynują mnie nowe technologie, gry wideo i składanie klocków Lego - tam też widzę logikę i kreatywność, które AI potrafi wzmacniać. Wierzę, że dobrze użyta sztuczna inteligencja to nie ogłupiające ułatwienie, lecz prawdziwy przełom w sposobie, w jaki myślimy, tworzymy i pracujemy.