De siste årene har det vært en gjenoppblomstring innen kunstig intelligens. Den har spredt seg utover den akademiske verden, med store figurer som Google , Microsoft og Facebook , som har opprettet egne forskerteam, og oppnådd imponerende anskaffelser .
Det kommenteres at dette kan tilskrives den store mengden rådata generert av brukere av sosiale nettverk, hvorav mye må analyseres, samt den prekære beregningskraften som er tilgjengelig gjennom GPGPUer .
Men utover disse fenomenene har denne gjenoppblomstringen i stor grad blitt drevet av en ny trend innen AI, spesielt i maskinlæring , kjent som 'deep learning'. I denne opplæringen skal jeg introdusere deg for nøkkelbegrepene og algoritmene bak dyp læring, og starter med den enkleste sammensetningsenheten helt til begrepene maskinlæring i Java.
( For en fullstendig beskrivelse: Jeg er også forfatter av et Java deep learning-bibliotek, tilgjengelig her , og eksemplene i denne artikkelen er implementert ved hjelp av biblioteket ovenfor. Hvis du liker det, kan du støtte det ved å gi det en stjerne på GitHub, som jeg vil være veldig takknemlig for. Bruksanvisning er tilgjengelig på hjemmesiden .)
Hvis du ikke er kjent, sjekk ut denne introduksjonen til maskinlæring :
Den generelle prosedyren er som følger:
Vi har en algoritme som får en håndfull eksempler på merking; for eksempel 10 bilder av hunder med tag 1 ('hund') og 10 bilder av andre ting merket 0 ('No dog') - Vær oppmerksom på at vi hovedsakelig bruker til dette innlegget, klassifisering overvåket Y binær .
Algoritmen 'lærer' å identifisere bilder av hunder, og når den får mat til et nytt bilde, forventer den å produsere riktig etikett (1 hvis det er et bilde av en hund, 0 ellers).
Dette oppsettet er veldig generelt: dataene kan være symptomer og sykdommer på etikettene, eller dataene dine kan være bilder av håndskrevne tegn og merkene tegnene de representerer.
En av de første veiledede treningsalgoritmene er perseptronen; en grunnleggende byggestein for nevrale nettverk.
Anta at vi har poeng n i planen, med etiketten '0' og '1'. De gir oss et nytt poeng, og vi vil gjette etiketten deres (dette ligner scenariet 'hund' og 'Ingen hund' ovenfor). Hvordan gjør vi det?
En god tilnærming kan være å se på nærmeste nabo og returnere merkelappen fra det punktet. Men en litt smartere måte å gjøre ting på ville være å velge en linje som skiller de merkede dataene bedre og bruke den som en klassifiseringsenhet.
I dette tilfellet blir hvert stykke inngangsdata representert som en vektor x = (x_1, x_2) og vår funksjon ville være omtrent som “‘ 0 ’hvis den er under linjen,‘ 1 ’hvis den er over den”.
For å representere dette matematisk, la separatoren vår være definert av en vektorgruppe w og en vertikal forskyvning bias b. Så vår funksjon ville kombinere innganger og vekter med en vektet sumoverføringsfunksjon:
Resultatet av denne overføringsfunksjonen vil deretter mates til en aktiveringsfunksjon for å produsere en etikett. I eksemplet ovenfor var triggerfunksjonen vår en grenseverdi (for eksempel 1 hvis den er større enn en viss verdi):
Trening av perceptron består av å mate flere treningsprøver og beregne utdata for hver av dem. Etter hver prøve, vekter i justeres på en slik måte at du minimerer avslutningsfeil , definert som forskjellen mellom utgangen ønsket (objektiv) og ekte . Det er andre feilfunksjoner, for eksempel gjennomsnittlig kvadratfeil , men det grunnleggende opplæringsprinsippet forblir det samme.
Den enkle perseptrontilnærmingen til dyp læring har en stor ulempe: du kan bare lære lineært separerbare funksjoner . Hvor viktig er denne ulempen? Ta XOR, en relativt enkel funksjon, og du vil legge merke til at den ikke kan klassifiseres av en lineær separator (merk det mislykkede forsøket nedenfor):
For å takle dette problemet, må vi bruke en flerlags perceptron, også kjent som et feedforward neuralt nettverk: faktisk skal vi komponere et stort antall av disse perseptronene for å skape en kraftigere mekanisme for læring.
Et nevralt nettverk er faktisk en sammensetning av perseptroner som er koblet på forskjellige måter, og fungerer med forskjellige aktiveringsfunksjoner.
Til å begynne med, la oss se på feedforward nevrale nettverk, som har følgende egenskaper:
Hva om hver av våre perseptroner bare har lov til å bruke en lineær aktiveringsfunksjon? Så den endelige utgangen fra nettverket vårt vil fremdeles være en lineær funksjon av inngangene, ganske enkelt utstyrt med massevis av forskjellige vekter som ble samlet gjennom nettverket. Med andre ord er en lineær sammensetning av en gruppe lineære funksjoner fremdeles bare en lineær funksjon. Hvis vi begrenser oss til lineære aktiveringsfunksjoner, er det fremadgående nevrale nettverket ikke kraftigere enn perceptronen, uansett hvor mange lag den har.
En lineær sammensetning av en haug med lineære funksjoner er fortsatt bare en lineær funksjon, så de fleste nevrale nettverk bruker ikke-lineære aktiveringsfunksjoner.På grunn av dette bruker de fleste nevrale nettverk ikke-lineære aktiveringsfunksjoner som logistisk , fishy , binær eller likeretter . Uten dem kan nettverket bare lære funksjoner som er kombinasjoner lineær av inngangene dine .
Den vanligste algoritmen for dyplæring for veiledet trening av flerlags perseptroner er kjent som omvendt forplantning. Den grunnleggende prosedyren:
Utgangsfeilen beregnes, vanligvis rotens gjennomsnittlige kvadratfeil:
Hvor t er målverdien og Y det er den faktiske utgangen av nettverket. Andre feilberegninger er også akseptable, men MSE er et godt alternativ.
Nettverksfeil reduseres ved hjelp av en metode som kalles stokastisk gradient nedstigning .
Gradientnedstigning er universell, men når det gjelder nevrale nettverk, vil dette være en graf over treningsfeilen som en funksjon av inngangsparametrene. Den optimale verdien for hver vekt er den der feilen når a globalt minimum . I løpet av treningsfasen oppdateres vektene i små trinn (etter hver treningsprøve eller en minigruppe på flere prøver) slik at de alltid prøver å nå det globale minimumet, men dette er ikke en enkel oppgave lenger. ender i lokale lavpunkter, som den som er sett til høyre. For eksempel, hvis vekten har en verdi på 0,6, bør den endres til 0,4.
Denne figuren representerer det enkleste tilfellet, hvor feilen avhenger av en enkelt parameter. Nettverksfeilen avhenger imidlertid av Hver nettverksvekt og feilfunksjon er mye, mye mer kompleks.
Heldigvis gir bakoverforplantning en metode for å oppdatere hver vekt mellom to nevroner, med hensyn til utgangsfeilen. De avledning i seg selv er ganske komplisert, men vektoppdateringen for en bestemt node har følgende (enkle) form:
Hvor ER er utgangsfeilen, og w_i er vekten av inngangen Jeg til nevronen.
I hovedsak er målet å bevege seg i retning av gradienten med hensyn til vekt Jeg . Nøkkelbegrepet er selvfølgelig avledet av feilen, som ikke alltid er lett å beregne: hvordan finner man dette derivatet for en tilfeldig vekt av en tilfeldig skjult node midt i et stort nettverk?
Svaret: gjennom tilbakeføring. Feilene blir først beregnet i utdataenhetene, der formelen er ganske enkel (basert på forskjellen mellom målet og standardverdiene), og deretter forplantes gjennom nettverket på en intelligent måte, slik at vi kan oppdatere fra effektivt få vektene våre under trening og (forhåpentligvis) nå et minimum.
Det skjulte laget er av spesiell interesse. For han universell tilnærmingsteori , kan et enkelt skjult lagnettverk med et endelig antall nevroner trenes til å tilnærme en vilkårlig tilfeldig funksjon. Med andre ord, et enkelt skjult lag er kraftig nok til å lære hvilken som helst funksjon. Når det er sagt, lærer vi ofte best i praksis med flere skjulte lag (dvs. dypere nettverk).
Det skjulte laget er der nettverket lagrer den interne abstrakte representasjonen av treningsdataene.Det skjulte laget er der nettverket lagrer den interne abstrakte representasjonen av treningsdataene, i likhet med måten en menneskelig hjerne (høyst forenklet analogi) har en intern representasjon av den virkelige verden. Fremover i opplæringen skal vi se på forskjellige måter å leke med det skjulte laget på.
Du kan se et enkelt nettverk (4-2-3 lag) av nevrale feedforward som klassifiserer datasettet IRIS , implementert i Java her , gjennom metoden testMLPSigmoidBP . Datasettet inneholder tre klasser av irisplanter med egenskaper som sepal lengde, kronblad lengde, etc. 50 prøver per klasse leveres til nettverket. Karakteristikkene er underlagt inngangsenhetene, mens hver utgangsenhet tilsvarer en enkelt klasse i datasettet: '1/0/0' indikerer at anlegget er Setosa-klasse, '0/1/0' angir versicolor og ' 0/0/1 'indikerer Virginica. Klassifiseringsfeilen er 2/150 (det vil si at den ikke klassifiserer 2 prøver riktig av 150).
Et nevralt nettverk kan ha mer enn ett skjult lag: i så fall bygger de øvre lagene nye abstraksjoner på toppen av de forrige lagene. Og som vi har nevnt før, kan du ofte lære bedre på jobben med større nettverk.
Å øke antallet skjulte lag fører imidlertid til to kjente problemer:
Forsvinningen av gradienten : Når vi legger til flere og flere skjulte lag, blir forplantning bakover mindre og mindre nyttig for å overføre informasjon til de nedre lagene. Når informasjonen videreformidles igjen, begynner gradvis gradvis å forsvinne og bli mindre i forhold til nettverkets vekter.
Overjustering : Kanskje dette er det sentrale problemet innen maskinlæring. Enkelt sagt, overmontering beskriver fenomenet med å tilpasse treningsdata for tett, kanskje under antagelse om at det er veldig komplekst. I et slikt tilfelle er studenten ferdig med å samle opplæringsdataene veldig bra, men vil prestere veldig dårlig i virkelige eksempler.
La oss se på noen dyplæringsalgoritmer for å løse disse spørsmålene.
De fleste innledende maskinlæringskurs har en tendens til å ende med feedforward nevrale nettverk. Men plassen til mulige nettverk er mye rikere, så la oss fortsette.
En autoencoder er vanligvis et feedforward neuralt nettverk, som tar sikte på å lære en komprimert og distribuert representasjon (koding) av et datasett.
Konseptuelt er nettverket i stand til å 'gjenskape' inngangen, det vil si at inngangen og måldataene er de samme. Med andre ord: du prøver å bruke det samme som output og input, men komprimert på en eller annen måte. Dette er en forvirrende tilnærming, så la oss se på et eksempel.
La oss si at treningsdataene består av 28x28 bilder i gråtoner, og verdien av hver piksel er satt til et inngangslagsneuron (det vil si at inngangslaget vil ha 784 nevroner). Da ville utgangslaget ha samme antall enheter (784) som inngangslaget, og målverdien for hver utgangsenhet ville være gråtoneverdien på en piksel i bildet.
Intuisjonen bak denne arkitekturen er at nettverket ikke vil lære en 'kartlegging' mellom treningsdataene og etikettene, men det vil lære intern struktur og egenskapene til selve dataene. (På grunn av dette kalles det skjulte laget også funksjon detektor .) Generelt er antallet skjulte enheter mindre enn inngangs- / utgangslagene, noe som tvinger nettverket til å lære bare de viktigste egenskapene og oppnår en reduksjon i dimensjonalitet.
Vi vil ha noen få noder i midten for å lære dataene på et konseptuelt nivå, og produsere en kompakt representasjon.I virkeligheten ønsker vi at noen få små noder i midten virkelig lærer dataene på et konseptuelt nivå, og produserer en kompakt representasjon som på en eller annen måte fanger de grunnleggende egenskapene til innspillene våre.
For å demonstrere autokodere enda mer, kommer vi til å se en applikasjon til. I dette tilfellet skal vi bruke et enkelt datasett, bestående av influensasymptomer (kreditt til denne oppføringen i Blogg av ideen). Hvis du er interessert, finner du koden for dette eksemplet i testAEBackpropagation metode .
Slik bryter datasettet seg:
Vi skal vurdere at en pasient er syk. Når han eller hun har minst to av de tre første egenskapene, og sunn hvis han eller hun har minst to av de tre siste (med tie-break som er ødelagt til fordel for sunne pasienter), for eksempel:
Vi skal trene en autokoder (ved å spre tilbake) med seks inngangsenheter og seks utgangsenheter, men bare to skjulte enheter .
Etter flere hundre iterasjoner observeres det at når hver av de 'syke' prøvene presenteres for maskinlæringsnettverket, viser en av de to skjulte enhetene (den samme enheten for hver 'syke' prøve) alltid en triggerverdi høyere enn annen. Tvert imot, når en 'sunn' prøve presenteres, har den andre skjulte enheten en høyere aktivering.
I hovedsak har våre to skjulte enheter lært en kompakt fremstilling av influensasymptomdatasettet. For å se hvordan dette forholder seg til læring, kommer vi tilbake til problemet med overmontering. Ved å trene nettverket vårt for å lære en kompakt representasjon av dataene, prioriterer vi en enklere representasjon snarere enn en svært kompleks hypotese som overpasser treningsdataene.
På en måte prøver vi å lære dataene i en sannere forstand ved å favorisere disse enklere representasjonene.
Det neste logiske trinnet er å se på Boltzmann-begrenset (MBR) , a generative nevrale nettverk som kan lære en sannsynlighetsfordeling over sitt eget sett med innganger.
Disse mekanismene er sammensatt av et skjult og synlig biaslag (bias). I motsetning til fremovernettverk er forbindelsene mellom synlige og skjulte lag ikke-rettet (verdier kan forplante seg i både synlig til skjult og skjult til synlig retning) og fullt tilkoblet (hver enhet i et lag er koblet til hver enhet i neste lag, hvis vi lar en enhet i et hvilket som helst lag koble seg til et hvilket som helst annet lag, ville vi ha en Boltzmann (i stedet for en begrenset Boltzmann-maskin ).
MBR-standarden har skjulte binære og synlige enheter: det vil si at aktivering av enheten er 0 eller 1 under a Bernoulli distribusjon , men det er varianter med andre ikke-lineariteter .
Mens forskere har kjent om MBR-er i noen tid, har den nylige introduksjonen av den uten tilsyn opplæringsalgoritmen til kontrastiv avvik , har fornyet interessen.
Ett-trinns kontrastiv divergensalgoritme (CD-1) fungerer slik:
Vektoppdatering :
Hvor til er læringsgraden og v , v ’ , h , h ’ , Y i de er vektorer.
Intuisjonen bak algoritmen er at den positive fasen ( h Dadaist v ) gjenspeiler den interne representasjonen av datanettverket til virkelige liv . I mellomtiden representerer den negative fasen et forsøk på å gjenskape dataene, basert på denne interne representasjonen ( v ’ Dadaist h ). Hovedmålet er at dataene som genereres er så nærme som mulig i det virkelige liv, og dette gjenspeiles i vektoppdateringsformelen.
Med andre ord har nettverket en oppfatning av hvordan inngangsdataene kan representeres, så det prøver å reprodusere dataene basert på denne oppfatningen. Hvis avspillingen ikke er nær virkeligheten, kan du gjøre en justering og prøve på nytt.
For å demonstrere kontrastiv divergens, vil vi bruke det samme datasett datasymptom som vi brukte tidligere. Testnettverket er en MBR med seks synlige stasjoner og to skjulte stasjoner. Vi skal trene nettverket ved å bruke kontrastiv avvik med symptomene v underlagt det synlige laget. Under testene presenteres symptomene tilbake til det synlige laget; deretter forplantes dataene til det skjulte laget. De skjulte stasjonene representerer den syke / sunne tilstanden, en arkitektur som ligner på autokoderen (datautbredelse fra det synlige til det skjulte laget).
Etter flere hundre iterasjoner observeres det samme resultatet som med autokodere: en av de skjulte enhetene har en høyere aktiveringsverdi når en av de 'syke' prøvene presenteres, mens den andre alltid er mer aktiv for prøvene. Av 'sunne' prøver. .
Du kan se dette eksemplet i aksjon i metoden testKontrastiv avvik .
Vi har nå vist at de skjulte lagene med autokodere og MBR fungerer som effektive funksjonsdetektorer; men det er sjelden vi kan bruke disse funksjonene direkte. Faktisk er datasettet ovenfor mer et unntak enn en regel. I stedet må vi finne ut hvordan vi kan bruke disse oppdagede funksjonene, indirekte.
Heldigvis, det ble oppdaget at disse strukturene kan være stablet å danne nettverk dyp . Disse nettverkene kan trenes grådig, ett lag om gangen, for å bidra til å overvinne forsvinningen av gradienter og problemer med overmontering assosiert med den klassiske tilbakespredningen.
De resulterende strukturene er ofte ganske kraftige og gir imponerende resultater. Ta for eksempel den berømte 'Katt' papir av Google, der de bruker en spesiell klasse med dype autokodere for å 'lære' påvisning av menneskets ansikt og katter, basert på data ikke merket.
La oss se nærmere på det.
Som navnet antyder, består dette nettverket av flere stablede autokodere.
Det skjulte laget av autokoder t fungerer som et inngangslag til autokoderen t + 1 . Inngangslaget til den første autokoderen er inngangslaget for hele nettverket. Den grådige lagvise treningsprosedyren fungerer slik:
Så stablede autokodere prøver å gi en effektiv pre-trening metode for å initialisere vektene til et nettverk, slik at du får en kompleks flerlags perceptron, som er klar til å trene (eller gjøre finjustering ).
Som med autokodere, kan vi også stable Boltzmann-maskiner for å lage en klasse kjent som dype tro nettverk (DBN) .
I dette tilfellet er det skjulte laget av MBR t fungerer som et synlig lag av MBR t + 1 . Inngangslaget til den første MBR er inngangslaget for hele nettverket, og det pre-training grådige lagmessige fungerer slik:
Denne prosedyren ligner på stablede autokodere, men med autokoderne blir erstattet av MBR, og bakoverforplantningen erstattes med den kontrastive divergensalgoritmen.
( Merk: For mer informasjon om å bygge og trene stablede autokodere eller dype trosnettverk, besøk eksemplet på koden her . )
Som en siste dyplæringsarkitektur, skal vi ta en titt på konvolusjonsnettverk, en spesielt interessant og spesiell klasse av fremovernettverk, som er veldig godt tilpasset bildegjenkjenning.
Bilde via DeepLearning.net
Før vi undersøker den virkelige strukturen til konvolusjonsnettverk, vil vi først definere a filter bilde eller en firkantet region med tilhørende vekter. Et filter blir brukt over et helt inngangsbilde, og du vil ofte bruke flere filtre. For eksempel kan du bruke fire 6x6 filtre på et gitt inngangsbilde. Deretter er utgangspikselet med 1,1 koordinater den vektede summen av en 6x6 inngangspikselkvadrat, med øvre venstre hjørne av 1.1 og filtervektene (som også er en 6x6 firkant). Utgangspiksel på 2,1 er resultatet av inngangsfeltet, med øvre venstre hjørne på 2.1 og så videre.
Med dette gjennomgått er disse nettverkene definert av følgende egenskaper:
Flere eksempler på trente konvolusjonsnettverk (spredt bakover) kan sees i datasettet MNIST (gråtonebilder av håndskrevne bokstaver) her , spesielt i metodene testLeNet * (Jeg vil anbefale testLeNetTiny2 ettersom det oppnår en lav feilrate på rundt 2% på relativt kort tid). Det er også en fin JavaScript-skjerm av et lignende nettverk her .
Nå som vi har gjennomgått de vanligste nevrale nettverksvarianter, vil jeg gjerne skrive litt om utfordringene som ble utført mens vi utførte disse dype læringsstrukturene.
Generelt sett er målet mitt med å skape en dyp læringsbibliotek var (og er fortsatt) å bygge et rammeverk basert på et nevralt nettverk, som ville oppfylle følgende kriterier:
For å oppfylle disse kravene tok jeg en trinnvis (eller modulær) tilnærming til programvaredesign.
La oss starte med det grunnleggende:
Denne strukturen er smidig nok til å brukes i klassiske feedforward-nettverk, så vel som til MBR og mer komplekse arkitekturer som ImageNet .
Det gjør det også mulig for et lag å være en del av mer enn ett nettverk. For eksempel lagene i en dypt tro nettverk de er også lag i deres tilsvarende MBR.
I tillegg tillater denne arkitekturen en DBN å bli sett på som en liste over stablede MBR-er i løpet av pre-training-fasen, og som et feed-forward-nettverk under finjusteringsfasen, som er intuitivt hyggelig, så vel som programmatisk praktisk.
Følgende modul håndterer forplantning av data over nettverket, en totrinnsprosess:
Som jeg nevnte tidligere, er en av grunnene til at nevrale nettverk har fått en oppgang de siste årene, at treningsmetodene deres er veldig befordrende for parallellitet, slik at du kan øke opplæringen betydelig, ved bruk av en GPGPU. I dette tilfellet bestemte jeg meg for å jobbe med Aparapi-biblioteket for å legge til GPU-støtte.
Aparapi pålegger noen viktige begrensninger på tilkoblingsregnemaskiner:
Dermed lagres det meste av dataene (vekter, inndata og utmatriser) i Matrix-forekomster, som bruker endimensjonale floatmatriser, internt. Alle Aparapi-tilkoblingsregnemaskiner bruker begge AparapiWeightedSum (for fullt tilkoblede lag og vektede suminngangsfunksjoner), AparapiSubsampling2D (for undersamplingslag), eller AparapiConv2D (for konvolusjonslag). Noen av disse begrensningene kan overvinnes med introduksjonen av Heterogen System Architecture (HSA) . Aparapi tillater også å kjøre den samme koden på både CPU og GPU.
De opplæringsmodul implementerer ulike treningsalgoritmer. Den bygger på de to forrige modulene. For eksempel, BackPropagationTrainer (alle trenere bruker Trener av basisklassen) bruker kalkulatoren for fremoverlag for fremoverfasen og en spesiell kalkulator for bredden, for å overføre feilen og oppdatere vektene.
Mitt siste arbeid støtter Java 8 og noen andre forbedringer, som er tilgjengelige i denne grenen og snart vil bli slått sammen med lærer .
Målet med denne Java-dyplæringsveiledningen var å gi deg en kort introduksjon til feltet for dyplæringsalgoritmer, med utgangspunkt i den mest grunnleggende sammensetningsenheten (perseptronen) og arbeide deg gjennom forskjellige populære og effektive arkitekturer, som begrenset Boltzmann-maskin.
Ideene bak nevrale nettverk har eksistert lenge; Men i dag kan du ikke sette foten i maskinlæringssamfunnet uten å høre om dype nett eller noen annen dyp læringsmening. Mote skal ikke forveksles med begrunnelse, men med fremskrittene innen GPGPU-databehandling og den imponerende fremgangen som forskere som Geoffrey Hinton, Yoshua Bengio, Yann LeCun og Andrew Ng har gjort, viser feltet absolutt store løfter. Det er ingen bedre tid å bli kjent og involvert som i dag.
Hvis du er interessert i å lære mer, fant jeg følgende svært nyttige ressurser under arbeidet mitt: