Simple kunstige neurale netværk

Et generelt kunstigt neuralt netværk består af en masse neuroner, som er sat sammen i en række lag. Det kunne for eksempel se ud som i figur 1, hvor de grønne neuroner i midten repræsenterer de såkaldte skjulte lag.

Figur 1: Generelt kunstigt neuralt netværk med flere skjulte lag.

I denne note vil vi se på et mere simpelt tilfælde, som det er vist i figur 2. Her er der kun to skjulte lag, og hver af disse lag består kun af én neuron. Sådanne netværk, hvor de skjulte lag netop kun består af én neuron, vil vi her kalde for simple kunstige neurale netværk. På den måde befinder disse netværk sig begrebsmæssigt "in between" perceptroner og kunstige neuroner på den ene side og generelle kunstige neurale netværk1 på den anden. De simple kunstige neurale netværk har den fordel, at de giver en fin forståelse af, hvad neurale netværk er – herunder hvad feedforward og backpropagation går ud på – men samtidig uden, at det bliver alt for matematisk svært.

1 Som vi ofte bare vil referere til som neurale netværk.

Så lad os komme i gang! Udgangspunktet er et eksempel om at lave en simpel vejrudsigt.

Kan vi forudsige vejret?

Forestil dig, at du gerne vil kunne forudsige, om det bliver regnvejr i morgen. Det er selvfølgelig ikke nogen helt simpel opgave, men man kunne forestille sig, at der vil være en række variable, som kan hjælpe med at lave den forudsigelse. Det kunne for eksempel være:

\[ \begin{aligned} &x_1: \textrm{Er det regnvejr i dag? Hvis 'ja' er } x_1=1 \textrm{ og } 0 \textrm{ ellers.} \\ &x_2: \textrm{Luftfugtigheden i dag.} \\ &x_3: \textrm{Temperaturen i dag.} \\ &x_4: \textrm{Lufttrykket i dag.} \\ \end{aligned} \tag{1}\]

Og der vil sikkert være en masse andre variable, som også kunne give mening. Disse variable \(x_1, x_2, \dots, x_n\) kaldes for inputvariable.

Vi vil nu se på, hvordan man ved hjælp af sådanne inputvariable kan prædiktere, om det bliver regnvejr i morgen.

Feedforward

Vi starter med at se på det mere generelle tilfælde, hvor vi har \(n\) inputvariable:

\[ x_1, x_2, \dots, x_n. \] Disse inputvariable sender vi nu ind i et forholdsvis simpelt neuralt netværk, som vist i figur 2.

Figur 2: Grafisk illustration af et neuralt netværk med \(n\) inputvariable og to skjulte lag, som hver består af én neuron.

De grønne og blå cirkler i figur 2 kaldes for neuroner. Idéen er, at vi på baggrund af inputværdierne (her vist som de lilla cirkler til venstre) i sidste ende vil beregne en outputværdi \(o\) (som er illustreret ved den blå cirkel længst til højre). Outputværdien skal i dette eksempel være et tal mellem \(0\) og \(1\), som skal kunne fortolkes som sandsynligheden for, at det bliver regnvejr i morgen baseret på inputværdierne \(x_1, x_2, \dots, x_n\). Herefter kunne man forestille sig følgende vejrudsigt:

\[ \textrm{Det bliver regnvejr i morgen: } \begin{cases} \textrm{Ja} & \textrm{hvis } o \geq 0.5\\ \textrm{Nej} & \textrm{hvis } o < 0.5\\ \end{cases} \] Lad os derfor se på, hvordan \(o\) kan beregnes. Det sker ved hjælp af en række vægte, som er repræsenteret ved pilene i figur 2. Inputværdierne sendes frem til den første neuron (vist som en lysegrøn cirkel i figur 2). Her beregnes den vægtede2 sum:

2 Strengt taget er der ikke tale om en vægtet sum på grund af konstantleddet \(r_0\). Men hvis man tilføjer en inputværdi \(x_0\), som altid er \(1\), så kan udtrykket skrives \(r_0 \cdot x_0 + r_1 \cdot x_1 + r_2 \cdot x_2 + \cdots + r_n \cdot x_n.\) I det tilfælde kan man tale om en vægtet sum af inputværdierne \(x_0, x_1, \dots, x_n\).

\[ r_0 + r_1 \cdot x_1 + r_2 \cdot x_2 + \cdots + r_n \cdot x_n. \]

Bemærk her, at der er \(n+1\) vægte, da der er inkluderet et konstantled \(r_0\).

Herefter benyttes en såkaldt aktiveringsfunktion på den vægtede sum. En ofte anvendt aktiveringsfunktion er sigmoid-funktionen \(\sigma\):

\[ \sigma (x) = \frac{1}{1+e^{-x}}. \tag{2}\]

Det vil sige, at vi beregner

\[ \begin{aligned} y &= h(x_1, x_2, \dots, x_n) \\ &=\sigma (r_0 + r_1 \cdot x_1 + r_2 \cdot x_2 + \cdots + r_n \cdot x_n) \\ &= \frac{1}{1+e^{-(r_0 + r_1 \cdot x_1 + r_2 \cdot x_2 + \cdots + r_n \cdot x_n)}}. \end{aligned} \]

Grafen for sigmoid-funktionen ses i figur 3.

Figur 3: Grafen for sigmoid-funktionen.

Her anskueliggøres det, at sigmoid-funktionen tager et vilkårligt reelt tal som input og giver et tal i intervallet \(]0,1[\) som output. Det kan skrives sådan her:

\[ \sigma : \mathbb{R} \rightarrow ]0,1[. \]

Det næste, der sker, er, at den første (lysegrønne) neuron i figur 2 sender værdien \(y\) videre i netværket, hvor \(0<y<1\). Ved den næste neuron i figur 2 (repræsenteret ved den mørkegrønne cirkel), beregnes først \(v_0 + v_1 \cdot y\) og herefter anvendes igen aktiveringsfunktionen:

\[ z = g(y) = \sigma (v_0 + v_1 \cdot y). \]

Denne værdi sendes nu frem til den sidste neuron i outputlaget og outputværdien \(o\) beregnes på tilsvarende måde

\[ o = f(z) = \sigma(w_0 + w_1 \cdot z). \]

Hele denne proces med at udregne outputværdien \(o\) på baggrund af inputværdierne \(x_1, x_2, \dots, x_n\) kaldes for feedforward og er opsummeret herunder:

Feedforward-udtryk

På baggrund af inputværdierne \(x_1, x_2, \dots, x_n\) beregnes outputværdien \(o\) på følgende måde.

Først beregnes:

\[ y = h(x_1, x_2, \dots, x_n) = \sigma (r_0 + r_1 \cdot x_1 + r_2 \cdot x_2 + \cdots + r_n \cdot x_n) \tag{3}\]

Dernæst beregnes:

\[ z = g(y)=\sigma (v_0 + v_1 \cdot y) \tag{4}\]

Og til sidst kan outputværdien \(o\) beregnes:

\[ o = f(z)=\sigma(w_0 + w_1 \cdot z) \tag{5}\]

Bemærk, at outputværdien \(o\) beregnes ved hjælp af sigmoid-funktionen, og derfor er et tal mellem \(0\) og \(1\), som tidligere ønsket – altså kan \(o\) fortolkes som en sandsynlighed.

Med udgangspunkt i feedforward-udtrykkene, kan vi også skrive outputværdien \(o\) direkte som en funktion af inputværdierne \(x_1, x_2, \dots, x_n\). Vi starter med at indsætte udtrykket for \(z\) i (4) i udtrykket for \(o\) i (5):

\[ \begin{aligned} o &= f(z)=f(g(y)) \\ &=\sigma(w_0 + w_1 \cdot (\sigma (v_0 + v_1 \cdot y))) \end{aligned} \]

Herefter erstatter vi \(y\) med udtrykket i (3):

\[ \begin{aligned} o &= f(z)=f(g(y))=f(g(h(x_1, x_2, \dots, x_n))) \\&= \sigma(w_0 + w_1 \cdot (\sigma (v_0 + v_1 \cdot (\sigma (r_0 + r_1 \cdot x_1 + r_2 \cdot x_2 + \cdots + r_n \cdot x_n) )))) \end{aligned} \]

