Innholdsfortegnelse[Gjemme seg][Forestilling]
Hjernen kan sammenlignes med nevrale nettverk. Dette er analogien som vanligvis brukes for å hjelpe noen som er nye i faget til å forstå ideene bak maskinlæring og kunstige nevrale nettverk.
Fordi det foregår flere lag med matematiske og statistiske beregninger bak kulissene, er det en mer avansert metode å definere disse nettverkene som en matematisk funksjon.
Dette er for folk som faktisk er interessert i maskinlæring og ønsker å se hvordan Python nevrale nettverkskode er skrevet.
I denne artikkelen skal vi demonstrere hvordan du konstruerer et fullt tilkoblet dypt nevralt nettverk (DNN) fra bunnen av Python 3.
En oversikt over filstrukturen for Python Neural Network Code
Det vil bli opprettet tre filer her. Den første er den enkle nn.py-filen, som vil bli diskutert i "Konfigurere hjelpefunksjoner" og "Bygge det nevrale nettverket fra bunnen av."
Vi vil også ha en fil som heter mnist loader.py for å laste testdataene, som beskrevet i «Laster MNIST-data».
Til slutt vil vi ha en fil som heter test.py som vil bli lansert i terminalen for å teste vårt nevrale nettverk.
Denne filen er beskrevet i detalj i "Kjøre tester."
Installasjon
NumPy Python-biblioteket må lastes ned for å følge denne opplæringen. Du kan oppnå dette ved å bruke følgende kommando på terminalen:
Importere moduler og sette opp hjelpefunksjonen
De eneste to bibliotekene vi trenger er random og NumPy, som vi importerer med en gang. For vårt nevrale nettverks innledende vekter, blander vi dem ved å bruke det tilfeldige biblioteket.
For å øke hastigheten på beregningene våre, bruker vi NumPy eller np (av konvensjon importeres det ofte som np). Våre to hjelpefunksjoner vil bli laget etter vår import. To sigmoid funksjoner: en og sigmoid prime.
Logistisk regresjon vil klassifisere data ved å bruke sigmoid-funksjonen, mens backpropagation vil beregne delta eller gradient ved å bruke sigmoid-primefunksjonen.
Opprette nettverksklasse
Å bygge et fullt koblet nevralt nettverk er det eneste fokuset i denne delen. Nettverksklassen vil omfatte alle funksjonene som kommer etter. Funksjonen Object() { [native code] } vil bli opprettet til å begynne med i nettverksklassen vår.
Ett argument, størrelser, kreves av funksjonen Object() { [native code] }. Størrelsesvariabelen er en samling av numeriske verdier som representerer antall inngangsnoder som er tilstede i hvert lag av vårt nevrale nettverk.
Vi initialiserer fire egenskaper i vår __init__ metode. Inndatavariablene, størrelser, brukes til å angi henholdsvis listen over lagstørrelser og antall lag, antall lag.
Det første trinnet er å tilfeldig tildele nettverkets innledende skjevheter til hvert lag som følger inndatalaget.
Til slutt har hver kobling mellom input- og output-lagene sine vekter tilfeldig generert. Np.Random.Randn() gir et tilfeldig utvalg trukket fra normalfordelingen for kontekst.
Fremmatingsfunksjon
I et nevralt nettverk sendes informasjon videre av feedforward-funksjonen. Ett argument, a, som indikerer den gjeldende aktiveringsvektoren, vil være nødvendig for denne funksjonen.
Denne funksjonen estimerer aktiveringene ved hvert lag ved å iterere over alle skjevheter og vekter i nettverket. Svaret som er gitt er prediksjonen, som er aktiveringene av det siste laget.
Mini-batch Gradient Descent
Nettverksklassens arbeidshest er Gradient Descent. I denne versjonen bruker vi mini-batch (stokastisk) gradientnedstigning, en modifisert variant av gradientnedstigning.
Dette indikerer at en liten gruppe datapunkter vil bli brukt til å oppdatere modellen vår. Fire nødvendige og ett valgfritt argument sendes til denne metoden. De fire nødvendige variablene er treningsdatasettet, antall epoker, størrelsen på minibatchene og læringshastigheten (eta).
Testdata er tilgjengelig på forespørsel. Vi leverer testdata når vi til slutt evaluerer dette nettverket. Antall prøver i denne funksjonen settes først til lengden på listen når treningsdataene har blitt transformert til en listetype.
Vi bruker også samme prosess for testdata som er gitt i. Dette er fordi i stedet for å bli returnert til oss som lister, er de egentlig zipper av lister. Når vi laster inn MNIST-dataprøvene senere, vil vi lære mer om dette.
Hvis vi kan sørge for at vi leverer begge typer data som lister, er ikke denne type-casting nødvendigvis nødvendig.
Når vi har dataene, går vi gjennom treningsepokene i en loop. En treningsperiode er bare én runde med nevrale nettverkstrening. Vi blander først dataene i hver epoke for å sikre tilfeldighet før vi lager en liste over mini-batcher.
Oppdateringsminibatchfunksjonen, som diskuteres nedenfor, vil bli kalt for hver minibatch. Testnøyaktigheten vil også bli returnert hvis testdataene er tilgjengelige.
Kostnadsavledet hjelpefunksjon
La oss utvikle en hjelpefunksjon kalt kostnadsderiverte først før vi virkelig lager tilbakepropageringskoden. Hvis vi gjør en feil i utdatalaget vårt, vil kostnadsderivatfunksjonen vise det.
Den krever to innganger: utgangsaktiveringsmatrisen og y-koordinatene til de forventede utgangsverdiene.
Tilbakepropageringsfunksjon
Vår nåværende aktiveringsvektor, aktivering, så vel som alle andre aktiveringsvektorer, aktiveringer og z-vektorer, zs, må alle huskes. Et lag kalt inngangslaget aktiveres først.
Vi går gjennom hver skjevhet og vekt etter å ha satt dem opp. Hver sløyfe innebærer å beregne z-vektoren som punktproduktet av vektene og aktiveringen, legge den til listen over zs, beregne aktiveringen på nytt og legge den oppdaterte aktiveringen til listen over aktiveringer.
Til slutt regnestykket. Deltaet, som er lik feilen fra forrige lag multiplisert med sigmoid-primtallet til det siste elementet i zs-vektorene, beregnes før vi starter vår bakoverpassering.
Det siste laget av nabla b er satt til å være deltaet, og det siste laget av nabla w er satt til å være punktproduktet av deltaet og det nest siste laget med aktiveringer (transponert slik at vi faktisk kan regne ut) .
Vi fortsetter som før, starter med det andre laget og avslutter med det siste, og gjentar prosessen etter å ha fullført disse siste lagene. Nablaene blir deretter gitt tilbake som en tuppel.
Oppdaterer Mini-batch gradient nedstigning
Vår SGD-metode (stokastisk gradientnedstigning) fra før inkluderer mini-batch-oppdatering. Siden den brukes i SGD, men også krever backprop, diskuterte jeg hvor jeg skulle plassere denne funksjonen.
Til slutt tok jeg valget om å legge det ut her. Det begynner med å generere 0 vektorer av skjevhetene og vektenes nablas, akkurat som backprop-funksjonen vår gjorde.
Den krever mini-batch og eta-læringshastigheten som sine to innganger. I mini-batchen bruker vi deretter backprop-funksjonen for å få deltaet til hver nabla-array for hver inngang, x, og utgang, y. Nabla-listene oppdateres deretter med disse deltaene.
Til slutt bruker vi læringsraten og nablaene til å oppdatere nettverkets vekter og skjevheter. Hver verdi oppdateres til den nyeste verdien, minus læringshastigheten, multiplisert med minibatch-størrelsen, og deretter lagt til nabla-verdien.
Evaluer funksjon
Evalueringsfunksjonen er den siste vi må skrive. Testdataene er den eneste inngangen for denne funksjonen. I denne funksjonen sammenligner vi bare utgangene fra nettverket med det forventede resultatet, y. Ved å mate inngangen, x, fremover, bestemmes utgangene til nettverket.
Komplett kode
Når vi kombinerer all koden, er det slik den fremstår.
Testing av nevrale nettverk
Laster inn MNIST-data
De MNIST-data er i .pkl.gz-format, som vi åpner med GZIP og laster med pickle. La oss skrive en rask metode for å laste disse dataene som en tuppel av størrelse tre, delt inn i trenings-, validerings- og testdata.
For å gjøre dataene våre enklere å administrere, skriver vi en annen funksjon for å kode y til en 10-elements matrise. Matrisen vil være alle 0-er bortsett fra en 1 som samsvarer med bildets riktige siffer.
Vi bruker de grunnleggende innlastingsdataene og én hot encode-metode for å laste inn dataene våre til et lesbart format. En annen funksjon vil bli skrevet som vil konvertere x-verdiene våre til en liste med størrelse 784, som samsvarer med bildets 784 piksler, og y-verdiene våre til deres enkelt varmekodede vektorform.
Deretter kombinerer vi x- og y-verdiene slik at den ene indeksen matcher den andre. Dette gjelder trenings-, validerings- og testdatasettene. Vi returnerer deretter de endrede dataene.
Kjører tester
Vi lager en ny fil kalt "mnist loader" som vil importere både det nevrale nettverket vi etablerte tidligere (enkelt nn) og MNIST-datasettlasteren før vi begynner å teste.
I denne filen trenger vi bare å importere dataene, bygge et nettverk med en inputlagstørrelse på 784 og en utgangslagstørrelse på 10, kjøre nettverkets SGD-funksjon på treningsdataene og deretter teste den ved å bruke testdataene.
Husk at for vår liste over inputlag spiller det ingen rolle hva tallene er mellom 784 og 10. Vi kan endre de andre lagene slik vi vil; bare inngangs- og utdatastørrelsene er faste.
Tre lag er ikke nødvendig; vi kan bruke fire, fem, eller til og med bare to. Ha det gøy å eksperimentere med det.
konklusjonen
Her, ved hjelp av Python 3, lager vi et nevralt nettverk fra bunnen av. Sammen med matematikk på høyt nivå diskuterte vi også spesifikasjonene ved implementering.
Vi begynte med å implementere hjelpefunksjoner. For at nevronene skal fungere, er sigmoid- og sigmoid-hovedfunksjonene avgjørende. Vi implementerer deretter feedforward-funksjonen, som er den grunnleggende prosessen for å mate data inn i det nevrale nettverket.
Deretter opprettet vi gradient descent-funksjonen i Python, motoren som driver vårt nevrale nettverk. For å finne "lokale minima" og optimalisere deres vekter og skjevheter, bruker vårt nevrale nettverk gradientnedstigning. Vi opprettet tilbakepropageringsfunksjonen ved hjelp av gradient nedstigning.
Ved å levere oppdateringer når utgangene ikke samsvarer med de riktige etikettene, gjør denne funksjonen det mulig for det nevrale nettverket å "lære".
Til slutt legger vi vår splitter nye Python nevrale nettverket til testen ved å bruke MNIST-datasettet. Alt fungerte knirkefritt.
Glad koding!
Legg igjen en kommentar