Hvordan backpropagation fungerer, og hvordan du kan bruge Python til at opbygge et neuralt netværk

Neurale netværk kan være skræmmende, især for folk, der er nye inden for maskinlæring. Denne vejledning vil imidlertid nedbryde, hvordan et neuralt netværk fungerer nøjagtigt, og du vil have et fungerende fleksibelt neuralt netværk ved udgangen. Lad os komme igang!

Forståelse af processen

Med cirka 100 milliarder neuroner behandler den menneskelige hjerne data med hastigheder så hurtigt som 268 mph! I det væsentlige er et neuralt netværk en samling neuroner forbundet med synapser .

Denne samling er organiseret i tre hovedlag: input senere, det skjulte lag og outputlaget.

Du kan have mange skjulte lag, hvor udtrykket dyb læring spiller ind. I et kunstigt neuralt netværk er der flere indgange, der kaldes funktioner , der producerer mindst en output - som kaldes en label .

På tegningen ovenfor repræsenterer cirklerne neuroner, mens linjerne repræsenterer synapser.

Synapsens rolle er at tage og multiplicere input og vægte .

Du kan tænke på vægte som "styrken" af forbindelsen mellem neuroner. Vægte definerer primært output fra et neuralt netværk. De er dog meget fleksible. Derefter anvendes en aktiveringsfunktion til at returnere en output.

Her er en kort oversigt over, hvordan et simpelt feedforward neuralt netværk fungerer:

  1. Tag input som en matrix (2D-række af tal)
  2. Multiplicer inputene med et sæt vægte (dette gøres ved matrixmultiplikation, også ved at tage 'dot-produktet')
  3. Anvend en aktiveringsfunktion
  4. Returner en output
  5. Fejl beregnes ved at tage forskellen mellem det ønskede output fra modellen og det forudsagte output. Dette er en proces kaldet gradientnedstigning, som vi kan bruge til at ændre vægten.
  6. Vægtene justeres derefter i henhold til den fejl, der blev fundet i trin 5.
  7. For at træne gentages denne proces 1.000+ gange. Jo mere dataene trænes, jo mere nøjagtige bliver vores output.

I kernen er neurale netværk enkle.

De udfører bare matrixmultiplikation med input og vægte og anvender en aktiveringsfunktion.

Når vægte justeres via gradient af tabsfunktion, tilpasser netværket sig ændringerne for at producere mere nøjagtige output.

Vores neurale netværk vil modellere et enkelt skjult lag med tre indgange og en output. I netværket vil vi forudsige resultatet af vores eksamen baseret på input af, hvor mange timer vi studerede, og hvor mange timer vi sov dagen før. Outputtet er 'testscore'.

Her er vores eksempeldata om, hvad vi træner vores neurale netværk om:

Som du måske har bemærket, ?repræsenterer i dette tilfælde det, vi ønsker, at vores neurale netværk skal forudsige. I dette tilfælde forudsiger vi testresultatet for en person, der studerede i fire timer og sov i otte timer baseret på deres tidligere præstation.

Fremad formidling

Lad os begynde at kode denne dårlige dreng! Åbn en ny python-fil. Du vil gerne importere, numpyda det hjælper os med bestemte beregninger.

Lad os først importere vores data som dumme arrays ved hjælp af np.array. Vi vil også gerne normalisere vores enheder, da vores input er i timer, men vores output er en testscore fra 0-100. Derfor er vi nødt til at skalere vores data ved at dividere med den maksimale værdi for hver variabel.

Lad os derefter definere en python classog skrive en initfunktion, hvor vi specificerer vores parametre som input, skjulte og output lag.

Det er tid til vores første beregning. Husk, at vores synapser udfører et punktprodukt eller matrixmultiplikation af input og vægt. Bemærk, at vægte genereres tilfældigt og mellem 0 og 1.

Beregningerne bag vores netværk

I datasættet er vores inputdata X,, en 3x2 matrix. Vores outputdata yer en 3x1 matrix. Hvert element i matrix Xskal ganges med en tilsvarende vægt og derefter tilføjes sammen med alle de andre resultater for hver neuron i det skjulte lag. Sådan beregner det første inputdataelement (2 timer at studere og 9 timers søvn) en output i netværket:

Dette billede nedbryder, hvad vores neurale netværk faktisk gør for at producere et output. For det første summeres produkterne fra tilfældigt genererede vægte (.2, .6, .1, .8, .3, .7) på hver synaps og de tilsvarende input for at ankomme som de første værdier for det skjulte lag. Disse summer er i en mindre skrifttype, da de ikke er de endelige værdier for det skjulte lag.

For at få den endelige værdi for det skjulte lag skal vi anvende aktiveringsfunktionen.

En aktiveringsfunktions rolle er at indføre ikke-linearitet. En fordel ved dette er, at output er kortlagt fra et interval på 0 og 1, hvilket gør det lettere at ændre vægte i fremtiden.

Der er mange aktiveringsfunktioner derude til mange forskellige brugssager. I dette eksempel holder vi os til en af ​​de mere populære - sigmoid-funktionen.

Nu skal vi bruge matrixmultiplikation igen med et andet sæt tilfældige vægte til at beregne vores outputlagsværdi.

Endelig, for at normalisere output, anvender vi bare aktiveringsfunktionen igen.

Og der går du! Teoretisk set beregnes .85det neurale netværk med disse vægte som vores testscore! Men vores mål var .92. Vores resultat var ikke dårligt, det er bare ikke det bedste, det kan være. Vi blev bare lidt heldige, da jeg valgte tilfældige vægte til dette eksempel.

