- Je implementeert activaties en hun lokale afgeleiden.
- Je bouwt een niet-lineaire oplossing voor XOR en verklaart de grenzen van de demonstratie.
Een laag heeft gewogen sommen berekend. Hoeveel daarvan geeft zij door, en hoe gevoelig is de uitvoer voor een kleine verandering? Een activatiefunctie bepaalt beide: haar waarde stuurt de volgende laag en haar afgeleide bepaalt later hoe een leersignaal teruggaat.
Je vergelijkt ReLU en tanh en bouwt daarna een klein netwerk dat XOR oplost. De gewichten van dat netwerk kiezen we met de hand. Het voorbeeld laat zien wat een verborgen laag kan uitdrukken; het is nog geen bewijs dat training die oplossing vanzelf vindt.
1. ReLU laat de positieve helft door
Je kent ReLU uit het eerste neuron: negatieve invoer wordt nul, positieve invoer blijft gelijk. Voor z = [−1,0,1] krijg je [0,0,1]. Op een hele array kun je diezelfde vergelijking elementgewijs uitvoeren.
import numpy as np
def relu(z):
z = np.asarray(z, dtype=float)
return np.maximum(0, z)
z = np.array([-1., 0., 1.])
a = relu(z)
print(a.tolist()) # [0.0, 0.0, 1.0]
De lokale helling is nul onder nul en één boven nul. Precies op de knik bestaat geen gewone afgeleide. In deze cursus kiezen we daar de rekenconventie nul, zodat de terugweg een vaste afspraak heeft.
gevoelig = (z > 0).astype(float)
print(gevoelig.tolist()) # [0.0, 0.0, 1.0]
De vergelijking maakt een booleaanse array; .astype(float) zet False en True om naar 0.0 en 1.0. Maak relu(z) en relu_afgeleide(z) als NumPy-arrays met dezelfde vorm als de invoer. Ook een matrix moet element voor element werken.
Een negatieve som krijgt langs deze rekenroute dus geen lokaal leersignaal terug. Als een ReLU voor alle trainingsvoorbeelden negatief blijft, kan die eenheid moeilijk weer actief worden. Een nulafgeleide betekent niet dat de volledige verliesfunctie nul is.
012. Tanh buigt geleidelijk en verzadigt
Tanh, de hyperbolische tangens, maakt een vloeiende S-vorm tussen −1 en 1. De functie is oneven: de waarde bij −z is het tegengestelde van de waarde bij z. Bij nul is de waarde nul en de helling één.
In de formule is e het vaste getal ongeveer 2.718; e tot de macht z is de exponentiële functie, in NumPy np.exp(z).
Bij z = 1 is tanh ongeveer 0.761594 en de afgeleide ongeveer 0.419974. Bij z = −1 draait de waarde van teken om, maar blijft de afgeleide positief en even groot. Gebruik np.tanh voor de numerieke berekening; rechtstreeks grote exponenten uitrekenen kan overlopen.
z = np.array([-1., 0., 1., 4.])
a = np.tanh(z)
g = 1 - a * a
print(np.round(a, 6).tolist())
# [-0.761594, 0.0, 0.761594, 0.999329]
print(np.round(g, 6).tolist())
# [0.419974, 1.0, 0.419974, 0.001341]
Maak tanh_en_afgeleide(z) als (activatie,afgeleide) met twee NumPy-arrays. Bewaar de juiste activatietekens: alleen haar kwadraat controleren zou een tekenfout in de uitvoer verbergen.
Groen: activatie. Oranje: afgeleide. Verplaats de invoer en vergelijk de twee getallen.
Vergelijk in het diagram tanh bij z = 0 en z = 4. De uitvoer nadert één, terwijl de afgeleide bijna verdwijnt: verzadiging. Bij meerdere terugwaartse vermenigvuldigingen kunnen zulke kleine factoren het signaal sterk verzwakken.
Schakel daarna naar ReLU en vergelijk −1 met 1. Een grote uitvoer en een grote afgeleide zijn verschillende eigenschappen; kijk steeds naar beide getallen.
023. Maak twee verborgen features voor XOR
XOR geeft één wanneer precies één van twee binaire invoeren één is. De positieve gevallen [0,1] en [1,0] liggen op tegenoverliggende hoeken; één rechte grens kan ze niet beide van [0,0] en [1,1] scheiden. Met twee geknikte features lukt het wel.
Bereken eerst s = x₁+x₂. Laat h₁ = ReLU(s) en h₂ = ReLU(s−1), en combineer ze tot h₁−2h₂. De tweede verborgen feature trekt alleen bij de dubbele één weer twee af.
| Invoer | s | h₁ | h₂ | Uitvoer |
|---|---|---|---|---|
| [0,0] | 0 | 0 | 0 | 0 |
| [0,1] | 1 | 1 | 0 | 1 |
| [1,0] | 1 | 1 | 0 | 1 |
| [1,1] | 2 | 2 | 1 | 0 |
x = np.array([[0, 0], [0, 1],
[1, 0], [1, 1]], dtype=float)
s = x.sum(axis=1)
h1 = relu(s)
h2 = relu(s - 1)
uitvoer = h1 - 2 * h2
print(uitvoer.tolist()) # [0.0,1.0,1.0,0.0]
sum(axis=1) telt de twee features binnen iedere rij op en geeft één getal per voorbeeld. Maak xor_netwerk(x) voor een matrix met twee binaire kolommen en retourneer een uitvoervector. Gebruik je eigen ReLU-functie voor de twee verborgen features.
Veelgemaakte fout: alleen extra affine lagen stapelen en dezelfde scheiding verwachten. De niet-lineariteit maakt hier het verschil; de laatste combinatie zelf mag gewoon lineair zijn. Buiten de vier binaire hoeken heeft dit handgekozen netwerk niet automatisch een zinvolle betekenis.
03Wat neem je mee?
- Activatiewaarde en afgeleide beschrijven wat doorgaat en hoe gevoelig dat is.
- ReLU heeft een knikconventie; tanh kan aan beide kanten verzadigen.
- Verborgen niet-lineaire features maken een scheiding mogelijk die één rechte grens mist.
Hierna zet je meerdere uitvoerscores om in een kansverdeling en bereken je het passende verlies.