Dropout i detalj
Kunna förklara dropout som ensemble och varför den stängs av vid inferens.
Förkunskaper
Intuition
Under träning nollställs varje aktivering med sannolikhet p, oberoende. Varje minibatch tränar alltså ett slumpmässigt delnät.
Två sätt att förstå varför det hjälper:
- Implicit ensemble. Med n neuroner finns 2ⁿ möjliga delnät. Träningen samtränar dem med delade vikter, och vid inferens (utan dropout) approximeras medelvärdet av dem alla. Ensembler minskar varians — det är precis effekten.
- Motverkar samanpassning. En neuron kan inte förlita sig på att en viss annan neuron finns kvar, så den måste bidra med något eget användbart.
Vid inferens stängs dropout av — annars blir svaret slumpmässigt. Det är därför model.eval() inte är valfritt.
Formellt
Inverterad dropout (det alla bibliotek använder) skalar under träning i stället för vid inferens:
Då blir , och inferensen behöver inte göra någonting alls — vilket är poängen: inferenskoden blir identisk med och utan dropout.
(Den ursprungliga formuleringen skalade i stället med vid inferens. Matematiskt ekvivalent, praktiskt sämre.)
Val av p:
| Placering | Typiskt p |
|---|---|
| Fullt kopplade lager | 0,3–0,5 |
| Faltningslager | 0,0–0,2 (få parametrar, stark viktdelning) |
| Transformerblock (residual, attention) | 0,0–0,1 |
| Indatalager | 0,1–0,2 om alls |
Stora transformers använder ofta ingen dropout alls vid förträning: med tillräckligt mycket data är överanpassning inte problemet, och dropout kostar då bara effektiv kapacitet. Vid finjustering på lite data kommer den tillbaka.
MC-dropout: låt dropout vara på vid inferens och sampla n gånger. Spridningen i förutsägelserna blir en grov osäkerhetsskattning. Billigt men trubbigt — bättre än ingenting när kalibrerad osäkerhet behövs.
Kod
import numpy as np
def dropout_framat(a, p, traning, rng):
if not traning or p == 0:
return a # inferens: ingenting händer
mask = (rng.random(a.shape) > p).astype(a.dtype)
return a * mask / (1 - p) # inverterad: skala vid TRÄNING
rng = np.random.default_rng(0)
a = np.ones(10_000)
ut = dropout_framat(a, p=0.3, traning=True, rng=rng)
print(round(ut.mean(), 3), round((ut == 0).mean(), 3)) # 1.002 0.299
# väntevärdet bevarat ↑ ↑ ~30 % nollställda
# MC-dropout för osäkerhet
def mc_dropout(modell, x, n=30):
modell.train() # dropout PÅ, medvetet
with torch.no_grad():
p = torch.stack([modell(x).softmax(-1) for _ in range(n)])
modell.eval()
return p.mean(0), p.std(0) # medel och osäkerhet per klass
Behärskning innebär
- Förklarar dropout som implicit ensemble
- Beskriver inverterad dropout och varför den stängs av vid inferens
- Väljer p efter lagertyp
Logga in för att göra övningarna och bygga upp din behärskning.
Källor
- arXiv — Dropout: A Simple Way to Prevent Neural Networks from Overfitting (JMLR) — arXiv (öppen åtkomst; licens per artikel)
- arXiv — Dropout as a Bayesian Approximation (MC-dropout) — arXiv (öppen åtkomst; licens per artikel)