Simple Neural Network Library - libsnnl

Features   Dokumentation   Beispiele   Download   Übersetzung   Links  

Das Projekt libsnnl ist im meine Belegarbeit im Fach Neuroinformatik des Studiengangs Informatik (6. Semester) an der HTW-Dresden.

Die Aufgabe bestand darin, ein neuronales Feed Forward Netz in einer C++ Bibliothek zu implementieren. Als Lernalgorithmus sollte Backpropagation umgesetzt werden.

Die dabei entstandene libsnnl implementiert ein Multilayer Perceptron Netzwerk in Form einer statisch linkbaren Bibliothek. Simple Network Library deswegen, weil sich die Bibliothek meiner Meinung nach sehr einfach benutzen lässt (siehe Beispiele).

Die Anzahl der Netzwerk-Schichten und die Anzahl der darin enthaltenen Neuronen können variabel bestimmt werden. Es werden drei Arten von Schichten unterschieden, Input, Hidden und Output. Für jeden Schichtentyp können verschiedene Aktivierungsfunktionen gesetzt werden. Die Lernfunktionalität ist in eine extra Klasse Teacher ausgelagert. Diese Klasse enthält auch Funktionalität zum Umgang mit Trainingssätzen, zum Beispiel Laden, Speichern, Shuffeln und so weiter.

Das Projekt ist voll und ganz unter Zuhilfenahme von freier Software entwickelt worden und liegt GNU-konform vor. Das heißt das sich die Bibliothek auf jedem unixoiden Betriebssystem übersetzen und benutzen lässt. Für Windows Nutzer sind außerdem entsprechende Visual Studio Projekte enthalten. Was kann die Bibliothek im Detail?

Features

Dokumentation

Die Dokumentation wurde mit Doxygen direkt aus dem Quellcode heraus erstellt. Das hat den Vorteil das sich die Dokumentation direkt im Quellcode befindet. Doxygen wurde so konfiguriert, dass der Quellcode mit in die Dokumentation aufgenommen wurde. Somit hat man die Funktionalität verbal beschrieben und sieht gleichzeitig wie es praktisch umgesetzt wurde. Als Sprache wurde Englisch gewählt. An geeigneter Stelle wird in der Dokumentation auch die mathematische Beschreibung des implementierten Algorithmus abgebildet.

Zusätzlich liegt ein Klassendiagramm in UML-Notation vor.

Wie im Klassendiagramm ersichtlich besteht das Projekt hauptsächlich aus 5 Klassen. Dabei stellt die Klasse Network das eigentliche Netz dar. Wenn das Netz einmal trainiert und einsatzbereit ist, stellt diese Klasse die alleinige Schnittstelle zum Nutzer dar. Mit den Klassen Layer und Neuron kommt man als Nutzer der Bibliothek nicht in Berührung. Die Lernfunktionalität ist in der Klasse Teacher implementiert. Diese Klasse wird nur zum Trainieren eines Netzes benötigt. Dies ist auch der Grund warum die Lernfunktionalität ausgelagert wurde. So wird erreicht, dass eine trainierte Netz-Instanz nur den minimal benötigten Code enthält. Außerdem ist es so auch möglich, dass eine Teacher-Instanz mehrere Netze trainieren kann. Die Benutzung an sich, so denke ich, wird am Besten durch die Beispiele klar die im Folgenden beschrieben werden.

Beispiele

Alle Beispiel befinden sich im Unterverzeichnis test des Projektes. Sie werden automatisch beim Übersetzen der Bibliothek mit gebaut. Die Beispiele sollen zum einen den Umgang mit der Bibliothek verdeutlichen, dienen aber gleichzeitig zum verifizieren der korrekten Arbeitsweise. Zum experimentieren mit den Beispielen ist keine Installation der Bibliothek nötig. Will man selbst Änderungen im Code vornehmen, genügt ein simples "make" zum neu bauen der geänderten Teile. Zum Visualisierung der Ausgaben ist die Installation von gnuplot und graphviz empfehlenswert. Im test-Verzeichnis liegt ein entsprechendes Perl-Script vor, was die Ausgaben der Beispiele zur Visualisierung vorbereitet.

libtest_create (Code)

Dieses Beispiel zeigt kurz und prägnant wie man sich Instanzen der Klassen Network und Teacher erzeugen kann und wie diese Klassen mit einander interagieren. Es werden 3 Netzwerke auf unterschiedliche Art und Weise erzeugt. Zum Schluss werden diese "gedumpt", sprich im graphviz Format gespeichert. Im Header des Quellcodes befindet sich, wie bei jedem anderen Beispiel auch, eine kurze Gebrauchsanweisung.

libtest_xor (Code)

Das obligatorische xor-Beispiel darf auch hier nicht fehlen. Es wird ein bereits trainiertes Netz geladen und benutzt. Die Funktionalität der Teacher-Klasse wird in diesem Beispiel nicht benötigt. Der Netzwerk-Graph wird auch hier in eine Datei geschrieben und sieht visualisiert folgendermaßen aus.

Das xor Netz

In den Zeilen 55-57 kann man den typischen Gebrauch des Netzes sehen, Eingabe setzen, durch das Netz propagieren, Ausgabe abholen. Die Programmausgabe.:
%> ./libtest_xor
x       y       net_output
0       0       0
0       1       1
1       0       1
1       1       0

libtest_binclassify (Code)

In diesem Beispiel geht es darum ein Netz Binärzahlen lernen und erkennen zu lassen, sprich Binärzahlen in die entsprechende dezimale Form umzuwandeln. Es wird in diesem Beispiel speziell der Umgang mit der Teacher-Klasse ersichtlich. Die Programmausgabe.:

%> ./libtest_binclassify
train network ...
   errorfile activated (dump/libtest_binclassify_error.dat)
