Vodič za produbljivanje4j

1. Uvod

U ovom ćemo članku stvoriti jednostavnu neuronsku mrežu s knjižnicom deeplearning4j (dl4j) - modernim i moćnim alatom za strojno učenje.

Prije nego što započnemo, nije da ovaj vodič ne zahtijeva duboko poznavanje linearne algebre, statistike, teorije strojnog učenja i puno drugih tema neophodnih za dobro utemeljenog inženjera ML-a.

2. Što je duboko učenje?

Neuronske mreže su računski modeli koji se sastoje od međusobno povezanih slojeva čvorova.

Čvorovi su neuronski procesori numeričkih podataka. Oni uzimaju podatke sa svojih ulaza, primjenjuju neke težine i funkcije na te podatke i šalju rezultate na izlaze. Takva mreža može se uvježbati s nekoliko primjera izvornih podataka.

Trening u osnovi štedi neko numeričko stanje (težine) u čvorovima što kasnije utječe na izračunavanje. Primjeri treninga mogu sadržavati podatkovne stavke sa značajkama i određene poznate klase tih predmeta (na primjer, „ovaj skup od 16 × 16 piksela sadrži ručno napisano slovo„ a “).

Nakon završetka treninga, neuronska mreža možeizvući podatke iz novih podataka, čak i ako prije nije vidio ove određene stavke podataka. Dobro modelirana i dobro uvježbana mreža može prepoznati slike, rukom napisana slova, govor, obrađivati ​​statističke podatke kako bi proizvela rezultate za poslovnu inteligenciju i još mnogo toga.

Duboke neuronske mreže postale su moguće posljednjih godina, napretkom visokih performansi i paralelnog računanja. Takve se mreže razlikuju od jednostavnih neuronskih mreža po tomesastoje se od više srednjih (ili skrivenih) slojeva. Ova struktura omogućuje mrežama da obrađuju podatke na puno složeniji način (na rekurzivan, ponavljajući, konvolucionaran način itd.) I iz njih izvlače puno više informacija.

3. Postavljanje projekta

Da bismo koristili knjižnicu, treba nam barem Java 7. Također, zbog nekih izvornih komponenata, radi samo s 64-bitnom JVM verzijom.

Prije početka s vodičem, provjerimo jesu li ispunjeni zahtjevi:

$ java -verzija java verzija "1.8.0_131" Java (TM) SE Runtime Environment (gradnja 1.8.0_131-b11) Java HotSpot (TM) 64-bitni poslužitelj VM (gradnja 25.131-b11, mješoviti način)

Prvo, dodajmo potrebne knjižnice u naš Maven pom.xml datoteka. Izdvojit ćemo verziju knjižnice u unos svojstva (za najnoviju verziju knjižnica pogledajte spremište Maven Central):

 0.9.1 org.nd4j nd4j-native-platforma $ {dl4j.version} org.deeplearning4j deeplearning4j-core $ {dl4j.version} 

Imajte na umu da nd4j-native-platforma ovisnost je jedna od nekoliko dostupnih implementacija.

Oslanja se na matične knjižnice dostupne za mnoge različite platforme (macOS, Windows, Linux, Android itd.). Također bismo mogli prebaciti pozadinu na nd4j-cuda-8.0-platforma, ako smo željeli izvršiti proračune na grafičkoj kartici koja podržava CUDA programski model.

4. Priprema podataka

4.1. Priprema datoteke DataSet

Napisat ćemo “Hello World” strojnog učenja - klasifikacija skupa podataka cvijeta irisa. Ovo je skup podataka prikupljenih iz cvjetova različitih vrsta (Iris setosa, Iris versicolor, i Iris virginica).

Te se vrste razlikuju po duljini i širini latica i čašica. Bilo bi teško napisati precizan algoritam koji klasificira ulaznu stavku podataka (tj. Određuje kojoj vrsti pripada određeni cvijet). Ali dobro obučena neuronska mreža može je klasificirati brzo i s malo pogrešaka.

Upotrijebit ćemo CSV verziju ovih podataka, gdje stupci 0..3 sadrže različite značajke vrste, a stupac 4 sadrži klasu zapisa ili vrstu, kodiranu s vrijednošću 0, 1 ili 2:

5.1,3.5,1.4,0.2,0 4.9,3.0,1.4,0.2,0 4.7,3.2,1.3,0.2,0 … 7.0,3.2,4.7,1.4,1 6.4,3.2,4.5,1.5,1 6.9,3.1,4.9,1.5,1 …

4.2. Vektoriziranje i čitanje podataka

Klasu kodiramo brojem jer neuronske mreže rade s brojevima. Pretvaranje stvarnih podataka u nizove brojeva (vektora) naziva se vektorizacija - deeplearning4j za to koristi knjižnicu podatakavec.

Prvo, upotrijebimo ovu knjižnicu za unos datoteke s vektoriziranim podacima. Prilikom stvaranja CSVRecordReader, možemo odrediti broj redaka koje treba preskočiti (na primjer, ako datoteka ima redak zaglavlja) i simbol razdvajača (u našem slučaju zarez):

probajte (RecordReader recordReader = novi CSVRecordReader (0, ',')) {recordReader.initialize (novi FileSplit (novi ClassPathResource ("iris.txt"). getFile ())); //…}

Da bismo prelistavali zapise, možemo koristiti bilo koju od višestrukih implementacija DataSetIterator sučelje. Skupovi podataka mogu biti prilično masivni, a sposobnost listanja ili predmemoriranja vrijednosti mogla bi vam dobro doći.

Ali naš mali skup podataka sadrži samo 150 zapisa, pa čitajmo sve podatke u memoriju odjednom uz poziv iterator.next ().

Također specificiramo indeks stupca klase što je u našem slučaju isto kao i broj značajki (4) i ukupan broj časova (3).

Također, imajte na umu da moramo promiješati skup podataka da bismo se riješili redoslijeda klasa u izvornoj datoteci.

Navodimo konstantno slučajno sjeme (42) umjesto zadanog System.currentTimeMillis () nazovite kako bi rezultati miješanja bili uvijek isti. To nam omogućuje stabilne rezultate svaki put kad pokrenemo program:

DataSetIterator iterator = novi RecordReaderDataSetIterator (recordReader, 150, FEATURES_COUNT, CLASSES_COUNT); Postavljanje podataka allData = iterator.next (); allData.shuffle (42);

4.3. Normaliziranje i cijepanje

Još jedna stvar koju bismo trebali učiniti s podacima prije treninga je njihova normalizacija. Normalizacija je dvofazni proces:

  • prikupljanje neke statistike o podacima (fit)
  • mijenjajući (transformirajući) podatke na neki način kako bi ih ujednačili

Normalizacija se može razlikovati za različite vrste podataka.

Na primjer, ako želimo obraditi slike različitih veličina, prvo bismo trebali prikupiti statistiku veličine, a zatim ih prilagoditi na jednoličnu veličinu.

Ali za brojeve normalizacija obično znači pretvaranje u takozvanu normalnu raspodjelu. The NormalizerStandardize razred nam može pomoći u tome:

Normalizator podatakaNormalizacija = novi NormalizerStandardize (); normalizer.fit (allData); normalizer.transform (allData);

Sad kad su podaci pripremljeni, skup moramo podijeliti na dva dijela.

Prvi dio koristit će se na treningu. Upotrijebit ćemo drugi dio podataka (koji mreža uopće ne bi vidjela) za testiranje osposobljene mreže.

To bi nam omogućilo da potvrdimo da klasifikacija djeluje ispravno. Za trening ćemo uzeti 65% podataka (0,65), a ostatak 35% za testiranje:

SplitTestAndTrain testAndTrain = allData.splitTestAndTrain (0,65); DataSet trainingData = testAndTrain.getTrain (); Skup podataka testData = testAndTrain.getTest ();

5. Priprema mrežne konfiguracije

5.1. Tečni graditelj konfiguracije

Sada možemo izgraditi konfiguraciju naše mreže s modnim tečnim graditeljem:

Konfiguracija MultiLayerConfiguration = new NeuralNetConfiguration.Builder () .iterations (1000) .activation (Activation.TANH) .weightInit (WeightInit.XAVIER) .learningRate (0.1) .regularization (true) .l2 (0.0001) .list () .layer ( 0, novi DenseLayer.Builder (). NIn (FEATURES_COUNT) .nOut (3) .build ()) .layer (1, novi DenseLayer.Builder (). NIn (3) .nOut (3) .build ()). sloj (2, novi OutputLayer.Builder (LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD) .aktivacija (Aktivacija.SOFTMAX) .nIn (3) .nOut (CLASSES_COUNT) .build ()) .backprop (true) .pretrain (false) .build ( );

Čak i uz ovaj pojednostavljeni tečni način izrade mrežnog modela, puno je toga za probaviti i puno parametara za dotjerivanje. Razbijemo ovaj model.

5.2. Postavljanje mrežnih parametara

The ponavljanja () builder metoda određuje broj optimizacijskih iteracija.

Iterativna optimizacija znači izvođenje više prolaza na treningu sve dok mreža ne konvergira do dobrih rezultata.

Obično, kada treniramo na stvarnim i velikim skupovima podataka, koristimo više epoha (potpuni prolasci podataka kroz mrežu) i jednu iteraciju za svaku epohu. No budući da je naš početni skup podataka minimalan, koristit ćemo jednu epohu i više iteracija.

The aktivacija () je funkcija koja se izvodi unutar čvora da bi odredila njegov izlaz.

Najjednostavnija aktivacijska funkcija bila bi linearna f (x) = x. No, ispada da samo nelinearne funkcije omogućuju mrežama rješavanje složenih zadataka pomoću nekoliko čvorova.

Dostupno je puno različitih funkcija aktivacije koje možemo potražiti u org.nd4j.linalg.activations.Activation nabrajanje. Po potrebi bismo mogli napisati i našu funkciju aktiviranja. Ali koristit ćemo navedenu funkciju hiperboličkog tangenta (tanh).

The weightInit () metoda određuje jedan od mnogih načina postavljanja početnih pondera za mrežu. Ispravne početne težine mogu duboko utjecati na rezultate treninga. Ne ulazeći previše u matematiku, postavimo je na oblik Gaussove raspodjele (WeightInit.XAVIER), jer je ovo obično dobar izbor za početak.

Sve ostale metode inicijalizacije težine mogu se potražiti u org.deeplearning4j.nn.weights.WeightInit nabrajanje.

Stopa učenja je presudni parametar koji duboko utječe na sposobnost mreže za učenje.

Mogli bismo potrošiti puno vremena prilagođavajući ovaj parametar u složenijim slučajevima. Ali za naš jednostavan zadatak upotrijebit ćemo prilično značajnu vrijednost 0,1 i postaviti ga s razina učenja () metoda graditelja.

Jedan od problema s treningom neuronskih mreža je slučaj prekomjerne opreme kada mreža "zapamti" podatke o treningu.

To se događa kada mreža postavlja pretjerano velike težine za podatke treninga i daje loše rezultate na bilo kojim drugim podacima.

Da bismo riješili ovaj problem, postavit ćemo l2 regularizaciju s crtom .regularizacija (točno) .l2 (0,0001). Regularizacija "kažnjava" mrežu za prevelike težine i sprječava prekomjerno opremanje.

5.3. Izgradnja mrežnih slojeva

Dalje, stvaramo mrežu gustih (poznatih i kao potpuno povezanih) slojeva.

Prvi sloj trebao bi sadržavati jednaku količinu čvorova kao i stupci u podacima o treningu (4).

Drugi gusti sloj sadržavat će tri čvora. To je vrijednost koju možemo mijenjati, ali broj izlaza u prethodnom sloju mora biti jednak.

Završni izlazni sloj trebao bi sadržavati broj čvorova koji se podudaraju s brojem klasa (3). Struktura mreže prikazana je na slici:

Nakon uspješnog treninga imat ćemo mrežu koja putem svojih ulaza prima četiri vrijednosti i šalje signal na jedan od svoja tri izlaza. Ovo je jednostavan klasifikator.

Konačno, da bismo dovršili izgradnju mreže, postavljamo povratno razmnožavanje (jednu od najučinkovitijih metoda treninga) i onemogućujemo pred-trening linijom .backprop (true) .pretrain (false).

6. Stvaranje i osposobljavanje mreže

Ajmo sada stvoriti neuronsku mrežu iz konfiguracije, inicijalizirati je i pokrenuti:

MultiLayerNetwork model = novi MultiLayerNetwork (konfiguracija); model.init (); model.fit (trainingData);

Sada možemo isprobati obučeni model korištenjem ostatka skupa podataka i provjeriti rezultate mjernim podacima za tri razreda:

INDArray izlaz = model.output (testData.getFeatureMatrix ()); Procjena eval = nova procjena (3); eval.eval (testData.getLabels (), izlaz);

Ako sada isprintamo eval.stats (), vidjet ćemo da je naša mreža prilično dobra u klasificiranju cvijeća irisa, iako je tri puta pogrešno shvatila razred 1 za razred 2.

Primjeri označeni kao 0 klasificirani po modelu kao 0: 19 puta Primjeri označeni kao 1 klasificirani po modelu kao 1: 16 puta Primjeri označeni kao 1 klasificirani po modelu kao 2: 3 puta Primjeri označeni kao 2 klasificirani po modelu kao 2: 15 puta == ======================== Rezultati =========================== =============== Broj klasa: 3 Točnost: 0,9434 Preciznost: 0,9444 Opoziv: 0,9474 F1 Ocjena: 0,9411 Preciznost, opoziv i F1: prosjek makronaredbe (podjednako ponderirani prosjek 3 razreda ) ====================================================== =======================

Tečni graditelj konfiguracije omogućuje nam brzo dodavanje ili modificiranje slojeva mreže ili podešavanje nekih drugih parametara kako bismo vidjeli može li se naš model poboljšati.

7. Zaključak

U ovom smo članku izgradili jednostavnu, ali moćnu neuronsku mrežu pomoću biblioteke deeplearning4j.

Kao i uvijek, izvorni kôd članka dostupan je na GitHubu.