Her bliver det meget tydeligt, at

  1. Outputværdien afhænger af inputværdierne \(x_1, x_2, \dots, x_n\):

    \[ o = \sigma(w_0 + w_1 \cdot (\sigma (v_0 + v_1 \cdot (\sigma (r_0 + r_1 \cdot {\color{#F288B9} x_1} + r_2 \cdot {\color{#F288B9} x_2} + \cdots + r_n \cdot {\color{#F288B9} x_n}) )))) \]

    Det er den måde, vi forstår feedforward-udtrykkene på: Vi beregner outputværdien \(o\) ud fra inputværdierne \(x_1, x_2, \dots, x_n\). Vi kan altså her tænke på outputværdien som en funktion af inputværdierne \(x_1, x_2, \dots, x_n\).

  2. Outputværdien afhænger også af alle vægtene \(w_0, w_1, v_0, v_1, r_0, r_1, \dots, r_n\): \[ o =\sigma({\color{#8086F2} w_0} + {\color{#8086F2} w_1} \cdot (\sigma ({\color{#8086F2} v_0} + {\color{#8086F2} v_1} \cdot (\sigma ({\color{#8086F2} r_0} + {\color{#8086F2} r_1} \cdot x_1 + {\color{#8086F2} r_2} \cdot x_2 + \cdots + {\color{#8086F2} r_n} \cdot x_n) )))) \] Her tænker vi på \(o\) som en funktion af vægtene \(w_0, w_1, v_0, v_1, r_0, r_1, \dots, r_n\). Det er denne tankegang, vi skal bruge, når vi skal i gang med at træne netværket. Her er inputværdierne nemlig givet, mens vi ønsker at justere på vægtene, så netværk bliver så godt som muligt til at forudsige vejret.

og

  1. Outputværdien \(o\) kan udtrykkes ved hjælp af flere sammensatte funktioner (her markeret med gult).

    \[ o ={\color{#F2B33D} \sigma}({w_0} + {w_1} \cdot ({\color{#F2B33D} \sigma} ({v_0} + {v_1} \cdot ({\color{#F2B33D} \sigma} ({r_0} + {r_1} \cdot x_1 + {r_2} \cdot x_2 + \cdots + {r_n} \cdot x_n) )))) \]

    Det er årsagen til, at vi senere får brug for kædereglen, når vi skal i gang med at differentiere ovenstående med hensyn til vægtene.

Bortset fra det er feedforward-udtrykkene ovenfor nok nemmere at overskue!

Fint nok – nu har vi altså en model, som kan bruges til at forudsige vejret. Men måske er du skeptisk. Det bør du i hvert tilfælde være! For hvem siger, at outputværdien \(o\) siger noget som helst om sandsynligheden for, at det bliver regnvejr i morgen? Det korte svar er: Det gør den heller ikke nødvendigvis! I hvert tilfælde ikke sådan uden videre. Det kræver nemlig, at alle vægtene er "indstillet" sådan, at den beregnede outputværdi rent faktisk kan fortolkes som en sandsynlighed for, at det bliver regnvejr i morgen. For at lave denne "indstilling" skal vi bruge to ting: 1) træningsdata og 2) en tabsfunktion. Det kommer her.

Træningsdata og tabsfunktion

Nu tænker vi os, at du registrerer de fire størrelser i (1) på en række forskellige dage, ligesom du også den efterfølgende dag registrerer, om det regner eller ej. Denne sidste registrering kunne for eksempel ske på denne måde:

\[ t= \begin{cases} 1 & \textrm{hvis det regner den efterfølgende dag} \\ 0 & \textrm{hvis det ikke regner den efterfølgende dag} \\ \end{cases} \] Variablen \(t\) kaldes for en targetvariabel. Det er netop denne værdi, vi gerne vil kunne forudsige. Man kan derfor tænke på variablen \(t\), som en slags facitliste. Man siger også, vi gerne vil prædiktere \(t\).

Hvis vi for eksempel laver denne registrering på 10 forskellige dage kan vi skrive det op på denne måde:

\[ \begin{aligned} &\text{Dag 1:} \quad (x_1^{(1)}, x_2^{(1)}, x_3^{(1)}, x_4^{(1)}, t^{(1)}) \\ &\text{Dag 2:} \quad (x_1^{(2)}, x_2^{(2)}, x_3^{(2)}, x_4^{(2)}, t^{(2)}) \\ & \quad \vdots \\ &\text{Dag 10:} \quad (x_1^{(10)}, x_2^{(10)}, x_3^{(10)}, x_4^{(10)}, t^{(10)}) \\ \end{aligned} \]

Det hævede tal i parentes angiver altså nummeret på dagen. For eksempel angiver \(x_3^{(2)}\) temperaturen på dag 2, mens \(t^{(2)}\) er 1, hvis det regner dagen efter dag 2 og 0 ellers. Bemærk, at dagene ikke behøver at komme efter hinanden. Det kan tværtimod være en fordel, hvis dagene er spredt ud, så der ikke kommer afhængigheder mellem værdierne.

Ovenstående kaldes for træningsdata. Helt generelt med \(n\) inputvariable og \(M\) observationer i træningsdata vil vi opskrive træningsdatasættet sådan her:

\[ \begin{aligned} &\text{Træningseksempel 1:} \quad (x_1^{(1)}, x_2^{(1)}, \dots, x_n^{(1)}, t^{(1)}) \\ & \quad \quad \quad \quad \vdots \\ &\text{Træningseksempel m:} \quad (x_1^{(m)}, x_2^{(m)}, \dots, x_n^{(m)}, t^{(m)}) \\ & \quad \quad \quad \quad \vdots \\ &\text{Træningseksempel M:} \quad (x_1^{(M)}, x_2^{(M)}, \dots, x_n^{(M)}, t^{(M)}) \\ \end{aligned} \]

Vi kan nu tage hvert træningsdataeksempel og sende det ind i netværket i figur 2. Det gør vi ved hjælp af feedforward-udtrykkene i (3), (4) og (5). Vi får derfor for hvert træningseksempel beregnet en outputværdi \(o\). Outputværdien for det \(m\)’te træningseksempel vil vi kalde for \(o^{(m)}\).

Hvis netværket er godt – det vil sige, hvis vi har fundet nogle "gode" værdier af vægtene, så vil outputværdien \(o\) kunne fortolkes som sandsynligheden for, om det bliver regnvejr i morgen.

Det betyder, at et godt netværk har denne egenskab:

  • Hvis \(t=1\), så er \(o \approx 1\).
  • Hvis \(t=0\), så er \(o \approx 0\).

I begge tilfælde betyder det, at \[ t-o \approx 0. \]

Det er præcis denne differens, som vi vil bruge som et mål for, hvor godt netværket er.

Nu kan denne differens både være positiv og negativ. Derfor vil vi se på den kvadrerede differens:

\[ (t-o)^2. \]

Hvis netværket er godt, vil denne kvadrerede differens stadig være tæt på \(0\). Samtidig vil der jo også være en differens for hvert træningsdataeksempel:

\[ (t^{(1)}-o^{(1)})^2, (t^{(2)}-o^{(2)})^2, \dots, (t^{(M)}-o^{(M)})^2. \]

Det er summen af alle disse differenser (ganget3 med \(1/2\)), som vi vil bruge som mål for, hvor godt netværket er:

3 At vi ganger med \(1/2\) er ikke så vigtigt – du ser senere, hvorfor det er smart.

\[ E = \frac{1}{2} \sum_{m=1}^M (t^{(m)}-o^{(m)})^2 \]

Denne funktion er den, som vi kalder for en tabsfunktion (eller på engelsk error function – deraf \(E\)’et). Som vi har argumenteret for ovenfor, så er vi netop på jagt efter de værdier af vægtene, som minimerer tabsfunktionen.

Tabsfunktionen ovenfor kan også omskrives en smule:

\[ \begin{aligned} E &= \frac{1}{2} \sum_{m=1}^M (t^{(m)}-o^{(m)})^2 \\ &= \sum_{m=1}^M \frac{1}{2} (t^{(m)}-o^{(m)})^2 \\ &= \sum_{m=1}^M E^{(m)}, \end{aligned} \tag{6}\]

hvor

\[ E^{(m)} = \frac{1}{2} (t^{(m)}-o^{(m)})^2 \tag{7}\]

er det bidrag til tabsfunktionen, som stammer fra det \(m\)’te træningseksempel.

For at finde værdier af vægtene som minimerer tabsfunktionen bruges en metode, som kaldes for backpropagation. Det forklarer vi lige om lidt, men vi kan allerede nu afsløre, at vi får brug for at kunne differentiere tabsfunktionen. Vi har tidligere set, at alle outputværdierne \(o^{(m)}\) er en sammensat funktion. Derfor bliver tabsfunktionen også en sammensat funktion. Det betyder, at vi får brug for at kunne differentiere sammensatte funktioner, og det siger kædereglen noget om. Men først skal vi se, hvordan kædereglen kan opskrives på en smart måde, hvilket vi skal bruge i forbindelse med backpropagation.

Kædereglen

Du kender godt de sammensatte funktioner. Det kunne for eksempel være en funktion4 \(k\):

4 Bemærk her, at vi kalder en funktion for \(k\), men det er altså ikke at veksle med en konstant, som vi også ofte kalder for \(k\)!

\[ k(x)= f(g(x)) \]

Funkionen \(k\) afhænger af \(x\), men det sker via den indre funktion \(g\) og den ydre funktion \(f\). Altså \(k\) er sammensat af en indre og en ydre funktion:

  • Indre funktion: \(u=g(x)\)
  • Ydre funktion: \(f(u)\)

Idéen er illustreret i figur 4.

Figur 4: Illustration af funktionen \(k\) som er sammensat af den indre funktion \(g\) og den ydre funktion \(f\).

For at beregne \(k(x)\) "sender" vi først \(x\) ind i "funktionsmaskinen" for \(g\). Her bliver \(g(x)\) beregnet. Denne værdi "sendes" så ind i "funktionsmaskinen" for \(f\) og dermed bliver \(f(g(x))\) beregnet, som netop er \(k(x)\).

Hvis vi skal differentiere funktionen \(k\), så skal vi bruge reglen for at differentiere sammensatte funktioner:

\[ k'(x)=f'(g(x)) \cdot g'(x) \tag{8}\]

Det er altså den ydre funktion differentieret taget på den indre5 gange den indre funktion differentieret.

5 Det betyder, at der står \(f'(g(x))\) og for eksempel ikke \(f'(x)\).

Hvis vi erstatter \(g(x)\) med \(u\) kan det skrives:

\[ k'(x)=f'(u) \cdot g'(x) \]

Du har måske også lært, at man i stedet for at bruge mærker til at angive, at man har differentieret, kan skrive sådan her (kært barn har som bekendt mange navne):

\[ \frac{dk}{dx} = \frac{df}{du} \cdot \frac{du}{dx} \]

Denne måde at skrive reglen for at differentiere sammensatte funktioner på kaldes for kædereglen6. Navnet kædereglen kommer af, at de diffenrentialkvotienter, som indgår på højre side bliver "kædet" sammen. Det er nemmest at illustrere med farver:

6 Bemærk, at denne måde at skrive en differentialkvotient på (\(\frac{dk}{dx}\)) ikke er en egentlig brøk, selvom det ligner. Det svarer derimod til grænseværdien af en brøk (nemlig grænseværdien af en differenskvotient).

\[ \frac{dk}{dx} = \frac{df}{\color{#8086F2} du} \color{black}\cdot \frac{\color{#8086F2} du \color{black}}{dx} \]

Bemærk, at denne notation jo er noget kortere end udtrykket i (8), men vi har også "fejet noget ind under gulvtæppet". Det er nemlig ikke tydeligt, hvad de afledede funktioner skal evalueres i. I (8) ses det tydeligt, at \(f'\) skal evalueres i \(g(x)\), mens \(g'\) skal evalueres i \(x\). Denne information er underforstået, når vi bruger "kæderegelsnotationen" ovenfor. Hvis man vil, kan man pakke kædereglen lidt mere ud, så det bliver tydeligere:

\[ \frac{dk}{dx} (x) = \frac{df}{du} (u) \cdot \frac{du}{dx} (x), \]

hvor

\[ u = g(x). \] Selvom denne måde at skrive det på er mere korrekt, vil vi alligevel for enkelthedens skyld holde fast i notationen i (8).

Kædereglen bliver endnu tydeligere, hvis vi ser på en funktion, som er sammensat af ikke bare to, men tre funktioner:

\[ k(x) = f(g(h(x))) \] Denne funktion er sammensat af tre funktioner:

  • Indre funktion: \(y=h(x)\)
  • Indre funktion: \(z=g(y)\)
  • Ydre funktion: \(f(z)\)

For at differentiere \(k\) må vi først bruge kædereglen én gang:

\[ k'(x)= f'(g(h(x))) \cdot \left ( g(h(x))\right)' \] For at differentiere den sidste faktor må vi bruge kædereglen endnu en gang:

\[ \left ( g(h(x))\right)' = g'(h(x)) \cdot h'(x) \]

Det vil sige, at vi samlet set ender med:

\[ k'(x)= f'(g(h(x))) \cdot g'(h(x)) \cdot h'(x) \] Bruger vi notation med \(dk/dx\) og husker på, at

\[ z = g(y) \qquad \textrm{og} \qquad y = h(x) \]

kan ovenstående skrives som:

\[ \frac{dk}{dx} = \frac{df}{dz} \cdot \frac{dz}{dy} \cdot \frac{dy}{dx} \]

Og med farver bliver det tydeligt, hvorfor der er tale om en kæderegel:

\[ \frac{dk}{dx} = \frac{df}{\color{#8086F2} dz} \cdot \frac{\color{#8086F2} dz}{\color{#F288B9} dy} \cdot \frac{\color{#F288B9} dy}{dx} \]

Denne måde at skrive kædereglen på får vi brug for i det følgende.

Backpropagation

Husk på at vi gerne vil bestemme de værdier af vægtene, så tabsfunktionen i (6) bliver minimeret. Når man skal minimere en funktion af flere variable kan man egentlig bare sætte alle de partielle afledede lig med 0. Det vil give lige så mange ligninger, som der er vægte (og alle ligninger vil være koblet til hinanden). I vores simple eksempel her vil det ikke være noget problem at løse de ligninger. Men i virkelighedens verden, hvor de kunstige neurale netværk afhænger af millioner eller milliarder af vægte, er denne fremgangsmåde beregningsmæssigt alt for tung. Det vil dels tage alt for lang tid, og det vil dels tage for meget plads på computeren.

Man bruger derfor en anden metode, som kaldes for backpropagation. I backpropagation bruger man for det første gradientnedstigning, så den tager vi lige først.

Vi forestiller os, at vi har en funktion \(f\), som afhænger af \(x_1, x_2, \dots, x_n\). Vi "stiller" os nu et tilfældigt sted på grafen for \(f\) og udregner gradienten

\[ \nabla f(x_1, x_2, \dots, x_n) = \begin{pmatrix} \frac{\partial f}{\partial x_1} \\ \frac{\partial f}{\partial x_2} \\ \vdots \\ \frac{\partial f}{\partial x_n} \end{pmatrix}. \]

Så viser det sig, at gradienten peger i den retning, hvor funktionsværdien vokser mest. Derfor vil minus gradienten pege i den retning, hvor funktionsværdien aftager mest. Visuelt kan man forestille sig, at man står i et bakkelandskab, hvor man gerne vil ned i en dal. Så kan man tænke på den negative gradient, som den retning vi skal bevæge os i, hvis vi gerne vil gå allermest nedad bakke (og det er jo smart, hvis man gerne vil ende i dalen). Man udregner derfor gradienten og går et lille stykke i den negative gradients retning. Nu er det jo ikke sikkert, at man hele tiden skal gå i den samme retning, så derfor er man nødt til at udregne gradienten igen på det nye sted, man nu står og så korrigere sin retning i forhold det næste lille skridt, man tager.

Det er altså idéen, hvis man gerne vil bestemme minimum. Man stiller sig simpelthen et tilfældigt sted på grafen for \(f\) og udregner gradienten. Så bevæger man sig et lille stykke i den negative gradients retning. I det nye punkt udregner man gradienten igen og går et lille stykke i den nye negative gradients retning. Sådan fortsætter man, indtil funktionsværdien ikke ændrer sig ret meget, og man er landet i et minimum (eventuelt kun lokalt).

Nu hedder vores funktion ikke \(f\), men \(E\) (det var tabsfunktionen). \(E\) afhænger af vægtene \(r_0, r_1, \dots, r_n, v_0, v_1, w_0\) og \(w_1\). Vi vælger derfor nogle tilfældige værdier af disse vægte og udregner gradienten. Så opdaterer vi alle vægtene ved at gå et lille stykke \(\eta\) i den negative gradients retning. For at beregne den nye værdi af \(w_1\), som vi her vil kalde for \(w_1^{\textrm{ny}}\), vil det for eksempel se sådan her ud:

\[ w_1^{\textrm{ny}} \leftarrow w_1 - \eta \cdot \frac{\partial E}{\partial w_1} \]

Det lille stykke \(\eta\), som vi går i den negative gradients retning, kaldes også for en learning rate. Her er \(w_1\) den "nuværende" værdi af vægten, og pilen til venstre betyder, at der foretages en opdatering. Den nye værdi af vægten kaldes, som sagt, for \(w_1^{\textrm{ny}}\).

I backpropagation opdateres vægtene ved at bruge ovenstående opdateringsregel, men det gøres på en snedig måde. Nemlig ved at opdatere vægtene tættest på outputlaget først – det vil sige \(w_0\) og \(w_1\). Dernæst går man en skidt længere tilbage i netværket i figur 2 og opdaterer \(v_0\) og \(v_1\) og endelig opdaterer man til sidst vægtene tættest på inputlaget \(r_0, r_1, \dots, r_n\). Vi skal nok forklare, hvorfor det er smart, men det er altså årsagen til, at metoden kaldes for backpropagation: Fordi vægtene opdateres fra outputlaget og bagud.

Inden opdateringen af vægtene går i gang sættes alle vægtene til en tilfældig værdi. Herefter tager vi alle \(M\) træningsdata og sender ind i netværket. Det vil sige, at vi på baggrund af feedforward-udtrykkene i (3), (4) og (5) udregner følgende for det \(m\)’te træningsdataeksempel:

\[ y^{(m)} = \sigma (r_0 + r_1 \cdot x_1^{(m)} + r_2 \cdot x_2^{(m)} + \cdots + r_n \cdot x_n^{(m)}) \tag{9}\]

\[ z^{(m)} = \sigma (v_0 + v_1 \cdot y^{(m)}) \tag{10}\]

\[ o^{(m)} = \sigma(w_0 + w_1 \cdot z^{(m)}) \tag{11}\]

og det gør vi altså for alle \(M\) træningsdata \(m \in \{1, 2, \dots, M\}\). Alle disse værdier af \(y^{(m)}\), \(z^{(m)}\) og \(o^{(m)}\) får vi nemlig brug for, når vi skal i gang med at opdatere vægtene.

Vi er nu klar til at opdatere vægtene \(w\)-vægtene, som ligger tættest på outputlaget.

Opdatering af \(w\)-vægtene

Ved at bruge gradientnedstigning bliver opdateringsligningerne for \(w\)-vægtene følgende:

\[ \begin{aligned} w_0^{\textrm{ny}} &\leftarrow w_0 - \eta \cdot \frac{\partial E}{\partial w_0} \\ w_1^{\textrm{ny}} &\leftarrow w_1 - \eta \cdot \frac{\partial E}{\partial w_1} \end{aligned} \tag{12}\]

Vi skal altså differentiere tabsfunktionen

\[ \begin{aligned} E = \sum_{m=1}^M \frac{1}{2} (t^{(m)}-o^{(m)})^2 = \sum_{m=1}^M E^{(m)}, \end{aligned} \] hvor

\[ E^{(m)} = \frac{1}{2} (t^{(m)}-o^{(m)})^2 \] med hensyn til \(w_0\) og \(w_1\). Lad os starte med \(w_1\). For det første skal vi huske, at man kan differentiere ledvist (det er sumreglen). Det giver:

\[ \frac{\partial E}{\partial w_1} = \sum_{m=1}^M \frac{\partial E^{(m)}}{\partial w_1} \]

For det andet får vi brug for kædereglen, da \(E^{(m)}\) jo er en sammensat funktion. På figur 2 kan man se, at tabsfunktionen afhænger af \(w_1\) via outputværdien \(o^{(m)}\). Derfor giver kædereglen:

\[ \frac{\partial E}{\partial w_1} = \sum_{m=1}^M \frac{\partial E^{(m)}}{\partial o^{(m)}} \cdot \frac{\partial o^{(m)}}{\partial w_1} \tag{13}\]

Vi ser nu på hver faktor i denne sum for sig. For at bestemme \(\frac{\partial E^{(m)}}{\partial o^{(m)}}\) skal vi bruge definitionen i (7):

\[ E^{(m)} = \frac{1}{2} (t^{(m)}-o^{(m)})^2 \]

Her bruger vi også kædereglen. Det giver

\[ \begin{aligned} \frac{\partial E^{(m)}}{\partial o^{(m)}} &= \frac{1}{2} \cdot 2 \cdot (t^{(m)}-o^{(m)}) \cdot (-1) \\ &= - (t^{(m)}-o^{(m)}) \end{aligned} \tag{14}\]

Bemærk for øvrigt, at \(\frac{1}{2}\) og \(2\) forkorter ud. Det var derfor, at vi gangede tabsfunktionen i (6) med \(\frac{1}{2}\).

For at finde \(\frac{\partial o^{(m)}}{\partial w_1}\) skal vi bruge feedforward-ligningen i (11):

\[ o^{(m)} = \sigma(w_0 + w_1 \cdot z^{(m)}) \]

Det er også en sammensat funktion, og bruger vi kædereglen på dette udtryk, får vi

\[ \frac{\partial o^{(m)}}{\partial w_1} = \sigma'(w_0 + w_1 \cdot z^{(m)}) \cdot z^{(m)}, \]

idet den indre funktion \(w_0 + w_1 \cdot z^{(m)}\) differentieret med hensyn til \(w_1\) bare giver \(z^{(m)}\). Af ovenstående fremgår det, at vi får brug for at differentiere sigmoid-funktionen. Det viser sig, at den afledede sigmoid-funktion kan udtrykkes simpelt ved hjælp af sigmoid-funktionen selv på denne måde7:

7 Se eventuelt mere i opgave 2 her.

Den afledede sigmoid-funktion

\[ \sigma'(x) = \sigma(x) \cdot (1-\sigma(x)) \tag{15}\]


Bruger vi denne særlige egenskab, får vi

\[ \frac{\partial o^{(m)}}{\partial w_1} = \sigma(w_0 + w_1 \cdot z^{(m)}) \cdot (1-\sigma(w_0 + w_1 \cdot z^{(m)})) \cdot z^{(m)} \]

Og da \(o^{(m)}=\sigma(w_0 + w_1 \cdot z^{(m)})\) kan dette skrives som

\[ \frac{\partial o^{(m)}}{\partial w_1} = o^{(m)} \cdot (1-o^{(m)}) \cdot z^{(m)} \tag{16}\]

Hvis vi indsætter udtrykket i (14) og (16) i (13), får vi

\[ \frac{\partial E}{\partial w_1}= - \sum_{m=1}^M (t^{(m)}-o^{(m)}) \cdot o^{(m)} \cdot (1-o^{(m)}) \cdot z^{(m)} \]

Indsættes dette i (12) bliver opdateringsreglen for \(w_1\):

\[ w_1^{\textrm{ny}} \leftarrow w_1 + \eta \cdot \sum_{m=1}^M (t^{(m)}-o^{(m)}) \cdot o^{(m)} \cdot (1-o^{(m)}) \cdot z^{(m)} \]

Hvis vi lader

\[ \delta_w^{(m)} = (t^{(m)}-o^{(m)} ) \cdot o^{(m)} \cdot (1-o^{(m)}) \tag{17}\]

kan det skrives kort som

\[ w_1^{\textrm{ny}} \leftarrow w_1 + \eta \cdot \sum_{m=1}^M \delta_w^{(m)} \cdot z^{(m)} \]

På helt tilsvarende vis kan opdateringsreglen for \(w_0\) udledes, og vi ender med:

Opdateringsregler for \(w\)-vægtene

\[ \begin{aligned} w_0^{\textrm{ny}} \leftarrow & w_0 + \eta \cdot \sum_{m=1}^{M} \delta_w^{(m)} \cdot 1\\ w_1^{\textrm{ny}} \leftarrow & w_1 + \eta \cdot \sum_{m=1}^{M} \delta_w^{(m)} \cdot z^{(m)}\\ \end{aligned} \] hvor \[ \delta_w^{(m)} = (t^{(m)}-o^{(m)} ) \cdot o^{(m)} \cdot (1-o^{(m)}) \]

Bemærk her, at fordi vi allerede ved hjælp af feedforward-udtrykkene har beregnet \(z^{(m)}\) og \(o^{(m)}\), så alle størrelser, som indgår i ovenstående opdateringsregler, er allerede udregnet.

Opdatering af \(v\)-vægtene

Vi træder nu et skridt tilbage i netværket i figur 2 og opdaterer \(v\)-vægtene. Gradientnedstigning giver helt generelt følgende opdateringsregler:

\[ \begin{aligned} v_0^{\textrm{ny}} &\leftarrow v_0 - \eta \cdot \frac{\partial E}{\partial v_0} \\ v_1^{\textrm{ny}} &\leftarrow v_1 - \eta \cdot \frac{\partial E}{\partial v_1} \end{aligned} \tag{18}\]

Vi vælger at udlede den sidste regel og skal derfor finde \(\frac{\partial E}{\partial v_1}\). Det kan ses på figur 2, at \(v\)-vægtene påvirker tabsfunktionen \(E\) først via værdien \(z\) og dernæst via outputværdien \(o\). Når vi skal differentiere tabsfunktionen i (6) med hensyn til \(v_1\) kan du derfor igen bruge kædereglen sådan her:

\[ \begin{aligned} \frac{\partial E}{\partial v_1} &= \sum_{m=1}^M \frac{ \partial E^{(m)}}{\partial v_1} \\ &= \sum_{m=1}^M \frac{ \partial E^{(m)}}{\partial o^{(m)}} \cdot \frac{ \partial o^{(m)}}{\partial z^{(m)} } \cdot \frac{ \partial z^{(m)}}{\partial v_1} \end{aligned} \tag{19}\]

Vi har allerede i (14) fundet ud af, at

\[ \frac{ \partial E^{(m)}}{\partial o^{(m)}} = -(t^{(m)}-o^{(m)}) \]

Bruger vi feedforward-ligningen i (11):

\[ o^{(m)} = \sigma(w_0 + w_1 \cdot z^{(m)}) \] hvor vi nu differentierer med hensyn til \(z^{(m)}\) får vi:

\[ \begin{aligned} \frac{ \partial o^{(m)}}{\partial z^{(m)} } &= \sigma'(w_0 + w_1 \cdot z^{(m)}) \cdot w_1 \\ &= o^{(m)} \cdot (1-o^{(m)}) \cdot w_1 \end{aligned} \tag{20}\]

Her har vi igen brugt den særlige egenskab i (15).

Nu mangler vi blot at bestemme \(\frac{ \partial z^{(m)}}{\partial v_1}\), og her får vi brug for feedward ligningen i (10)

\[ z^{(m)} = \sigma (v_0 + v_1 \cdot y^{(m)}). \]

Derfor er

\[ \begin{aligned} \frac{ \partial z^{(m)}}{\partial v_1} &= \sigma' (v_0 + v_1 \cdot y^{(m)}) \cdot y^{(m)} \\ &= z^{(m)} \cdot (1-z^{(m)}) \cdot y^{(m)} \end{aligned} \tag{21}\]

Igen på grund af (15).

Vi kan nu indsætte (14), (20) og (21) i (19) og få

\[ \begin{aligned} \frac{\partial E}{\partial v_1} &= \sum_{m=1}^M \underbrace{-(t^{(m)}-o^{(m)})}_{\frac{\partial E^{(m)}}{\partial o^{(m)}}} \cdot \underbrace{o^{(m)} \cdot (1-o^{(m)}) \cdot w_1}_{\frac{ \partial o^{(m)}}{\partial z^{(m)} }} \cdot \underbrace{z^{(m)} \cdot (1-z^{(m)}) \cdot y^{(m)}}_{\frac{ \partial z^{(m)}}{\partial v_1}} \\ &= - \sum_{m=1}^M \delta_w^{(m)} \cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)}) \cdot y^{(m)} \end{aligned} \]

da \[ \delta_w^{(m)} = (t^{(m)}-o^{(m)} ) \cdot o^{(m)} \cdot (1-o^{(m)}). \]

På tilsvarende vis kan man vise, at

\[ \frac{\partial E}{\partial v_1} = - \sum_{m=1}^M \delta_w^{(m)} \cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)}) \cdot 1 \]

Indsættes i (18) får vi altså disse opdateringsregler:

Opdateringsregler for \(v\)-vægtene

\[ \begin{aligned} v_0^{\textrm{ny}} \leftarrow & v_0 + \eta \cdot \sum_{m=1}^{M} \delta_w^{(m)}\cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)})\cdot 1\\ v_1^{\textrm{ny}} \leftarrow & v_1 + \eta \cdot \sum_{m=1}^{M} \delta_w^{(m)} \cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)})\cdot y^{(m)}\\ \end{aligned} \] hvor \[ \delta_w^{(m)} = (t^{(m)}-o^{(m)} ) \cdot o^{(m)} \cdot (1-o^{(m)}) \]

Her kan vi igen se, at vi på grund af feedforward allerede har beregnet \(y^{(m)}\), \(z^{(m)}\) og \(o^{(m)}\).

Opdatering af \(r\)-vægtene

Vi er nu nået til det sidste lag i netværket, som er tættest på inputlaget. Her bliver de generelle opdateringsregler:

\[ \begin{aligned} r_0^{\textrm{ny}} &\leftarrow r_0 - \eta \cdot \frac{\partial E}{\partial r_0} \\ r_1^{\textrm{ny}} &\leftarrow r_1 - \eta \cdot \frac{\partial E}{\partial r_1} \\ & \quad \vdots \\ r_n^{\textrm{ny}} &\leftarrow r_n - \eta \cdot \frac{\partial E}{\partial r_n} \end{aligned} \tag{22}\]

figur 2 ses det, at tabsfunktionen afhænger af disse \(r\)-vægte via \(o^{(m)}\), \(z^{(m)}\) og \(y^{(m)}\). Der kommer derfor lidt mere fut i kædereglen nu. Den partielle afledede med hensyn til \(r_i\) (hvor \(i \in \{1, 2, \dots, n\}\)) bliver

\[ \begin{aligned} \frac{\partial E}{\partial r_i} &= \sum_{m=1}^M \frac{ \partial E^{(m)}}{\partial r_i} \\ &= \sum_{m=1}^M \frac{ \partial E^{(m)}}{\partial o^{(m)}} \cdot \frac{ \partial o^{(m)}}{\partial z^{(m)} } \cdot \frac{ \partial z^{(m)}}{\partial y^{(m)}} \cdot \frac{ \partial y^{(m)}}{\partial r_i} \end{aligned} \tag{23}\]

Nu er vi heldige, for vi har allerede udregnet de to første faktorer i denne sum i (14) og (20):

\[ \frac{\partial E^{(m)}}{\partial o^{(m)}} = - (t^{(m)}-o^{(m)}) \]

og

\[ \frac{ \partial o^{(m)}}{\partial z^{(m)} } = o^{(m)} \cdot (1-o^{(m)}) \cdot w_1 \]

Nu mangler vi bare de to sidste faktorer i (23). Feedforward-ligningen i (10) giver

\[ \begin{aligned} \frac{\partial z^{(m)}}{\partial y^{(m)}} &= \sigma ' (v_0 + v_1 \cdot y^{(m)}) \cdot v_1 \\ &= z^{(m)} \cdot (1-z^{(m)})\cdot v_1. \end{aligned} \tag{24}\]

Her har vi endnu en gang brugt (15).

Ved hjælp af feedforward-ligningen i (9) kan vi bestemme

\[ \begin{aligned} \frac{\partial y^{(m)}}{\partial r_i} &= \sigma '(r_0 + r_1 \cdot x_1^{(m)} + r_2 \cdot x_2^{(m)} + \cdots + r_n \cdot x_n^{(m)}) \cdot x_i^{(m)} \\ &= y^{(m)} \cdot (1-y^{(m)}) \cdot x_i^{(m)}. \end{aligned} \tag{25}\]

Sidste lighedstegn følger af (15) og at

\[ y^{(m)} = \sigma(r_0 + r_1 \cdot x_1^{(m)} + r_2 \cdot x_2^{(m)} + \cdots + r_n \cdot x_n^{(m)}). \]

Bemærk her, at hvis vi differentierer med hensyn til \(r_0\), så bliver

\[ \frac{\partial y^{(m)}}{\partial r_0}=y^{(m)} \cdot (1-y^{(m)}) \cdot 1. \]

Vi kan nu som tidligere indsætte (14), (20), (24) og (25) i (23):

\[ \begin{aligned} \frac{\partial E}{\partial r_i} = \sum_{m=1}^M \underbrace{-(t^{(m)}-o^{(m)})}_{\frac{\partial E^{(m)} }{\partial o^{(m)}}} \cdot &\underbrace{o^{(m)} \cdot (1-o^{(m)}) \cdot w_1}_{\frac{\partial o^{(m)}}{\partial z^{(m)}}} \cdot \\ &\underbrace{z^{(m)} \cdot (1-z^{(m)})\cdot v_1}_{\frac{\partial z^{(m)}}{\partial y^{(m)}}} \cdot \underbrace{y^{(m)} \cdot (1-y^{(m)}) \cdot x_i^{(m)}}_{\frac{\partial y^{(m)}}{\partial r_i}} \end{aligned} \]

Definitionen af \(\delta_w^{(m)}\) i (17) tillader os at forkorte ovenstående en smule:

\[ \frac{\partial E}{\partial r_i} = - \sum_{m=1}^M \delta_w^{(m)} \cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)})\cdot v_1 \cdot y^{(m)} \cdot (1-y^{(m)}) \cdot x_i^{(m)} \] Opdateringsreglen for \(r_i\) bliver derfor ifølge (22):

\[ r_i^{\textrm{ny}} \leftarrow r_i + \eta \cdot \sum_{m=1}^M \delta_w^{(m)} \cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)})\cdot v_1 \cdot y^{(m)} \cdot (1-y^{(m)}) \cdot x_i^{(m)} \] Og for samtlige \(r\)-vægte ender vi med følgende:

Opdateringsregler for \(r\)-vægtene

\[ \begin{aligned} r_0^{\textrm{ny}} &\leftarrow r_0 + \eta \cdot \sum_{m=1}^M \delta_w^{(m)} \cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)})\cdot v_1 \cdot y^{(m)} \cdot (1-y^{(m)}) \cdot 1 \\ r_1^{\textrm{ny}} &\leftarrow r_1 + \eta \cdot \sum_{m=1}^M \delta_w^{(m)} \cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)})\cdot v_1 \cdot y^{(m)} \cdot (1-y^{(m)}) \cdot x_1^{(m)} \\ & \quad \vdots \\ r_n^{\textrm{ny}} &\leftarrow r_n + \eta \cdot \sum_{m=1}^M \delta_w^{(m)} \cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)})\cdot v_1 \cdot y^{(m)} \cdot (1-y^{(m)}) \cdot x_n^{(m)} \\ \end{aligned} \]

hvor \[ \delta_w^{(m)} = (t^{(m)}-o^{(m)} ) \cdot o^{(m)} \cdot (1-o^{(m)}) \]

Igen har vi – fordi vi forud for opdateringen af vægtene har lavet en feedforward i netværket – udregnet \(y^{(m)}\), \(z^{(m)}\) og \(o^{(m)}\), som skal bruges for at beregne ovenstående opdateringer.

Opsummering af backpropagation

Vi vil nu lave en samlet opsummering af de tre forskellig opdateringsregler for at få et bedre overblik over, hvad der egentlig sker, når man laver backpropagation.

Opdateringsreglerne for laget tættest på outputlaget (\(w\)-vægtene) er:

\[ \begin{aligned} w_0^{\textrm{ny}} \leftarrow & w_0 + \eta \cdot \sum_{m=1}^{M} \delta_w^{(m)} \cdot 1\\ w_1^{\textrm{ny}} \leftarrow & w_1 + \eta \cdot \sum_{m=1}^{M} \delta_w^{(m)} \cdot z^{(m)}\\ \end{aligned} \] hvor \[ \delta_w^{(m)} = (t^{(m)}-o^{(m)} ) \cdot o^{(m)} \cdot (1-o^{(m)}) \]

Træder vi et skridt bagud i netværket opdateres \(v\)-vægtene således:

\[ \begin{aligned} v_0^{\textrm{ny}} \leftarrow & v_0 + \eta \cdot \sum_{m=1}^{M} \delta_w^{(m)}\cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)})\cdot 1\\ v_1^{\textrm{ny}} \leftarrow & v_1 + \eta \cdot \sum_{m=1}^{M} \delta_w^{(m)} \cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)})\cdot y^{(m)}\\ \end{aligned} \]

