Gradient Descent
Hoe vindt een AI de juiste gewichten? Het geheim achter machine learning: afdalen naar het dal van de minste fouten.
1. Het probleem: hoe leert een machine?
In Module 1 zagen we dat een perceptron gewichten en een bias nodig heeft om te werken. We gebruikten een simpele leerregel: als het antwoord fout is, schuif de gewichten een beetje. Maar bij complexere problemen werkt dat niet meer.
De vraag is: hoe vind je systematisch de beste gewichten?
De "berg" is de loss function (foutfunctie) — een formule die meet hoe ver je model ernaast zit. De "hoogte" is de fout. Het "dal" is het punt waar de fout het kleinst is. Gradient descent helpt je daar te komen.
2. Loss functions: fouten meten
Voordat je kunt leren, moet je kunnen meten hoe fout je model is. Dat doet een loss function. De twee meest gebruikte:
Mean Squared Error (MSE)
Je neemt het verschil tussen wat je verwacht en wat het model voorspelt, kwadreert dat (zodat negatieve fouten ook meetellen), en neemt het gemiddelde over alle voorbeelden.
| Verwacht | Voorspeld | Verschil | Kwadraat |
|---|---|---|---|
| 1 | 0.7 | 0.3 | 0.09 |
| 0 | 0.2 | -0.2 | 0.04 |
| 1 | 0.9 | 0.1 | 0.01 |
| MSE = | (0.09 + 0.04 + 0.01) / 3 = 0.047 | ||
Mean Absolute Error (MAE)
Simpeler — neem gewoon de absolute waarde van elk verschil. Minder gevoelig voor uitschieters, maar lastiger om mee te rekenen bij gradient descent.
3. De gradient: welke kant op?
Nu je weet hoe je fouten meet, is de volgende vraag: hoe pas je de gewichten aan zodat de fout kleiner wordt?
Hier komt de afgeleide (derivative) om de hoek kijken. De afgeleide van de loss function ten opzichte van een gewicht vertelt je:
- De richting — moet het gewicht groter of kleiner worden?
- De steilheid — hoe snel verandert de fout als je het gewicht aanpast?
Het minteken is cruciaal: je gaat de tegenovergestelde richting van de gradient op. Als de helling omhoog gaat (positieve gradient), verklein je het gewicht. Als de helling omlaag gaat (negatieve gradient), vergroot je het.
De afgeleide van MSE
Voor een enkel neuron met één gewicht en MSE als loss:
voorspeld = w × x + b
∂Loss / ∂w = -2 × (verwacht - voorspeld) × x
∂Loss / ∂b = -2 × (verwacht - voorspeld)
In de praktijk laten we de factor 2 vaak weg (het is toch maar een constante die de learning rate absorbeert).
4. Learning rate: de stapgrootte
De learning rate (leertempo) bepaalt hoe groot elke stap is. Dit is een van de belangrijkste keuzes in machine learning.
| Learning rate | Effect | Risico |
|---|---|---|
| Te klein (0.0001) | Hele kleine stapjes, zeer langzaam | Duurt eeuwen, kan vastlopen in lokaal minimum |
| Goed (0.01 - 0.1) | Stabiele convergentie | — |
| Te groot (1.0+) | Grote sprongen, overschiet het dal | Stuitert heen en weer, convergeert nooit |
5. Varianten van gradient descent
Het basis-algoritme heeft drie varianten, afhankelijk van hoeveel data je per stap gebruikt:
| Variant | Data per stap | Eigenschap |
|---|---|---|
| Batch GD | Alle data | Stabiel maar langzaam bij grote datasets |
| Stochastic GD (SGD) | 1 voorbeeld | Snel maar onrustig (veel ruis) |
| Mini-batch GD | Klein groepje (16-256) | Beste van beide werelden — dit wordt het meest gebruikt |
6. Python code: gradient descent in actie
We trainen een enkel neuron om een simpele functie te leren: y = 2x + 1
import random
# --- Data genereren: y = 2x + 1 ---
data = []
for _ in range(100):
x = random.uniform(0, 10)
y = 2 * x + 1 + random.gauss(0, 0.5) # beetje ruis
data.append((x, y))
# --- Neuron parameters ---
w = random.uniform(-1, 1) # gewicht (we zoeken: 2)
b = random.uniform(-1, 1) # bias (we zoeken: 1)
lr = 0.001 # learning rate
# --- Training loop ---
for epoch in range(200):
total_loss = 0
for x, y_true in data:
# Forward pass
y_pred = w * x + b
# Loss (MSE per punt)
loss = (y_true - y_pred) ** 2
total_loss += loss
# Gradient berekenen
dw = -2 * (y_true - y_pred) * x # dLoss/dw
db = -2 * (y_true - y_pred) # dLoss/db
# Gewichten updaten
w -= lr * dw
b -= lr * db
avg_loss = total_loss / len(data)
if epoch % 20 == 0:
print(f"Epoch {epoch:3d} | Loss: {avg_loss:.4f} | w={w:.4f}, b={b:.4f}")
print(f"\nGeleerd: y = {w:.2f}x + {b:.2f}")
print(f"Werkelijk: y = 2.00x + 1.00")
Verwachte output (ongeveer):
Epoch 0 | Loss: 45.2310 | w=0.8321, b=-0.1234
Epoch 20 | Loss: 1.3456 | w=1.7823, b=0.6543
Epoch 40 | Loss: 0.2891 | w=1.9567, b=0.9234
...
Epoch 180 | Loss: 0.2501 | w=2.0012, b=0.9987
Geleerd: y = 2.00x + 1.00
Werkelijk: y = 2.00x + 1.00
Interactieve demo 1: De bal die het dal zoekt
Versleep de bal naar een startpositie en klik Start. De bal daalt af langs de loss-curve via gradient descent. Experimenteer met de learning rate!
Interactieve demo 2: Een lijn leren
Het neuron probeert een rechte lijn te fitten door de datapunten. Klik Train en kijk hoe de lijn (en de loss) zich aanpast. Je kunt ook eigen punten klikken op het linkervlak.
7. Valkuilen: lokale minima en zadelpunten
Bij een simpele functie zoals x² is er maar één dal — het globale minimum. Maar bij complexe neurale netwerken is het landschap vol heuvels en dalen.
- Lokaal minimum — een dal dat niet het diepste is. Je bal kan hier vastlopen.
- Zadelpunt — een punt dat in één richting een dal is en in een andere richting een heuvel (zoals een bergpas).
- Plateau — een vlak stuk waar de gradient bijna nul is. Je bal beweegt nauwelijks.
Probeer in Demo 1 het "Hobbelig landschap" en start de bal op verschillende posities. Je zult zien dat hij soms in een lokaal minimum landt, niet in het diepste dal.
- Momentum — geef de bal "snelheid" zodat hij over kleine heuvels heen rolt
- Random restarts — begin meerdere keren op verschillende plekken
- Adam optimizer — past learning rate automatisch per gewicht aan
- Stochastic noise — de ruis van SGD helpt om uit lokale minima te ontsnappen
8. Vooruitblik: backpropagation
Gradient descent werkt prima voor één neuron. Maar wat als je honderden neuronen in meerdere lagen hebt? Hoe bereken je dan de gradient voor elk gewicht?
Het antwoord is backpropagation — een slim algoritme dat de chain rule uit de wiskunde gebruikt om de fout "terug te propageren" van de output naar elke laag. In Module 3 gaan we dit in detail behandelen.
Elke schakel in de keten vertelt hoe gevoelig de uiteindelijke fout is voor die specifieke weight. Zo kan elk gewicht in het netwerk individueel worden bijgestuurd.
Samenvatting
- Een loss function meet hoe ver je model ernaast zit (MSE, MAE).
- De gradient (afgeleide) vertelt in welke richting en hoe snel de fout verandert.
- Gradient descent past gewichten aan in de tegenovergestelde richting van de gradient.
- De learning rate bepaalt de stapgrootte — te klein is langzaam, te groot is instabiel.
- Er zijn drie varianten: batch, stochastic en mini-batch (meest gebruikt).
- Lokale minima en zadelpunten zijn valkuilen — momentum en Adam helpen hiertegen.
- Backpropagation (Module 3) maakt gradient descent mogelijk voor diepe netwerken.
Een gratis cursus van iCt Horse — Connecting the dots
