Werkplaats / De werkplaats
In jouw eigen tempo
← Neurale netwerken
MODULE 02 · LES 04

Een laag rekent veel neuronen tegelijk uit

Gebruik matrixvormen om een dense laag te bouwen, parameters te tellen en twee affine lagen samen te vouwen.

60 min3 checkpoints
DIT GA JE ONTDEKKEN
  • Je rekent een batch door met XW+b en controleert de vormen.
  • Je verklaart waarom meer affine lagen zonder activatie geen nieuwe modelklasse opleveren.

Eén neuron verwerkt één voorbeeld en geeft één score. Nu wil je meerdere scores per plant én meerdere planten tegelijk verwerken, met dezelfde instellingen voor iedere plant. Een dense laag bundelt de gewogen sommen in een matrixberekening.

Iedere rij is één voorbeeld en iedere kolom één feature. Zo'n groep voorbeelden heet een batch. De batchgrootte verandert hoeveel je tegelijk doorrekent; zij voegt geen nieuwe modelgewichten toe.

1. Laat de binnenste maten overeenkomen

Neem twee planten met features [1,2] en [3,4]. We maken twee uitvoerscores met gewichtenmatrix W = [[1,−1],[2,0]] en biasvector [0.5,1]. Een kolom van W bevat de gewichten van één uitvoerneuron.

Voor de eerste plant wordt score 1 gelijk aan 1×1+2×2+0.5 = 5.5. Score 2 wordt 1×(−1)+2×0+1 = 0. Voor de tweede plant krijg je 11.5 en −2.

Z=XW+b

Bij n voorbeelden, d invoerfeatures en h uitvoerneuronen heeft X vorm (n,d), W vorm (d,h) en b vorm (h,). Z krijgt vorm (n,h). De binnenste maat d verbindt de matrices; de bias wordt bij iedere uitvoerrij opgeteld.

import numpy as np
X = np.array([[1, 2], [3, 4]], dtype=float)
W = np.array([[1, -1], [2, 0]], dtype=float)
b = np.array([0.5, 1.0])
Z = X @ W + b
print(Z.tolist())
# [[5.5,0.0],[11.5,-2.0]]
print(X.shape, W.shape, b.shape, Z.shape)
# (2,2) (2,2) (2,) (2,2)

np.array maakt een NumPy-array en dtype=float kiest opslag met kommagetallen. .shape geeft de aslengtes; .ndim telt de assen. @ is het matrixproduct, terwijl NumPy de bias hier automatisch over de rijen herhaalt: broadcasting.

Maak dense(x,w,b) en geef een NumPy-array terug. Zet de invoer om met np.asarray(...,dtype=float), zodat ook lijsten bruikbaar zijn. Controleer vóór het product dat x en w tweedimensionaal zijn, b eendimensionaal is, de binnenste maten overeenkomen en iedere uitvoerkolom één bias heeft; anders geef je ValueError.

Een toevallig broadcastbare b met vorm (1,h) voldoet dus niet aan ons afgesproken vectorcontract. De vormcontrole maakt een verkeerd model zichtbaar vóór NumPy misschien een andere berekening uitvoert.

DE BINNENSTE MATEN MOETEN PASSENVolg een batch door XW+b

Elk vakje is één getal. Deze vaste voorbeeldwaarden veranderen mee met de gekozen vormen.

X2 × 2
0.5112
invoer per rij
W2 × 3
0.50-0.510.50
trainbare gewichten
Z = XW+b2 × 3
1.30.602.51.1-0.3
uitvoer per rij
Parameters9Eerste uitvoerrij1.25 · 0.60 · -0.05

Bias b = [0.0, 0.1, 0.2], eenmaal per uitvoerneuron. Matrixvakjes tonen één decimaal; de uitvoerrij twee.

Verhoog in het diagram alleen n. Voorspel welke matrix groter wordt en of het parameteraantal verandert. Verhoog daarna h en controleer zowel het aantal kolommen als de extra biases.

01
CHECKPOINTVolg de vormen door de laag

2. Tel gewichten en biases afzonderlijk

Een laag met d invoeren en h uitgangen heeft d×h gewichten en h biases. Bij breedtes [2,3,1] heeft de eerste laag 2×3+3 = 9 parameters. De tweede heeft 3×1+1 = 4: samen 13.

widths = [2, 3, 1]
totaal = 0
for i in range(len(widths) - 1):
    d, h = widths[i], widths[i+1]
    aantal = d * h + h
    print(aantal)  # eerst 9, daarna 4
    totaal = totaal + aantal
print(totaal)  # 13