Vi ser nu, at \(\delta_w^{(m)}\cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)})\) går igen i begge opdateringsregler. Vi sætter derfor

\[ \delta_v^{(m)} = \delta_w^{(m)}\cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)}). \tag{26}\]

Opdateringen af \(v\)-vægtene kan derfor skrives på denne måde:

\[ \begin{aligned} v_0^{\textrm{ny}} \leftarrow & v_0 + \eta \cdot \sum_{m=1}^{M} \delta_v^{(m)}\cdot 1\\ v_1^{\textrm{ny}} \leftarrow & v_1 + \eta \cdot \sum_{m=1}^{M} \delta_v^{(m)}\cdot y^{(m)}\\ \end{aligned} \]

De sidste opdateringsregler for \(r\)-vægtene ser sådan her ud:

\[ r_i^{\textrm{ny}} \leftarrow r_i + \eta \cdot \sum_{m=1}^M \delta_w^{(m)} \cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)})\cdot v_1 \cdot y^{(m)} \cdot (1-y^{(m)}) \cdot x_i^{(m)} \]

Indsætter vi udtrykket i (26) kan det forkortes til:

\[ r_i^{\textrm{ny}} \leftarrow r_i + \eta \cdot \sum_{m=1}^M \delta_v^{(m)} \cdot v_1 \cdot y^{(m)} \cdot (1-y^{(m)}) \cdot x_i^{(m)} \] Og lader vi

