Panduan untuk Deeplearning4j

1. Pengenalan

Dalam artikel ini, kami akan membuat rangkaian saraf sederhana dengan perpustakaan deeplearning4j (dl4j) - alat moden dan berkuasa untuk pembelajaran mesin.

Sebelum kita memulakan, bukan bahawa panduan ini tidak memerlukan pengetahuan mendalam tentang aljabar linear, statistik, teori pembelajaran mesin dan banyak topik lain yang diperlukan untuk jurutera ML yang berpengalaman.

2. Apa itu Pembelajaran Dalam?

Rangkaian saraf adalah model komputasi yang terdiri daripada lapisan nod yang saling berkaitan.

Nod adalah pemproses data angka seperti neuron. Mereka mengambil data dari input mereka, menerapkan beberapa bobot dan fungsi pada data ini dan mengirimkan hasilnya ke output. Rangkaian tersebut dapat dilatih dengan beberapa contoh data sumber.

Latihan pada dasarnya menyimpan beberapa keadaan angka (bobot) di nod yang kemudiannya mempengaruhi pengiraan. Contoh latihan mungkin mengandungi item data dengan ciri dan kelas tertentu yang diketahui dari item ini (misalnya, "set 16 × 16 piksel ini berisi huruf tulisan tangan" a ").

Setelah latihan selesai, rangkaian saraf dapat memperoleh maklumat dari data baru, walaupun sebelum ini belum pernah melihat item data tertentu ini . Rangkaian yang dimodelkan dan dilatih dengan baik dapat mengenali gambar, surat tulisan tangan, ucapan, memproses data statistik untuk menghasilkan hasil untuk kecerdasan perniagaan, dan banyak lagi.

Rangkaian neural mendalam menjadi mungkin dalam beberapa tahun kebelakangan ini, dengan kemajuan pengkomputeran berprestasi tinggi dan selari. Rangkaian sedemikian berbeza dengan rangkaian saraf sederhana kerana ia terdiri daripada beberapa lapisan pertengahan (atau tersembunyi) . Struktur ini membolehkan rangkaian memproses data dengan cara yang jauh lebih rumit (dengan cara rekursif, berulang, konvolusional, dll.), Dan mengekstrak lebih banyak maklumat darinya.

3. Menyiapkan Projek

Untuk menggunakan perpustakaan, kita memerlukan sekurang-kurangnya Java 7. Juga, kerana beberapa komponen asli, ia hanya berfungsi dengan versi JVM 64-bit.

Sebelum memulakan panduan, mari kita periksa sama ada syarat dipenuhi:

$ java -version java version "1.8.0_131" Java(TM) SE Runtime Environment (build 1.8.0_131-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

Pertama, mari tambahkan perpustakaan yang diperlukan ke fail Maven pom.xml kami . Kami akan mengekstrak versi perpustakaan ke entri harta tanah (untuk versi perpustakaan terkini, lihat repositori Maven Central):

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

Perhatikan bahawa kebergantungan nd4j-native-platform adalah salah satu daripada beberapa pelaksanaan yang tersedia.

Ia bergantung pada perpustakaan asli yang tersedia untuk pelbagai platform (macOS, Windows, Linux, Android, dll.). Kami juga dapat menukar backend ke platform nd4j-cuda-8.0 , jika kami ingin menjalankan perhitungan pada kad grafik yang menyokong model pengaturcaraan CUDA.

4. Menyiapkan Data

4.1. Menyiapkan Fail Set Data

Kami akan menulis "Hello World" pembelajaran mesin - klasifikasi set data bunga iris. Ini adalah sekumpulan data yang dikumpulkan dari bunga dari pelbagai spesies ( Iris setosa , Iris versicolor , dan Iris virginica ).

Spesies ini berbeza panjang dan lebar kelopak dan sepal. Sukar untuk menulis algoritma yang tepat yang mengklasifikasikan item data input (iaitu, menentukan spesies mana bunga tertentu). Tetapi rangkaian saraf yang terlatih dapat mengklasifikasikannya dengan cepat dan dengan sedikit kesilapan.

Kami akan menggunakan versi CSV data ini, di mana lajur 0..3 mengandungi ciri-ciri spesies yang berbeza dan lajur 4 mengandungi kelas rekod, atau spesies, yang dikodkan dengan nilai 0, 1 atau 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. Memanfaatkan dan Membaca Data

Kami mengekodkan kelas dengan nombor kerana rangkaian saraf berfungsi dengan nombor. Mengubah item data dunia nyata menjadi siri nombor (vektor) dipanggil vektorisasi - deeplearning4j menggunakan perpustakaan datavec untuk melakukan ini.

Pertama, mari gunakan perpustakaan ini untuk memasukkan fail dengan data vektor. Semasa membuat CSVRecordReader , kita dapat menentukan jumlah baris yang akan dilangkau (misalnya, jika fail tersebut mempunyai baris header) dan simbol pemisah (dalam hal ini koma):

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

Untuk mengulangi catatan, kita dapat menggunakan salah satu dari beberapa implementasi antara muka DataSetIterator . Set data dapat sangat besar, dan kemampuan untuk membuat halaman atau menyimpan nilai-nilai mungkin berguna.

But our small dataset contains only 150 records, so let’s read all the data into memory at once with a call of iterator.next().

We also specify the index of the class column which in our case is the same as feature count (4) and the total number of classes (3).

Also, note that we need to shuffle the dataset to get rid of the class ordering in the original file.

We specify a constant random seed (42) instead of the default System.currentTimeMillis() call so that the results of the shuffling would always be the same. This allows us to get stable results each time we will run the program:

DataSetIterator iterator = new RecordReaderDataSetIterator( recordReader, 150, FEATURES_COUNT, CLASSES_COUNT); DataSet allData = iterator.next(); allData.shuffle(42);

4.3. Normalizing and Splitting

Another thing we should do with the data before training is to normalize it. The normalization is a two-phase process:

  • gathering of some statistics about the data (fit)
  • changing (transform) the data in some way to make it uniform

Normalization may differ for different types of data.

For instance, if we want to process images of various sizes, we should first collect the size statistics and then scale the images to a uniform size.

But for numbers, normalization usually means transforming them into a so-called normal distribution. The NormalizerStandardize class can help us with that:

DataNormalization normalizer = new NormalizerStandardize(); normalizer.fit(allData); normalizer.transform(allData);

Now that the data is prepared, we need to split the set into two parts.

The first part will be used in a training session. We'll use the second part of the data (which the network would not see at all) to test the trained network.

This would allow us to verify that the classification works correctly. We will take 65% of the data (0.65) for the training and leave the rest 35% for the testing:

SplitTestAndTrain testAndTrain = allData.splitTestAndTrain(0.65); DataSet trainingData = testAndTrain.getTrain(); DataSet testData = testAndTrain.getTest();

5. Preparing the Network Configuration

5.1. Fluent Configuration Builder

Now we can build a configuration of our network with a fancy fluent builder:

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

Even with this simplified fluent way of building a network model, there’s a lot to digest and a lot of parameters to tweak. Let’s break this model down.

5.2. Setting Network Parameters

The iterations() builder method specifies the number of optimization iterations.

The iterative optimization means performing multiple passes on the training set until the network converges to a good result.

Usually, when training on real and large datasets, we use multiple epochs (complete passes of data through the network) and one iteration for each epoch. But since our initial dataset is minimal, we'll use one epoch and multiple iterations.

The activation() is a function that runs inside a node to determine its output.

The simplest activation function would be linear f(x) = x. But it turns out that only non-linear functions allow networks to solve complex tasks by using a few nodes.

There are lots of different activation functions available which we can look up in the org.nd4j.linalg.activations.Activation enum. We could also write our activation function if needed. But we'll use the provided hyperbolic tangent (tanh) function.

The weightInit() method specifies one of the many ways to set up the initial weights for the network. Correct initial weights can profoundly affect the results of the training. Without going too much into the math, let’s set it to a form of Gaussian distribution (WeightInit.XAVIER), as this is usually a good choice for a start.

All other weight initialization methods can be looked up in the org.deeplearning4j.nn.weights.WeightInit enum.

Learning rate is a crucial parameter that profoundly affects the ability of the network to learn.

We could spend a lot of time tweaking this parameter in a more complex case. But for our simple task, we'll use a pretty significant value of 0.1 and set it up with the learningRate() builder method.

One of the problems with training neural networks is a case of overfitting when a network “memorizes” the training data.

This happens when the network sets excessively high weights for the training data and produces bad results on any other data.

To solve this issue, we’re going to set up l2 regularization with the line .regularization(true).l2(0.0001). Regularization “penalizes” the network for too large weights and prevents overfitting.

5.3. Building Network Layers

Next, we create a network of dense (also known as fully connect) layers.

The first layer should contain the same amount of nodes as the columns in the training data (4).

The second dense layer will contain three nodes. This is the value we can variate, but the number of outputs in the previous layer has to be the same.

The final output layer should contain the number of nodes matching the number of classes (3). The structure of the network is shown in the picture:

After successful training, we'll have a network that receives four values via its inputs and sends a signal to one of its three outputs. This is a simple classifier.

Finally, to finish building the network, we set up back propagation (one of the most effective training methods) and disable pre-training with the line .backprop(true).pretrain(false).

6. Creating and Training a Network

Sekarang mari kita buat rangkaian saraf dari konfigurasi, mulakan dan jalankan:

MultiLayerNetwork model = new MultiLayerNetwork(configuration); model.init(); model.fit(trainingData);

Sekarang kita dapat menguji model terlatih dengan menggunakan set data yang lain dan mengesahkan hasilnya dengan metrik penilaian untuk tiga kelas:

INDArray output = model.output(testData.getFeatureMatrix()); Evaluation eval = new Evaluation(3); eval.eval(testData.getLabels(), output);

Sekiranya sekarang kita mencetak eval.stats () , kita akan melihat bahawa rangkaian kita cukup bagus untuk mengklasifikasikan bunga iris, walaupun itu kesalahan kelas 1 untuk kelas 2 tiga kali.

Examples labeled as 0 classified by model as 0: 19 times Examples labeled as 1 classified by model as 1: 16 times Examples labeled as 1 classified by model as 2: 3 times Examples labeled as 2 classified by model as 2: 15 times ==========================Scores======================================== # of classes: 3 Accuracy: 0.9434 Precision: 0.9444 Recall: 0.9474 F1 Score: 0.9411 Precision, recall & F1: macro-averaged (equally weighted avg. of 3 classes) ========================================================================

Pembangun konfigurasi yang lancar membolehkan kami menambah atau mengubah lapisan rangkaian dengan cepat, atau mengubah beberapa parameter lain untuk melihat apakah model kami dapat diperbaiki.

7. Kesimpulannya

Dalam artikel ini, kami telah membina rangkaian saraf yang sederhana namun kuat dengan menggunakan perpustakaan deeplearning4j.

Seperti biasa, kod sumber untuk artikel tersebut terdapat di GitHub.