Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Oppiskele Takaisinkytkennän Toteutus | Neuroverkon Rakentaminen Alusta Alkaen
Johdatus neuroverkkoihin

bookTakaisinkytkennän Toteutus

Yleinen lähestymistapa

Eteenpäin suuntautuvassa laskennassa jokainen kerros ll ottaa edellisen kerroksen tuottamat arvot, al1a^{l-1}, syötteinä ja laskee omat lähtönsä. Tämän vuoksi forward()-luokan Layer-metodi ottaa edellisen kerroksen lähtövektorin ainoana parametrinaan, kun taas muu tarvittava tieto säilytetään luokan sisällä.

Taaksepäin suuntautuvassa laskennassa jokainen kerros ll tarvitsee vain dalda^l laskeakseen vastaavat gradientit ja palauttaakseen dal1da^{l-1}, joten backward()-metodi ottaa parametrinaan dalda^l-vektorin. Loput tarvittavasta tiedosta on jo tallennettu Layer-luokkaan.

Aktivointifunktioiden derivaatat

Koska aktivointifunktioiden derivaattoja tarvitaan taaksepäin suuntautuvassa laskennassa, aktivointifunktiot kuten ReLU ja sigmoid kannattaa toteuttaa luokkina erillisten funktioiden sijaan. Tämä mahdollistaa sekä:

  1. Itse aktivointifunktion (toteutettu __call__()-metodilla), jolloin sitä voidaan käyttää suoraan Layer-luokassa muodossa self.activation(z);
  2. Sen derivaatan (toteutettu derivative()-metodilla), mikä mahdollistaa tehokkaan taaksepäin suuntautuvan laskennan ja käytön Layer-luokassa muodossa self.activation.derivative(z).

Rakentamalla aktivointifunktiot olioiksi ne voidaan helposti välittää Layer-luokalle ja käyttää dynaamisesti.

ReLU

ReLU-aktivointifunktion derivaatta on seuraava, missä ziz_i on esiaaktivaatioiden vektorin zz alkio:

f(zi)={1,zi>00,zi0f'(z_i) = \begin{cases} 1, z_i > 0\\ 0, z_i \le 0 \end{cases}
class ReLU:
    def __call__(self, z):
        return np.maximum(0, z)

    def derivative(self, z):
        return (z > 0).astype(float)

Sigmoid

Sigmoid-aktivointifunktion derivaatta on seuraava:

f(zi)=f(zi)(1f(zi))f'(z_i) = f(z_i) \cdot (1 - f(z_i))
class Sigmoid:
    def __call__(self, x):
        return 1 / (1 + np.exp(-z))

    def derivative(self, z):
        sig = self(z)
        return sig * (1 - sig)

Molempia näitä aktivointifunktioita käytetään koko vektoriin zz, samoin niiden derivaattoja. NumPy suorittaa operaation automaattisesti jokaiselle vektorin alkiolle. Esimerkiksi, jos vektori zz sisältää 3 alkiota, derivointi tapahtuu seuraavasti:

f(z)=f([z1z2z3])=[f(z1)f(z2)f(z3)]f'(z) = f'( \begin{bmatrix} z_1\\ z_2\\ z_3 \end{bmatrix} ) = \begin{bmatrix} f'(z_1)\\ f'(z_2)\\ f'(z_3) \end{bmatrix}

backward()-metodi

backward()-metodi vastaa gradienttien laskemisesta alla olevien kaavojen mukaisesti:

dzl=dalfl(zl)dWl=dzl(al1)Tdbl=dzldal1=(Wl)Tdzl\begin{aligned} dz^l &= da^l \odot f'^l(z^l)\\ dW^l &= dz^l \cdot (a^{l-1})^T\\ db^l &= dz^l\\ da^{l-1} &= (W^l)^T \cdot dz^l \end{aligned}

a^{l-1} ja zlz^l tallennetaan inputs- ja outputs-attribuutteihin Layer-luokassa. Aktivointifunktio ff tallennetaan activation-attribuuttiin.

Kun kaikki tarvittavat gradientit on laskettu, painot ja biasit voidaan päivittää, koska niitä ei enää tarvita jatkolaskentaan:

Wl=WlαdWlbl=blαdbl\begin{aligned} W^l &= W^l - \alpha \cdot dW^l\\ b^l &= b^l - \alpha \cdot db^l \end{aligned}

Täten learning_rate (α\alpha) on toinen tämän metodin parametri.

def backward(self, da, learning_rate):
    dz = ...
    d_weights = ...
    d_biases = ...
    da_prev = ...

    self.weights -= learning_rate * d_weights
    self.biases -= learning_rate * d_biases

    return da_prev
Note
Huomio

Operaattori * suorittaa alkiokohtaisen kertolaskun, kun taas np.dot()-funktio suorittaa pistetulon NumPyssa. Attribuutti .T transponoi taulukon.

question mark

Mikä seuraavista kuvaa parhaiten backward()-metodin roolia Layer-luokassa takaisinkytkennän aikana?

Select the correct answer

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 2. Luku 8

Kysy tekoälyä

expand

Kysy tekoälyä

ChatGPT

Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme

Awesome!

Completion rate improved to 4

bookTakaisinkytkennän Toteutus

Pyyhkäise näyttääksesi valikon

Yleinen lähestymistapa

Eteenpäin suuntautuvassa laskennassa jokainen kerros ll ottaa edellisen kerroksen tuottamat arvot, al1a^{l-1}, syötteinä ja laskee omat lähtönsä. Tämän vuoksi forward()-luokan Layer-metodi ottaa edellisen kerroksen lähtövektorin ainoana parametrinaan, kun taas muu tarvittava tieto säilytetään luokan sisällä.

Taaksepäin suuntautuvassa laskennassa jokainen kerros ll tarvitsee vain dalda^l laskeakseen vastaavat gradientit ja palauttaakseen dal1da^{l-1}, joten backward()-metodi ottaa parametrinaan dalda^l-vektorin. Loput tarvittavasta tiedosta on jo tallennettu Layer-luokkaan.

Aktivointifunktioiden derivaatat

Koska aktivointifunktioiden derivaattoja tarvitaan taaksepäin suuntautuvassa laskennassa, aktivointifunktiot kuten ReLU ja sigmoid kannattaa toteuttaa luokkina erillisten funktioiden sijaan. Tämä mahdollistaa sekä:

  1. Itse aktivointifunktion (toteutettu __call__()-metodilla), jolloin sitä voidaan käyttää suoraan Layer-luokassa muodossa self.activation(z);
  2. Sen derivaatan (toteutettu derivative()-metodilla), mikä mahdollistaa tehokkaan taaksepäin suuntautuvan laskennan ja käytön Layer-luokassa muodossa self.activation.derivative(z).

Rakentamalla aktivointifunktiot olioiksi ne voidaan helposti välittää Layer-luokalle ja käyttää dynaamisesti.

ReLU

ReLU-aktivointifunktion derivaatta on seuraava, missä ziz_i on esiaaktivaatioiden vektorin zz alkio:

f(zi)={1,zi>00,zi0f'(z_i) = \begin{cases} 1, z_i > 0\\ 0, z_i \le 0 \end{cases}
class ReLU:
    def __call__(self, z):
        return np.maximum(0, z)

    def derivative(self, z):
        return (z > 0).astype(float)

Sigmoid

Sigmoid-aktivointifunktion derivaatta on seuraava:

f(zi)=f(zi)(1f(zi))f'(z_i) = f(z_i) \cdot (1 - f(z_i))
class Sigmoid:
    def __call__(self, x):
        return 1 / (1 + np.exp(-z))

    def derivative(self, z):
        sig = self(z)
        return sig * (1 - sig)

Molempia näitä aktivointifunktioita käytetään koko vektoriin zz, samoin niiden derivaattoja. NumPy suorittaa operaation automaattisesti jokaiselle vektorin alkiolle. Esimerkiksi, jos vektori zz sisältää 3 alkiota, derivointi tapahtuu seuraavasti:

f(z)=f([z1z2z3])=[f(z1)f(z2)f(z3)]f'(z) = f'( \begin{bmatrix} z_1\\ z_2\\ z_3 \end{bmatrix} ) = \begin{bmatrix} f'(z_1)\\ f'(z_2)\\ f'(z_3) \end{bmatrix}

backward()-metodi

backward()-metodi vastaa gradienttien laskemisesta alla olevien kaavojen mukaisesti:

dzl=dalfl(zl)dWl=dzl(al1)Tdbl=dzldal1=(Wl)Tdzl\begin{aligned} dz^l &= da^l \odot f'^l(z^l)\\ dW^l &= dz^l \cdot (a^{l-1})^T\\ db^l &= dz^l\\ da^{l-1} &= (W^l)^T \cdot dz^l \end{aligned}

a^{l-1} ja zlz^l tallennetaan inputs- ja outputs-attribuutteihin Layer-luokassa. Aktivointifunktio ff tallennetaan activation-attribuuttiin.

Kun kaikki tarvittavat gradientit on laskettu, painot ja biasit voidaan päivittää, koska niitä ei enää tarvita jatkolaskentaan:

Wl=WlαdWlbl=blαdbl\begin{aligned} W^l &= W^l - \alpha \cdot dW^l\\ b^l &= b^l - \alpha \cdot db^l \end{aligned}

Täten learning_rate (α\alpha) on toinen tämän metodin parametri.

def backward(self, da, learning_rate):
    dz = ...
    d_weights = ...
    d_biases = ...
    da_prev = ...

    self.weights -= learning_rate * d_weights
    self.biases -= learning_rate * d_biases

    return da_prev
Note
Huomio

Operaattori * suorittaa alkiokohtaisen kertolaskun, kun taas np.dot()-funktio suorittaa pistetulon NumPyssa. Attribuutti .T transponoi taulukon.

question mark

Mikä seuraavista kuvaa parhaiten backward()-metodin roolia Layer-luokassa takaisinkytkennän aikana?

Select the correct answer

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 2. Luku 8
some-alt