\[ \delta_r^{(m)} = \delta_v^{(m)} \cdot v_1 \cdot y^{(m)} \cdot (1-y^{(m)}) \]

ender vi med

\[ r_i^{\textrm{ny}} \leftarrow r_i + \eta \cdot \sum_{m=1}^M \delta_r^{(m)} \cdot x_i^{(m)} \]

Det fine er, at det nu er blevet meget tydeligt, at alle opdateringsregler faktisk minder ret meget om hinanden. Vi kan derfor sammenfatte opdateringsreglener på denne måde:

Backpropagation

Backpropagation foregår samlet set på denne måde:

  1. Sæt alle vægtene til en tilfældig værdi og vælg en værdi for learning raten \(\eta\).

  2. For alle træningsdataeksempler udregnes \(y^{(m)}\), \(z^{(m)}\) og \(o^{(m)}\) ved hjælp af feedforward-udtrykkene:

    \[ \begin{aligned} y^{(m)} &= \sigma (r_0 + r_1 \cdot x_1^{(m)} + r_2 \cdot x_2^{(m)} + \cdots + r_n \cdot x_n^{(m)}) \\ z^{(m)} &= \sigma (v_0 + v_1 \cdot y^{(m)}) \\ o^{(m)} &= \sigma(w_0 + w_1 \cdot z^{(m)}) \end{aligned} \]

  3. Udregn følgende:

    \[ \begin{aligned} \delta_w^{(m)} &= (t^{(m)}-o^{(m)} ) \cdot o^{(m)} \cdot (1-o^{(m)}) \\ \delta_v^{(m)} &= \delta_w^{(m)}\cdot w_1 \cdot z^{(m)} \cdot (1-z^{(m)}) \\ \delta_r^{(m)} &= \delta_v^{(m)} \cdot v_1 \cdot y^{(m)} \cdot (1-y^{(m)}) \end{aligned} \] Bemærk her, at vi kender \(y^{(m)}\), \(z^{(m)}\) og \(o^{(m)}\) på grund af feedforward, mens \(w_1\) og \(v_1\) er de nuværende værdier af vægtene (inden opdatering). Bemærk også, at for at beregne \(\delta_v^{(m)}\) må vi først have beregnet \(\delta_w^{(m)}\) (som hører til det sidste lag). Tilsvarende for at beregne \(\delta_r^{(m)}\) må vi først have beregnet \(\delta_v^{(m)}\) (som hører til det næstsidste lag). Det er derfor, at algoritmen hedder backpropagation.

  4. Vægtene opdatereres:

    \(w\)-vægtene: \[ \begin{aligned} w_0^{\textrm{ny}} &\leftarrow w_0 + \eta \cdot \sum_{m=1}^{M} \delta_w^{(m)} \cdot 1\\ w_1^{\textrm{ny}} &\leftarrow w_1 + \eta \cdot \sum_{m=1}^{M} \delta_w^{(m)} \cdot z^{(m)}\\ \end{aligned} \] \(v\)-vægtene: \[ \begin{aligned} v_0^{\textrm{ny}} &\leftarrow v_0 + \eta \cdot \sum_{m=1}^{M} \delta_v^{(m)}\cdot 1\\ v_1^{\textrm{ny}} &\leftarrow v_1 + \eta \cdot \sum_{m=1}^{M} \delta_v^{(m)}\cdot y^{(m)}\\ \end{aligned} \] \(r\)-vægtene: \[ \begin{aligned} r_0^{\textrm{ny}} &\leftarrow r_0 + \eta \cdot \sum_{m=1}^M \delta_r^{(m)} \cdot 1 \\ r_1^{\textrm{ny}} &\leftarrow r_1 + \eta \cdot \sum_{m=1}^M \delta_r^{(m)} \cdot x_1^{(m)} \\ & \quad \vdots \\ r_n^{\textrm{ny}} &\leftarrow r_n + \eta \cdot \sum_{m=1}^M \delta_r^{(m)} \cdot x_n^{(m)} \end{aligned} \]

