- Je initialiseert lagen reproduceerbaar met Xavier- of He-schaal.
- Je onderscheidt variantie van het tweede moment en meet signaalgroei door een netwerk.
Een netwerk kan al vóór de eerste update zijn signaal kwijtraken of opblazen. Geef je alle verborgen neuronen dezelfde beginwaarden, dan kunnen ze bovendien dezelfde feature blijven leren. We kiezen daarom verschillende willekeurige gewichten, met een schaal die bij de laag past.
Begin bij de visualisatie: vergelijk klein, He en groot, en verhoog het aantal lagen. Dezelfde vaste normale trekkingen worden anders geschaald. Kijk naar het tweede moment, een straks uitgelegde maat voor activatiegrootte, én de variantie; de berekening gaat over echt doorgerekende activaties.
64 voorbeelden, 16 features per laag, ReLU en nulbias. Dezelfde vaste normale trekkingen worden anders geschaald.
Laag 0 is de invoer. De as is begrensd van 10⁻¹⁰ tot 10¹⁰. De gemeten waarden hieronder blijven onbegrensd; He is ook hier geen perfecte behoudsgarantie.
1. Meer ingangen vragen een andere schaal
Een neuron telt bijdragen van alle ingangen op. Als je meer bijdragen toevoegt zonder hun schaal te verkleinen, kan de spreiding van de som groeien. Fan-in telt de ingangen per neuron; fan-out telt de uitvoerneuronen van de laag.
We gebruiken twee startregels voor normaal verdeelde gewichten met gemiddelde nul. Xavier-normal houdt rekening met beide breedtes en past bij ongeveer lineaire of niet sterk verzadigde symmetrische activaties. He-normal kiest voor ReLU een grotere variantie: onder symmetrieaannames valt bij ReLU ongeveer de helft van het tweede moment weg.
Hier zijn n-in en n-uit de twee laagbreedtes, σ² de gewichtsvariantie en σ de standaardafwijking. Bij vier ingangen en twaalf uitgangen is de Xaviervariantie 2/16 = 0.125 en de Hevariantie 2/4 = 0.5. De standaardafwijkingen zijn ongeveer 0.353553 en 0.707107.
import numpy as np
fan_in, fan_out = 4, 12
varianten = [2/(fan_in+fan_out), 2/fan_in]
for variantie in varianten:
print(variantie,
round(np.sqrt(variantie), 6))
# 0.125 0.353553
# 0.5 0.707107
Maak startvariantie(fan_in,fan_out,method) voor xavier en he. We gebruiken gehele laagbreedtes; weiger niet-positieve fans aan beide kanten en onbekende methodes met ValueError. De functie geeft variantie terug, terwijl de normale generator straks standaardafwijking verwacht.
2. Herhaalbare gewichten, verschillende neuronen
Maak initialiseer(fan_in,fan_out,method="he",seed=7) als tuple (w,b). W krijgt vorm (fan_in,fan_out) en de nulbias vorm (fan_out,). Nulbias is hier een vaste startkeuze; de verschillende gewichten doorbreken de symmetrie tussen neuronen.
Gebruik voor deze oefening np.random.default_rng(seed) als lokale generator. Zo kunnen we dezelfde beginlaag volgen zonder de globale toevalsreeks van andere experimenten te veranderen. Trek één matrix uit de normale verdeling met gemiddelde nul en de gekozen standaardafwijking.
rng = np.random.default_rng(7)
std = np.sqrt(2/(4+12))
w = rng.normal(0, std, size=(4,12))
b = np.zeros(12)
print(w.shape, b.shape) # (4, 12) (12,)
nogmaals = np.random.default_rng(7)
zelfde = nogmaals.normal(0,std,(4,12))
print(np.array_equal(w, zelfde)) # True
Dezelfde seed herhaalt in dezelfde omgeving de laag; een andere seed geeft andere gewichten. Trek niet voor iedere kolom opnieuw met dezelfde seed, want dan maak je juist identieke neuronen. Een kleine steekproef hoeft bovendien niet exact de theoretische variantie te hebben.
023. Meet variantie én tweede moment
De visualisatie gebruikt zestien ingangen, dus He heeft daar standaardafwijking √(2/16), ongeveer 0.354. Toch blijft het signaal niet perfect gelijk. De schaalregels steunen op aannames; meet wat jouw concrete netwerk doet.
Het tweede moment is het gemiddelde kwadraat. In de formule benoemt a een activatiewaarde en betekent E[...] het gemiddelde over alle arraywaarden. Variantie trekt daar het kwadraat van het gemiddelde af; ReLU maakt een positief gemiddelde mogelijk, waardoor die twee maten uit elkaar gaan.
Voor [−1,1] zijn gemiddelde 0, variantie 1 en tweede moment 1. Na ReLU krijg je [0,1]: gemiddelde 0.5, variantie 0.25, tweede moment 0.5. Gebruik populatievariantie, dus ddof=0, omdat we deze concrete array beschrijven.
a = np.array([-1., 1.])
for waarden in [a, np.maximum(0,a)]:
print(waarden.mean(), waarden.var(),
(waarden*waarden).mean())
# 0.0 1.0 1.0
# 0.5 0.25 0.5
Maak activatiestatistiek(x,weights) als lijst dictionaries met mean, var en second. Neem eerst de invoer op; voer daarna telkens het matrixproduct en ReLU uit en voeg de statistieken van die laag toe. Laat invoer en gewichtsmatrices intact, ook bij verschillende laagbreedtes.
a = np.array([[-1.,1.], [1.,-1.]])
weights = [np.eye(2), np.ones((2,2))]
moments = [float((a*a).mean())]
for w in weights:
a = np.maximum(0, a@w)
moments.append(float((a*a).mean()))
print(moments) # [1.0, 0.5, 1.0]
03Wat neem je mee?
- Kies schaal op basis van laagbreedte en activatie; gebruik de wortel als standaardafwijking.
- Een lokale seed maakt een beginlaag herhaalbaar zonder andere experimenten te verstoren.
- Meet tweede moment en variantie apart; initialisatie geeft een bruikbaar begin, geen trainingsgarantie.
Hierna kies je hoeveel voorbeelden samen één trainingsupdate bepalen.