• AI FTW
  • Posts
  • Slik virker et nevralt nettverk - Enkelt forklart

Slik virker et nevralt nettverk - Enkelt forklart

To enkele måter å forklare et nevralt nettverk

Slik fungerer et nevralt nettverk på det mest grunnleggende nivået (sånn -ish).

Det slår meg at dette er noe ChatGPT sikkert kan gjøre like godt, men jeg fikk uansett lyst å prøve.

For enkelthets skyld kom jeg opp med en utrolig enkel forklaring, og en ganske enkel forklaring.

Forklaring 1 - Sykt enkel:

Ok. Se for deg en slags leke. Den er rektangulær og stående. Omentrent slik ⬇️

En enkel leke

Denne leke fungerer slik at du slipper en av ballene ned i boksen fra toppen, og så vil den ende i en av boksene på bunn. Målet er å prøve å gjøre slik at ball 1 faller i boks 1 i bunn, ball 2 i boks 2 og ball 3 i boks 3. Når vi starter opp er ikke det tilfelle.

Et nevralt nettverk består i sin enkleste form av tre komponenter. Input layer (ballene), Hidden layers (pinnene) og Output layer (hullene i bunn)

Vi slipper en tilfeldig ball ned i boksen fra toppen. På veien treffer den tilfeldige pinner som endrer kursen til ballen. Til slutt lander den i en av boksene i bunn -- Dette er Forward propagation

Når vi starter opp så står pinnene helt random fordelt og ballene vil dette ned i en hvilken som helst boks i bunn.

Men for hver gang vi har sluppet ned en ball, og den har landet i en boks, så får vi lov til å flytte litt på pinnene - Dette er Backward propagation. For å få det til å funke må vi slippe ned mange baller og gjøre mange justeringer.

Etter at vi har sluppet ballene ned noen tusen ganger og flyttet på pinnene noen tusen ganger, så har vi forhåpentligvis satt de slik at ballene faller i riktig boks 98.7% av gangene (tilfeldig valgt tall)

Dette er i sin aller, aller enkleste form hvordan et nevralt nettverk fungerer. (Jeg dobbeltsjekket med GPT-4, som var veldig fornøyd med eksempelet mitt, men ville legge til at dette eksemplet ikke dekker såkalte aktiveringsfunksjoner, men det er ikke så viktig nå)

Forklaring 2 - Ganske enkel

Vi prøver en til!

Ok, så det heter et “neural network” fordi det på mange måter simulerer måten hjernen jobber på.. -ish (uten at jeg er ekspert på hjernen).

Eksemplet som gjorde at jeg forsto det var gjennom et eksempel for å gjennkjenne tall.

La oss si at vi har noen tusen eksempler med håndskrevene tall fra 0 til 9. Det finnes og heter MNIST og ser slik ut

Det er ca. 70.000 bilder i dette datasettet

La oss si at vi tok et av disse tallene og så på det litt forstøret. Dette er for enkelhets skyld satt opp i 16×16 pixler.

Hver pixel har et tall (en verdi) for hvor hvit den er (sagt veldig enkelt). 0 er svart, 255 er helt hvit.

Fikk litt hjelp av ChatGPT til å formatere bildet som verdier fra 0 til 255 - Og så puttet jeg det inn in Google Sheets.

Du kan se selve arket her

Se for deg at vi tok og stablet hver rad med pixler etter hverandre slik at det ble et høyt tårn av pixler. Omentrent slik (får ikke plass til hele her)

Eller bare en veldig lang rekke med tall fra 0 til 255. Det blir faktisk 256 tall (8-bit 😉 )

utdrag av 256 tall i en kolonne

Her er noen enkle skisser som prøver å vise hvordan det ser ut (grafisk, ikke matematisk)

Alle nodene i vårt “input layer” - mao. alle pixlene med sine verdier stacket oppå hverandre

I Figur 1 har vi listet opp alle pixlene i den første kolonnen. Dette heter “input layer”. Litt forvirrende i dette tilfelle kanskje, men de har alle en slags ID (det heter index) fra 0 til 255. Samtidig så har de alle en verdi, også fra 0 til 255, men her er det jo mange som har verdi 255 (helt hvit) men det er bare en som har index 255 (den siste).

Figur 1

Input Layer

OBS OBS OBS. For enkelhets skyld valgte vi kun ett hidden layer, med kun 8 noder. For at dette skal være effektivt burde vi sikkert ha kanskje to hidden layers og sikkert 16+ noder i hver av dem (det er ikke et fast tall. Velg noe som passer)

Fra hver eneste node i det som heter input layer kan du se at det går en “tråd” eller en “weight” (altså alle de 256 tallene våre) til hver av de 8 nodene i vårt hidden layer (jeg har bare tegnet det for de tre første, men her ville det blitt veldig mange streker). Hver av disse trådene starter med et tilfeldig tall (gjerne mellom 0 og 1). Og hver av disse nodene (de små rundingene) i vårt hidden layer har det som kalles en bias, som også er et tilfeldig tall mellom 0 og 1.

Hidden Layer

Og så for hver av de 8 nodene i vårt hidden layer skal det da gjøres følgende utregning:

