Kuinka rakentaa kolmikerroksinen neuroverkko tyhjästä

Kuva Thaï Hamelin on Unsplash

Tässä viestissä aion käydä läpi tarvittavat vaiheet kolmikerroksisen hermoverkon rakentamiseksi. Tutkan ongelman ja selitän sinulle prosessin tärkeimmistä käsitteistä matkan varrella.

Ratkaistava ongelma

Italialaisella maanviljelijällä oli ongelmia merkintäkoneellaan: se sekoitti kolmen viinilajikkeen etiketit. Nyt hänellä on jäljellä 178 pulloa, ja kukaan ei tiedä, mikä lajike teki ne! Tämän köyhän miehen auttamiseksi rakennamme luokittelijan, joka tunnistaa viinin 13 viinin ominaisuuden perusteella.

Se, että tietomme on merkitty (yhdellä kolmesta lajikkeen etiketistä), tekee tästä valvotun oppimisongelman. Pohjimmiltaan se, mitä haluamme tehdä, on käyttää syöttötietojamme (178 luokittelematonta viinipulloa), laittaa neuraaliverkostomme läpi ja saada sitten kunkin viinilajikkeen oikea etiketti tulosteena.

Koulutamme algoritmiamme paremmin ennustamaan (y-hattu), mikä pullo mihin etikettiin kuuluu.

Nyt on aika aloittaa hermoverkon rakentaminen!

Lähestyä

Neuraaliverkon rakentaminen on melkein kuin erittäin monimutkaisen funktion rakentamista tai erittäin vaikean reseptin laatimista. Aluksi tarvitsemasi ainesosat tai vaiheet saattavat tuntua ylivoimaisilta. Mutta jos hajotat kaiken ja tee se askel askeleelta, saat hyvin.

Yleiskatsaus 3-kerroksisesta neuroverkosta, viininluokittelija

Lyhyesti:

  • Tulokerros (x) koostuu 178 neuronista.
  • A1, ensimmäinen kerros, koostuu 8 neuronista.
  • Toinen kerros A2 koostuu 5 neuronista.
  • A3, kolmas ja lähtökerros, koostuu 3 neuronista.

Vaihe 1: tavallinen prep

Tuo kaikki tarvittavat kirjastot (NumPy, skicit-oppi, pandat) ja tietojoukot ja määritä x ja y.

# kaikkien kirjastojen ja tietoaineiston tuonti
tuoda pandat pd-muodossa
Tuo numerot kuin np
df = pd.read_csv ('../ input / W1data.csv')
df.head ()
# Pakkausten tuonti
# Matplotlib
tuo matplotlib
Tuo matplotlib.pyplot plt
# SciKitLearn on koneoppimisapuohjelmakirjasto
tuo sklearn
# Sklearn-tietojoukkomoduuli auttaa luomaan tietojoukkoja
Tuo sklearn.datasets
Tuo sklearn.linear_model
sklearn.preprocessing -tuonnista OneHotEncoder
sivustosta sklearn.metrics tuo tarkkuus_kohteet

Vaihe 2: alustaminen

Ennen kuin voimme käyttää painoja, meidän on alustettava ne. Koska meillä ei vielä ole painoihin käytettäviä arvoja, käytämme satunnaisarvoja välillä 0–1.

Pythonissa random.seed-funktio tuottaa ”satunnaislukuja”. Satunnaislukut eivät kuitenkaan ole todella satunnaisia. Luodut numerot ovat näennäissatunnaisia, eli numerot generoidaan monimutkaisella kaavalla, jonka avulla se näyttää satunnaiselta. Lukujen generoimiseksi kaava ottaa syötteensä aikaisemman luodun arvon. Jos aiempaa arvoa ei ole luotu, se vie usein aikaa ensimmäisenä arvona.

Siksi siemenämme generaattoria - varmistaaksemme, että saamme aina samat satunnaislukut. Tarjoamme kiinteän arvon, josta numerogeneraattori voi aloittaa, mikä on tässä tapauksessa nolla.

np.random.seed (0)

Vaihe 3: eteneminen eteenpäin

Neuraaliverkon kouluttamisessa on suunnilleen kaksi osaa. Ensinnäkin, etenet eteenpäin NN: n kautta. Toisin sanoen olet "askelmassa" eteenpäin ja vertaamalla näitä tuloksia todellisiin arvoihin saadaksesi ero tulosteen ja sen, minkä sen pitäisi olla. Periaatteessa näet kuinka NN menee ja löydät virheet.

