Simple kunstige neruale netværk til regression
Hvis du har læst nogle af vores andre noter om kunstige neurale netværk, så har de alle handlet om klassifikation. Det kunne for eksempel være: aktiverer en kunde et tilbud i en app? (ja/nej), bliver det regnvejr i morgen? (ja/nej), har en patient en bestemt sygdom? (ja/nej), hvilket af fire valg skal jeg træffe? De tre første eksempler er eksempler på det, som man kalder for binær klassifikation (fordi der kun er to muligheder), mens det sidste eksempel er et eksempel på multipel klassifikation (fordi der er mere end to muligheder). I denne note vil vi se på, hvordan man kan bruge kunstige neurale netværk til at forudsige en såkaldt numerisk variabel – mere konkret vil vi her se på, hvordan man kan lave et kunstigt neuralt netværk, som kan bruges til at prædiktere huspriser.
Hvad koster mit hus?
Vi forestiller os helt generelt en række inputvariable eller features: \(x_1, x_2, \dots, x_n\) på baggrund af hvilke vi gerne vil kunne forudsige en targetvariabel \(t\), som her er salgsprisen på et hus.
Eksempel 1 (House Price datasættet) På kaggle.com kan man downloade et utal af forskellige datasæt. Vi vil her se nærmere på datasættet House Price Dataset for Regression Models, som du kan downloade som Excel fil her.
Datasættet indeholder oplysninger om \(545\) hussalg i USA.
Targetvariablen \(t\) står i kolonnen price og angiver salgsprisen målt i dollar. Derudover indeholder datasættet en lang række features:
area: boligens areal målt i square feetbedrooms: antal værelserbathrooms: antal badeværelserstories: antal etagermainroad: om huset har adgang til hovedvejen (ja=1, nej=0)guestroom: om huset har et gæsteværelse (ja=1, nej=0)basement: om huset har kælder (ja=1, nej=0)hotwaterheating: om huset har fjernvarme (ja=1, nej=0)airconditioning: om huset har air conditioning (ja=1, nej=0)parking: antal parkeringspladserprefarea: om huset ligger i et eftertragtet område (ja=1, nej=0)furnishingstatus: om huset et umøbleret, delvist møbleret eller fuldt møbleret
I det følgende vil vi holde det simpelt og kun se på følgende features:
- \(x_1\): boligens areal målt i square feet (
area) - \(x_2\): antal værelser (
bedrooms) - \(x_3\): antal badeværelser (
bathrooms) - \(x_4\): om huset har kælder (
basement)
Lad os starte simpelt og opstille en kunstig neuron til formålet. Så vil vi sige, at vores prædiktion af husprisen skal være en outputværdi \(o\), som helt generelt er den vægtede sum af vores inputvariable:
\[ o = w_0 + w_1 \cdot x_1 + w_2 \cdot x_2 + \cdots + w_n \cdot x_n \]
Her kaldes \(w_0, w_1, w_2, \dots, w_n\) for vægte.
Hvis du har læst noten om kunstige neuroner, så er den eneste forskel her, at vi ikke længere bruger sigmoid-funktionen som aktiveringsfunktion1, fordi vi ikke her har brug for at få en outputværdi, som ligger mellem \(0\) og \(1\).
1 Vi bruger sådan set stadig en aktiveringsfunktion – det bare den funktion, som kaldes for identiteten med forskrift \(f(x)=x\).
Vi ønsker nu, at bestemme vægtene \(w_0, w_1, w_2, \dots, w_n\) sådan at vores prædikterede huspris \(o\) kommer så tæt som muligt på den faktiske huspris \(t\).
Det vil sige, at vi ønsker, at forskellen
\[ t-o = t - \left ( w_0 + w_1 \cdot x_1 + w_2 \cdot x_2 + \cdots + w_n \cdot x_n \right ) \]
bliver så lille som mulig.
Da denne differens både kan være positiv og negativ, men vi egentlig ikke er interesseret i fortegnet – blot om differensen er lille eller stor, så vælger vi i stedet at se på den kvadrerede forskel:
\[ \left ( t - \left ( w_0 + w_1 \cdot x_1 + w_2 \cdot x_2 + \cdots + w_n \cdot x_n \right ) \right )^2 \]
Vi får en sådan kvadreret differens for hvert eneste hus i vores træningsdatasæt, og vi vælger derfor blot at lægge alle disse størrelser sammen:
\[ E = \frac{1}{2}\sum \left ( t - \left ( w_0 + w_1 \cdot x_1 + w_2 \cdot x_2 + \cdots + w_n \cdot x_n \right ) \right )^2 \]
Størrelsen \(E\) kaldes for en tabsfunktion. Læg mærke til, at hvis vores kunstige neuron er god til at forudsige huspriser, så får vi en lille værdi af tabsfunktionen, mens vi får en stor værdi af \(E\), hvis modellen er dårlig til at forudsige huspriser. Vi har her valgt at gange med \(\frac{1}{2}\), fordi det senere kommer til at forkorte ud, men det er faktisk ikke så afgørende.
Idéen er så bare at bestemme værdier af vægtene \(w_0, w_1, w_2, \dots, w_n\), sådan at tabsfunktionen minimeres.
Inden vi forklarer, hvordan det gøres, så lad os lige blive lidt mere specifikke i forhold til notationen af vores træningsdata. Vi forestiller os, at vi har information om \(M\) huspriser (i eksemplet er \(M=545\)). Så vil vi nummerer vores træningsdata på denne måde:
\[ \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} \]
Gør vi det, bliver tabsfunktionen:
\[ \begin{aligned} E(w_0, w_1, &\dots, w_n) \\ &= \frac{1}{2} \sum_{m=1}^{M} \left (t^{(m)}- (w_0 + w_1 \cdot x_1^{(m)} + \cdots + w_n \cdot x_n^{(m)}) \right)^2. \end{aligned} \]
Hvis vi samtidig indfører, at vi kalder outputværdien for det \(m\)’te træningseksempel for \(o^{(m)}\):
\[ o^{(m)} = w_0 + w_1 \cdot x_1^{(m)} + \cdots + w_n \cdot x_n^{(m)} \] Så kan tabsfunktionen udtrykkes kort på denne måde:
\[ \begin{aligned} E(w_0, w_1, &\dots, w_n) \\ &= \frac{1}{2} \sum_{m=1}^{M} \left (t^{(m)}- o^{(m)} \right)^2 \end{aligned} \]
hvor det nu så bare ikke er helt så tydeligt, at \(E\) jo faktisk afhænger af alle vægtene.
For at bestemme de værdier af vægtene, som minimerer tabsfunktionen, vil vi bruge en metode, som kaldes for gradientnedstigning. Vi har lavet videoer om både funktioner af to variable og gradientnedstigning, hvis du vil vide mere.
Idéen i gradientnedstigning er, at vi opdaterer alle vægtene ved at gå et lille stykke i den negative gradients retning. Det kommer til at se sådan her ud:
\[ \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} \\ &\vdots \\ w_n^{(\textrm{ny})} \leftarrow & w_n - \eta \cdot \frac{\partial E }{\partial w_n} \\ \end{aligned} \]
hvor \(\eta\) kaldes for en learning rate.
Vi får derfor brug for alle de partielle afledede af \(E\) med hensyn til \(w_i\) for \(i \in \{0, 1, 2, \dots, n\}\). Det er ikke svært at vise, at
\[ \begin{aligned} \frac{\partial E}{\partial w_i} &= - \sum_{m=1}^M \left (t^{(m)}- (w_0 + w_1 \cdot x_1^{(m)} + \cdots + w_n \cdot x_n^{(m)}) \right) \cdot x_i^{(m)} \\ &= - \sum_{m=1}^M \left (t^{(m)}- o^{(m)} \right) \cdot x_i^{(m)} \end{aligned} \] for \(i \in \{1, 2, \dots, n\}\) og
\[ \frac{\partial E}{\partial w_0} = - \sum_{m=1}^M \left (t^{(m)}- o^{(m)} \right) \] Opdateringsreglerne for vægtene bliver derfor:
At opstille en kunstig neuron til regression, som vi har gjort her, svarer til det man kalder for multipel lineær regression, som egentlig bare er en udvidelse af lineær regression, som I kender det, blot med flere inputvariable/features.
Det gode ved at opstille en kunstig neuron til regression, som vi her har gjort det, er, at man kan give en fortolkning af vægtene.
Fortolkning af vægtene
Lad os sige, at vi har bestemt vægtene \(w_0, w_1, \dots, w_n\), så tabsfunktionen er blevet minimeret, og at \(x_1\) fortsat angiver boligarealet. Vi vil her forklare, hvordan vi kan fortolke \(w_1\).
Vi forstiller os, at vi har to hus med præcis samme værdier af de \(n\) features \(x_1, x_2, \dots, x_n\) bortset fra, at det ene hus er præcis \(1\) square feet større end det andet. Så det ene hus har en størrelse på \(x_1\) square feet, mens det andet har en størrelse på \(x_1+1\) square feet – de resterende features er ens.
Det giver følgende prædikterede boligpriser \(o_1\) og \(o_2\) for de to huse:
\[ \begin{aligned} o_1 &= w_0 + w_1 \cdot x_1 + w_2 \cdot x_2 + \cdots + w_n \cdot x_n \\ \\ o_2 &= w_0 + w_1 \cdot (x_1 + 1) + w_2 \cdot x_2 + \cdots + w_n \cdot x_n \\ &= w_0 + w_1 \cdot x_1 + w_1 + w_2 \cdot x_2 + \cdots + w_n \cdot x_n \end{aligned} \]
Da bliver forskellen mellem de to prædikterede boligpriser:
\[ \begin{aligned} o_2 - o_1 &= w_0 + w_1 \cdot x_1 + w_1 + w_2 \cdot x_2 + \cdots + w_n \cdot x_n \\ & \quad \quad - \left ( w_0 + w_1 \cdot x_1 + w_2 \cdot x_2 + \cdots + w_n \cdot x_n \right) \\ &= w_0 + w_1 \cdot x_1 + w_1 + w_2 \cdot x_2 + \cdots + w_n \cdot x_n \\ & \quad \quad - w_0 - w_1 \cdot x_1 - w_2 \cdot x_2 - \cdots - w_n \cdot x_n \\ & = w_1 \end{aligned} \]
Det vil sige, at hvis alt andet er holdt ens, så vil en forøgelse i boligarealet på én square feet give en forøgelse i den prædikterede boligpris på \(w_1\) kroner.
Da \(x_4\) angiver, om boligen har kælder eller ej (hvor \(x_4=1\) svarer til at boligen har kælder og \(x_4=0\) svarer til, at boligen ikke har kælder), så vil \(w_4\) helt tilsvarende kunne fortolkes som den størrelse, den prædikterede boligpris vil stige med, hvis en bolig har kælder sammenlignet med en helt tilsvarende bolig uden kælder.
Vi illustrerer dette med et eksempel:
Eksempel 2 (Fortolkning af vægtene) Træner vi en kunstig neuron på datasættet om huspriser, hvor vi sætter alle startvægte til \(0\), vælger en learning rate på \(0.0001\) og antal iterationer til \(500\), får vi følgende værdier af vægtene
| \(w_0\) |
\(w_1\) ( area) |
\(w_2\) ( bedrooms) |
\(w_3\) ( bathrooms) |
\(w_4\) ( basement) |
|---|---|---|---|---|
| \(-221293.3671\) | \(376.4762\) | \(387528.7807\) | \(1355117.6023\) | \(447658.8766\) |
For eksempel kan vi se, at \(w_1 = 376.4762\). Det vil sige, at ifølge modellen vil husprisen på et hus, som er præcis én square feet større end et andet tilsvarende2 hus, være cirka \(376 \, \$\) højere.
2 Et tilsvarende hus vil her mere præcist betyde et hus med det samme antal soveværelser, badeværelser og kælder (ja/nej).
Vi ser også, at \(w_4=447658.8766\), som betyder, at hvis vi står med to tilsvarende huse, hvor det ene er med kælder, og det andet er uden kælder, så vil huset med kælder ifølge vores model koste \(447659 \, \$\) mere end huset uden kælder.
Prædiktion af huspriser – nu med skjulte lag!
Der skal helst ikke være skjulte fejl og mangler, når man skal sælge sit hus. Til gengæld kan det være en super god idé med nogle skjulte lag, når man skal prædiktere huspriser!
I det ovenstående kommer de prædikterede huspriser til at afhænge lineært af inputvariablene. Men verden er sjældent lineær! Og en af styrkerne ved kunstige neurale netværk er netop, at de kan prædiktere størrelse eller kategorier ved hjælp af funktioner, som ikke er lineære. Vi skal derfor nu opstille et simpelt kunstigt neuralt netværk til prædiktion af huspriser. Vi vil lave et netværk med fire features \(x_1, x_2, x_3, x_4\), men nu med et såkaldt skjult lag, som består af to neuroner. Det kan illustreres, som vist i figur 1:
Som det ses i figur 1, er der til hver pil knyttet en vægt, som skal bruges til at udregne outputværdien \(o\). Hvis vi for en stund forestiller os, at vi kender alle vægtene, så udregner vi outputværdien \(o\) på følgende måde:
Ved hjælp af inputvariablene og \(v\)-vægtene beregner vi \(z_1\):
\[ z_1 = \sigma (v_0 + v_1 \cdot x_1 + v_2 \cdot x_2 + v_3 \cdot x_3 + v_4 \cdot x_4) \] som selvfølgelig kan generaliseres til
\[ z_1 = \sigma (v_0 + v_1 \cdot x_1 + \cdots + v_n \cdot x_n) \]
Her er \(\sigma(x)\) sigmoid-funktionen med forskrift
\[ \sigma(x)=\frac{1}{1+\mathrm{e}^{-x}} \tag{1}\]
og grafen ses i figur 2.
Sigmoid-funktionen kaldes også for en aktiveringsfunktion, og det er den, der gør, at vi ender med at prædiktere huspriserne på en ikke-lineær måde.
På tilsvarende vis udregner vi \(z_2\) ved at bruge \(u\)-vægtene:
\[ z_2 = \sigma (u_0 + u_1 \cdot x_1 + u_2 \cdot x_2 + u_3 \cdot x_3 + u_4 \cdot x_4) \]
Når vi nu har \(z_1\) og \(z_2\) beregnes outputværdien \(o\), som vi gjorde det tidligere:
\[ o = w_0 + w_1 \cdot z_1 + w_2 \cdot z_2 \]
Ovenstående udtryk for beregning af \(z_1\), \(z_2\) og \(o\) kaldes for feedforward ligninger, fordi man laver beregninger "fremad" i netværket fra venstre mod højre. Hvis vi samtidig holder styr på hvilket træningseksempel vi står med, får vi følgende:
Tabsfunktionen definerer vi nu som før
\[ \begin{aligned} E(v_0, v_1, \dots, v_4, u_0, u_1, \dots, u_u,w_0, w_1, w_2) \\ &= \frac{1}{2} \sum_{m=1}^{M} \left (t^{(m)}- o^{(m)} \right)^2 \end{aligned} \]
hvor \(o^{(m)}\) er givet ved udtrykket i (4). Læg mærke til, at tabsfunktionen afhænger af alle \(u\)-, \(v\)- og \(w\)-vægte, men for nemheds skyld vil vi blot skrive \(E\) i det følgende.
Man kan nu igen bruge gradientnedstigning til at bestemme de værdier er \(v\)-, \(u\)- og \(w\)-vægtene, som minimerer tabsfunktionen. Det er her en vigtig beregningsfinte, at man bevæger sig "bagud" i netværket og først opdaterer \(w\)-vægtene (som er tættest på outputlaget) og dernæst \(u\)- og \(v\)-vægtene, som er tættest på inputlaget. Dette kaldes for backpropagation.
Gør man det ender, man med følgende opdateringsregler:
Ser vi på opdateringsreglerne for \(w\)-vægtene, kan vi se, at der i alle regler indgår en faktor
\[ \left ( t^{(m)}-o^{(m)}\right) \]
som er et udtryk for den fejl netværket begår med de nuværende værdier af vægtene (nemlig forskellen på den ønskede targetværdi \(t^{(m)}\) og den prædikterede outputværdi \(o^{(m)}\)). Der er to ting, som er værd at bemærke i den forbindelse:
- Hvis fejlen er stor, bliver \(w\) vægtene opdateret forholdsvis meget – og omvendt hvis fejlen er lille.
- Når vi har opdateret \(w\)-vægtene, har vi allerede beregnet fejlen \(t^{(m)}-o^{(m)}\). Denne "fejlfaktor" indgår også i opdateringsreglerne for \(v\)- og \(u\)-vægtene, og den allerede beregnede fejl kan altså genbruges, når \(v\)- og \(u\)-vægtene skal opdateres.
Det kan her virke fuldstændig ligegyldigt, om vi skal beregne fejlen et par ekstra gange eller ej, men i virkelighedens anvendelser af kunstige neurale netværk, er det lige præcis denne beregningsmæssige finte, som gør, at det overhovedet kan lade sig gøre at bruge gradientnedstigning. Det sparer nemlig både tid og lagringsplads på computeren, at tidligere beregnede størrelser kan genbruges i de næste opdateringer.
Hvis du gerne vil bevise ovenstående, er der lidt hjælp at hente i nedenstående boks.