Nodes verdi * vekt + bias —> den skal så gjennom en “activation function” som basically bare er en funksjon som sier om tallet skal brukes eller ikke. For meg er dette kanskje den mest uoversiktlige delen. Det finnes mange forskjellige slike funksjoner, men den som ofte brukes heter ReLU (Rectified Linear Unit). Det eneste den gjør er å ta tallet vi fikk nå nettopp og avgjøre om det er mindre enn null. Hvis det er mindre enn null, så stopper noden. Er det større så sender den tallet vi fikk videre.

Figur 2

Rent praktisk: I figur 2 starter jeg med Node 1 (som egt er feil, det er Node 0, men det driter vi i). Så har jeg satt vekten på den første tråden til 0.3 (tilfeldig tall). Jeg har satt bias på den første noden i vårt hidden layer til 0.2. Pixelverdien fra Node 1 (eller 0, hvis du skal pirke) er 255 (helt hvit). Den gjør vi om til et tall mellom 0 og 1 (Hvit er 1, grå blir 0.5 og svart er 0) Da får vi det enkle regnestykket (1×0.3)+0.2 = 0.5. —> 0.5 er altså verdien i den første noden i vårt hidden layer. Yay!

Men nå skal vi holde tungen litt rett i munnen, for det blir plutselig ganske mange utregninger å holde styr på. Med 256 pixler blir det ikke mindre enn 2048 “tråder” fra vårt input layer til vårt hidden layer (256 × 8). Så skal det regnes ut vekter og verdier og legges til bias for alle disse, før de blir sendt gjennom ildprøven kjent som ReLU.

Det siste som skjer nå er at hver av nodene i vårt hidden layer sender sin summerte verdi videre til hver node i vårt output layer. De tallene kan gjerne være ganske store, men vi er på utkikk etter en verdi mellom 0 og 1, så i siste ledd blir de gjerne sendt gjennom en siste squeeze-funksjon som tar et hvilket som helst tall og skviser det ned til et tall mellom 0 og 1 (Sigmoid er en kjent slik funksjon)

Output Layer

Squeeeeze-funksjon (Sigmoid)

Etter å ha regnet ut en halv milliard tall står vi da igjen med en rekke på 10 tall i vårt output layer. De ti tallene representerer alle de mulige resultatene vi ønsker å finne ut av. Mao er dette et 4-tall, eller et 6-tall? (eller et annet tall).

Figur 3

I figur 3 har jeg forsøkt å “blåse opp” vårt output layer slik at vi kan se hvilke tall vi til slutt endte opp med for hvert av tallene våre.

Her er et superviktig konsept å forstå. Når vi snakker om å trene opp et nevralt nettverk så er det nettop det som kommer nå de snakker om. Så følg godt med:

Tallene i hver av disse nodene representerer hva vårt nevrale nettverk mener vår input var. Hvis det f.eks. sto 0.99 i node nr. 4 så betyr det at nettverket tror dette helt sikkert er et 3-tall (fordi den starter på 0, ikkesant). Så 0.99 i dette tilfelle betyr: “99% sikker på at dette er et 3-tall. Bænkers!” mens f.eks. 0.12 blir 12%. “Det er kun 12% sjanse for at dette er et 3-tall”

Siden vi startet med tilfeldige tall som vekter og til bias, så vil du få rubbish resultat første gang du gjør dette. Fordi alle tallene dine var random, ikkesant!

Nå kommer den helt kritiske delen, og det som gjør at et neural network faktisk funker.

Når vi har kalkulert dette første gang, så kjører vi en prosess som heter Backwards Propagation. (sykt fancy ord, men jeg gidder ikke skrive det hver gang, så fra nå av er det BP). Med BP så sier man bascially.

“Oisann.. dette skulle jo bli en 6-er, ikke alt mulig annet. Så vi setter node 7 (6-tallet) til 1 og de andre til 0. Og så spiller vi prosessen baklengs på en måte. Vi endrer på vektene og biasene i vårt hidden layer slik at de vil gi et resultat som er nærmere det vi ønsker oss.”

BP er en prosess jeg ikke egentlig forstår så mye av, men for de av dere som vil dykke ned i det er det bare å søke på loss functions, cross entropy og gradient descent. Lykke til 👋🏻 ⬇️

Men hvis vi hopper bukk over den syke matten så kan du si det så enkelt som at vi går tilbake og justerer på tallene våre slik at de matcher bedre opp med det resultatet vi tenkte vi skulle få.

Det vi gjør nå er å sende inn et nytt bilde av en annen 6-er som vi har skrevet for hånd. Denne vil sikkert være ganske annerledes, men også noe lik. Vi gjentar prosessen fra toppen og ender opp med kanskje noen prosent bedre gjetting av maskinen. Så kjører vi en ny runde med BP, før vi sender inn ENDA en 6-er.

Hvis vi gjør dette mange tusen ganger, så vil det oppstå et mønster i trådene våre som gjør at når nettverket “ser” en 6-er så vil den etterhvert gi et høyere og høyere verdier for den noden (tenk 0.9748), mens de andre får lavere og lavere verdier (f.eks. 0.167).

Egentlig er det ganske enkelt.. ish

Håper du ble litt klokere 🧠