Einführung in Neuroph

1. Einleitung

Dieser Artikel befasst sich mit Neuroph - einer Open-Source-Bibliothek zum Erstellen neuronaler Netze und zum Einsatz von maschinellem Lernen.

In dem Artikel werfen wir einen Blick auf die Kernkonzepte und einige Beispiele, wie man alles zusammensetzt.

2. Neuroph

Wir können mit Neuroph interagieren, indem wir:

  • ein GUI-basiertes Tool
  • eine Java-Bibliothek

Beide Ansätze beruhen auf einer zugrunde liegenden Klassenhierarchie, die künstliche neuronale Netze aus Schichten von Neuronen aufbaut .

Wir werden uns auf die programmatische Seite konzentrieren, uns aber auf mehrere gemeinsame Klassen aus Neurophs GUI-basiertem Ansatz beziehen, um zu klären, was wir tun.

Weitere Informationen zum GUI-basierten Ansatz finden Sie in der Neuroph-Dokumentation.

2.1. Abhängigkeiten

Um Neuroph verwenden zu können, müssen wir den folgenden Maven-Eintrag hinzufügen:

 org.beykery neuroph 2.92 

Die neueste Version finden Sie auf Maven Central.

3. Schlüsselklassen und Konzepte

Alle verwendeten grundlegenden konzeptionellen Bausteine ​​haben entsprechende Java-Klassen.

Neuronen sind mit Schichten verbunden, die dann in NeuralNetworks gruppiert werden . NeuralNetworks werden anschließend mit LearningRules und DataSets trainiert .

3.1. Neuron

Die Neuron- Klasse hat vier Hauptattribute:

  1. inputConnection: gewichtete Verbindungen zwischen Neuronen
  2. inputFunction: Spezifiziert Gewichte und Summen - Vektor auf eingehende Verbindungsdaten angewendet
  3. transferFunction: Gibt Gewichte und Vektorsummen an, die auf ausgehende Daten angewendet werden

  4. output: Der Ausgabewert, der sich aus der Anwendung von transferFunctions und inputFunctions auf eine inputConnection ergibt

Zusammen bestimmen diese vier Hauptattribute das Verhalten:

output = transferFunction(inputFunction(inputConnections));

3.2. Schicht

Die Schichten sind im wesentlichen Gruppierungen von Neuronen , so dass jedes Neuro n in der Schicht (Regel) nur mit angeschlossenen Neurons in den vorhergehenden und nachfolgenden Schichten .

Schichten leiten daher Informationen zwischen ihnen durch die gewichteten Funktionen, die auf ihren Neuronen existieren .

Neuronen können Schichten hinzugefügt werden:

Layer layer = new Layer(); layer.addNeuron(n);

3.3. Neurales Netzwerk

Das NeuralNetwork der Superklasse der obersten Ebene ist in verschiedene bekannte Arten künstlicher neuronaler Netze unterteilt, darunter Faltungs-Neuronale Netze (Unterklasse ConvolutionalNetwork ), Hopfield-Neuronale Netze (Unterklasse Hopfield ) und Mehrschicht-Perzeptron-Neuronale Netze (Unterklasse MultilayerPerceptron ).

Alle NeuralNetworks bestehen aus Schichten, die normalerweise in einer Trichotomie organisiert sind:

  1. Eingabeebenen
  2. versteckte Schichten
  3. Ausgabeebenen

Wenn wir den Konstruktor einer Unterklasse von verwenden NeuralNetwork (wie Perceptron ), können wir den Pass Layer - s, die Anzahl der Neuron s für jede Schicht und deren Index mit diesem einfachen Verfahren:

NeuralNetwork ann = new Perceptron(2, 4, 1);

Manchmal möchten wir dies manuell tun (und es ist gut zu sehen, was unter der Haube vor sich geht). Die grundlegende Operation zum Hinzufügen einer Ebene zu einem NeuralNetwork wird folgendermaßen ausgeführt:

NeuralNetwork ann = new NeuralNetwork(); Layer layer = new Layer(); ann.addLayer(0, layer); ann.setInputNeurons(layer.getNeurons()); 

Das erste Argument gibt den Index der Ebene im NeuralNetwork an . Das zweite Argument gibt die Ebene selbst an. Manuell hinzugefügte Ebenen sollten mithilfe der ConnectionFactory- Klasse verbunden werden:

ann.addLayer(0, inputLayer); ann.addLayer(1, hiddenLayerOne); ConnectionFactory.fullConnect(ann.getLayerAt(0), ann.getLayerAt(1));

Die erste und letzte Schicht sollten ebenfalls verbunden sein:

ConnectionFactory.fullConnect(ann.getLayerAt(0), ann.getLayerAt(ann.getLayersCount() - 1), false); ann.setOutputNeurons(ann.getLayerAt( ann.getLayersCount() - 1).getNeurons());

Denken Sie daran, dass die Stärke und Leistung eines NeuralNetworks weitgehend von Folgendem abhängt:

  1. die Anzahl der Ebenen im NeuralNetwork
  2. die Anzahl der Neuronen in jeder Schicht (und die gewichteten Funktionen zwischen ihnen) und
  3. die Effektivität der Trainingsalgorithmen / Genauigkeit des DataSet

3.4. Training unseres NeuralNetworks

