Suuren kuvankäsittelyoppiminen: Tekstin luokittelu hermoverkkojen ja TensorFlow-ohjelmien avulla

Kehittäjät sanovat usein, että jos haluat aloittaa koneoppimisen, sinun on ensin opittava, kuinka algoritmit toimivat. Mutta kokemukseni osoittavat toisin.

Sanon, että sinun pitäisi ensin nähdä iso kuva: kuinka sovellukset toimivat. Kun ymmärrät tämän, on paljon helpompaa sukeltaa syvälle ja tutkia algoritmien sisäisiä toimia.

Joten miten kehittää intuitio ja saavuttaa tämä kokonaisvaltainen käsitys koneoppimisesta? Hyvä tapa tehdä tämä on luoda koneoppimismalleja.

Olettaen, että et edelleenkään tiedä kuinka luoda kaikkia näitä algoritmeja tyhjästä, haluat käyttää kirjastoa, jossa kaikki nämä algoritmit on jo asennettu sinulle. Ja se kirjasto on TensorFlow.

Tässä artikkelissa luomme koneoppimallin tekstien luokittelemiseksi luokkiin. Käsittelemme seuraavia aiheita:

  1. Kuinka TensorFlow toimii
  2. Mikä on koneoppimismalli
  3. Mikä on hermoverkko
  4. Kuinka hermoverkko oppii
  5. Kuinka manipuloida tietoja ja siirtää ne hermoverkon tuloihin
  6. Kuinka ajaa mallia ja saada ennustetuloksia

Opit todennäköisesti paljon uutta, joten aloitetaan!

TensorFlow

TensorFlow on Googlen luoma avoimen lähdekoodin kirjasto koneoppimiseen. Kirjaston nimi auttaa meitä ymmärtämään, kuinka työskentelemme sen kanssa: Tenorit ovat moniulotteisia taulukkoja, jotka virtaavat graafin solmujen läpi.

tf.Graph

Jokainen TensorFlow-laskenta on esitetty datavirtakaaviona. Tässä kaaviossa on kaksi elementtiä:

  • joukko tf.operaatiota, joka edustaa laskentayksiköitä
  • joukko tf.Tensor, joka edustaa datayksiköitä

Luo tämä tiedonkulkukaavio nähdäksesi kuinka tämä kaikki toimii:

Kaavio, joka laskee x + y

Määrität x = [1,3,6] ja y = [1,1,1]. Koska kuvaaja toimii tf.Tensorin kanssa yksikköyksiköinä, luot jatkuvat tenorit:

tuo tensorflow tf: nä
x = tf.vakio ([1,3,6])
y = tf.vakio ([1,1,1])

Nyt määrität toimintayksikön:

tuo tensorflow tf: nä
x = tf.vakio ([1,3,6])
y = tf.vakio ([1,1,1])
op = tf.add (x, y)

Sinulla on kaikki kuvaajaelementit. Nyt sinun on rakennettava kuvaaja:

tuo tensorflow tf: nä
my_graph = tf.Graph ()
with my_graph.as_default ():
    x = tf.vakio ([1,3,6])
    y = tf.vakio ([1,1,1])
    op = tf.add (x, y)

Näin TensorFlow-työnkulku toimii: luot ensin kaavion, ja vasta sen jälkeen voit tehdä laskelmia (todella "ajaa" kaavion solmuja toiminnoilla). Suorittaaksesi kaavion sinun on luotava tf.Session.

tf.Session

Tf.Session-objekti kapseloi sen ympäristön, jossa operaatioobjektit suoritetaan, ja Tensor-objektit arvioidaan (asiakirjoista). Tätä varten meidän on määritettävä, mitä kuvaajaa käytetään istunnossa:

tuo tensorflow tf: nä
my_graph = tf.Graph ()
kanssa tf.Session (kuvaaja = oma_kuva) istunnona:
    x = tf.vakio ([1,3,6])
    y = tf.vakio ([1,1,1])
    op = tf.add (x, y)

Suorita operaatiot menetelmällä tf.Session.run (). Tämä menetelmä suorittaa yhden "askeleen" TensorFlow-laskennasta suorittamalla tarvittavan kaavion fragmentin suorittaaksesi kaikki operaatioobjektit ja arvioidaksesi kaikki argumenttihaussa lävitetyt Tensorit. Sinun tapauksessasi suoritetaan vaihe summanoperaatioista:

tuo tensorflow tf: nä
my_graph = tf.Graph ()
kanssa tf.Session (kuvaaja = oma_kuva) istunnona:
    x = tf.vakio ([1,3,6])
    y = tf.vakio ([1,1,1])
    op = tf.add (x, y)
    tulos = sess.run (hakee = op)
    print (tulos)
>>> [2 4 7]

Ennustava malli

Nyt kun tiedät miten TensorFlow toimii, sinun on opittava luomaan ennustava malli. Lyhyesti,

Koneoppimisalgoritmi + data = ennustava malli

Prosessin rakentaminen malli on seuraava:

Ennustavan mallin luomisprosessi

Kuten näette, malli koostuu koneellisesta algoritmista, joka on ”koulutettu” tiedoilla. Kun sinulla on malli, saat tällaisia ​​tuloksia:

Ennustamisen työnkulku

Luomamasi mallin tavoitteena on luokitella tekstit luokkiin, määrittelemme seuraavan:

syöttö: teksti, tulos: luokka

Meillä on harjoitustiedot, joissa kaikki tekstit on merkitty (jokaisella tekstillä on tarra, joka osoittaa mihin luokkaan se kuuluu). Koneoppimisessa tämäntyyppinen tehtävä on nimeltään Ohjattu oppiminen.

”Tiedämme oikeat vastaukset. Algoritmi tekee toistuvasti ennusteita harjoitustiedoista ja opettaja korjaa ne. ”- Jason Brownlee

Luokittelet tiedot luokkiin, joten se on myös luokitustyö.

Mallin luomiseksi aiomme käyttää hermoverkkoja.

Neuraaliverkot

Neuraaliverkko on laskennallinen malli (tapa kuvata järjestelmää käyttämällä matemaattista kieltä ja matemaattisia käsitteitä). Nämä järjestelmät ovat itseoppivia ja koulutettuja, eikä niinkään ohjelmoituja.

Neuraaliverkot ovat inspiroituneet keskushermostoamme. He ovat kytkeneet solmut, jotka ovat samanlaisia ​​kuin neuronimme.

Neuraali verkko

Perceptron oli ensimmäinen hermoverkkoalgoritmi. Tämä artikkeli selittää todella hyvin perceptronin sisäisen toiminnan ("Keinotekoisen neuronin sisällä" -animaatio on upea).

Ymmärtääksesi, kuinka hermoverkko toimii, rakennamme hermoverkkoarkkitehtuurin TensorFlow-ohjelmalla. Tätä arkkitehtuuria käytti Aymeric Damien tässä esimerkissä.

Neuraaliverkkoarkkitehtuuri

Neuraaliverkossa on 2 piilotettua tasoa (sinun on valittava, kuinka monta piilotettua tasoa verkolla on, on osa arkkitehtuurisuunnittelua). Kunkin piilotetun kerroksen tehtävänä on muuntaa tulot jollekin, jota lähtökerros voi käyttää.

Piilotettu kerros 1

Tulokerros ja ensimmäinen piilotettu kerros

Sinun on myös määritettävä, kuinka monta solmua ensimmäisellä piilotetulla kerroksella on. Näitä solmuja kutsutaan myös piirteiksi tai neuroneiksi, ja yllä olevassa kuvassa niitä edustaa kukin ympyrä.

Tulokerroksessa jokainen solmu vastaa tietojoukon sanaa (näemme kuinka tämä toimii myöhemmin).

Kuten tässä selitetään, kukin solmu (neuroni) kerrotaan painolla. Jokaisella solmulla on painoarvo, ja harjoitusvaiheen aikana hermoverkko säätää näitä arvoja oikean tuloksen tuottamiseksi (odota, opimme siitä lisää minuutissa).

Sen lisäksi, että jokainen tulosolmu kerrotaan painolla, verkko lisää myös bias (bias rooli hermoverkoissa).

Kun arkkitehtuurissasi kerrotaan tulot painoilla ja summataan arvot biasointiin, data ohittaa myös aktivointitoiminnon. Tämä aktivointitoiminto määrittelee kunkin solmun lopullisen ulostulon. Analogia: Kuvittele, että jokainen solmu on lamppu, aktivointitoiminto kertoo, syttyykö lamppu vai ei.

