Künstliche Intelligenz (KI) als Hobby / Artificial Intelligence (AI) as a Hobby

Facebook Gruppe: Künstliche Intelligenz (KI) als Hobby

Neuronales Netz in PHP

Um in das Thema neuronale Netze praktisch einzusteigen, soll hier ein "fertiges" Skript an einem Praxisbeispiel in PHP vorgestellt werden.

Quelle der verwendeten PHP-Klasse: https://github.com/infostreams/neural-network

Ausführlicher Kurs/Einführung in neuronale Netze über 33 Seiten: http://www.chemgapedia.de/vsengine/vlu/vsc/de/ch/13/vlu/daten/neuronalenetze/neuronalenetze1.vlu.html

Vorraussetzungen für neuronale Netze

Trainigs-Daten: Eine wichtige Voraussetzung für die Berechnung mit einem neuronalen Netz ist, dass die Datenbasis (mit der trainiert werden soll) in einem für das Netz sinnvoll lesbarem Format vorhanden ist. So ist es üblich, die Daten im Vorfeld z.B. mit der Sigmoid Funktion anzugleichen, sodass sich nur Input-Werte zwischen 0 und 1 ergeben.

Schritt 1: Einbinden der Klasse

Am Anfang muss die PHP-Klasse z.B. über include eingebunden werden.

Direkt danach wird ein neues "NeuralNetwork" erstellt und mit Voreinstellungen (Settings) versehen.

Schritt 2: Grundstruktur des neuronalen Netzes definieren

20171117_NeuronalesNetz_Skizze.jpg

$n: Die Grundstruktur des neuronalen Netzes erstellen wir, indem die Anzahl der Input-Neuronen, der mittleren Neuronen und der Output-Neuronen vorgegeben wird. Im Beispiel sollen 4 Input-Neuronen verwendet werden, die mit jeweils 4 mittleren Neuronen verbunden sind (4 x 4 = 16 Verbindungen), welche dann mit 1 Output-Neuron verbunden sind (4 x 1 Verbindungen).

Schritt 3: Vorgabewerte für das Training definieren

$max: Wenn beim ersten Trainings-Durchlauf kein signifikantes Ergebnis herauskommt, wird das Netz maximal so oft trainiert, bevor abgebrochen wird.

$epochs: Eine "Epoche" meint bei dem Trainig ein Schritt nach vorne vom Input zum Output durch das Netz und die entsprechende Berechnung zurück. Nach der Vorgegeben Anzahl wird das Training abgebrochen.

$squarederror: Gemeint ist, wie weit die vom neuronalen Netz berechneten Output-Daten (nach dem Training) von den original Input-Daten abweichen darf.

Input: Hidden: Output:
 
include ("class_neuralnetwork.php");

//Create new
$n = new NeuralNetwork(4, 4, 1); // 4 input neurons, 4 hidden neurons, and 1 output neuron
$n->setVerbose(false);

//Settings
$max = 3;					// we try training the network for at most $max times
$i = 0;
$epochs = 1000;			// Maximum Epochs
$squarederror = 0.01;		// Squared Error

Schritt 4: Einlesen der Trainings-Daten (z.B. aus einer MySQL Datenbank)

In diesem Beispiel habe ich die historischen Daten des DAX (Tages-Basis von finanzen.net) in einer MySQL Datenbank gespeichert und per normaler select Abfrage in ein array() eingelesen.

Der Code dazu ist etwas umständlich, was aber nur mit der Zielsetzung zu tun hat, immer genau 4 Tage (bzw. 5) aus der Datenreihe gleichzeitig zu betrachten. Jedes der 4 Input-Neuronen soll also den Wert von einem der 4 Tage bekommen. (Ob das in der Form eine qualitativ sinnvolle DAX-Analyse ist, sei dahingestellt, hier geht es ja nur um die prinzpielle, quantitative Vorgehensweise bei neuronalen Netzen ;-).)

Grundsätzlich passiert hier folgendes:

Es werden die täglichen Start- und End-Kurse des DAX verglichen, um die Veränderung (Plus oder Minus) dieses Tages als Input-Wert zu berechnen.

4 Tage (0-1) werden in einem Input-Array zusammengefasst.

Am 5. Tag (4) wird der Wert in einem parallelen Output-Array als Output-Wert gespeichert.

$n->addTestData: Hier werden an jedem 5. Tag Input- und Output-Array zusammen an das neuronale Netz $n (vgl. Schritt 2) übergeben.

 

$result = mysql_query("SELECT * FROM daxhistory ORDER BY date ASC LIMIT 50 ");