Alle vægtene er nu opdateret, og vi kan gentage punkt 2 til 4, hvor feedforward i 2 hver gang er baseret på de netop opdaterede vægte fra det foregående gennemløb. Opdateringen af vægtene fortsætter indtil værdien af tabsfunktionen næsten ikke ændrer sig. Håbet er nu, at vi har fundet et minimum (eventuelt kun lokalt) for tabsfunktionen.

Og hvor blev den vejrudsigt så af?

Vi tog jo egentlig udgangspunkt i et eksempel om at forudsige vejret, men hvis du har læst med så langt, er du sikkert ikke en gang klar over, om solen skinner, eller det regner lige nu! Så lad os lige prøve at zoome ud og komme tilbage til den vejrudsigt.

Vi havde de fire inputvariable:

\[ \begin{aligned} &x_1: \textrm{Er det regnvejr i dag? Hvis 'ja' er } x_1=1 \textrm{ og } 0 \textrm{ ellers.} \\ &x_2: \textrm{Luftfugtigheden i dag.} \\ &x_3: \textrm{Temperaturen i dag.} \\ &x_4: \textrm{Lufttrykket i dag.} \\ \end{aligned} \]

Vi forestiller os, at vi har samlet et stort træningsdatasæt, som beskrevet i afsnittet Træningsdata og tabsfunktion. Herefter bruger vi træningsdata og backpropagation, som gennemgået ovenfor, til at bestemme værdier af vægtene \(w_0, w_1, v_0, v_1, r_0, r_1, \dots, r_n\), så tabsfunktionen minimeres.