NeuralNetworks werden mithilfe der Klassen DataSet und LearningRule trainiert .

DataSet wird zur Darstellung und Bereitstellung der Informationen verwendet, die gelernt oder zum Trainieren des NeuralNetwork verwendet werden sollen . DataSets zeichnen sich durch ihre Eingabegröße, Ausgabegröße und Zeilen (DataSetRow) aus.

int inputSize = 2; int outputSize = 1; DataSet ds = new DataSet(inputSize, outputSize); DataSetRow rOne = new DataSetRow(new double[] {0, 0}, new double[] {0}); ds.addRow(rOne); DataSetRow rTwo = new DataSetRow(new double[] {1, 1}, new double[] {0}); ds.addRow(rTwo);

LearningRule gibt an, wie das DataSet vom NeuralNetwork unterrichtet oder trainiert wird . Zu den Unterklassen von LearningRule gehören BackPropagation und SupervisedLearning .

NeuralNetwork ann = new NeuralNetwork(); //... BackPropagation backPropagation = new BackPropagation(); backPropagation.setMaxIterations(1000); ann.learn(ds, backPropagation);

4. Alles zusammenfügen

Now let's put those building blocks together into a real example. We're going to start by combining several layers together into the familiar input layer, hidden layer, and output layer pattern exemplified by most neural network architectures.

4.1. Layers

We'll assemble our NeuralNetwork by combining four layers. Our goal is to build a (2, 4, 4, 1) NeuralNetwork.

Let's first define our input layer:

Layer inputLayer = new Layer(); inputLayer.addNeuron(new Neuron()); inputLayer.addNeuron(new Neuron());

Next, we implement hidden layer one:

Layer hiddenLayerOne = new Layer(); hiddenLayerOne.addNeuron(new Neuron()); hiddenLayerOne.addNeuron(new Neuron()); hiddenLayerOne.addNeuron(new Neuron()); hiddenLayerOne.addNeuron(new Neuron());

And hidden layer two:

Layer hiddenLayerTwo = new Layer(); hiddenLayerTwo.addNeuron(new Neuron()); hiddenLayerTwo.addNeuron(new Neuron()); hiddenLayerTwo.addNeuron(new Neuron()); hiddenLayerTwo.addNeuron(new Neuron());

Finally, we define our output layer:

Layer outputLayer = new Layer(); outputLayer.addNeuron(new Neuron()); 

4.2. NeuralNetwork

Next, we can put them together into a NeuralNetwork:

NeuralNetwork ann = new NeuralNetwork(); ann.addLayer(0, inputLayer); ann.addLayer(1, hiddenLayerOne); ConnectionFactory.fullConnect(ann.getLayerAt(0), ann.getLayerAt(1)); ann.addLayer(2, hiddenLayerTwo); ConnectionFactory.fullConnect(ann.getLayerAt(1), ann.getLayerAt(2)); ann.addLayer(3, outputLayer); ConnectionFactory.fullConnect(ann.getLayerAt(2), ann.getLayerAt(3)); ConnectionFactory.fullConnect(ann.getLayerAt(0), ann.getLayerAt(ann.getLayersCount()-1), false); ann.setInputNeurons(inputLayer.getNeurons()); ann.setOutputNeurons(outputLayer.getNeurons());

4.3. Training

For training purposes, let's put together a DataSet by specifying the size of both the input and resulting output vector:

int inputSize = 2; int outputSize = 1; DataSet ds = new DataSet(inputSize, outputSize);

We add an elementary row to our DataSet adhering to the input and output constraints defined above – our goal in this example is to teach our network to do basic XOR (exclusive or) operations:

DataSetRow rOne = new DataSetRow(new double[] {0, 1}, new double[] {1}); ds.addRow(rOne); DataSetRow rTwo = new DataSetRow(new double[] {1, 1}, new double[] {0}); ds.addRow(rTwo); DataSetRow rThree = new DataSetRow(new double[] {0, 0}, new double[] {0}); ds.addRow(rThree); DataSetRow rFour = new DataSetRow(new double[] {1, 0}, new double[] {1}); ds.addRow(rFour);

Next, let's train our NeuralNetwork with the built in BackPropogation LearningRule:

BackPropagation backPropagation = new BackPropagation(); backPropagation.setMaxIterations(1000); ann.learn(ds, backPropagation); 

4.4. Testing

Now that our NeuralNetwork is trained up let's test it out. For each pair of logical values passed into our DataSet as a DataSetRow, we run the following kind of test:

ann.setInput(0, 1); ann.calculate(); double[] networkOutputOne = ann.getOutput(); 

An important thing to remember is that NeuralNetworks only output a value on the inclusive interval of 0 and 1. To output some other value, we must normalize and denormalize our data.

In this case, for logical operations, 0 and 1 are perfect for the job. The output will be:

Testing: 1, 0 Expected: 1.0 Result: 1.0 Testing: 0, 1 Expected: 1.0 Result: 1.0 Testing: 1, 1 Expected: 0.0 Result: 0.0 Testing: 0, 0 Expected: 0.0 Result: 0.0 

We see that our NeuralNetwork successfully predicts the right answer!

5. Conclusion

We've just reviewed the basic concepts and classes used by Neuroph.

Further information on this library is available here, and the code examples used in this article can be found over on GitHub.