Hvordan træner vi vores model til at lære? Nå, vi finder ud af det meget snart. Lad os indtil videre tælle kodning af vores netværk.

Hvis du stadig er forvirret, vil jeg varmt anbefale dig at tjekke denne informative video, der forklarer strukturen i et neuralt netværk med det samme eksempel.

Implementering af beregningerne

Lad os nu generere vores vægte tilfældigt ved hjælp af np.random.randn(). Husk, vi har brug for to sæt vægte. Den ene går fra input til det skjulte lag, og den anden går fra det skjulte til outputlaget.

Når vi har konfigureret alle variablerne, er vi klar til at skrive vores forwardformeringsfunktion. Lad os give vores input, Xog i dette eksempel kan vi bruge variablen ztil at simulere aktiviteten mellem input og output lag.

Som forklaret skal vi tage et prikprodukt af input og vægte, anvende en aktiveringsfunktion, tage et andet prikprodukt af det skjulte lag og andet sæt vægte og til sidst anvende en endelig aktiveringsfunktion for at modtage vores output:

Endelig skal vi definere vores sigmoid-funktion:

Og der har vi det! Et (utrænet) neuralt netværk, der er i stand til at producere et output.

Som du måske har bemærket, er vi nødt til at træne vores netværk til at beregne mere nøjagtige resultater.

Backpropagation - "læringen" af vores netværk

Da vi har et tilfældigt sæt vægte, skal vi ændre dem for at gøre vores input lig med de tilsvarende output fra vores datasæt. Dette gøres ved hjælp af en metode kaldet backpropagation.

Backpropagation fungerer ved hjælp af en tabsfunktion til at beregne, hvor langt netværket var fra måludgangen .

Beregningsfejl

En måde at repræsentere tabsfunktionen på er ved at bruge den gennemsnitlige sum kvadratiske tabsfunktion :

I denne funktion oer vores forudsagte output, og yer vores faktiske output. Nu hvor vi har tabsfunktionen, er vores mål at få den så tæt som muligt på 0. Det betyder, at vi bliver nødt til næsten ikke at have noget tab. Når vi træner vores netværk, er alt, hvad vi laver, at minimere tabet.

For at finde ud af, hvilken retning vi skal ændre vægten, er vi nødt til at finde ændringshastigheden for vores tab i forhold til vores vægte. Med andre ord er vi nødt til at bruge afledningen af ​​tabsfunktionen til at forstå, hvordan vægtene påvirker input.

I dette tilfælde bruger vi et delvis derivat for at tillade os at tage højde for en anden variabel.

Denne metode er kendt som gradientnedstigning . Ved at vide, hvilken vej vi skal ændre vores vægte, kan vores output kun blive mere nøjagtige.

Sådan beregner vi den trinvise ændring af vores vægte:

  1. Find fejlmarginen for outputlaget (o) ved at tage forskellen mellem det forudsagte output og det faktiske output (y)
  2. Anvend derivatet af vores sigmoid-aktiveringsfunktion til outputlagfejlen. Vi kalder dette resultat delta-udgangssummen .
  3. Brug delta-outputsummen af ​​outputlagfejlen til at finde ud af, hvor meget vores z² (skjulte) lag bidrog til outputfejlen ved at udføre et punktprodukt med vores anden vægtmatrix. Vi kan kalde dette z²-fejlen.
  4. Beregn delta-output-summen for z²-laget ved at anvende derivatet af vores sigmoid-aktiveringsfunktion (ligesom trin 2).
  5. Juster vægtene for det første lag ved at udføre et prikprodukt af inputlaget med den skjulte () delta- outputsum . For den anden vægt skal du udføre et prikprodukt af det skjulte (z²) lag og output (o) delta- outputsummen .

Beregning af delta-outputsummen og derefter anvendelse af derivatet af sigmoid-funktionen er meget vigtig for backpropagation. Afledningen af ​​sigmoid, også kendt som sigmoid prime , giver os ændringshastigheden eller hældningen af ​​aktiveringsfunktionen ved outputsummen.

Lad os fortsætte med at kode vores Neural_Networkklasse ved at tilføje en sigmoidPrime (derivat af sigmoid) funktion:

Derefter vil vi oprette vores backwardformeringsfunktion, der gør alt, hvad der er specificeret i de fire trin ovenfor:

Vi kan nu definere vores output gennem igangsættelse af foward-formering og intensivere den bagudgående funktion ved at kalde den i trainfunktionen:

For at køre netværket er alt, hvad vi skal gøre, at køre trainfunktionen. Selvfølgelig vil vi gerne gøre dette flere gange eller måske tusinder af gange. Så vi bruger en forløkke.

Her er de fulde 60 linjer med fantastiskhed:

Der har du det! Et fuldt udviklet neuralt netværk, der kan lære af input og output.

Mens vi tænkte på vores input som timer at studere og sove, og vores output som testresultater, er du velkommen til at ændre disse til hvad du vil og observere, hvordan netværket tilpasser sig!

Når alt kommer til alt, ser alt netværket numrene. De beregninger, vi foretog, så komplekse som de syntes at være, spillede alle en stor rolle i vores læringsmodel.

Hvis du gerne vil forudsige en output baseret på vores uddannede data, såsom at forudsige testresultatet, hvis du studerede i fire timer og sov i otte, skal du tjekke den fulde tutorial her.

Demo & kilde

Referencer

Steven Miller

Welch Labs

Kabir Shah

Denne tutorial blev oprindeligt udgivet på Enlight, et websted, der er vært for en række tutorials og projekter at lære ved at bygge! Tjek det for flere projekter som disse :)