Så står vi her i dag og vil gerne forudsige vejret i morgen. Kig lige ud af vinduet. Regner det eller ej? Mål luftfugtigheden, temperaturen og lufttrykket. Du har nu fire konkret værdier af \(x_1\), \(x_2\), \(x_3\) og \(x_4\). Nu bruger du feedforward-udtrykkene i (3), (4) og (5) til at beregne outputværdien \(o\).

  • Er \(o \geq 0.5\)? Find paraplyen frem – din højteknologiske og banebrydende vejrudsigt forudsiger, at det bliver regnvejr i morgen.

  • Er \(o<0.5\)? No worries – i morgen bliver det ikke regnvejr. Så lad bare paraplyen stå.

Det var faktisk "bare" det. Sådan kan man altså bruge kunstig intelligens til at forudsige vejret (og så kan du nok godt forestille dig, at i virkelighedens verden, er det hele lidt mere kompliceret).

Relaterede forløb

Forløb Kort beskrivelse
Aktiveringsfunktioner I opbygningen af kunstige neurale netværk er aktiveringsfunktioner helt centrale. Og aktiveringsfunktioner skal differentieres – det handler dette forløb om.
Screeningsprogrammer Kan man lave screeningsprogrammer for sygdomme baseret på genetiske markører med brug af AI? Det undersøger vi i dette forløb, som med fordel kan foregå i et samarbejde med bioteknologi.
Opklar et mord! Der er blevet begået et mord på skolen i nat. Det er jeres opgave at opklare det!
Opdatering af vægte i et simpelt neuralt netværk med to skjulte lag En øvelse i at opdatere vægtene i et simpelt neuralt netværk med to skjulte lag.
Opdatering af vægte i et simpelt neuralt netværk med ét skjult lag (men med cross-entropy som tabsfunktion) En øvelse i at opdatere vægtene i et neuralt netværk med ét skjult lag med cross-entropy som tabsfunktion.
No matching items