Kun olemme alustaneet painoja pseudosatunnaisella numerolla, otamme lineaarisen askeleen eteenpäin. Laskemme tämän ottamalla syötteemme A0-kertaisesti satunnaisten alustettujen painojen pistekertoimen plus ennakkoluulo. Aloitimme nolla-asteella 0. Tätä edustaa:

Nyt otamme z1: n (lineaarinen askelmme) ja kuljemme sen ensimmäisen aktivointitoimintomme läpi. Aktivointitoiminnot ovat erittäin tärkeitä hermoverkoissa. Pohjimmiltaan ne muuntaa tulosignaalin lähtösignaaliksi - siksi niitä kutsutaan myös siirtofunktioiksi. Ne tuovat funktioihimme epälineaariset ominaisuudet muuntamalla lineaarisen sisääntulon epälineaariseksi lähdöksi, mikä mahdollistaa monimutkaisempien funktioiden esittämisen.

Aktivointitoimintoja on erilaisia ​​(selitetään perusteellisesti tässä artikkelissa). Valitsimme tässä mallissa tanhin aktivointitoiminnon kahdelle piilotetulle kerroksellemme - A1 ja A2 -, joka antaa meille lähtöarvon välillä -1 ja 1.

Koska tämä on moniluokkainen luokitteluongelma (meillä on 3 tulostetarraa), käytämme lähtökerroksen A3 softmax-funktiota, koska tämä laskee luokkien todennäköisyydet sirpottamalla arvon välillä 0 ja 1.

tanh-toiminto

Ohjaamalla z1 aktivointitoiminnon läpi, olemme luoneet ensimmäisen piilotetun kerroksen - A1 -, jota voidaan käyttää sisääntulona seuraavan lineaarisen vaiheen z2 laskemiseen.

Pythonissa tämä prosessi näyttää tältä:

# Tämä on eteenpäin etenemisfunktio
def forward_prop (malli, a0):
    
    # Lataa parametrit mallista
    W1, b1, W2, b2, W3, b3 = malli ['W1'], malli ['b1'], malli ['W2'], malli ['b2'], malli ['W3'], malli [' b3' ]
    
    # Suorita ensimmäinen lineaarinen vaihe
    z1 = a0.dot (W1) + b1
    
    # Laita se ensimmäisen aktivointitoiminnon läpi
    a1 = np.tanh (z1)
    
    # Toinen lineaarinen askel
    z2 = a1.dot (W2) + b2
    
    # Käynnistä toinen aktivointitoiminto
    a2 = np.tanh (z2)
    
    #Kolmas lineaarinen askel
    z3 = a2.dot (W3) + b3
    
    #Kolmannessa lineaarisessa aktivointitoiminnossa käytämme softmax-toimintoa
    a3 = softmax (z3)
    
    #Säilytä kaikki tulokset näissä arvoissa
    välimuisti = {'a0': a0, 'z1': z1, 'a1': a1, 'z2': z2, 'a2': a2, 'a3': a3, 'z3': z3}
    palauta välimuisti

Lopulta kaikki arvomme tallennetaan välimuistiin.

Vaihe 4: eteneminen taaksepäin

Sen jälkeen kun olemme eteenpäin levinneet NN: n kautta, eteenpäin siirrämme virhegradienttia päivittääksemme painoparametrit. Tiedämme virheemme ja haluamme minimoida sen niin paljon kuin mahdollista.

Teemme tämän ottamalla virhefunktion derivaatan suhteessa NN: n painoihin (W) gradienttien laskeutumisen avulla.

Antaa visualisoida tämän prosessin analogisesti.

Kuvittele, että olet mennyt kävelylle vuorille iltapäivällä. Mutta nyt on aika myöhemmin ja olet hieman nälkäinen, joten on aika mennä kotiin. Ainoa ongelma on, että on pimeää ja puita on paljon, joten et näe kotiasi tai sijaintiasi. Voi, ja unohdit puhelimesi kotona.

Mutta sitten muistat, että talosi on laaksossa, koko alueen alin piste. Joten jos kävelet vain vuorelta askel askeleelta, kunnes et tunne mitään kaltevuutta, teoriassa sinun pitäisi saapua kotiisi.