Aktivointitoimintoja on monen tyyppisiä. Käytät puhdistettua lineaarista yksikköä (ReLu). Tämä toiminto määritetään tällä tavalla:

f (x) = max (0, x) [lähtö on x tai 0 (nolla), sen mukaan kumpi on suurempi]

Esimerkkejä: ifx = -1, niin f (x) = 0 (nolla); jos x = 0,7, niin f (x) = 0,7.

Piilotettu kerros 2

Toinen piilotettu kerros tekee tarkalleen mitä ensimmäinen piilotettu kerros tekee, mutta nyt toisen piilotetun kerroksen tulo on ensimmäisen kerroksen lähtö.

1. ja 2. piilotettu kerros

Tulostekerros

Ja lopulta pääsimme viimeiseen kerrokseen, lähtökerrokseen. Käytä yksi-kuumaa koodausta saadaksesi tämän kerroksen tulokset. Tässä koodauksessa vain yhdellä bitillä on arvo 1 ja kaikilla muilla bitteillä on nolla-arvo. Jos esimerkiksi haluamme koodata kolme luokkaa (urheilu, avaruus- ja tietokonegrafiikka):

+ ------------------- + ----------- +
| luokka | arvo |
+ ------------------- | ----------- +
| urheilu | 001 |
| tila | 010 |
| tietokonegrafiikka | 100 |
| ------------------- | ----------- |

Joten ulostulosolmujen lukumäärä on syötetietoaineiston luokkien lukumäärä.

Lähtökerroksen arvot kerrotaan myös painoilla ja lisäämme myös esijännityksen, mutta nyt aktivointitoiminto on erilainen.

Haluat merkitä jokaisen tekstin luokalla, ja nämä luokat ovat toisiaan poissulkevia (teksti ei kuulu kahteen luokkaan samanaikaisesti). Harkitsemaan tätä, sen sijaan, että käytät ReLu-aktivointitoimintoa, käytät Softmax-toimintoa. Tämä funktio muuttaa kunkin yksikön lähdön arvoksi välillä 0 ja 1 ja varmistaa myös, että kaikkien yksiköiden summa on yhtä. Tällä tavalla lähtö antaa meille kunkin luokan tekstin todennäköisyyden.

| 1,2 0,46 |
| 0,9 -> [softmax] -> 0,34 |
| 0,4 0,20 |

Ja nyt sinulla on hermoverkon tietovirtakaavio. Kääntämällä kaikki tähän mennessä näkemämme koodiksi, tulos on:

# Verkkoparametrit
n_hidden_1 = 10 # ensimmäisen kerroksen ominaisuuksien lukumäärä
n_hidden_2 = 5 # 2. kerroksen ominaisuuksien lukumäärä
n_input = total_words # sanat sanakirjassa
n_classes = 3 # Luokat: grafiikka, avaruus ja baseball
def multilayer_perceptron (input_tensor, painot, painotukset):
    layer_1_multiplication = tf.matmul (input_tensor, painot ['h1'])
    layer_1_addition = tf.add (layer_1_multiplication, biases ['b1'])
    layer_1_activation = tf.nn.relu (layer_1_addition)
# Piilotettu kerros RELU-aktivoinnin kanssa
    layer_2_multiplication = tf.matmul (layer_1_activation, painot ['h2'])
    layer_2_addition = tf.add (layer_2_multiplication, biases ['b2'])
    layer_2_activation = tf.nn.relu (layer_2_addition)
# Lähtökerros lineaarisella aktivoinnilla
    out_layer_multiplication = tf.matmul (kerros_2_aktivointi, painot ['out'])
    out_layer_addition = out_layer_multiplication + puolueellisuus ['out']
palauta lisäkerros

(Puhumme myöhemmin lähtökerroksen aktivointitoiminnon koodista.)

Kuinka hermoverkko oppii

Kuten aiemmin näimme, painoarvoja päivitetään verkon harjoittamisen aikana. Nyt näemme, miten tämä tapahtuu TensorFlow-ympäristössä.

tf.Variable

Painot ja poikkeamat tallennetaan muuttujiin (tf.Varable). Nämä muuttujat ylläpitävät kuvaajan tilaa suoritettavien kutsujen välillä (). Koneoppimisessa aloitamme paino- ja ennakkoluuloarvot yleensä normaalijakauman kautta.

painot = {
    'h1': tf.Variable (tf.random_normal ([n_input, n_hidden_1])),
    'h2': tf.Variable (tf.random_normal ([n_hidden_1, n_hidden_2])),
    'out': tf.Variable (tf.random_normal ([n_hidden_2, n_classes])))
}
puolueellisuus = {
    'b1': tf.Variable (tf.random_normal ([n_hidden_1])),
    'b2': tf.Variable (tf.random_normal ([n_hidden_2])),
    'out': tf.Variable (tf.random_normal ([n_classes]))
}

Kun ajamme verkkoa ensimmäistä kertaa (ts. Painoarvot ovat normaalin jakauman määrittelemiä):

tuloarvot: x
painot: w
puolueellisuus: b
lähtöarvot: z
odotetut arvot: odotetut

Jotta voit tietää, onko verkko oppimassa vai ei, sinun on verrattava lähtöarvoja (z) odotettuihin arvoihin (odotettuihin). Ja kuinka laskemme tämän eron (menetys)? Tätä varten on monia menetelmiä. Koska työskentelemme luokittelutehtävän kanssa, paras menetyksen mitta on risti-entropiavirhe.

James D. McCaffrey kirjoitti loistavan selityksen miksi tämä on paras tapa tällaiseen tehtävään.

TensorFlow: lla voit laskea ristin entrooppivirheen tf.nn.softmax_cross_entropy_with_logits () -menetelmällä (tässä on softmax-aktivointitoiminto) ja laskea keskimääräinen virhe (tf.reduce_mean ()).

# Rakenna malli
ennustus = monikerros_perceptron (input_tensor, painot, painotukset)
# Määritä menetys
entropy_loss = tf.nn.softmax_cross_entropy_with_logits (logit = ennustus, tarrat = output_tensor)
tappio = tf.reduce_mean (entropy_loss)

Haluat löytää parhaat painojen ja poikkeamien arvot tulostusvirheen minimoimiseksi (erotus saaman arvon ja oikean arvon välillä). Tätä varten käytetään gradientin laskeutumismenetelmää. Tarkemmin sanottuna käytät stokastista gradientin laskeutumista.

Kaltevuuden laskeutuminen. Lähde: https://sebastianraschka.com/faq/docs/closed-form-vs-gd.html

On myös monia algoritmeja laskeaksesi kaltevuuslaskun. Käytät Adaptive Moment Estimation (Adam) -sovellusta. Jotta tätä algoritmia voitaisiin käyttää TensorFlow-ohjelmassa, sinun on läpäistävä oppimisarvon arvo, joka määrittelee arvojen lisäysvaiheet parhaiden painoarvojen löytämiseksi.

Menetelmä tf.train.AdamOptimizer (learning_rate) .minimize (loss) on syntaattinen sokeri, joka tekee kaksi asiaa:

  1. compute_gradients (menetys, )
  2. apply_gradients ()

Menetelmä päivittää kaikki tf.muuttujat uusilla arvoilla, joten meidän ei tarvitse siirtää muuttujaluetteloa. Ja nyt sinulla on koodi verkon kouluttamiseen:

oppimisarvo = 0,001
# Rakenna malli
ennustus = monikerros_perceptron (input_tensor, painot, painotukset)
# Määritä menetys
entropy_loss = tf.nn.softmax_cross_entropy_with_logits (logit = ennustus, tarrat = output_tensor)
tappio = tf.reduce_mean (entropy_loss)
optimoija = tf.train.AdamOptimizer (learning_rate = learning_rate) .minimize (loss)

Tietojen manipulointi

Käytettävässä tietojoukossa on monia englanninkielisiä tekstejä, ja meidän on käsiteltävä näitä tietoja siirtääksemme neuroverkkoon. Voit tehdä sen kahdella tavalla:

  1. Luo hakemisto jokaiselle sanalle
  2. Luo jokaiselle tekstille matriisi, jonka arvot ovat 1, jos sana on tekstissä, ja 0, jos ei

Katsotaanpa koodi ymmärtääksesi tätä prosessia:

Tuo numerot nimellä np #numpy on tieteellisen laskennan paketti
kokoelmista tuota laskuri
vocab = laskuri ()
text = "Hei Brasiliasta"
#Hanki kaikki sanat
sanalle text.split (''):
    vocab [sana] + = 1
        
# Muunna sanat hakemistoihin
def get_word_2_index (vocab):
    word2index = {}
    i: lle, sana enumeratessa (vocab):
        word2index [sana] = i
        
    palauta word2index
#Nyt meillä on hakemisto
word2index = get_word_2_index (vocab)
total_words = len (vocab)
# Näin luomme numpy-taulukon (matriisimme)
matriisi = np.zeros ((yhteensä_sanat), dtype = float)
#Nyt täytämme arvot
sanalle text.split ():
    matriisi [word2index [word]] + = 1
tulosta (matriisi)
>>> [1. 1. 1.]

Yllä olevassa esimerkissä teksti oli 'Hei Brasiliasta' ja matriisi oli [1. 1. 1.]. Entä jos teksti oli vain "Hei"?

matriisi = np.zeros ((yhteensä_sanat), dtype = float)
text = "Hei"
sanalle text.split ():
    matriisi [word2index [word.lower ()]] + = 1
tulosta (matriisi)
>>> [1. 0. 0.]

Pääset samaan kohtaan tarrojen (tekstiluokkien) kanssa, mutta käytät nyt yhtä kuumaa koodausta:

y = np.zeros ((3), tyyppi = kellua)
jos luokka == 0:
    y [0] = 1. # [1. 0. 0.]
elif-luokka == 1:
    y [1] = 1. # [0. 1. 0.]
else:
     y [2] = 1. # [0. 0. 1.]

Suoritetaan kaavio ja saadaan tulokset

Nyt on paras osa: tulosten saaminen mallista. Katsotaanpa ensin lähemmin syöttötietojoukkoa.

Tietojoukko

Käytät 20 uutisryhmää, tietojoukko, jonka 18.000 viestiä on noin 20 aihetta. Voit ladata tämän tietojoukon scikit-oppikirjastolla. Käytämme vain kolmea luokkaa: comp.graphics, sci.space ja rec.sport.baseball. Scikit-oppimisella on kaksi osajoukkoa: yksi harjoitteluun ja toinen testaamiseen. Suositus on, että sinun ei tulisi koskaan katsoa testitietoja, koska se voi häiritä valintasi mallin luomisen aikana. Et halua luoda mallia tämän tietyn testitiedon ennustamiseksi. Haluat luoda mallin, jolla on hyvä yleistys.

Voit ladata tietojoukot seuraavasti:

sklearn.datasets -sovelluksesta tuo fetch_20newsgroups
Kategoriat = ["comp.graphics", "sci.space", "rec.sport.baseball"]
newsgroups_train = fetch_20uutisryhmät (alajoukko = 'juna', luokat = luokat)
newsgroups_test = fetch_20uutisryhmät (alajoukko = 'testi', luokat = luokat)

Kouluta malli

Neuraaliverkkoterminologiassa yksi aikakausi = yksi eteenpäinläpäisy (lähtöarvojen saaminen) ja yksi taaksepäinläpäisy (painojen päivittäminen) kaikista harjoitteluesimerkeistä.

Muistatko tf.Session.run () -menetelmän? Katsotaanpa sitä lähemmin:

tf.Session.run (hakee, feed_dict = Ei mitään, options = Ei mitään, run_metadata = None)

Tämän artikkelin alun datavirtakaaviossa käytit summaoperaatiota, mutta voimme myös välittää luettelon suoritettavista asioista. Tässä hermoverkon suorituksessa suoritat kaksi asiaa: menetyksen laskeminen ja optimointivaihe.

Parametri feed_dict välittää tiedot jokaisesta ajovaiheesta. Tämän tiedon välittämiseksi meidän on määritettävä tf.placeholders (syötteen feed_dict syöttämiseksi).

Kuten TensorFlow-dokumentaatiossa sanotaan:

”Paikallismerkki on olemassa yksinomaan syötteiden kohdeksi. Se ei ole alustettu eikä sisällä mitään tietoja. ”- Lähde

Joten määrität paikkamerkkisi näin:

n_input = total_words # sanat sanakirjassa
n_classes = 3 # Luokat: grafiikka, sci.space ja baseball
input_tensor = tf.placeholder (tf.float32, [ei mitään, n_input], nimi = "input")
output_tensor = tf.placeholder (tf.float32, [ei mitään, n_luokka], nimi = "output")

Erotat harjoitustiedot erissä:

”Jos käytät paikkamerkkejä syötteen syöttämiseen, voit määrittää muuttuvan erämitan luomalla paikkamerkin tf.placeholderilla (…, muoto = [Ei mitään,…]). Kuvan mikään elementti ei vastaa muuttuvan kokoista mittaa. ”- Lähde

Syötämme levyn suuremmalla erällä mallia testattaessa, siksi sinun on määritettävä muuttuva erämitta.

Get_batches () -toiminto antaa meille erien koon sisältävien tekstien määrän. Ja nyt voimme ajaa mallia:

koulutusjaksot = 10
# Käynnistä kaavio
kanssa tf.Session () sessiona:
    sess.run (init) #initset muuttujat (normaali jakauma, muistatko?)
    # Harjoittelujakso
    kauden vaihteluvälille (training_epochs):
        keskimääräinen hinta = 0.
        total_batch = int (len (newsgroups_train.data) / batch_size)
        # Sijoita kaikki erät
        i: lle alueella (total_batch):
            batch_x, batch_y = get_batch (newsgroups_train, i, batch_size)
            # Suorita optimointi op (backprop) ja cost op (saada tappioarvo)
            c, _ = sess.run ([menetys, optimoija], feed_dict = {input_tensor: batch_x, output_tensor: batch_y})

Nyt sinulla on malli, koulutettu. Testaaksesi se, sinun on myös luotava kuvaajaelementit. Mittaamme mallin tarkkuuden, joten sinun on haettava ennustetun arvon indeksi ja oikean arvon indeksi (koska käytämme yksi-kuumaa koodausta), tarkista onko ne yhtä suuret ja laskea keskiarvo kaikki testitiedot

    # Testimalli
    index_prediction = tf.argmax (ennuste, 1)
    hakemiston oikea = tf.argmax (output_tensor, 1)
    oikea_ennuste = tf.equal (indeksi_ennuste, indeksin_korjaus)
    # Laske tarkkuus
    tarkkuus = tf.reduce_mean (tf.cast (oikea_ennuste, "kelluva"))
    total_test_data = len (newsgroups_test.target)
    batch_x_test, batch_y_test = get_batch (uutisryhmien testi, 0, kokonaistiedot)
    tulosta ("Tarkkuus:", tarkkuus.aika ({input_tensor: batch_x_test, output_tensor: batch_y_test}))
>>> Aika: 0001 tappio = 1133.908114347
    Aikakausi: 0002 tappio = 329,093700409
    Kausi: 0003 tappio = 111,876660109
    Aikakausi: 0004 tappio = 72,552971845
    Aikakausi: 0005 tappio = 16,673050320
    Aika: 0006 tappio = 16,481995190
    Kausi: 0007 tappio = 4,848220565
    Aikakausi: 0008 tappio = 0.759822878
    Aikakausi: 0009 tappio = 0,000000000
    Kausi: 0010 tappio = 0,079848485
    Optimointi valmis!
    Tarkkuus: 0.75

Ja siinä kaikki! Loit mallin neuroverkon avulla luokittelemaan tekstit kategorioihin. Onnittelut!

Näet kannettavan lopullisella koodilla täällä.

Vihje: muokkaa määriteltyjä arvoja nähdäksesi kuinka muutokset vaikuttavat harjoitusaikaan ja mallin tarkkuuteen.

Onko sinulla kysymyksiä tai ehdotuksia? Jätä ne kommentteihin. Voi, kiitos lukemisesta!

Löysitkö tästä artikkelista apua? Yritän parhaani mukaan kirjoittaa syväsukellusartikkeli joka kuukausi. Voit saada sähköpostia, kun julkaisen uuden.

Se merkitsisi paljon, jos napsautat -painiketta ja jaat sen ystävien kanssa. Seuraa minua saadaksesi lisätietoja datatieteestä ja koneoppimisesta.