Försvinnande och exploderande gradienter
Kunna diagnostisera gradientproblem och åtgärda med initiering, normalisering och residualer.
Förkunskaper
- DAktiveringsfunktionerkrävs
- DBackpropagationkrävs
Intuition
Gradienten till lager 1 i ett djupt nät är en produkt av många faktorer. Små avvikelser från 1 förstärks exponentiellt:
| Faktor per lager | Efter 30 lager |
|---|---|
| 0,8 | 0,001 — försvunnen |
| 0,95 | 0,21 |
| 1,0 | 1,0 |
| 1,05 | 4,3 |
| 1,2 | 237 — exploderad |
Symptomen skiljer sig:
- Försvinnande: de tidiga lagren lär sig inte alls; lossen planar ut på en dålig nivå; gradientnormen i lager 1 är storleksordningar mindre än i sista lagret.
- Exploderande: loss blir NaN eller hoppar våldsamt; gradientnormen skjuter i höjden ett enskilt steg.
Diagnosen är enkel: logga gradientnormen per lager. Problemet syns direkt.
Formellt
Fyra åtgärder, och vad var och en faktiskt gör:
| Åtgärd | Mekanism |
|---|---|
| He/Xavier-initiering | håller variansen konstant genom lagren från start |
| ReLU/GELU i stället för sigmoid/tanh | derivatan mättas inte mot 0 för stora |x| |
| Normalisering (batch/layer) | håller aktiveringarna i ett rimligt intervall lager för lager |
| Residualkopplingar | ger — en genväg med faktor 1 |
Residualkopplingen är den viktigaste av dem. Den är skälet till att nät med hundratals lager är tränbara: gradienten har alltid en väg tillbaka där den multipliceras med 1.
Gradientklippning mot exploderande gradienter: skala ner hela gradientvektorn om dess norm överskrider ett tak. Klipp på global norm, inte per parameter — annars förvrids riktningen. c = 1,0 är standard för transformers.
Viktig nyansering: klippning behandlar symptomet. Om du behöver klippa varje steg är något annat fel — för hög lr, dålig initiering, eller en bugg i förlusten.
Kod
import torch
def gradientprofil(modell):
"""Logga per lager — här syns problemet direkt."""
rader = []
for namn, p in modell.named_parameters():
if p.grad is not None and p.dim() > 1:
rader.append((namn, float(p.grad.norm()), float(p.norm())))
for namn, g, w in rader:
print(f"{namn:34s} |grad| {g:.2e} |w| {w:.2e} förhållande {g/max(w,1e-12):.2e}")
return rader
# I träningsloopen
loss.backward()
norm = torch.nn.utils.clip_grad_norm_(modell.parameters(), max_norm=1.0) # global norm
if norm > 10:
print(f"varning: gradientnorm {norm:.1f} före klippning")
opt.step(); opt.zero_grad()
# Typisk utskrift vid försvinnande gradient:
# blocks.0.attn.W_q |grad| 3.1e-08 ← storleksordningar mindre
# blocks.15.attn.W_q |grad| 2.4e-04
# blocks.31.attn.W_q |grad| 1.9e-03
Förhållandet |grad|/|w| är ofta mer informativt än gradientnormen själv: det säger hur stor relativ förändring steget innebär.
Behärskning innebär
- Diagnostiserar gradientproblem med gradientnormer
- Åtgärdar med initiering, normalisering och residualer
- Använder gradientklippning rätt
Logga in för att göra övningarna och bygga upp din behärskning.
Källor
- arXiv — Deep Residual Learning for Image Recognition — arXiv (öppen åtkomst; licens per artikel)
- arXiv — On the difficulty of training Recurrent Neural Networks — arXiv (öppen åtkomst; licens per artikel)
- Dive into Deep Learning (CC BY-SA 4.0) — CC BY-SA 4.0