done, need 8 epoch's
network output:
dec     input   opt_output      net_output
0       0000    000000000       000000000
1       0001    100000000       100000000
2       0010    110000000       110000000
3       0011    111000000       111000000
4       0100    111100000       111100000
5       0101    111110000       111110000
6       0110    111111000       111111000
7       0111    111111100       111111100
8       1000    111111110       111111110
9       1001    111111111       111111111

libtest_sin (Code)

Dies ist ein etwas größeres Beispiel, in dem es darum geht einem Netz die Sinus-Funktion zu lernen. Bei diesem Beispiel ist es möglich etwas mit den Lernparametern zu experimentieren. Diese kann man dem Programm per Kommandozeile übergeben. Es werden 10 Durchläufe zu je 10 Epochen gelernt. Nach Jedem der 10 Durchläufe wird das Netz geprüft. Die Ausgabe kann man sich mittels gnuplot visualisieren lassen.

10 Epochen Sinus-Kurve

libtest_encoder_decoder (Code)

In diesem Beispiel ist ein 8-3-8 Bit Encoder-Decoder realisiert. Das Trainset wird von Datei geladen. Während der Lernphase wird Protokoll über den Verlauf des Fehlers geführt. Diesen kann man sich anschließend mit gnuplot visualisieren lassen.

Fehler Verlauf

In diesem Fall hat das Netz 30 Epochen benötigt bis es die Daten fehlerfrei reproduzieren konnte. Nach jeder Epoche wurden die Trainingsdaten durcheinander gewürfelt, daraus resultieren auch die Fehler-Schwankungen. Die Programmausgabe.:
%> ./libtest_encoder_decoder
   errorfile activated (dump/libtest_encoder_error.dat)
train network ...
need 30 epoch's
network output:
--------+-------+--------
00100000|->-3->-|00100000
00000100|->-3->-|00000100
00000010|->-3->-|00000010
00001000|->-3->-|00001000
10000000|->-3->-|10000000
01000000|->-3->-|01000000
00010000|->-3->-|00010000
00000001|->-3->-|00000001

libtest_two_spirals (Code)

Das Problem der zwei Spiralen ist ein bekanntes und oft herangezogenes Beispiel wenn es darum geht Netzarchiteturen und Lernalgorithmen zu vergleichen beziehungsweise zu benchmarken. Es geht bei diesem Problem darum ein Netz mit x-y-Koordinaten (194 Datensätze) von zwei Spiralen anzulernen um später klassifizieren zu können, zu welcher Spirale eine Koordinate gehört. Dazu existieren 770 Testdatensätze. Die Spiralen sind 3 mal in einander verwickelt. Es handelt sich hierbei um eine sehr schwierige Aufgabe für Backpropagation-Netzwerke da die Daten hochgradig nicht-linear sind.

2 Spiralen Problem Train-Daten

2 Spiralen Problem Test-Daten

Der 2 Spiralen Benchmark eignet sich außerdem hervorragend um die Generalisierungsfähigkeit eines Netzes zu prüfen da sehr viel mehr Testdatensätze als Trainingsdatensätze zu absolvieren sind. Mittels libsnnl ist es mir gelungen, eine 97.8%'ige Trefferquote bei den Testdatensätzen zu erreichen. Es wird ein 2-20-10-2 Netz mit einer Lernrate von 0.002, einem Momentum von 0.7 und einer Optimal-Toleranz von 0.16 eingesetzt. Der Lernvorgang wird bei unterschreiten eines Fehlers von 0.005 abgebrochen. Abschließend der Fehlerverlauf eines Lernvorganges bei dem 9678 Lern-Epochen benötigt wurden.

2 Spiralen Problem
Fehlerkurve

Die Programmausgabe.:
%> ./libtest_spirals
   errorfile activated (dump/libtest_spiral_error.dat)
train network ... 9678 epoch's needed
network saved to dump/spiral_network.net
--- verifing with test-data-set ---
x       y       optout  network         network - analog value
6.50    0.00    1       1       |       0.87
-6.50   -0.00   0       0       |       -0.03
6.48    0.32    1       1       |       0.95
-6.48   -0.32   0       0       |       -0.90
6.44    0.63    1       1       |       0.97
...
-0.52   0.03    0       0       |       -0.02
0.50    0.00    1       1       |       0.84
-0.50   -0.00   0       0       |       0.05
accuracy: 97.8%

Download

Das komplette Projekt ist als Quellcode-Packet mit Dokumentation unter folgendem Link erhältlich.

Übersetzung und Installation

Unix typisch erfolgt die Übersetzung im gewohnten Kommando-Tripel im Rootverzeichnis des Projektes.:

  $> ./configure [--prefix ...]
  $> make
  $> make install
Wie gewohnt kann über den Prefix-Schalter das Installationsziel angegeben werden. Installiert werden die Bibliothek und die benötigen Header-Dateien, nicht jedoch die Testprogramm.

Das Projekt wurde erfolgreich auf FreeBSD, NetBSD, SuSE Linux und Windows Systemen übersetzt und getestet.

Für die Benutzung der Bibliothek ist eine Installation nicht zwingend notwendig. Es reicht auch dem Compiler den entsprechenden Library-Pfad mit zu teilen. Ebenfalls muss dem Compiler der Include-Pfad zu den Header-Dateien mitgeteilt werden. Das könnte zum Beispiel so aus sehen.

  $> c++ -L../src -I../src/include libtest.cpp -lsnnl -o libtest
Für die Benutzung auf Windows Systemen stehen im Verzeichnis MSVS7 entsprechende Visual Studio Projekte zur Verfügung. Das Projekt lib ist dabei als erstes zu übersetzen.

Links

Interessante Links zum Thema Neuronale Netze.