Faza 03 · lecția 08
Inițializarea ponderilor și stabilitatea antrenării
Scopul lecției: Inițializați greșit și antrenarea nu începe. Inițializați potrivit și 50 de straturi se pot antrena aproape la fel de lin ca trei.
Versiunea curentă AlexBred.com: primele 100 de lecții ale programului în limba română.
Cuprinsul lecției
- Obiective de învățare
- Problema
- Conceptul
- Problema simetriei
- Propagarea varianței prin straturi
- Inițializarea Xavier/Glorot
- Inițializarea Kaiming/He
- Inițializarea transformatoarelor
- Amplitudinea activărilor prin 50 de straturi
- Alegerea inițializării
- Construiți
- Pasul 1: strategii de inițializare
- Pasul 2: funcțiile de activare
- Pasul 3: propagarea înainte prin 50 de straturi
- Pasul 4: experimentul
- Pasul 5: demonstrarea simetriei
- Pasul 6: raportul amplitudinii strat cu strat
- Folosiți
- Livrați
- Exerciții
- Termeni-cheie
- Lecturi suplimentare
Inițializați greșit și antrenarea nu începe. Inițializați potrivit și 50 de straturi se pot antrena aproape la fel de lin ca trei.
Tip: Construire Limbaje: Python Cerințe preliminare: Lecția 03.04 — Funcții de activare; lecția 03.07 — Regularizare Durată: ~90 de minute
Obiective de învățare
- Să implementați inițializarea cu zero, aleatoare, Xavier/Glorot și Kaiming/He și să măsurați efectul asupra activărilor prin 50 de straturi.
- Să deduceți de ce inițializarea Xavier folosește
Var(w) = 2/(fan_in + fan_out), iar Kaiming foloseșteVar(w) = 2/fan_in. - Să demonstrați problema simetriei la inițializarea cu zero și să explicați de ce o scară aleatoare arbitrară nu este suficientă.
- Să asociați strategia de inițializare cu activarea: Xavier pentru sigmoidă și
tanh, Kaiming pentru ReLU și, ca punct de pornire, pentru activări asemănătoare ReLU.
Problema
Inițializați toate ponderile cu zero. Nimic nu învață în configurația complet simetrică. Fiecare neuron calculează aceeași funcție, primește același gradient și se actualizează identic. După 10.000 de epoci, stratul ascuns cu 512 neuroni poate rămâne format din 512 de copii ale aceluiași neuron. Ați plătit pentru lățime, dar ați obținut o singură caracteristică repetată.
Inițializați ponderile cu valori prea mari. Activările pot exploda prin rețea. Într-un exemplu, la stratul 10 valorile ajung la 1e15, iar la stratul 20 produc overflow până la infinit. Gradienții pot urma în sens invers o dinamică la fel de instabilă.
Inițializați-le aleator din distribuția normală standard. Metoda poate funcționa pentru trei straturi, dar la 50 semnalul poate dispărea sau exploda, în funcție de scară, arhitectură și activare. Intervalul scalelor stabile se poate îngusta odată cu profunzimea.
Inițializarea ponderilor este o decizie esențială în învățarea profundă. Arhitectura primește lucrări, optimizatorii primesc articole, iar inițializarea uneori doar o notă de subsol. Dacă scările inițiale sunt nepotrivite, activările și gradienții pot fi inutilizabili înainte ca optimizatorul să aibă șansa de a corecta modelul.
Notă tehnică a traducerii: Inițializarea tuturor ponderilor cu aceeași valoare păstrează simetria numai când și restul arhitecturii și actualizărilor sunt simetrice. Biasurile diferite, ponderile de ieșire diferite sau alte surse de aleatorietate pot rupe simetria; afirmația originală descrie cazul uzual în care toți parametrii relevanți pornesc identic.
Conceptul
Problema simetriei
Fiecare neuron dintr-un strat are aceeași structură: înmulțește intrările cu ponderile, adaugă un bias și aplică activarea. Dacă toate ponderile pornesc cu aceeași valoare — zero este cazul extrem —, fiecare neuron calculează aceeași ieșire. În retropropagare, neuronii simetrici primesc aceiași gradienți și se modifică la fel.
Rețeaua rămâne blocată în subspațiul simetric. Are sute de parametri, dar aceștia se deplasează sincron. Inițializarea aleatoare este metoda directă de rupere a simetriei: fiecare neuron pornește dintr-un punct diferit al spațiului ponderilor și poate învăța altă caracteristică.
Dar „aleator” nu este suficient. Scara distribuției determină dacă semnalul și gradienții rămân utilizabili.
Propagarea varianței prin straturi
Considerați un singur strat cu fan_in intrări:
z = w1*x1 + w2*x2 + ... + w_n*x_n
Dacă fiecare pondere wi este extrasă dintr-o distribuție cu varianța Var(w), iar fiecare intrare xi are varianța Var(x), atunci, sub ipotezele uzuale de medie zero și independență sau necorelare:
Var(z) = fan_in * Var(w) * Var(x)
Dacă Var(w) = 1 și fan_in = 512, varianța ieșirii este de 512 ori varianța intrării. După zece straturi, factorul idealizat devine 512^10 = 1.2e27, iar semnalul explodează.
Dacă Var(w) = 0.001, varianța se înmulțește cu 0.001 * 512 = 0.512 la fiecare strat. După zece straturi: 0.512^10 ≈ 0.00124. Semnalul s-a micșorat drastic.
Notă tehnică a traducerii: Sursa dă eronat
0.512^10 = 0.00013; valoarea corectă este aproximativ0.00124. Formula varianței presupune ponderi și intrări cu medie zero, termeni necorelați și bias neglijat. Aceste ipoteze nu se păstrează exact după activări neliniare sau în timpul antrenării.
Obiectivul propagării înainte este alegerea lui Var(w) astfel încât scara lui Var(z) să rămână comparabilă cu Var(x). Pentru propagarea înapoi trebuie controlată și varianța gradienților.
Inițializarea Xavier/Glorot
Glorot și Bengio au propus în 2010 o soluție de compromis pentru fluxul înainte și înapoi, potrivită activărilor cu comportament aproximativ liniar în jurul originii:
Var(w) = 2 / (fan_in + fan_out)
În practică, ponderile pot fi extrase din:
w ~ Uniform(-limit, limit) unde limit = sqrt(6 / (fan_in + fan_out))
sau:
w ~ Normal(0, sqrt(2 / (fan_in + fan_out)))
Această inițializare este folosită frecvent cu tanh și sigmoidă deoarece păstrează preactivările într-o zonă mai puțin saturată. Poate stabiliza scara prin multe straturi, dar nu garantează antrenarea oricărei rețele sigmoidale profunde.
Notă tehnică a traducerii: Când
fan_in != fan_out, o singură varianță nu poate satisface simultan condițiile ideale înainte și înapoi; formula Glorot este un compromis. Sigmoida logistică are și ieșire cu medie pozitivă, astfel încât ipotezele simple de medie zero nu se păstrează.
Inițializarea Kaiming/He
ReLU aduce la zero valorile negative. Pentru intrări simetrice, aproximativ jumătate dintre activări devin zero, iar al doilea moment este redus. Inițializarea Xavier nu compensează complet acest efect.
He și colaboratorii au ajustat în 2015 formula:
Var(w) = 2 / fan_in
Ponderile sunt extrase din:
w ~ Normal(0, sqrt(2 / fan_in))
Factorul 2 compensează, în analiza idealizată, anularea jumătății negative prin ReLU. Fără această compensare, al doilea moment s-ar putea micșora aproximativ cu 0,5 la fiecare strat. După 50 de straturi, 0.5^50 = 8.8e-16. Inițializarea Kaiming urmărește să prevină acest colaps.
Notă tehnică a traducerii: Formula
2/fan_ineste dedusă pentru rectificatoare și ipoteze statistice specifice. GELU și Swish nu anulează exact jumătate dintre valori, deci Kaiming pentru ReLU este doar un punct de pornire, nu o potrivire teoretică exactă pentru aceste activări.
Inițializarea transformatoarelor
GPT-2 a popularizat un tipar suplimentar. Conexiunile reziduale adaugă ieșirea fiecărui subnivel la intrare:
x = x + sublayer(x)
Dacă ramurile reziduale ar contribui independent cu aceeași varianță, fiecare adunare ar mări varianța. În implementările de tip GPT-2, ponderile proiecțiilor reziduale sunt inițializate cu o abatere standard redusă prin factorul 1/sqrt(2N), unde N este numărul straturilor. Factorul 2 reflectă cele două ramuri reziduale principale pe bloc.
Notă tehnică a traducerii: Afirmația că Llama 3 folosește aceeași schemă
1/sqrt(2N)nu este susținută de descrierea sau implementarea publică standard Llama, care folosește o abatereinitializer_rangepentru straturile liniare. Strategiile de scalare reziduală diferă între familiile de transformatoare și nu trebuie transferate prin analogie.
Amplitudinea activărilor prin 50 de straturi
Notă tehnică a traducerii: Valorile originale „~1,0 la stratul 50” nu rezultă din teorie și nici din metrica scriptului. Experimentul măsoară media valorilor absolute, nu varianța; pentru sigmoidă, ieșirile sunt centrate în jurul lui 0,5, nu 1. Xavier și Kaiming urmăresc în principal momente statistice sub ipoteze idealizate, nu o amplitudine medie universală.
Alegerea inițializării
Notă tehnică a traducerii: Intervalul original 0,5–2,0 pentru amplitudini nu este un criteriu universal. Monitorizați media, varianța, fracția de unități saturate sau inactive și normele gradienților în raport cu activarea și normalizarea folosite.
weight-init-variance
Construiți
Pasul 1: strategii de inițializare
Patru moduri de a inițializa o matrice de ponderi. Fiecare întoarce o listă de liste — o matrice bidimensională — cu fan_in coloane și fan_out rânduri.
import math
import random
def zero_init(fan_in, fan_out):
return [[0.0 for _ in range(fan_in)] for _ in range(fan_out)]
def random_init(fan_in, fan_out, scale=1.0):
return [[random.gauss(0, scale) for _ in range(fan_in)] for _ in range(fan_out)]
def xavier_init(fan_in, fan_out):
std = math.sqrt(2.0 / (fan_in + fan_out))
return [[random.gauss(0, std) for _ in range(fan_in)] for _ in range(fan_out)]
def kaiming_init(fan_in, fan_out):
std = math.sqrt(2.0 / fan_in)
return [[random.gauss(0, std) for _ in range(fan_in)] for _ in range(fan_out)]
Pasul 2: funcțiile de activare
Avem nevoie de sigmoidă, tanh și ReLU pentru a testa fiecare strategie cu activarea căreia îi este destinată.
def sigmoid(x):
x = max(-500, min(500, x))
return 1.0 / (1.0 + math.exp(-x))
def tanh_act(x):
return math.tanh(x)
def relu(x):
return max(0.0, x)
Pasul 3: propagarea înainte prin 50 de straturi
Propagați date aleatoare printr-o rețea profundă și măsurați amplitudinea medie a activării la fiecare strat.
def forward_deep(init_fn, activation_fn, n_layers=50, width=64, n_samples=100):
random.seed(42)
layer_magnitudes = []
inputs = [[random.gauss(0, 1) for _ in range(width)] for _ in range(n_samples)]
for layer_idx in range(n_layers):
weights = init_fn(width, width)
biases = [0.0] * width
new_inputs = []
for sample in inputs:
output = []
for neuron_idx in range(width):
z = sum(weights[neuron_idx][j] * sample[j] for j in range(width)) + biases[neuron_idx]
output.append(activation_fn(z))
new_inputs.append(output)
inputs = new_inputs
magnitudes = []
for sample in inputs:
magnitudes.append(sum(abs(v) for v in sample) / width)
mean_mag = sum(magnitudes) / len(magnitudes)
layer_magnitudes.append(mean_mag)
return layer_magnitudes
Notă tehnică a traducerii: Funcția nu măsoară varianța și nici gradienții, deși lecția motivează inițializările prin ambele. Pentru un diagnostic complet, înregistrați media și varianța preactivărilor și activărilor și executați o propagare înapoi pentru normele gradienților.
Pasul 4: experimentul
Rulați toate combinațiile: zero, aleator N(0,1), aleator N(0,0.01), Xavier cu sigmoidă, Xavier cu tanh și Kaiming cu ReLU. Afișați amplitudinea la straturile-cheie.
def run_experiment():
configs = [
("Zero init + Sigmoid", lambda fi, fo: zero_init(fi, fo), sigmoid),
("Random N(0,1) + ReLU", lambda fi, fo: random_init(fi, fo, 1.0), relu),
("Random N(0,0.01) + ReLU", lambda fi, fo: random_init(fi, fo, 0.01), relu),
("Xavier + Sigmoid", xavier_init, sigmoid),
("Xavier + Tanh", xavier_init, tanh_act),
("Kaiming + ReLU", kaiming_init, relu),
]
print(f"{'Strategy':<30} {'L1':>10} {'L5':>10} {'L10':>10} {'L25':>10} {'L50':>10}")
print("-" * 80)
for name, init_fn, act_fn in configs:
mags = forward_deep(init_fn, act_fn)
row = f"{name:<30}"
for idx in [0, 4, 9, 24, 49]:
val = mags[idx]
if val > 1e6:
row += f" {'EXPLODED':>10}"
elif val < 1e-6:
row += f" {'VANISHED':>10}"
else:
row += f" {val:>10.4f}"
print(row)
Pasul 5: demonstrarea simetriei
Arătați că inițializarea cu zero produce neuroni identici.
def symmetry_demo():
random.seed(42)
weights = zero_init(2, 4)
biases = [0.0] * 4
inputs = [0.5, -0.3]
outputs = []
for neuron_idx in range(4):
z = sum(weights[neuron_idx][j] * inputs[j] for j in range(2)) + biases[neuron_idx]
outputs.append(sigmoid(z))
print("\nSymmetry Demo (4 neurons, zero init):")
for i, out in enumerate(outputs):
print(f" Neuron {i}: output = {out:.6f}")
all_same = all(abs(outputs[i] - outputs[0]) < 1e-10 for i in range(len(outputs)))
print(f" All identical: {all_same}")
print(f" Effective parameters: 1 (not {len(weights) * len(weights[0])})")
Notă tehnică a traducerii: Demonstrația arată numai că ieșirile inițiale coincid; nu execută retropropagarea și nu demonstrează direct că rămân identice după actualizare. Numărul „1 parametru efectiv” este o metaforă pentru un singur neuron distinct, nu un calcul formal al gradelor de libertate.
Pasul 6: raportul amplitudinii strat cu strat
Afișați o diagramă textuală a amplitudinilor activărilor prin 50 de straturi.
def magnitude_report(name, magnitudes):
print(f"\n{name}:")
for i, mag in enumerate(magnitudes):
if i % 5 == 0 or i == len(magnitudes) - 1:
if mag > 1e6:
bar = "X" * 50 + " EXPLODED"
elif mag < 1e-6:
bar = "." + " VANISHED"
else:
bar_len = min(50, max(1, int(mag * 10)))
bar = "#" * bar_len
print(f" Layer {i+1:3d}: {bar} ({mag:.6f})")
Folosiți
PyTorch oferă aceste strategii ca funcții integrate:
import torch
import torch.nn as nn
layer = nn.Linear(512, 256)
nn.init.xavier_uniform_(layer.weight)
nn.init.xavier_normal_(layer.weight)
nn.init.kaiming_uniform_(layer.weight, nonlinearity='relu')
nn.init.kaiming_normal_(layer.weight, nonlinearity='relu')
nn.init.zeros_(layer.bias)
La apelarea nn.Linear(512, 256), PyTorch inițializează implicit ponderile uniform în intervalul [-1/sqrt(fan_in), 1/sqrt(fan_in)]. Implementarea internă folosește kaiming_uniform_ cu parametrul a=sqrt(5), ceea ce produce acest interval; nu este inițializarea Kaiming standard pentru ReLU cu varianța 2/fan_in.
Notă tehnică a traducerii: Originalul spune simplu că
nn.Linearfolosește implicit Kaiming uniform și că aceasta este „alegerea corectă”. Deși implementarea apelează funcția Kaiming, parametrul speciala=sqrt(5)o reduce la distribuția documentată mai sus. Stratul nu cunoaște activarea următoare, deci inițializarea implicită este generică, nu adaptată automat la ReLU.
Pentru transformatoare, modelele Hugging Face gestionează adesea inițializarea în metoda _init_weights. Implementarea GPT-2 scalează proiecțiile reziduale în funcție de numărul straturilor. Dacă construiți de la zero un transformator, urmați schema arhitecturii alese și verificați statisticile, nu presupuneți că aceeași regulă se aplică tuturor modelelor.
Livrați
Această lecție produce:
outputs/prompt-init-strategy.md— un prompt care diagnostichează problemele inițializării ponderilor și recomandă o strategie potrivită.
Exerciții
-
Adăugați inițializarea LeCun —
Var = 1/fan_in, folosită cu activarea SELU. Rulați experimentul cu 50 de straturi folosind LeCun plustanhși comparați cu Xavier plustanh. -
Implementați scalarea reziduală în stil GPT-2: scalați ramurile reziduale cu
1/sqrt(2*N)prin inițializarea proiecțiilor sau printr-o formulare echivalentă atent definită. Rulați 50 de straturi cu și fără scalare și măsurați creșterea fluxului rezidual. -
Creați o funcție de „verificare a sănătății inițializării” care primește dimensiunile straturilor și tipul activării, apoi recomandă inițializarea și avertizează asupra riscurilor configurației curente.
-
Rulați experimentul cu
fan_in = 16și cufan_in = 1024. Xavier și Kaiming se adaptează lafan_in, dar inițializarea aleatoare cu scară fixă nu. Arătați cum se schimbă intervalul dintre funcționare și instabilitate pentru straturi mai late. -
Implementați inițializarea ortogonală: generați o matrice aleatoare, calculați-i SVD și folosiți factorul ortogonal potrivit formei,
UsauV^T. Comparați cu Kaiming pentru rețele ReLU cu 50 de straturi.
Termeni-cheie
| Termen | Ce spun oamenii | Ce înseamnă de fapt |
|---|---|---|
| Inițializarea ponderilor | „Stabiliți aleator ponderile inițiale” | Strategia de alegere a parametrilor inițiali, care influențează scara activărilor și gradienților și stabilitatea antrenării |
| Ruperea simetriei | „Faceți neuronii diferiți” | Folosirea inițializării nesimetrice pentru ca neuronii să poată învăța caracteristici distincte |
| Fan-in | „Numărul intrărilor unui neuron” | Numărul conexiunilor de intrare, care determină acumularea varianței în suma ponderată |
| Fan-out | „Numărul ieșirilor unui neuron” | Numărul conexiunilor de ieșire, relevant pentru propagarea varianței gradientului |
| Inițializare Xavier/Glorot | „Inițializarea pentru sigmoidă” | Var(w) = 2/(fan_in + fan_out), un compromis pentru păstrarea scărilor înainte și înapoi |
| Inițializare Kaiming/He | „Inițializarea pentru ReLU” | Var(w) = 2/fan_in, dedusă pentru a compensa rectificarea activărilor simetrice |
| Propagarea varianței | „Cum cresc sau se micșorează semnalele” | Analiza schimbării varianței activărilor și gradienților în funcție de scara ponderilor și de ipotezele distribuționale |
| Scalare reziduală | „Trucul de inițializare GPT-2” | Reducerea scării proiecțiilor ramurilor reziduale în funcție de profunzime pentru a controla acumularea |
| Rețea moartă | „Nu se antrenează nimic” | Rețea în care inițializarea produce gradienți nuli, activări saturate sau alte dinamici care împiedică învățarea |
| Activări care explodează | „Valorile tind la infinit” | Creșterea rapidă a activărilor prin straturi când scara efectivă a transformărilor este prea mare |
Lecturi suplimentare
- Glorot și Bengio, „Understanding the difficulty of training deep feedforward neural networks” (2010) — lucrarea originală despre inițializarea Xavier și analiza varianței.
- He și colaboratorii, „Delving Deep into Rectifiers” (2015) — a introdus inițializarea Kaiming pentru rețele cu rectificatoare.
- Radford și colaboratorii, „Language Models are Unsupervised Multitask Learners” (2019) — raportul GPT-2 asociat scalării inițiale a proiecțiilor reziduale.
- Mishkin și Matas, „All You Need is a Good Init” (2016) — inițializare secvențială pe straturi cu varianță unitară, o alternativă empirică la formulele analitice.
Sursă: Originalul în limba engleză
Navigare: ← Lecția 03.07 — Regularizare · Faza 3 — Fundamentele învățării profunde · Catalog complet