//Add DAX Test Data 
$day = 0;
$days = array(); 
while ($row = mysql_fetch_array($result)) {
	if ($day < 4) {
		if ($row['end'] < $row['open']) {$days[$day] = -1;} else {$days[$day] = 1;};
		$sigmoid = 1 / (1 + pow(M_EULER, - ($row['open'] - $row['end'])  ));  $days[$day] = $sigmoid;
		$day++;
	};
	if ($day == 4) {
		if ($row['end'] < $row['open']) {$days[$day] = -1;} else {$days[$day] = 1;};
		$sigmoid = 1 / (1 + pow(M_EULER, - ($row['open'] - $row['end'])  ));  $days[$day] = $sigmoid; 
		$n->addTestData(array ($days[0], $days[1], $days[2], $days[3]), array ( $days[4])); 
		$days = array(); $day = 0; 
	};
}; 

Zwischenschritt: Ausgabe vom neuronalen Netz ($n)

Um mal zu gucken, was bereits alles in $n (also unserem neuronalen Netz) enthalten ist, geben wir das ganze Array mit print_r($n) aus.

Dabei finden wir auch unsere in Schritt gegebene Neuronen-Anzahl wieder, die unter "nodeCount" zu finden ist (4,4,1).

Dazu kommen jetzt die Trainingsdaten aus MySQL, die als 4 (0-3) Tagesdaten "trainInputs" zu finden sind.

Weiter unten tauchen dann die jeweiligen "trainOutput" Daten auf, die jeweils den 5. Tag (4) aus der MySQL Abfrage darstellen:

NeuralNetwork Object
(
    [nodeCount:protected] => Array
        (
            [0] => 
            [1] => 
            [2] => 
        )

    [nodeValue:protected] => Array
        (
        )

    [nodeThreshold:protected] => Array
        (
        )

    [edgeWeight:protected] => Array
        (
        )

    [learningRate:protected] => Array
        (
            [0] => 0.1
        )

    [layerCount:protected] => 3
    [previousWeightCorrection:protected] => Array
        (
        )

    [momentum:protected] => 0.8
    [isVerbose:protected] => 
    [weightsInitialized:protected] => 
    [trainInputs] => Array
        (
            [0] => Array
                (
                    [0] => 1
                    [1] => 0.0015244988357185
                    [2] => 3.7813065445789E-12
                    [3] => 0.81264207957637
                )

            [1] => Array
                (
                    [0] => 0.67379324182845
                    [1] => 0.81761061524285
                    [2] => 1
                    [3] => 4.2435972752287E-8
                )

            [2] => Array
                (
                    [0] => 8.2512879062143E-9
                    [1] => 1
                    [2] => 1.4773279204776E-5
                    [3] => 1.8613789776927E-22
                )

            [3] => Array
                (
                    [0] => 0.99989259954948
                    [1] => 1
                    [2] => 1
                    [3] => 0.99999453609769
                )

            [4] => Array
                (
                    [0] => 2.9365499177987E-9
                    [1] => 0.029452829260216
                    [2] => 0.99678654647372
                    [3] => 0.99999999999974
                )

            [5] => Array
                (
                    [0] => 0.99990482874448
                    [1] => 9.3122379295558E-13
                    [2] => 0.99999991330489
                    [3] => 1
                )

            [6] => Array
                (
                    [0] => 9.3634092757926E-12
                    [1] => 1
                    [2] => 0.99993414101052
                    [3] => 6.1335382962624E-19
                )

            [7] => Array
                (
                    [0] => 0.99999999999289
                    [1] => 0.99705623182813
                    [2] => 0.93626992561648
                    [3] => 0.99999999999941
                )

            [8] => Array
                (
                    [0] => 0.99999897204831
                    [1] => 0.99999999997015
                    [2] => 1
                    [3] => 3.2065398618288E-11
                )

            [9] => Array
                (
                    [0] => 1.7908603215815E-12
                    [1] => 1
                    [2] => 0.02390691139658
                    [3] => 4.508031777541E-8
                )

            [10] => Array
                (
                    [0] => 7.4346883885203E-22
                    [1] => 0.99999999999915
                    [2] => 0.99999999577959
                    [3] => 1.0112223775472E-11
                )

            [11] => Array
                (
                    [0] => 1.6223428111262E-18
                    [1] => 1.3607055234616E-17
                    [2] => 8.16322929165E-26
                    [3] => 5.4359095681198E-29
                )

        )

    [trainOutput] => Array
        (
            [0] => Array
                (
                    [0] => 0.81264207957637
                )

            [1] => Array
                (
                    [0] => 4.2435972752287E-8
                )

            [2] => Array
                (
                    [0] => 1.8613789776927E-22
                )

            [3] => Array
                (
                    [0] => 0.99999453609769
                )

            [4] => Array
                (
                    [0] => 0.99999999999974
                )

            [5] => Array
                (
                    [0] => 1
                )

            [6] => Array
                (
                    [0] => 6.1335382962624E-19
                )

            [7] => Array
                (
                    [0] => 0.99999999999941
                )

            [8] => Array
                (
                    [0] => 3.2065398618288E-11
                )

            [9] => Array
                (
                    [0] => 4.508031777541E-8
                )

            [10] => Array
                (
                    [0] => 1.0112223775472E-11
                )

            [11] => Array
                (
                    [0] => 5.4359095681198E-29
                )

        )

    [trainDataID] => Array
        (
            [0] => 
            [1] => 
            [2] => 
            [3] => 
            [4] => 
            [5] => 
            [6] => 
            [7] => 
            [8] => 
            [9] => 
            [10] => 
            [11] => 
        )

    [controlInputs] => Array
        (
        )

    [controlOutput] => Array
        (
        )

    [controlDataID] => Array
        (
        )

    [epoch:protected] => 
    [errorTrainingset:protected] => 
    [errorControlset:protected] => 
    [success:protected] => 
)