Joten sinä menet, askel askeleelta varovasti alaspäin. Ajattele nyt vuoria tappiofunktiota, ja olet algoritmi, joka yrittää löytää kotisi (ts. Alimman pisteen). Joka kerta kun otat askeleen alaspäin, päivitämme sijaintikoordinaatit (algoritmi päivittää parametrit).

Tappiofunktiota edustaa vuori. Pienen häviön saavuttamiseksi algoritmi noudattaa häviöfunktion kaltevuutta - eli johdannaista.

Kun kävelemme mäellä, päivitämme sijaintikoordinaatit. Algoritmi päivittää hermoverkon parametrit. Menemällä lähemmäksi minimipistettä lähestymme tavoitetta minimoida virheemme.

Todellisuudessa gradientin laskeutuminen näyttää enemmän tältä:

Aloitamme aina häviöfunktion kaltevuuden laskemisen suhteessa z: iin, mittaamme lineaarisen askeleen kaltevuuteen.

Merkintä on seuraava: dv on häviöfunktion johdannainen suhteessa muuttujaan v.

Seuraavaksi lasketaan häviöfunktion kaltevuus suhteessa painoihimme ja esijännitteisiin. Koska tämä on 3-kerroksinen NN, jatkamme tätä prosessia z3,2,1 + W3,2,1 ja b3,2,1: lle. Eteneminen taaksepäin ulostulosta tulokerrokseen.

Näin tämä prosessi näyttää Pythonissa:

# Tämä on taaksepäin leviävä toiminto
def taaksepäin_prop (malli, välimuisti, y):
# Lataa parametrit mallista
    W1, b1, W2, b2, W3, b3 = malli ['W1'], malli ['b1'], malli ['W2'], malli ['b2'], malli ['W3'], malli [' b3' ]
    
    # Lataa eteenpäin leviämisen tulokset
    a0, a1, a2, a3 = välimuisti ['a0'], välimuisti ['a1'], välimuisti ['a2'], välimuisti ['a3']
    
    # Hanki näytteiden lukumäärä
    m = y.muoto [0]
    
    # Laske tappiojohdannainen suhteessa tuotokseen
    dz3 = tappiojohdannainen (y = y, y_hat = a3)
# Laske tappiojohdannainen suhteessa toisen kerroksen painoihin
    dW3 = 1 / m * (a2.T) .dot (dz3) # dW2 = 1 / m * (a1.T) .dot (dz2)
    
    # Laske tappiojohdannainen suhteessa toisen kerroksen poikkeamiin
    db3 = 1 / m * np.sum (dz3, akseli = 0)
    
    # Laske tappiojohdannainen suhteessa ensimmäiseen kerrokseen
    dz2 = np.multiply (dz3.dot (W3.T), tanh_derivative (a2))
    
    # Laske tappiojohdannainen suhteessa ensimmäisen kerroksen painoihin
    dW2 = 1 / m * np.dot (a1.T, dz2)
    
    # Laske tappiojohdannainen suhteessa ensimmäisen kerroksen poikkeamiin
    db2 = 1 / m * np.sum (dz2, akseli = 0)
    
    dz1 = np.kertaisesti (dz2.dot (W2.T), tanh_derivative (a1))
    
    dW1 = 1 / m * np.dot (a0.T, dz1)
    
    db1 = 1 / m * np.sum (dz1, akseli = 0)
    
    # Säilytä kaltevuudet
    asteikot = {'dW3': dW3, 'db3': db3, 'dW2': dW2, 'db2': db2, 'dW1': dW1, 'db1': db1}
    palata arvosanat

Vaihe 5: harjoitusvaihe

Jotta päästäisiin optimaalisiin painoihin ja ennakkoluuloihin, jotka antavat meille halutun tuloksen (kolme viinilajiketta), meidän on koulutettava hermoverkkoamme.

Mielestäni tämä on hyvin intuitiivista. Melkein mitä tahansa elämässä sinun on harjoiteltava ja harjoiteltava useita kertoja, ennen kuin olet siinä hyvä. Samoin hermostoverkon on läpikäytävä useita ajanjaksoja tai iteraatioita, jotta meille voidaan antaa tarkka ennuste.

