Skalningslagar
Kunna läsa och tillämpa skalningslagar för att välja modellstorlek och datamängd för en beräkningsbudget.
Förkunskaper
Intuition
Skalningslagar säger att förlusten faller förutsägbart som en potenslag i tre storheter: antal parametrar , antal träningstokens , och beräkning .
I log-log-skala blir det en rak linje, och det är det anmärkningsvärda: man kan mäta på små modeller och extrapolera till stora, över flera tiopotenser.
Vad det används till: innan man spenderar miljoner på en träningskörning kör man en serie små modeller, anpassar kurvan, och förutsäger vad den stora kommer att ge. Det gör skalning till en ingenjörsdisciplin i stället för en gissning.
Två saker att hålla isär:
| Betyder | |
|---|---|
| Förlusten faller förutsägbart | ja, det är vad lagarna säger |
| Förmågor växer förutsägbart | nej — det är en annan och mycket omdiskuterad fråga |
Formellt
Chinchilla-resultatet (Hoffmann m.fl. 2022) är det mest praktiskt användbara. Med en fast beräkningsbudget FLOPs är förlusten minimerad när
alltså cirka 20 träningstokens per parameter.
Det var en omvälvande slutsats, eftersom dåtidens största modeller var kraftigt underträade:
| Modell | Parametrar | Tokens | Tokens/param | Chinchilla-optimalt |
|---|---|---|---|---|
| GPT-3 (2020) | 175 B | 300 B | 1,7 | 3 500 B |
| Gopher (2021) | 280 B | 300 B | 1,1 | 5 600 B |
| Chinchilla (2022) | 70 B | 1 400 B | 20 | ✓ |
Chinchilla slog Gopher trots att den var fyra gånger mindre — den hade tränats på rätt mängd data för sin storlek.
Men Chinchilla optimerar träningskostnaden, inte totalkostnaden. Ska modellen köras miljarder gånger dominerar inferensen, och då lönar det sig att träna en mindre modell längre än vad Chinchilla säger. Det är därför moderna öppna modeller ofta tränas på 100–1 000 tokens per parameter — långt bortom det «optimala» — eftersom en mindre modell är billigare att köra i evighet.
Hur man gör i praktiken:
- Träna 5–8 små modeller av olika storlek, alla till sin Chinchilla-optimala datamängd.
- Anpassa i log-log.
- Extrapolera till målstorleken.
- Kontrollera mot en punkt i mitten som inte användes i anpassningen.
Steg 4 är det som skiljer en användbar förutsägelse från en förhoppning.
Vad skalningslagar inte förutsäger:
| Fråga | Svar |
|---|---|
| Nedströmsprestanda på en specifik uppgift | nej — förlusten är inte träffsäkerheten |
| När en förmåga «dyker upp» | omdiskuterat; Schaeffer m.fl. (2023) visade att många «emergenta» språng försvinner med kontinuerliga mått |
| Effekten av datakvalitet | nej — lagarna antar samma datafördelning |
| Var kurvan planar ut | extrapolering bortom mätområdet är osäker |
Den tredje raden är den mest praktiskt betydelsefulla: skalningslagarna säger ingenting om att bättre data kan flytta hela kurvan nedåt, vilket den gör. Att rensa och filtrera korpuset är ofta billigare än att tiodubbla beräkningen.
Kod
import numpy as np
def chinchilla_optimal(budget_flops):
"""C ≈ 6ND och D ≈ 20N ⟹ C ≈ 120N²."""
N = (budget_flops / 120) ** 0.5
return {"parametrar_md": round(N / 1e9, 2),
"tokens_md": round(20 * N / 1e9, 1),
"kontroll_flops": f"{6 * N * 20 * N:.2e}"}
for budget in (1e21, 1e22, 1e23, 1e24):
print(f"{budget:.0e} FLOPs → {chinchilla_optimal(budget)}")
# 1e+21 FLOPs → {'parametrar_md': 2.89, 'tokens_md': 57.7, ...}
# 1e+23 FLOPs → {'parametrar_md': 28.87, 'tokens_md': 577.4, ...}
# Anpassa en potenslag till mätdata och extrapolera
def anpassa_potenslag(N, L, L_inf=1.6):
"""L = L_inf + a·N^(-alfa). Linjär regression i log-log på (L - L_inf)."""
x = np.log(np.asarray(N, float))
y = np.log(np.asarray(L, float) - L_inf)
alfa_neg, log_a = np.polyfit(x, y, 1)
return {"alfa": round(float(-alfa_neg), 4), "a": round(float(np.exp(log_a)), 2),
"forutsag": lambda n: L_inf + np.exp(log_a) * n ** alfa_neg}
# Mätpunkter från små modeller
N = np.array([1e7, 3e7, 1e8, 3e8, 1e9])
L = 1.6 + 25.0 * N ** -0.30 # syntetisk «mätning»
f = anpassa_potenslag(N, L)
print(f"anpassad alfa {f['alfa']}, a {f['a']}")
for mal in (1e10, 1e11, 1e12):
print(f" N={mal:.0e}: förutsagd förlust {float(f['forutsag'](mal)):.4f}")
# Håll ut en punkt för kontroll — det är detta steg som oftast hoppas över
N_tr, L_tr = np.delete(N, 2), np.delete(L, 2)
f2 = anpassa_potenslag(N_tr, L_tr)
print(f"kontrollpunkt N=1e8: sant {L[2]:.4f}, förutsagt {float(f2['forutsag'](N[2])):.4f}")
# Chinchilla optimerar TRÄNING — räkna på totalkostnaden inklusive inferens
def total_kostnad(N, D, inferenstokens, kr_per_1e18_flops=50.0):
traning = 6 * N * D
inferens = 2 * N * inferenstokens
return {"traning_flops": f"{traning:.2e}", "inferens_flops": f"{inferens:.2e}",
"total_kr": round((traning + inferens) / 1e18 * kr_per_1e18_flops, 1),
"inferensandel": round(inferens / (traning + inferens), 3)}
print(total_kostnad(7e9, 140e9, 1e15)) # liten modell, mycket inferens
print(total_kostnad(70e9, 1400e9, 1e15)) # stor modell, samma inferensvolym
# ↑ vid hög inferensvolym lönar sig den mindre modellen även om den tränats längre
Behärskning innebär
- Tolkar en potenslag i log-log-skala
- Tillämpar Chinchilla-förhållandet
- Vet vad skalningslagar inte förutsäger
Logga in för att göra övningarna och bygga upp din behärskning.
Källor
- arXiv — Training Compute-Optimal Large Language Models (Chinchilla) — arXiv (öppen åtkomst; licens per artikel)
- arXiv — Scaling Laws for Neural Language Models — arXiv (öppen åtkomst; licens per artikel)
- arXiv — Are Emergent Abilities of Large Language Models a Mirage? — arXiv (öppen åtkomst; licens per artikel)