Maak parameter_aantal(widths) voor minstens twee positieve gehele breedtes. De batchgrootte staat niet in deze lijst: dezelfde gewichten worden voor ieder voorbeeld gebruikt. Veelgemaakte fout: alleen matrixcellen tellen en de biasvectoren vergeten.

02
CHECKPOINTTel gewichten én biases

3. Vouw twee lagen zonder activatie samen

Een gewogen som zonder bias is lineair; met een bias heet zij affien. Twee affine lagen achter elkaar blijven samen één affine laag. De eerste bias wordt daarbij ook door de tweede gewichtenmatrix vermenigvuldigd.

Wsamen=W1W2bsamen=b1W2+b2

Neem W₁ = [[1,0],[0,2]], b₁ = [1,−1], W₂ = [[2],[3]] en b₂ = [0.5]. De gecombineerde gewichten worden [[2],[6]] en de bias 1×2−1×3+0.5 = −0.5. Onze twee planten krijgen daarmee 13.5 en 29.5.

W1 = np.array([[1., 0.], [0., 2.]])
b1 = np.array([1., -1.])
W2 = np.array([[2.], [3.]])
b2 = np.array([0.5])
samen_W = W1 @ W2
samen_b = b1 @ W2 + b2
twee = (X @ W1 + b1) @ W2 + b2
een = X @ samen_W + samen_b
print(twee.tolist())  # [[13.5],[29.5]]
print(np.allclose(een, twee))  # True

allclose vergelijkt getallen met ruimte voor afronding. Maak vouw_samen(w1,b1,w2,b2) als (w,b) voor passende laagvormen. Alleen b₁+b₂ optellen zou het effect van de tweede laag op de eerste bias missen.

Met een activatie ertussen geldt dit samenvoegen in het algemeen niet meer. Gebruik voor één nieuwe rij de bekende ReLU, nu elementgewijs met np.maximum:

u = np.array([[-1., -1.]])
h = np.maximum(0, u @ W1 + b1)
print((h @ W2 + b2).tolist())  # [[0.5]]
print((u @ samen_W + samen_b).tolist())
# [[-8.5]]

De verborgen som [0,−3] wordt door ReLU [0,0]. Die knik verklaart het verschil: meerdere lagen krijgen pas met zulke omzettingen extra vormen van gedrag.

03
CHECKPOINTZonder kromming blijft het één affine laag

Wat neem je mee?

  • Matrixvormen leggen vast welke voorbeelden, features en uitgangen je combineert.
  • Parameters horen bij de laag; meer voorbeelden vergroten alleen de batch.
  • Twee affine lagen zijn samen te vouwen, maar een niet-lineaire activatie verandert dat.

Hierna onderzoek je hoe activaties zowel waarden als leersignalen doorgeven.

Verder lezen & bronnen

Inhoud gecontroleerd op 2026-10-28.
DE VOLGENDE STAPEen activatie maakt een nieuwe grens mogelijk
JOUW EXPERIMENT

Probeer het zelf

Python
main.py

Python start zodra jij code uitvoert.

UITVOER

Je uitvoer verschijnt hier.
Alles rekent in je eigen browser.

Jouw checkpoints0 / 3
01
Volg de vormen door de laag

Schrijf dense(x,w,b). Geef een NumPy-array terug en werp ValueError bij ongeldige dimensies of vormen.

Een hint

Zet invoer om met np.asarray(...,dtype=float); controleer ndim en de gedeelde dimensies vóór x@w+b.

02
Tel gewichten én biases

Schrijf parameter_aantal(widths) voor minstens twee positieve gehele laagbreedtes.

Een hint

Tel voor ieder aangrenzend paar d,h de bijdrage d*h+h.

03
Zonder kromming blijft het één affine laag

Schrijf vouw_samen(w1,b1,w2,b2) als (w,b) voor passende laagvormen.

Een hint

De tweede matrix werkt ook op de eerste bias. Alleen b1+b2 optellen klopt meestal niet.

Vastgelopen? Bekijk de voorbeeldoplossing
import numpy as np

def dense(x,w,b):
    x,w,b=[np.asarray(a,dtype=float) for a in (x,w,b)]
    if x.ndim!=2 or w.ndim!=2 or b.ndim!=1 or x.shape[1]!=w.shape[0] or w.shape[1]!=len(b):
        raise ValueError("Onverenigbare laagvormen")
    return x@w+b

def parameter_aantal(widths):
    return sum(d*h+h for d,h in zip(widths,widths[1:]))

def vouw_samen(w1,b1,w2,b2):
    w1,b1,w2,b2=[np.asarray(a,dtype=float) for a in (w1,b1,w2,b2)]
    return w1@w2,b1@w2+b2

Voer de code uit en verklaar voor jezelf waarom elke stap werkt.