Faza 03 · lecția 02
Rețele multistrat și propagarea înainte
Scopul lecției: Un neuron trasează o dreaptă. Așezați mai mulți în straturi și puteți trasa orice.
Versiunea curentă AlexBred.com: primele 100 de lecții ale programului în limba română.
Cuprinsul lecției
- Obiective de învățare
- Problema
- Conceptul
- Straturi: intrare, ascuns, ieșire
- Neuroni și activări
- Propagarea înainte: cum circulă datele
- Dimensiunile matricelor
- Teorema aproximării universale
- Compozabilitatea
- Construiți
- Pasul 1: activarea sigmoidă
- Pasul 2: clasa Layer
- Pasul 3: clasa Network
- Pasul 4: XOR cu ponderi reglate manual
- Pasul 5: clasificarea cercului
- Folosiți
- Livrați
- Exerciții
- Termeni-cheie
- Lecturi suplimentare
Un neuron trasează o dreaptă. Așezați mai mulți în straturi și puteți trasa orice.
Tip: Construire Limbaje: Python Cerințe preliminare: Faza 01 — Fundamente matematice; lecția 03.01 — Perceptronul Durată: ~90 de minute
Obiective de învățare
- Să construiți de la zero o rețea multistrat cu clasele
LayerșiNetwork, care execută o propagare înainte completă. - Să urmăriți dimensiunile matricelor prin fiecare strat al rețelei și să identificați nepotrivirile de formă.
- Să explicați cum așezarea în straturi a activărilor neliniare permite rețelei să învețe frontiere de decizie curbe.
- Să rezolvați problema XOR folosind o arhitectură 2-2-1 cu ponderi sigmoidale reglate manual.
Problema
Un singur neuron trasează drepte. Atât. O singură dreaptă prin date. Fiecare problemă reală din IA — recunoașterea imaginilor, înțelegerea limbajului, jocul Go — necesită curbe. Așezarea neuronilor în straturi este modul în care obțineți curbe.
În 1969, Minsky și Papert au demonstrat că această limitare era fatală: o rețea cu un singur strat nu poate învăța XOR. Nu doar „învață cu dificultate” — este imposibil matematic. Tabelul de adevăr XOR plasează [0,1] și [1,0] de o parte, iar [0,0] și [1,1] de cealaltă. Nicio dreaptă nu le separă.
Aceasta a oprit finanțarea rețelelor neurale pentru mai mult de un deceniu. Privind retrospectiv, soluția era evidentă: nu mai folosiți un singur strat. Așezați neuronii în straturi. Lăsați primul strat să decupeze spațiul intrărilor în caracteristici noi, iar al doilea să combine acele caracteristici în decizii pe care nicio dreaptă nu le-ar putea lua.
Această stivă este rețeaua multistrat. Ea reprezintă fundamentul fiecărui model de învățare profundă aflat astăzi în producție. Propagarea înainte — datele care curg de la intrare prin straturile ascunse până la ieșire — este primul lucru pe care trebuie să îl construiți înainte să poată funcționa orice altceva.
Notă tehnică a traducerii: Neseparabilitatea liniară a XOR este elementară, iar atribuirea declinului finanțării aproape exclusiv cărții Perceptrons este o simplificare istorică. De asemenea, nu orice model modern de învățare profundă este un MLP secvențial simplu; arhitecturile pot include atenție, convoluții, recurență, normalizare și conexiuni reziduale.
Conceptul
Straturi: intrare, ascuns, ieșire
O rețea multistrat are trei tipuri de straturi:
Stratul de intrare — nu este cu adevărat un strat. Păstrează datele brute. Două caracteristici înseamnă două noduri de intrare. Aici nu are loc niciun calcul.
Straturile ascunse — locul în care se desfășoară activitatea. Fiecare neuron primește fiecare ieșire a stratului precedent, aplică ponderi și un bias, apoi trece rezultatul printr-o funcție de activare. Sunt „ascunse” deoarece nu vedeți direct aceste valori în datele de antrenare.
Stratul de ieșire — răspunsul final. Pentru clasificare binară, un neuron cu sigmoidă. Pentru clasificare cu mai multe clase, câte un neuron pentru fiecare clasă.
Aceasta este o rețea 2-3-1. Două intrări, trei neuroni ascunși și o ieșire. Fiecare conexiune poartă o pondere. Fiecare neuron, cu excepția celor de intrare, are un bias.
Fiecare strat produce un vector de numere numit stare ascunsă. Pentru text, stările ascunse măresc dimensionalitatea — codifică un cuvânt prin 768 de numere pentru a surprinde semnificația semantică. Pentru imagini, reduc dimensionalitatea — comprimă milioane de pixeli într-o reprezentare gestionabilă. Starea ascunsă este locul în care se află învățarea.
Notă tehnică a traducerii: În clasificarea multiclasa cu clase mutual exclusive se folosesc frecvent câte un logit pentru fiecare clasă și o funcție softmax; câte o sigmoidă independentă este mai potrivită clasificării multilabel. Stările ascunse nu măresc sau reduc în mod inerent dimensionalitatea: forma lor depinde de arhitectură, iar „768” este doar o dimensiune întâlnită în anumite modele.
Neuroni și activări
Fiecare neuron face trei lucruri:
- Înmulțește fiecare intrare cu ponderea corespunzătoare.
- Adună toate produsele și adaugă un bias.
- Trece suma printr-o funcție de activare.
Pentru moment, activarea este sigmoida:
sigmoidă(z) = 1 / (1 + e^(-z))
Sigmoida comprimă orice număr în intervalul (0, 1). Intrările pozitive mari împing rezultatul spre 1. Intrările negative mari îl împing spre 0. Zero este transformat în 0,5. Această curbă netedă face posibilă învățarea — spre deosebire de treapta rigidă a perceptronului, sigmoida are gradient peste tot.
Propagarea înainte: cum circulă datele
Propagarea înainte împinge datele de intrare prin rețea, strat cu strat, până când ajung la ieșire. În timpul propagării înainte nu are loc învățarea. Este calcul pur: înmulțiți, adunați, activați, repetați.
La fiecare strat au loc, în ordine, trei operații:
z = W * intrare + b (transformare liniară)
a = sigmoidă(z) (activare)
Ieșirea unui strat devine intrarea următorului. Aceasta este întreaga propagare înainte.
Notă tehnică a traducerii: Diagrama sursă notează
W1drept(2×3), dar tabelul următor, formulaW*xși implementarea folosesc convenția(neuroni_curent, neuroni_anterior), deciW1are forma(3×2)șiW2forma(1×3). Cub ≠ 0, operațiaWx + beste afină, nu strict liniară.
Dimensiunile matricelor
Urmărirea dimensiunilor este cea mai importantă abilitate de depanare în învățarea profundă. Iată rețeaua 2-3-1:
| Pas | Operație | Dimensiuni | Forma rezultatului |
|---|---|---|---|
| Intrare | x | — | (2,) |
| Operație liniară ascunsă | W1 * x + b1 | W1: (3, 2), b1: (3,) | (3,) |
| Activare ascunsă | sigmoid(z1) | — | (3,) |
| Operație liniară de ieșire | W2 * h + b2 | W2: (1, 3), b2: (1,) | (1,) |
| Activare de ieșire | sigmoid(z2) | — | (1,) |
Regula: matricea ponderilor W din stratul k are forma (neuroni_în_stratul_k, neuroni_în_stratul_k_minus_1). Rândurile corespund stratului curent. Coloanele corespund stratului precedent. Dacă formele nu se aliniază, aveți o eroare.
Teorema aproximării universale
În 1989, George Cybenko a demonstrat ceva remarcabil: o rețea neurală cu un singur strat ascuns și suficienți neuroni poate aproxima orice funcție continuă cu orice precizie dorită.
Aceasta nu înseamnă că un singur strat ascuns este întotdeauna cea mai bună alegere. Înseamnă că arhitectura este capabilă în teorie. În practică, rețelele mai profunde — mai multe straturi și mai puțini neuroni în fiecare — învață aceleași funcții cu mult mai puțini parametri în total decât rețelele superficiale și late. Acesta este motivul pentru care funcționează învățarea profundă.
Intuiția: fiecare neuron din stratul ascuns învață câte o „proeminență” sau caracteristică. Suficiente proeminențe plasate în locurile potrivite pot aproxima orice curbă netedă. Mai mulți neuroni, mai multe proeminențe, aproximare mai bună.
Notă tehnică a traducerii: Rezultatul lui Cybenko privește aproximarea uniformă a funcțiilor continue pe compactul unitate, cu combinații finite și activări sigmoidale adecvate. Nu oferă o limită practică a numărului de neuroni, nu garantează că antrenarea găsește aproximarea și nici că adâncimea folosește întotdeauna mai puțini parametri; avantajele de adâncime sunt dependente de clasa funcției.
Compozabilitatea
Rețelele neurale sunt compozabile. Le puteți așeza în straturi, înlănțui sau rula în paralel. Un model Whisper folosește o rețea encoder pentru a procesa sunetul și o rețea decoder separată pentru a genera text. LLM-urile moderne folosesc numai decoderul. BERT folosește numai encoderul. T5 este encoder–decoder. Alegerea arhitecturii definește ce poate face modelul.
Notă tehnică a traducerii: Acestea sunt descrieri de nivel înalt ale familiilor respective. Multe LLM-uri autoregresive sunt decoder-only, dar „LLM-urile moderne” nu sunt toate astfel; există și modele encoder–decoder sau encoder-only. Capacitățile nu sunt determinate numai de această etichetă, ci și de obiectiv, date, interfețe și antrenare.
mlp-forward
Construiți
Python pur. Fără NumPy. Fiecare operație matricială este scrisă de la zero.
Pasul 1: activarea sigmoidă
import math
def sigmoid(x):
x = max(-500.0, min(500.0, x))
return 1.0 / (1.0 + math.exp(-x))
Limitarea la [-500, 500] previne depășirea. math.exp(500) este mare, dar finit. math.exp(1000) este infinit.
Notă tehnică a traducerii: În Python/CPython,
math.exp(1000)ridică de regulăOverflowError, nu întoarceinf. Limitarea argumentului evită excepția; pentru implementări vectorizate se folosesc adesea formule sigmoidale stabile numeric.
Pasul 2: clasa Layer
Cea mai importantă operație din întreaga învățare profundă este înmulțirea matricelor. Fiecare strat, fiecare cap de atenție, fiecare propagare înainte — totul este o succesiune de înmulțiri matriciale. Un strat liniar primește un vector de intrare, îl înmulțește cu o matrice de ponderi și adaugă un vector de bias: y = Wx + b. Această singură ecuație reprezintă 90% din calculul unei rețele neurale.
Un strat păstrează o matrice de ponderi și un vector de bias. Metoda sa forward primește un vector de intrare și întoarce ieșirea activată.
class Layer:
def __init__(self, n_inputs, n_neurons, weights=None, biases=None):
if weights is not None:
self.weights = weights
else:
import random
self.weights = [
[random.uniform(-1, 1) for _ in range(n_inputs)]
for _ in range(n_neurons)
]
if biases is not None:
self.biases = biases
else:
self.biases = [0.0] * n_neurons
def forward(self, inputs):
self.last_input = inputs
self.last_output = []
for neuron_idx in range(len(self.weights)):
z = sum(
w * x for w, x in zip(self.weights[neuron_idx], inputs)
)
z += self.biases[neuron_idx]
self.last_output.append(sigmoid(z))
return self.last_output
Matricea ponderilor are forma (n_neurons, n_inputs). Fiecare rând conține ponderile unui neuron pentru toate intrările. Metoda forward parcurge neuronii, calculează suma ponderată plus biasul, aplică sigmoida și colectează rezultatele.
Notă tehnică a traducerii: Procentul „90%” este o aproximație dependentă de arhitectură, dimensiuni, hardware și operatori; nu este o constantă a rețelelor neurale. În plus,
ziptrunchiază silențios secvențele cu lungimi diferite, deci această clasă nu detectează automat nepotrivirile de formă pe care obiectivele lecției cer să le identificați. Codul de producție ar trebui să valideze formele ponderilor, biasurilor și intrărilor.
Pasul 3: clasa Network
O rețea este o listă de straturi. Propagarea înainte le înlănțuie: ieșirea stratului k intră în stratul k+1.
class Network:
def __init__(self, layers):
self.layers = layers
def forward(self, inputs):
current = inputs
for layer in self.layers:
current = layer.forward(current)
return current
Aceasta este întreaga propagare înainte. Patru linii de logică. Datele intră, curg prin fiecare strat și ies în partea cealaltă.
Pasul 4: XOR cu ponderi reglate manual
În lecția 01, am rezolvat XOR combinând perceptroni OR, NAND și AND. Acum faceți același lucru cu clasele Layer și Network. Arhitectura 2-2-1: două intrări, doi neuroni ascunși și o ieșire.
hidden = Layer(
n_inputs=2,
n_neurons=2,
weights=[[20.0, 20.0], [-20.0, -20.0]],
biases=[-10.0, 30.0],
)
output = Layer(
n_inputs=2,
n_neurons=1,
weights=20.0, 20.0,
biases=[-30.0],
)
xor_net = Network([hidden, output])
xor_data = [
([0, 0], 0),
([0, 1], 1),
([1, 0], 1),
([1, 1], 0),
]
for inputs, expected in xor_data:
result = xor_net.forward(inputs)
predicted = 1 if result[0] >= 0.5 else 0
print(f" {inputs} -> {result[0]:.6f} (rounded: {predicted}, expected: {expected})")
Ponderile mari — 20 și -20 — fac sigmoida să se comporte ca o funcție treaptă. Primul neuron ascuns aproximează OR. Al doilea aproximează NAND. Neuronul de ieșire le combină prin AND, rezultând XOR.
Pasul 5: clasificarea cercului
O problemă mai dificilă: clasificați puncte bidimensionale ca fiind în interiorul sau în exteriorul unui cerc cu raza 0,5, centrat în origine. Aceasta necesită o frontieră de decizie curbată — imposibilă pentru un singur perceptron.
import random
import math
random.seed(42)
data = []
for _ in range(200):
x = random.uniform(-1, 1)
y = random.uniform(-1, 1)
label = 1 if (x * x + y * y) < 0.25 else 0
data.append(([x, y], label))
circle_net = Network([
Layer(n_inputs=2, n_neurons=8),
Layer(n_inputs=8, n_neurons=1),
])
Cu ponderi aleatoare, rețeaua nu va clasifica bine. Dar propagarea înainte rulează în continuare. Acesta este scopul — propagarea înainte este doar calcul. Învățarea ponderilor potrivite înseamnă retropropagare, care urmează în lecția 03.
correct = 0
for inputs, expected in data:
result = circle_net.forward(inputs)
predicted = 1 if result[0] >= 0.5 else 0
if predicted == expected:
correct += 1
print(f"Accuracy with random weights: {correct}/{len(data)} ({100*correct/len(data):.1f}%)")
Ponderile aleatoare produc o acuratețe slabă — adesea mai mică decât ghicirea clasei majoritare. După antrenare — lecția 03 —, aceeași arhitectură cu 8 neuroni ascunși va trasa o frontieră curbată care separă interiorul de exterior.
Notă tehnică a traducerii: Opt neuroni sigmoizi pot aproxima o frontieră circulară suficient pentru acest eșantion, dar reușita nu este garantată de arhitectură singură; depinde de optimizare, inițializare, date și criteriul de oprire. Acuratețea ponderilor aleatoare poate varia și trebuie comparată cu prevalența efectivă a clasei majoritare.
Folosiți
PyTorch face tot ce este descris mai sus în patru linii:
import torch
import torch.nn as nn
model = nn.Sequential(
nn.Linear(2, 8),
nn.Sigmoid(),
nn.Linear(8, 1),
nn.Sigmoid(),
)
x = torch.tensor([[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]])
output = model(x)
print(output)
nn.Linear(2, 8) este clasa dumneavoastră Layer: matrice de ponderi cu forma (8, 2), vector de bias cu forma (8,). nn.Sigmoid() este funcția sigmoidă aplicată element cu element. nn.Sequential este clasa dumneavoastră Network: înlănțuie straturile în ordine.
Diferența este viteza și scara. PyTorch rulează pe GPU-uri, gestionează loturi de milioane de eșantioane și calculează automat gradienții pentru retropropagare. Însă logica propagării înainte este identică celei pe care tocmai ați construit-o de la zero.
Notă tehnică a traducerii: Dimensiunea lotului realizabilă depinde de memorie, tipul datelor și model; „milioane” nu este o garanție generală. În timpul antrenării, PyTorch poate înregistra operațiile propagării înainte într-un graf pentru diferențiere automată atunci când tensorii necesită gradienți, deci costul și starea diferă de inferența fără gradienți.
Livrați
Această lecție produce un prompt reutilizabil pentru proiectarea arhitecturilor de rețea:
outputs/prompt-network-architect.md
Folosiți-l când trebuie să decideți câte straturi, câți neuroni în fiecare strat și ce funcții de activare sunt potrivite unei probleme.
Exerciții
-
Construiți o rețea 2-4-2-1 — două straturi ascunse — și rulați propagarea înainte pe date XOR cu ponderi aleatoare. Afișați ieșirile intermediare ale straturilor ascunse pentru a vedea cum se transformă reprezentarea în fiecare strat.
-
Schimbați dimensiunea stratului ascuns din clasificatorul cercului de la 8 la 2, apoi la 32. Rulați de fiecare dată propagarea înainte cu ponderi aleatoare. Numărul neuronilor ascunși schimbă intervalul sau distribuția ieșirii? De ce?
-
Implementați în clasa
Networko metodăcount_parameterscare întoarce numărul total de ponderi și biasuri antrenabile. Testați-o pe o rețea 784-256-128-10 — arhitectura MNIST clasică. Câți parametri are? -
Construiți propagarea înainte pentru o rețea 3-4-4-2. Furnizați-i valori RGB ale culorilor, normalizate între 0 și 1, și observați cele două ieșiri. Aceasta este arhitectura unui clasificator simplu de culori cu două clase.
-
Înlocuiți sigmoida cu o funcție „treaptă cu scurgere”: întoarceți
0.01 * zdacăz < 0, altfel1.0. Rulați propagarea înainte pentru XOR cu aceleași ponderi reglate manual de la pasul 4. Mai funcționează? De ce este preferată sigmoida netedă limitelor rigide?
Termeni-cheie
| Termen | Ce spun oamenii | Ce înseamnă de fapt |
|---|---|---|
| Propagare înainte | „Rularea modelului” | Împingerea intrării prin fiecare strat — înmulțirea cu ponderile, adăugarea biasului, activarea — pentru a produce o ieșire |
| Strat ascuns | „Partea din mijloc” | Orice strat dintre intrare și ieșire ale cărui valori nu sunt observate direct în date |
| Rețea multistrat | „O rețea neurală profundă” | Straturi de neuroni așezate secvențial, unde ieșirea fiecărui strat alimentează intrarea următorului |
| Funcție de activare | „Nelinearitatea” | Funcție aplicată după transformarea liniară, care introduce curbe în frontiera de decizie |
| Sigmoidă | „Curba în S” | sigma(z) = 1/(1+e^(-z)); comprimă orice număr real în (0,1) și este netedă și diferențiabilă peste tot |
| Matrice de ponderi | „Parametrii” | Matrice W cu forma (neuronii_stratului_curent, neuronii_stratului_anterior), care conține intensitățile antrenabile ale conexiunilor |
| Vector de bias | „Deplasarea” | Vector adăugat după înmulțirea matricială, care permite neuronilor să se activeze chiar când toate intrările sunt zero |
| Aproximare universală | „Rețelele neurale pot învăța orice” | Un singur strat ascuns cu suficienți neuroni poate aproxima orice funcție continuă — dar „suficienți” poate însemna miliarde |
| Transformare liniară | „Pasul de înmulțire matricială” | z = W * x + b, calculul dinaintea activării, care mapează intrările într-un spațiu nou |
| Frontieră de decizie | „Locul în care clasificatorul comută” | Suprafața din spațiul intrărilor unde ieșirea rețelei traversează pragul de clasificare |
Notă tehnică a traducerii: În ultimul tabel,
z = W*x + beste o transformare afină cândbeste nenul. Numărul de neuroni necesar unei aproximații date depinde de funcție, domeniu, activare și toleranță; „miliarde” este o ilustrare, nu o consecință numerică a teoremei.
Lecturi suplimentare
- Michael Nielsen, „Neural Networks and Deep Learning”, capitolele 1–2 — explicație gratuită și clară despre propagarea înainte și structura rețelelor, cu vizualizări interactive.
- Cybenko, „Approximation by Superpositions of a Sigmoidal Function” (1989) — lucrarea originală despre teorema aproximării universale, surprinzător de accesibilă.
- 3Blue1Brown, „But what is a neural network?” — prezentare vizuală de 20 de minute despre straturi, ponderi și propagări înainte, care construiește modelul mental potrivit.
- Goodfellow, Bengio și Courville, „Deep Learning”, capitolul 6 — referința standard pentru rețele multistrat, disponibilă gratuit online.
Sursă: Originalul în limba engleză
Navigare: ← Lecția 03.01 — Perceptronul · Faza 3 — Fundamentele învățării profunde · Catalog complet