Schritt 5: Das eigentliche Training der XOR function

Jetzt wird eigentlich erst richtig mit den aufbereiteten Trainingsdaten gearbeitet.

Dazu wird die eigentliche PHP-Klasse benutzt, die mit den Trainings-Daten jetzt Runde für Runde die Verbindungen innerhalb des neuronalen Netzes anpasst.

//Training the XOR function
while (!($success = $n->train($epochs, $squarederror)) && ++$i $max) {
	echo "Round $i: No success... br />";
};
if ($success) {
    $epochs = $n->getEpoch();
	echo "Training: Success in $epochs training rounds! br />";
};

Zwischenschritt: Ausgabe der Runden-Ergebnisse

Training: Success in 1 training rounds!

Schritt 6: Test-Daten mit den Ergebnissen des neuronalen Netzes abgleichen

Jetzt werden die vom neuronalen Netz berechneten Output-Werte mit den "realen" Werten der Trainings-Daten vergleichen.

Dabei gibt es nun 2 Werte

1. Original Output = Der Wert, den wir aus der original MySQL Datenbank ermittelt haben (vgl. Schritt 4).

2. Trained Output = Der Wert, der die theoretische Vorhersage des neuronalen Netzes gewesen wäre.

Das neuronale Netz "funktioniert" also in der Anwendung um so besser, je besser diese beiden Werte zusammen passen, bzw. je näher diese beiden Werte beieinander liegen.

(In diesem Beispiel passen sie leider überhaupt nicht zusammen, womit der Beweis erbracht wurde, dass es schwer ist, Börsenkurse vorherzusagen ;-) )

//Result
for ($i = 0; $i   count($n->trainInputs); $i ++) {
	$output = $n->calculate($n->trainInputs[$i]);
	echo " div>Testdata $i; ";
	echo "Original output = (".implode(", ", $n->trainOutput[$i]).") ";
	echo "Trained Output = (".implode(", ", $output).")\n /div>";
}
Testdata 0; Original output = (0.81264207957637) Trained Output = ()
Testdata 1; Original output = (4.2435972752287E-8) Trained Output = ()
Testdata 2; Original output = (1.8613789776927E-22) Trained Output = ()
Testdata 3; Original output = (0.99999453609769) Trained Output = ()
Testdata 4; Original output = (0.99999999999974) Trained Output = ()
Testdata 5; Original output = (1) Trained Output = ()
Testdata 6; Original output = (6.1335382962624E-19) Trained Output = ()
Testdata 7; Original output = (0.99999999999941) Trained Output = ()
Testdata 8; Original output = (3.2065398618288E-11) Trained Output = ()
Testdata 9; Original output = (4.508031777541E-8) Trained Output = ()
Testdata 10; Original output = (1.0112223775472E-11) Trained Output = ()
Testdata 11; Original output = (5.4359095681198E-29) Trained Output = ()

Schritt 7: Gewichtungen im neuronalen Netz ansehen

Zuletzt können wir uns nun die auf Basis der Trainingsdaten generierten Verbindungen zwischen unseren Neuronen (4,4,1) ansehen.

Die Verbindungen werden als Gewichtung angegeben (Weights), mit denen der Wert des vorherigen Neurons an das folgende Neuron weitergegeben wird.

Dabei zeigt der erste Block unsere 4x4 Verbindungen von Input- zu mittleren Neuronen, und der zweite Block 4x1 Verbindungen von den mittleren Neuronen zum Output-Neuron.

Dazu bietet die PHP-Klasse einen einfachen Befehl:

$n->showWeights($force=true);


Weights:
Array
(
)

Thresholds:
Array
(
)

Bewerte diese Seite

Sterne: 1 2 3 4 5 Was könnte besser sein: