Dieser Artikel wurde mit dem Ziel verfasst, Menschen den Rücken zu drücken, die tiefes Lernen in Java betreiben möchten, aber nicht den ersten Schritt tun können. Sie können die Kraft des tiefen Lernens leicht erfahren, lesen Sie es also bitte.
Wir nehmen eine der folgenden Personen als Leser an.
Wenn Sie diesen Artikel lesen, können Sie mit Deeplearning4j mit IntelliJ eine Deep-Learning-Entwicklungsumgebung erstellen und handschriftliche Zahlen identifizieren. Zusätzlich zur Nummernidentifikation können Sie auch viele Deep-Learning-Beispiele ausführen. Sie können die Theorie des tiefen Lernens jedoch nicht aus diesem Artikel lernen. Um die Theorie des tiefen Lernens zu lernen "[Deep Learning von Grund auf - Die Theorie und Implementierung des mit Python gelernten tiefen Lernens](https://www.amazon.co.jp/%E3%82%BC%E3%83%] AD% E3% 81% 8B% E3% 82% 89% E4% BD% 9C% E3% 82% 8BTiefenlernen-% E2% 80% 95Python% E3% 81% A7% E5% AD% A6% E3% 81 % B6% E3% 83% 87% E3% 82% A3% E3% 83% BC% E3% 83% 97% E3% 83% A9% E3% 83% BC% E3% 83% 8B% E3% 83% B3 % E3% 82% B0% E3% 81% AE% E7% 90% 86% E8% AB% 96% E3% 81% A8% E5% AE% 9F% E8% A3% 85-% E6% 96% 8E% Wir empfehlen, dass Sie E8% 97% A4-% E5% BA% B7% E6% AF% 85 / dp / 4873117585 lesen.
Ich denke, dass der erste Schritt, um mit dem Lernen von Deep Learning zu beginnen, darin besteht, das Programm tatsächlich auszuführen und es zu "erleben", um Sie zum Lernen zu motivieren. Siehe unten.
Wenn Sie eine handschriftliche Nummer eingeben, zeigt dieses Programm die identifizierte (vorhergesagte) Nummer unter "Vorhersage:" am unteren Bildschirmrand an.
Wenn Sie ein Programm schreiben möchten, das das Bild der handschriftlichen Nummer "7" ohne Verwendung einer speziellen Bibliothek identifiziert, welchen Algorithmus würden Sie verwenden? Ist es in Ordnung, wenn der Algorithmus "7" unterscheidet, wenn sich oben im Bild eine horizontale Linie und vom Endpunkt eine nach unten gerichtete Linie befindet? Kann der Algorithmus eine der folgenden Angaben korrekt als "7" identifizieren? Und wie setzen Sie es in Ihr Programm ein?
Das Identifizieren von Zahlen, die für Menschen einfach sind, ist für Computer nicht so einfach (wenn versucht wird, sie mit Algorithmen zu erreichen). Aber tiefes Lernen kann dies tun. Und in diesem Artikel werden wir das obige Programm tatsächlich ausführen.
Die Systemanforderungen für Deeplearning4j lauten wie folgt:
--Java 1.7 oder höher 64-Bit-Version (auch JAVA_HOME setzen)
Die Umgebung, in der dieser Artikel geschrieben wurde, ist wie folgt.
$ mvn -version
Apache Maven 3.5.0
Maven home: /usr/share/maven
Java version: 1.8.0_171, vendor: Oracle Corporation
Java home: /usr/lib/jvm/java-8-openjdk-amd64/jre
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "4.13.0-21-generic", arch: "amd64", family: "unix"
$ git --version
git version 2.14.1
Es nimmt viel Speicherplatz in Anspruch, daher möchten Sie möglicherweise nur das Teilprojekt "dl4j-examples" der "dl4j-examples" erstellen. Wenn Sie das gesamte Projekt erstellen möchten, benötigen Sie mindestens 15 GB freien Speicherplatz.
: warning: Viele Jars werden in die folgenden Verzeichnisse heruntergeladen. Wenn Sie also das Verzeichnis von Deeplearning4j löschen, das "git clone" war, löschen Sie auch dieses Verzeichnis.
.m2/repository/org/deeplearning4j/
Gehen Sie wie folgt vor, um die Entwicklungsumgebung zu erstellen:
$ git clone https://github.com/deeplearning4j/dl4j-examples.git
$ cd dl4j-examples/dl4j-examples
$ mvn clean install
Da es jedoch zum Zeichnen des Bildschirms verwendet wird, installieren Sie bei Bedarf auch OpenJFX (Java FX). Ohne Java FX wird beim Erstellen der folgende Fehlermeldung angezeigt:
[ERROR] /home/tamura/git/dl4j-examples/dl4j-examples/src/main/java/org/deeplearning4j/examples/recurrent/character/harmonies/Piano.java:[4,24]Paket javafx.Animation existiert nicht
Wenn Sie Ubuntu 17.10 haben, können Sie es installieren mit:
$ sudo apt-get install openjfx
Lassen Sie uns nach dem Erstellen der Entwicklungsumgebung versuchen, handschriftliche Zahlen (das Beispiel, das wir zuvor gesehen haben) zu identifizieren, die beim tiefen Lernen wie "Hallo Welt!" Positioniert sind. Beim Deep Learning wird zunächst eine große Datenmenge "gelernt", um die optimalen Parameter abzuleiten. Darauf aufbauend machen wir dann eine "Vorhersage". Das Verfahren ist wie folgt.
Wenn der Build abgeschlossen ist, öffnen Sie das Projekt in IntelliJ.
Öffnen Sie den Quellcode von org.deeplearning4j.examples.convolution.mnist.MnistClassifier
und führen Sie ihn aus (klicken Sie auf die Schaltfläche Ausführen des grünen Dreiecks auf der linken Seite des Editors) (dieser Schritt führt" Lernen "aus). ..
以下のようなメッセージが出力されます。
/usr/lib/jvm/java-8-openjdk-amd64/bin/java -javaagent:/home/tamura/idea-IC-181.5087.20 ... (weggelassen) ... org.deeplearning4j.examples.convolution.mnist.MnistClassifier
o.d.e.c.m.MnistClassifier - Data load and vectorization...
o.d.i.r.BaseImageRecordReader - ImageRecordReader: 10 label classes inferred using label generator ParentPathLabelGenerator
o.d.i.r.BaseImageRecordReader - ImageRecordReader: 10 label classes inferred using label generator ParentPathLabelGenerator
o.d.e.c.m.MnistClassifier - Network configuration and training...
o.n.l.f.Nd4jBackend - Loaded [CpuBackend] backend
o.n.n.NativeOpsHolder - Number of threads used for NativeOps: 1
o.n.n.Nd4jBlas - Number of threads used for BLAS: 1
o.n.l.a.o.e.DefaultOpExecutioner - Backend used: [CPU]; OS: [Linux]
o.n.l.a.o.e.DefaultOpExecutioner - Cores: [4]; Memory: [0.9GB];
o.n.l.a.o.e.DefaultOpExecutioner - Blas vendor: [MKL]
o.d.n.m.MultiLayerNetwork - Starting MultiLayerNetwork with WorkspaceModes set to [training: ENABLED; inference: ENABLED], cacheMode set to [NONE]
o.d.o.l.ScoreIterationListener - Score at iteration 0 is 2.4694731759178388
o.d.o.l.ScoreIterationListener - Score at iteration 10 is 1.078069156582683
o.d.o.l.ScoreIterationListener - Score at iteration 20 is 0.7327581484283221
... (weggelassen) ... o.d.o.l.ScoreIterationListener - Score at iteration 1100 is 0.20279510458591593 o.d.o.l.ScoreIterationListener - Score at iteration 1110 is 0.10997898485405874 o.d.e.c.m.MnistClassifier - Completed epoch 0 o.d.e.c.m.MnistClassifier -
========================Evaluation Metrics========================
# of classes: 10
Accuracy: 0.9891
Precision: 0.9891
Recall: 0.9890
F1 Score: 0.9891
Precision, recall & F1: macro-averaged (equally weighted avg. of 10 classes)
=========================Confusion Matrix=========================
0 1 2 3 4 5 6 7 8 9
---------------------------------------------------
973 0 0 0 0 0 2 2 3 0 | 0 = 0
0 1132 0 1 0 1 1 0 0 0 | 1 = 1
2 3 1018 1 0 0 1 6 1 0 | 2 = 2
0 0 1 1000 0 3 0 4 1 1 | 3 = 3
0 0 1 0 973 0 3 0 0 5 | 4 = 4
1 0 0 5 0 882 2 1 1 0 | 5 = 5
5 2 0 0 2 3 944 0 2 0 | 6 = 6
0 2 4 0 0 0 0 1017 2 3 | 7 = 7
3 0 2 1 0 0 1 2 961 4 | 8 = 8
4 2 1 1 3 0 0 6 1 991 | 9 = 9
Confusion matrix format: Actual (rowClass) predicted as (columnClass) N times
==================================================================
Process finished with exit code 0
```
Was ist der Mechanismus, um dies zu erreichen? Handgeschriebene numerische Bilder "lernen" [Mnist Classifier-Quellcode](https://github.com/deeplearning4j/dl4j-examples/blob/master/dl4j-examples/src/main/java/org/deeplearning4j/examples/ Schauen wir uns Convolution (mnist / MnistClassifier.java) von oben an.
: information_source: Zum Verständnis der folgenden Abschnitte sind Grundkenntnisse in Deep Learning erforderlich.
Das erste ist das Download-Ziel des handgeschriebenen numerischen Bildes, die Konstanten des temporären Verzeichnisses zum Dekomprimieren und die Feldvariablen des Loggers.
MnistClassifier
public class MnistClassifier {
private static final Logger log = LoggerFactory.getLogger(MnistClassifier.class);
private static final String basePath = System.getProperty("java.io.tmpdir") + "/mnist";
private static final String dataUrl = "http://github.com/myleott/mnist_png/raw/master/mnist_png.tar.gz";
Und es wird die main () -Methode dieser Klasse. Wenn Sie diese Methode aufrufen, beginnt das Lernen. Das Eingabebild wird als 3D-Daten mit jeweils 1 Kanal und 28 Pixeln in vertikaler und horizontaler Richtung an die Eingabeebene übergeben. Da es Zahlen von 1 bis 10 identifiziert, verfügt es über 10 Ausgabeebenen, 54 Stapelgrößen und 1 Epoche.
public static void main(String[] args) throws Exception {
int height = 28;
int width = 28;
int channels = 1; // single channel for grayscale images
int outputNum = 10; // 10 digits classification
int batchSize = 54;
int nEpochs = 1;
int iterations = 1;
int seed = 1234;
Random randNumGen = new Random(seed);
Laden Sie als Nächstes das komprimierte mnist_png.tar.gz
von 70.000 handgeschriebenen Zahlenbildern von [GitHub] herunter (http://github.com/myleott/mnist_png/raw/master/mnist_png.tar.gz). Und entpacke es.
log.info("Data load and vectorization...");
String localFilePath = basePath + "/mnist_png.tar.gz";
if (DataUtilities.downloadFile(dataUrl, localFilePath))
log.debug("Data downloaded from {}", dataUrl);
if (!new File(basePath + "/mnist_png").exists())
DataUtilities.extractTarGz(localFilePath, basePath);
Es ist in Lern- (Trainings-) Daten (60.000 Elemente) und Testdaten (10.000 Elemente) unterteilt und in den Iteratorvariablen von "trainIter" bzw. "testIter" gespeichert.
// vectorization of train data
File trainData = new File(basePath + "/mnist_png/training");
FileSplit trainSplit = new FileSplit(trainData, NativeImageLoader.ALLOWED_FORMATS, randNumGen);
ParentPathLabelGenerator labelMaker = new ParentPathLabelGenerator(); // parent path as the image label
ImageRecordReader trainRR = new ImageRecordReader(height, width, channels, labelMaker);
trainRR.initialize(trainSplit);
DataSetIterator trainIter = new RecordReaderDataSetIterator(trainRR, batchSize, 1, outputNum);
// pixel values from 0-255 to 0-1 (min-max scaling)
DataNormalization scaler = new ImagePreProcessingScaler(0, 1);
scaler.fit(trainIter);
trainIter.setPreProcessor(scaler);
// vectorization of test data
File testData = new File(basePath + "/mnist_png/testing");
FileSplit testSplit = new FileSplit(testData, NativeImageLoader.ALLOWED_FORMATS, randNumGen);
ImageRecordReader testRR = new ImageRecordReader(height, width, channels, labelMaker);
testRR.initialize(testSplit);
DataSetIterator testIter = new RecordReaderDataSetIterator(testRR, batchSize, 1, outputNum);
testIter.setPreProcessor(scaler); // same normalization for better results
Fügen Sie als Nächstes die Lernrateneinstellung zur HashMap
mit dem Variablennamen lrSchedule
hinzu. Wenn die Lernrate hoch ist, wird das Lernen in der ersten Hälfte schnell fortgesetzt, in der zweiten Hälfte jedoch nicht leicht konvergieren, sodass die Lernrate entsprechend der Anzahl der verarbeiteten Fälle gesenkt wird. In diesem Programm wird das Training 1.111 Mal wiederholt (= Trainingsdaten: 60.000 / Chargengröße: 54). Die Lernrate wird entsprechend der Anzahl der Wiederholungen schrittweise gesenkt.
log.info("Network configuration and training...");
Map<Integer, Double> lrSchedule = new HashMap<>();
lrSchedule.put(0, 0.06); // iteration #, learning rate
lrSchedule.put(200, 0.05);
lrSchedule.put(600, 0.028);
lrSchedule.put(800, 0.0060);
lrSchedule.put(1000, 0.001);
Von hier aus wird die Hauptverarbeitung des Aufbaus eines neuronalen Netzwerks durchgeführt. Fügen Sie dem neuronalen Netzwerk eine Ebene hinzu, indem Sie sie mit der Methode "layer ()" von "NeuralNetConfiguration.Builder ()" aufrufen. Es ist keine zusätzliche Eingabeebene erforderlich, daher ist die erste hinzuzufügende Ebene die "Faltungsschicht". Als nächstes fügen wir eine "Unterabtastungsschicht" hinzu. Es wiederholt dies, gefolgt von "DenseLayer" (vollständig verbundene Ebene) und schließlich "OutputLayer" (Ausgabeebene). Dies ist eine CNN-Konfiguration (Convolutional Neural Network), die häufig bei der Bilderkennung verwendet wird.
MultiLayerConfiguration conf = new NeuralNetConfiguration.Builder()
.seed(seed)
.l2(0.0005)
.updater(new Nesterovs(new MapSchedule(ScheduleType.ITERATION, lrSchedule)))
.weightInit(WeightInit.XAVIER)
.list()
.layer(0, new ConvolutionLayer.Builder(5, 5)
.nIn(channels)
.stride(1, 1)
.nOut(20)
.activation(Activation.IDENTITY)
.build())
.layer(1, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
.kernelSize(2, 2)
.stride(2, 2)
.build())
.layer(2, new ConvolutionLayer.Builder(5, 5)
.stride(1, 1) // nIn need not specified in later layers
.nOut(50)
.activation(Activation.IDENTITY)
.build())
.layer(3, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
.kernelSize(2, 2)
.stride(2, 2)
.build())
.layer(4, new DenseLayer.Builder().activation(Activation.RELU)
.nOut(500).build())
.layer(5, new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
.nOut(outputNum)
.activation(Activation.SOFTMAX)
.build())
.setInputType(InputType.convolutionalFlat(28, 28, 1)) // InputType.convolutional for normal image
.backprop(true).pretrain(false).build();
Activation.IDENTITY
ist eine gleiche Funktion ($ \ scriptsize {f (x) = x} $, dh nichts tun) für die Aktivierungsfunktion, Activation.RELU
ist die ReLU-Funktion und Activation.SOFTMAX
ist soft. Bedeutet, die Max-Funktion zu verwenden.
Es kann schwierig sein, nur mit Worten zu verstehen, deshalb habe ich versucht, die Konfiguration des neuronalen Netzwerks zu veranschaulichen. Wenn Sie diese Zahl mit dem Quellcode vergleichen, überprüfen Sie bitte Deeplearning4j Cheat Sheet usw. Wenn Sie dies nicht verstehen. Wird nicht erklären).
Lass uns weitermachen. Wenn Sie es mit der Methode "setListeners ()" von "MultiLayerNetwork" aufrufen, wird der Lernstatus regelmäßig ausgegeben.
MultiLayerNetwork net = new MultiLayerNetwork(conf);
net.init();
net.setListeners(new ScoreIterationListener(10));
log.debug("Total num of params: {}", net.numParams());
Rufen Sie abschließend die Methode fit ()
auf, um das Training mit den Trainingsdaten zu starten. Wenn das Training abgeschlossen ist, geben Sie die Testdaten an "MultiLayerNetwork.evaluate ()" und werten Sie sie aus. Speichern Sie abschließend die abgeleiteten Parameter zusammen in "minist-model.zip".
// evaluation while training (the score should go down)
for (int i = 0; i < nEpochs; i++) {
net.fit(trainIter);
log.info("Completed epoch {}", i);
Evaluation eval = net.evaluate(testIter);
log.info(eval.stats());
trainIter.reset();
testIter.reset();
}
ModelSerializer.writeModel(net, new File(basePath + "/minist-model.zip"), true);
}
}
Eine andere Klasse, "MnistClassifierUI", liest dieses "minist-model.zip", um ein neuronales Netzwerk aufzubauen und handgeschriebene numerische Bilder "vorherzusagen". Eine ausführliche Erläuterung von MnistClassifierUI
wird weggelassen.
Lassen Sie uns den Quellcode von MnistClassifier
ein wenig ändern und verschiedene Experimente durchführen.
Lassen Sie uns die Listener-Klasse, die der Methode "setListeners ()" von "MultiLayerNetwork" zugewiesen wurde, in etwas anderes ändern. Legen Sie die in [dieser Seite] eingeführte Listener-Klasse fest (https://qiita.com/wmeddie/items/8f036e3eadfa3e012eed).
// net.setListeners(new ScoreIterationListener(10));
//Kommentieren Sie die obere Zeile aus und fügen Sie die unteren 4 Zeilen hinzu
UIServer uiServer = UIServer.getInstance();
StatsStorage statsStorage = new InMemoryStatsStorage();
uiServer.attach(statsStorage);
net.setListeners(Arrays.asList(new ScoreIterationListener(1), new StatsListener(statsStorage)));
Führen Sie das Programm nach dem Ändern des Quellcodes erneut aus. Das Folgende wird an die Standardausgabe ausgegeben:
o.d.u.p.PlayUIServer - DL4J UI Server started at http://localhost:9000
Wenn Sie auf http: // localhost: 9000 zugreifen, wird ein Diagramm angezeigt, das die aktuelle Lernsituation auf leicht verständliche Weise darstellt (siehe Abbildung unten).
: information_source: Klicken Sie auf die Registerkarte "Sprache" auf der rechten Seite des Bildschirms und wählen Sie Japanisch aus.
Sie können die Konfiguration dieses neuronalen Netzwerks in einem einfachen Diagramm sehen, indem Sie auf die Registerkarte "System" klicken.
Als nächstes ändern wir den Optimierungsalgorithmus in die SGD-Methode (Stocastic Gradient Descent). Ändern Sie die Nesterovs des Methodenarguments "updater ()" von "NeuralNetConfiguration.Builder ()" in "Sgd".
Und als ich das Programm ausführte, erhielt ich das folgende Ergebnis.
========================Evaluation Metrics========================
# of classes: 10
Accuracy: 0.9698
Precision: 0.9696
Recall: 0.9697
F1 Score: 0.9697
Precision, recall & F1: macro-averaged (equally weighted avg. of 10 classes)
=========================Confusion Matrix=========================
0 1 2 3 4 5 6 7 8 9
---------------------------------------------------
969 0 1 0 0 2 3 1 4 0 | 0 = 0
0 1120 3 2 0 1 3 0 6 0 | 1 = 1
6 2 993 4 6 3 3 9 6 0 | 2 = 2
1 0 7 976 0 7 0 9 7 3 | 3 = 3
1 1 2 0 955 0 5 2 2 14 | 4 = 4
2 1 0 11 1 866 5 1 3 2 | 5 = 5
10 3 1 0 6 3 933 0 2 0 | 6 = 6
2 8 16 2 1 0 0 982 3 14 | 7 = 7
6 0 1 4 4 5 4 6 941 3 | 8 = 8
5 7 0 9 11 7 1 5 1 963 | 9 = 9
Confusion matrix format: Actual (rowClass) predicted as (columnClass) N times
==================================================================
Die Genauigkeit ist etwas gesunken. Ich habe einige ausprobiert, aber in diesem Fall scheint "Nesterovs" (Nesterovs Methode des beschleunigten Gradientenabstiegs) eine gute Wahl zu sein.
Wagen wir es, es mit falschen Einstellungen zu verschieben. Geben Sie "WeightInit.ZERO" für die "weightInit ()" -Methode von "NeuralNetConfiguration.Builder ()", um das Anfangsgewicht auf Null zu setzen.
Auf diese Weise endet die Punktzahl fast unverändert bei 2,3. Und schließlich wird vorausgesagt, dass alle Bilder "1" sind.
=========================Confusion Matrix=========================
0 1 2 3 4 5 6 7 8 9
---------------------------------------------------
0 980 0 0 0 0 0 0 0 0 | 0 = 0
0 1135 0 0 0 0 0 0 0 0 | 1 = 1
0 1032 0 0 0 0 0 0 0 0 | 2 = 2
0 1010 0 0 0 0 0 0 0 0 | 3 = 3
0 982 0 0 0 0 0 0 0 0 | 4 = 4
0 892 0 0 0 0 0 0 0 0 | 5 = 5
0 958 0 0 0 0 0 0 0 0 | 6 = 6
0 1028 0 0 0 0 0 0 0 0 | 7 = 7
0 974 0 0 0 0 0 0 0 0 | 8 = 8
0 1009 0 0 0 0 0 0 0 0 | 9 = 9
Confusion matrix format: Actual (rowClass) predicted as (columnClass) N times
==================================================================
Dies liegt daran, dass alle Gewichtswerte einheitlich aktualisiert werden.
Also habe ich versucht, handschriftliche Zahlen mit Deeplearning4j leicht zu identifizieren. Ich denke, wir haben damit den ersten Schritt in Richtung Deep Learning in Java gemacht. Der Quellcode "Git Clone" enthält viele andere Beispiele. Als nächsten Schritt möchten Sie möglicherweise versuchen, ein anderes Programm auszuführen. Denjenigen, die die Theorie nicht verstehen, wird empfohlen, die oben genannten Bücher zu lesen.
Recommended Posts