Kun opit jotain, sanotaan, että luet kirjaa, sinulla on tietty vauhti. Tämä vauhti ei saisi olla liian hidas, koska kirjan lukeminen vie vuosia. Mutta sen ei pitäisi myöskään olla liian nopeaa, koska saatat unohtaa erittäin arvokkaan oppitunnin kirjassa.

Samalla tavalla sinun on määritettävä malli ”oppimisnopeus”. Oppimisnopeus on kerroin parametrien päivittämiselle. Se määrittelee kuinka nopeasti ne voivat muuttua. Jos oppimisaste on alhainen, harjoittelu vie pidempään. Jos oppimisprosentti on liian korkea, saatamme kuitenkin jäädä vähimmäismäärän. Oppimisprosentti ilmaistaan:

  • : = tarkoittaa, että tämä on määritelmä, ei yhtälö tai todistettu lause.
  • a on oppimisnopeus, jota kutsutaan alfaksi
  • dL (w) on johdannainen kokonaismenetyksestä suhteessa painoomme w
  • da on alfa-johdannainen

Valitsimme oppimisprosentiksi 0,07 kokeilun jälkeen.

# Tämän palaamme lopussa
malli = alustusparametrit (nn_input_dim = 13, nn_hdim = 5, nn_output_dim = 3)
malli = juna (malli, X, y, oppimisarvo = 0,07, aikakaudet = 4500, print_loss = totta)
plt.plot (tappiot)

Lopuksi on meidän kuvaajamme. Voit piirtää tarkkuutesi ja / tai menetyksesi saadaksesi mukavan kaavion ennusteiden tarkkuudesta. 4500 aikakauden jälkeen algoritmimme tarkkuus on 99.4382022472%.

Lyhyt yhteenveto

Aloitamme syöttämällä tietoa hermoverkkoon ja suoritamme useita matriisitoimenpiteitä tälle tulotiedolle kerros kerrallaan. Jokaisesta kolmesta kerroksesta otamme syötteen pistetuotteen painojen mukaan ja lisäämme ennakkoluulo. Seuraavaksi välitämme tämän lähdön valitun aktivointitoiminnon kautta.

Tämän aktivointitoiminnon lähtöä käytetään sitten tulona seuraavalle kerrokselle seurata samaa menettelyä. Tämä prosessi toistetaan kolme kertaa, koska meillä on kolme kerrosta. Lopputuloksemme on y-hattu, mikä on ennuste, johon viini kuuluu mihin lajikkeeseen. Tämä on eteenpäin leviämisen prosessin loppu.

Lasketaan sitten ennusteemme (y-hat) ja odotetun tuotoksen (y) välinen ero ja käytämme tätä virhearvoa jälkikasvatuksen aikana.

Takaisikasvatuksen aikana otamme virheen - ennusteen y-hat ja y välisen eron - ja työntämme sen matemaattisesti takaisin NN: n läpi toiseen suuntaan. Opimme virheistämme.

Ottamalla johdannainen toiminnoista, joita käytimme ensimmäisen prosessin aikana, yritämme selvittää, minkä arvon meidän tulisi antaa painot parhaan mahdollisen ennusteen saavuttamiseksi. Pohjimmiltaan haluamme tietää, mikä suhde on painomme arvon ja sen seurauksena saamme virheen välillä.

Ja monien aikakausien tai iteratioiden jälkeen NN on oppinut antamaan meille tarkempia ennusteita mukauttamalla parametrit tietokantaan.

Katsaus eteenpäin ja taaksepäin leviämiseen

Tämä viesti on inspiroinut 7. helmikuuta alkaneen Bletchley Machine Learning Bootcampin viikon 1 haasteen. Seuraavien yhdeksän viikon aikana olen yksi 50 opiskelijasta, jotka käyvät läpi koneoppimisen perusteet. Joka viikko keskustelemme eri aiheesta ja meidän on jätettävä haaste, joka edellyttää, että ymmärrät materiaalit todella.

Jos sinulla on kysyttävää tai ehdotuksia tai, kerro minulle!

Tai jos haluat tarkistaa koko koodin, löydät sen täältä Kagglessa.

Suositellut videot syvemmälle ymmärtämiseksi hermoverkoissa:

  • 3Blue1Brownin sarjat hermoverkoissa
  • Siraj Ravalin syvän oppimisen sarja