SNIPE - Scalable and Generalized Neural Information Processing Engine

Download

Folgende Dateien stehen zur Auswahl:

Bei manchen Browsern kann es passieren, dass Downloads nicht geladen werden. In diesem Fall auf den Link rechtsklicken und „speichern unter“ auswählen!

Was ist SNIPE?

SNIPE ist eine ausführlich dokumentierte JAVA-Bibliothek, welche ein schnelles, feature-reiches und einfach benutzbares Framework für Neuronale Netze implementiert. Für nichtkommerzielle Einsatzgebiete ist es kostenlos verfügbar. Wer plant, es kommerziell einzusetzen, möge bitte mit mir in Kontakt treten.

SNIPE ist ursprünglich für den Einsatz in Hochleistungssimulationen konzipiert, in denen sehr viele, auch große Netze gleichzeitig trainiert und ausgeführt werden. Vor kurzem habe ich mich nun entschieden, SNIPE als professionelle Referenzimplementierung zu meinem Manuskript "Ein kleiner Überblick über Neuronale Netze" online zu stellen, die sehr viele der dort behandelten Aspekte abdeckt, aber angesichts des ursprünglichen Design-Ziels effizienter arbeitet als die meisten anderen Implementierungen.

  1. Generalisierte, dynamische Datenstruktur für beliebige Netzwerktopologien, so dass praktisch alle Netzwerktopologien realisiert oder auch auf einfache Weise manuell modelliert werden können. Topologieveränderungen zur Laufzeit sind ebenfalls problemlos möglich. Im groben verwende ich eine speziell auf strukturvariable Neuronale Netze optimierte Adjazenzliste, um bei beliebigen Topologien stets folgende Features zu erfüllen:
    1. In-Situ-Datenverarbeitung: Editieren und benutzen des Netzes auf derselben Datenstruktur, also keine Vorverarbeitungen notwendig
    2. Speicherverbrauch in O(Synapsenanzahl)
    3. Batch-Lesen und Schreiben aller synaptischer Gewichte eines Neurons in O(SynapsenDesNeurons), damit komplette Vorwärts- / Rückwärtspropagierung in O(Synapsenanzahl)
    4. Lesen/Schreiben einzelner Gewichte in O(log(Neuronenanzahl)).
    5. Synapse zufügen/entfernen: O(Neuronenzahl*log(Neuronenzahl)).
    6. Neuron zufügen/entfernen: O(Neurons+Synapses) worst case.
  2. Direkt eingebaute, schnell und einfach zu verwendende Lernverfahren sowohl für gradientenbasiertes Lernen als auch für Evolutionäre Algorithmen.
  3. Mechanismen für Design und Kontrolle von großen Mengen von Netzen
  4. Gebrauch von Lowlevel-Datenstrukturen (arrays) für einfache Portabilität. Es ist nicht das Ziel, das letzte bisschen asymptotischer Komplexität aus dem Framework herauszuquetschen, sondern es in der Praxis schlank, benutzbar und schnell zu halten.
  5. Kein objektorientierter Overload. Ich habe schon Implementierungen gesehen, die eigene Objekte für Synapsen und Neurone vorsehen.

Der Lesbarkeit zuliebe sind ein paar der oben beschriebenen Laufzeiten leicht zu hoch angesetzt – wer möchte, kann sich im JavaDoc von core.NeuralNetwork einen genaueren Überblick verschaffen.

Was ist SNIPE nicht?

SNIPE ist kein Klicki-Bunti-Werkzeug mit schöner graphischer Oberfläche, um sich Netzwerke zusammenzuklicken – davon gibt es ja auch schon genug. Es ist ein JAVA-Framework, das einen Entwickler oder Studenten Neuronale Netze auf einfache, aber professionelle Weise einsetzen lässt. Nicht mehr, und nicht weniger.

Gebt Feedback!

Wenn ihr mir Feedback zu SNIPE gebt, seid sicher, dass ich mich freue, und es auf die eine oder andere Weise in die jeweils nächste Edition mit einfließt. Also: Wenn ihr irgendwelche Beschwerden, Fehlerberichtigungen, Vorschläge oder einfach Lob ;-) habt, her damit – entweder per Mail an mich, oder in den Diskussionsteil am Fuß dieser Seite.

Neuigkeiten

Klicken Sie auf einen Nachrichtentitel , um mehr zu erfahren.

2011-10-16: Snipe-Version 0.9 erschienen

2010-11-14: Snipe-Version 0.82

2010-05-11: SNIPE-Version 0.81

2010-03-28: SNIPE - Scalable and Generalized Neural Information Processing Engine

Loslegen mit SNIPE - eine kleine TODO-Liste

  1. JAVA lernen :-)
  2. Diese Seite komplett lesen, um eine kleine Einführung zu erhalten
  3. JAR herunterladen und in die JAVA-Entwicklungsumgebung einbinden
  4. Das JavaDoc herunterladen, unzippen und im Browser öffnen
  5. In die Dokumentation der Klasse com.dkriesel.snipe.core.NeuralNetworkDescriptor schauen, um die absoluten Basics zu lernen
  6. Soviel wie gewünscht der Klassendokumentation von com.dkriesel.snipe.core.NeuralNetwork lesen, um mehr Details, Eindrücke der Features von Snipe und deren Laufzeiten zu erhalten
  7. Die Code-Beispiele auf dieser Seite durchgehen
  8. Selbst ausprobieren. SNIPE wirft Exceptions bei vielen Fehlern, die man so machen kann, insbesondere falschen Argumenten, die in seine Methoden eingegeben werden. Also: Learning by doing!

Kurzer Überblick über die Pakete und Klassen

SNIPE besteht aus vier Hauptpaketen, welche jeweils mehrere Klassen enthalten. Alle Paketnamen beginnen mit com.dkriesel.snipe., wobei alle qualifizierten Klassennamen den Paketnamen als Präfix innehaben. Pakete und Klassen, die hier vorgestellt werden, sind grob nach Wichtigkeit geordnet: Wir fangen mit den grundlegendsten Klassen und Paketen an und arbeiten uns weiter in die Tiefen vor.

Das core-Paket (das wichtigste)

Dieses Paket enthält die beiden Kernklassen von SNIPE: NeuralNetworkDescriptor (wird benutzt um grobe Netzeigenschaften vorzugeben) und NeuralNetwork (das eigentliche Neuronale Netz, in dem alle Feinheiten definiert werden können, und was mit Hilfe von NeuralNetworkDescriptor-Instanzen erzeugt wird). Die Dokumentation beider Klassen enthält viel grundlegende Information über den Umgang mit SNIPE.

  • NeuralNetworkDescriptor: Diese Klasse als erstes instantiieren! Ein NeuralNetworkDescriptor-Objekt definiert eine Menge von sehr grundlegenden Netzeigenschaften, die dann auf einzelne Netze, oder aber auch riesige Netzpopulationen angewandt werden können. Um eine NeuralNetwork-Instanz zu erhalten, muss man zuerst eine NeuralNetworkDescriptor-Instanz definieren. Dieses Layout ist sehr sinnvoll, wenn man mit großen Populationen von Netzen umgehen muss, wie z.B. bei evolutionärer Optimierung oder ähnlichem. Überdies steht diverse grundlegende Information in der Dokumentation dieser Klasse.
  • NeuralNetwork: Diese Klasse wird als zweites mittels einer NeuralNetworkDescriptor-Instanz instantiiert. Sie repräsentiert die Kernfunktionalität von SNIPE: Ein Neuronales Netz beliebiger Topologie mit einer schlanken und Rechenzeit-Effizienten Datenstruktur und der Möglichkeit, nahezu beliebig detailliert verändert zu werden. Zusätzlich beinhaltet die zugehörige Klassendokumentation Details zur Datenstruktur, sowie eine reichhaltige Beschreibung der Features des Neuronalen Netzes und deren Rechenaufwand.

Das training-Paket

Enthält Klassen, die Trainingsdaten für Neuronale Netze speichern, sowie verschiedene Methoden der Trainingsfehlermessung.

  • ErrorMeasurement: Verschiedene, statische Fehlermessmethoden, wie RootMeanSquare, Euklidischer Fehler, und andere.
  • TrainingSampleLesson: Instanzen dieser Klasse speichern und optimieren Trainingsdaten.

Das neuronbehavior-Paket

Dieses Paket enthält verschiedene Neuronenverhalten (das sind verallgemeinerte Aktivierungsfunktionen), sowie ein Interface, um eigene zu implementieren. Ich stelle hier nur die wichtigsten Klassen vor.

  • NeuronBehavior: Dieses Interface kann für das Erzeugen eigener Verhaltensweisen implementiert werden.
  • TangensHyperbolicus und Fermi: Diese Klassen repräsentieren die in der Literatur oft verwendeten Aktivierungsfunktionen Tangens Hyperbolicus und Fermi-Funktion.
  • TangensHyperbolicusAnguita implementiert eine auf Geschwindigkeit getrimmte Approximation des Tangens Hyperbolicus, die ca. 200x schneller berechnet werden kann als das Original und auch noch andere Vorteile bietet. Es gibt auch noch weitere, abgewandelte Versionen des Tangens Hyperbolicus.
  • Verschiedene leaky integrators erlauben Neuronen-Individuelle Dynamik.

Das util-Paket

Enthält ein paar kleine Zusatzwerkzeuge für SNIPE.

  • GraphVizEncoder ist eine Klasse, die designten Code für die GraphViz DOT Engine ausgibt, so dass man Neuronale Netze einfach visualisieren kann. Vorsicht hiermit – dieses Werkzeug kann in wenigen Sekunden mehr Code für riesige Netze produzieren, als GraphViz noch verwalten kann :-|
  • MersenneTwisterFast ist ein schneller Pseudozufallszahlengenerator, der an vielen Stellen in SNIPE genutzt wird. Er ist nicht von mir – schaut in seine Dokumentation für Copyrightinformationen.

Beispielhafte Code Snippets

Hier ist etwas reich kommentierter Beispielcode, viel Spaß damit! Wenn man ihn in Dateien steckt, deren Namen zum jeweiligen Code-Titel korrespondiert, sind die Beispiele zum JavaDoc konsistent!

Mit Backprop einem Multilayer-Perceptron das 8-3-8-Problem trainieren

Dieses Snippet bietet eine Einführung in die vier am häufigsten benutzten Klassen in SNIPE: NeuralNetworkDescriptor, NeuralNetwork, TrainingSampleLesson und ErrorMeasurement. Es zeigt, wie man NeuralNetwork-Instanzen mittels NeuralNetworkDescriptor-Instanzen erzeugt, wie man eine vorgefertigte TrainingSampleLesson erzeugt und verwendet, und wie man Backpropagation mit verschiedenen Lernraten benutzt. Weiterhin wird gezeigt, wie man Werte durch ein Neuronales Netz propagiert und Fehler misst.

com/dkriesel/snipe/examples/MultilayerPerceptron838ProblemBackprop.java

package com.dkriesel.snipe.examples;
 
import java.text.DecimalFormat;
 
import com.dkriesel.snipe.core.NeuralNetwork;
import com.dkriesel.snipe.core.NeuralNetworkDescriptor;
import com.dkriesel.snipe.neuronbehavior.TangensHyperbolicusAnguita;
import com.dkriesel.snipe.training.ErrorMeasurement;
import com.dkriesel.snipe.training.TrainingSampleLesson;
 
/**
 * Very simple example program that trains an 8-3-8 multilayer perceptron
 * encoder problem with backpropagation of error.
 * 
 * @author David Kriesel / dkriesel.com
 * 
 */
public class MultilayerPerceptron838ProblemBackprop {
 
	/**
	 * Executes the example.
	 * 
	 * @param args
	 *            no args are parsed.
	 */
	public static void main(String[] args) {
 
		/*
		 * Create and configure a descriptor for feed forward networks without
		 * shortcut connections and with fastprop, an identity activity
		 * functions in the input layer and tangens hyperbolicus functions in
		 * hidden and output layers. To learn about fastprop, have a look into
		 * the NeuralNetworkDescriptor documentation.
		 */
		NeuralNetworkDescriptor desc = new NeuralNetworkDescriptor(8, 3, 8);
		desc.setSettingsTopologyFeedForward();
 
		/*
		 * If you want, remove the comment slashes from the following two lines
		 * to use a tuned tangens hyperbolicus approximation that is computed
		 * faster and provides better learning sometimes.
		 */
		// desc.setNeuronBehaviorHiddenNeurons(new TangensHyperbolicusAnguita());
		// desc.setNeuronBehaviorOutputNeurons(new TangensHyperbolicusAnguita());
 
		/*
		 * Create neural network using the descriptor (we could as well generate
		 * thousands of similar networks at this point of time). The network
		 * will be automatically added all allowed synapses according to the
		 * default settings in the descriptor.
		 */
		NeuralNetwork net = new NeuralNetwork(desc);
 
		/*
		 * Prepare Training Data: 8-Dimensional encoder problem with 1 as
		 * positive and -1 as negative value
		 */
		TrainingSampleLesson lesson = TrainingSampleLesson
				.getEncoderSampleLesson(8, 1, -1);
 
		/*
		 * Train that sucker with backprop in three phases with different
		 * learning rates. In between, display progress, and measure overall
		 * time.
		 */
		long startTime = System.currentTimeMillis();
		System.out.println("Root Mean Square Error before training:\t"
				+ ErrorMeasurement.getErrorRootMeanSquareSum(net, lesson));
		net.trainBackpropagationOfError(lesson, 250000, 0.2);
		System.out.println("Root Mean Square Error after phase 1:\t"
				+ ErrorMeasurement.getErrorRootMeanSquareSum(net, lesson));
		net.trainBackpropagationOfError(lesson, 250000, 0.05);
		System.out.println("Root Mean Square Error after phase 2:\t"
				+ ErrorMeasurement.getErrorRootMeanSquareSum(net, lesson));
		net.trainBackpropagationOfError(lesson, 250000, 0.01);
		System.out.println("Root Mean Square Error after phase 3:\t"
				+ ErrorMeasurement.getErrorRootMeanSquareSum(net, lesson));
		long endTime = System.currentTimeMillis();
		long time = endTime - startTime;
 
		/*
		 * Print out what the network learned (in a formatted way) and the time
		 * it took.
		 */
		DecimalFormat df = new DecimalFormat("#.#");
		System.out.println("\nNetwork output:");
		for (int i = 0; i < lesson.countSamples(); i++) {
			double[] output = net.propagate(lesson.getInputs()[i]);
			for (int j = 0; j < output.length; j++) {
				System.out.print(df.format(output[j]) + "\t");
			}
			System.out.println("");
		}
 
		System.out.println("\nTime taken: " + time + "ms");
	}
}

Neuronale Netze von Hand gestalten

Dieses Beispiel editiert die interne Struktur einer großen Population Neuronaler Netze. Am Ende wird GraphViz DOT-Code für ein Netzwerk ausgegeben. Unter dem Code-Snippet sieht man die Ergebnisse von GraphViz-Ausgaben in Bildern, so dass man die Topologieveränderungen ab Schritt 2 mitverfolgen kann. In den Bildern sind normalerweise 2 BIAS-Neurone, weil pro Schicht eins angegeben wird, damit die Bilder besser layoutet werden können. Das zweite habe ich hier jeweils aus dem Bild herausgeschnitten.

com/dkriesel/snipe/examples/HandCraftNetwork.java

package com.dkriesel.snipe.examples;
 
import com.dkriesel.snipe.core.NeuralNetwork;
import com.dkriesel.snipe.core.NeuralNetworkDescriptor;
import com.dkriesel.snipe.util.GraphVizEncoder;
 
/**
 * Simple example program that shows how to hand-craft even large numbers of
 * networks.
 * 
 * @author David Kriesel / dkriesel.com
 * 
 */
public class HandCraftNetwork {
 
	/**
	 * Executes the example.
	 * 
	 * @param args
	 *            no args are parsed.
	 */
	public static void main(String[] args) {
 
		/*
		 * Create a NeuralNetworkDescriptor outlining Networks with two input
		 * neurons, one hidden neuron and two output neurons. Tell the networks
		 * not to automatically initialize synapses that are allowed. Tell them
		 * to choose synaptic weight values out of [-0.1;0.1] when initializing
		 * synapse weights randomly.
		 */
		NeuralNetworkDescriptor desc = new NeuralNetworkDescriptor(2, 1, 2);
		desc.setInitializeAllowedSynapses(false);
		desc.setSynapseInitialRange(0.1);
 
		/*
		 * Create ten thousand of those networks.
		 */
		NeuralNetwork[] net = desc.createNeuralNetworks(10000);
 
		/*
		 * for-loop that customizes each of the networks
		 */
		for (int i = 0; i < net.length; i++) {
 
			/*
			 * Step 0: We now have 10000 neural networks with 2 input neurons
			 * (numbered 1,2), one hidden neuron (3) and two output neurons (4
			 * and 5). There are no synapses yet. The input layer is numbered 0,
			 * the hidden layer 1 and the output layer is numbered 2. We will
			 * see that the NeuralNetwork class maintains the ascending
			 * numbering of neurons and layers.
			 */
 
			/*
			 * Step 1: Now, in each network create three additional hidden
			 * neurons. The hidden layer now contains neurons with indices 3, 4,
			 * 5 and 6, while the indices of the output neurons have been
			 * increased.
			 */
			net[i].createNeuronInLayer(1);
			net[i].createNeuronInLayer(1);
			int thirdOne = net[i].createNeuronInLayer(1);
 
			/*
			 * Step 2: Create a synapse from the BIAS to the hidden neuron just
			 * added.
			 */
			net[i].setSynapse(0, thirdOne, 2.0);
 
			/*
			 * Step 3: Remove the hidden neuron that was added last. This
			 * decreases all following neuron indices and removes the incident
			 * synapse we added as well.
			 */
			net[i].removeNeuron(thirdOne);
 
			/*
			 * Step 4: Now, create a full connection set from hidden to output
			 * layer. Connections will be initialized with weight values out of
			 * [-0.1;0.1], as we defined in the descriptor.
			 */
			net[i].createSynapsesFromLayerToLayer(1, 2);
 
			/*
			 * Step 5: Add three forward connections from input layer to hidden
			 * layer.
			 */
			net[i].setSynapse(1, 3, 5.0);
			net[i].setSynapse(1, 4, 2.0);
			net[i].setSynapse(2, 5, 3.0);
 
			/*
			 * Step 6: Add two forward shortcuts from input layer to output
			 * layer.
			 */
			net[i].setSynapse(1, 6, 4.0);
			net[i].setSynapse(2, 7, 5.0);
 
			/*
			 * Step 7: Add two self-connections in hidden layer.
			 */
			net[i].setSynapse(3, 3, 6.0);
			net[i].setSynapse(5, 5, 7.0);
 
			/*
			 * Step 8: Add two lateral connections between the two output
			 * neurons. Now, we're done.
			 */
			net[i].setSynapse(6, 7, 8.0);
			net[i].setSynapse(7, 6, 9.0);
		}
 
		/*
		 * Print out GraphViz Code of one network. Weight labels of weak
		 * synapses (namely, the ones that were initialized with weight
		 * absolutes smaller or equal to 0.1) are suppressed. Those synapses are
		 * printed lighter as well.
		 */
		GraphVizEncoder graph = new GraphVizEncoder();
		String code = graph.getGraphVizCode(net[0], "NeuralNetwork");
		System.out.println(code);
	}
}

Haftungsausschluss und Nutzungsbedingungen

Diese Software wird „wie besehen“ und ohne Gewähr, weder ausdrücklich noch implizit, einschließlich aber nicht beschränkt auf die gesetzliche Gewährleistung der Gebrauchstauglichkeit und Eignung für einen bestimmen Zweck bereitgestellt. In keinem Fall, auch wenn sie von der Möglichkeit solcher Schäden unterrichtet wurden, haften der Urheberrechtsinhaber oder andere Personen, die das Programm wie oben erlaubt verändern bzw. Weitergeben für unmittelbare, indirekte, zugehörige, besondere, exemplarische Schäden oder Folgeschäden (einschließlich aber nicht beschränkt auf solche, die im Zusammenhang mit der Beschaffung von Ersatzwaren oder -dienstleistungen, einem Nutzungsausfall, Datenverlust, entgangenem Gewinn oder einer Arbeitsunterbrechung auftreten), die im Rahmen der Verwendung dieser Software entstehen. Dies gilt ungeachtet der Ursache und der Grundlage des Haftungsanspruchs, d. H. Aufgrund eines Vertrages, einer verschuldensunabhängigen Haftung oder eines zivilrechtlichen Delikts (z. B. Fahrlässigkeit).

SNIPE und seine Dokumentation sind unter der Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported lizensiert, bis auf einige wenige Kleinteile, die anderen Lizenzen bzw. Copyright unterstehen (das ist dann im JavaDoc auch so vermerkt). Natürlich berührt die Lizenz nicht den Source Code von SNIPE, der (zunächst) nicht veröffentlicht wird.

Comments

Aufgrund von Caching kann es bis zu zwei Minuten dauern, bis ein Kommentar erscheint!

Hallo,

ich wollte einmal fragen, wie ich ein Hopfield-Netz erstelle. Der NetworkDescriptor erlaubt ja nur mehrere Layer. Ein Hopfield-Netz besteht ja nur aus einem Layer. Wie muss ich da vorgehen, um ein Hopfield-Netz zu entwerfen ? Ich habe in den Dokus nichts dazu gefunden. Trotzdem vielen Dank für diese hervorragende Bibliothek.

MfG

1 |
Jeromin Gleß
| 2016/01/15 16:08 | reply

Wann kommt 1.0?

2 |
Zimmer
| 2016/04/26 16:14 | reply

NeuralNetwork.getLayerOfNeuron(int neuronIndex) hat ein Fehler. Wenn man neuron index angibt der zu gross ist (also grösser als neuronCount), gibt der method letztes Layer zurück.

3 |
Andrey
| 2016/08/17 12:31 | reply

Kurze Frage zu den organize….-Methoden welche ich dir gerne stellen würde, aber ich weiss nicht ob du noch aktiv bist auf dieser Seite

4 |
Christopher
| 2016/10/13 19:46 | reply

@Christopher: Das ist meine Webseite, und da bin ich sehr wohl aktiv. Es gibt doch auch aktuelle Blogartikel :-) Ich mail dir mal

5 |
David Kriesel
| 2016/10/13 20:47 | reply

Hallo Daniel, Ich habe mal eine Frage zur Methode getWeight().

Angenommen ich habe mein Netz trainiert und möchte mir nun die Gewichte in eine Datei schreiben um sie später nochmal auszulesen und wieder zu verwenden. Kann ich das dann mit der getWeight()-Methode des NeuralNetwork-Objekts machen? Bei mir sind da alle Einträge 0. Hast du eine Idee was ich falsch mache?

Liebe Grüße Matthias

6 | | 2017/02/23 01:58 | reply

Hallo Daniel, Ich habe einige Netze trainiert und habe diese nun mit der NeuralNetwork.exportToString() Methode abgespeichert. Beim laden über importFromString bekomme ich aber bei der gleichen TrainingsSampleLesson einen anderen Fehler raus. Hab ich da irgendwas falsch gemacht, oder werde vielleicht die gewichte vom BIAS-Neuron nicht abgespeichert?

Grüße Lion Reichl

7 |
lion Reichl
| 2017/06/14 17:52 | reply



P T H