Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Klassifizierung und Vorhersage mit neuronalen Netzen
In diesem Monatsartikel stelle ich dar, wie neuronale Netze zur Lösung von Klassifizierungs- und Vorhersageproblemen verwendet werden können. Das Ziel der Klassifizierung lässt sich am besten mit einem Beispiel erklären. Angenommen, Sie verfügen über historische Daten zu Irisblüten, die so aussehen:
5.1 3.5 1.4 0.2 Setosa
7.0 3.2 4.7 1.4 Versicolor
6.3 3.3 6.0 2.5 Virginica
6.4 3.2 4.5 1.5 Versicolor
...
Jede Zeile mit durch Abstand getrennten Feldern hat fünf Felder. Die ersten vier numerischen Felder sind Länge des Kelchblatts (der grünen Knospenabdeckung), Breite des Kelchblatts, Länge des Blütenblatts (des farbigen Teils der Blume) und Breite des Blütenblatts. Das fünfte Feld enthält die Art: Setosa, Versicolor oder Virginica. Das Ziel der Klassifizierung besteht darin, eine Gleichung oder einen Satz von Regeln festzulegen, die bzw. der vorhersagt, zu welcher Art oder Klasse eine Iris gehört. Der Regelsatz kann dann dazu verwendet werden, die Klasse einer neuen Iris aufgrund ihrer Werte für Länge und Breite von Kelch- und Blütenblatt vorherzusagen. Die Irisdaten sind ein klassisches Beispiel, das zuerst von R. A. Fisher 1936 verwendet wurde. Sie werden es nicht besonders aufregend finden, Klassifizierung ist jedoch außerordentlich wichtig. Beispiele sind die Klassifizierung der Bonität eines Bewerbers auf der Grundlage von Variablen wie Einkommen und monatlichen Ausgaben (oder, was auch dasselbe hinausläuft, die Vorhersage seiner Kreditwürdigkeit) und die Klassifizierung, ob ein Patient im Krankenhaus Krebs hat, auf Grundlage der Werte eines Bluttests.
Es gibt viele Verfahren zum Klassifizieren von Daten, darunter auch die Verwendung neuronaler Netze. Eine mögliche Beschreibung neuronaler Netze ist, dass es sich bei ihnen um virtuelle Input-Output-Geräte handelt, die eine beliebe Anzahl numerischer Inputs akzeptieren und eine beliebige Anzahl von numerischen Outputs produzieren. Um einen besseren Eindruck davon zu bekommen, worum es in diesem Artikel genau geht, können Sie sich den Screenshot in Abbildung 1 und das Bild in Abbildung 2 ansehen. Abbildung 1 zeigt die Klassifizierung durch neuronales Netz in Aktion. Um die Begriffe der Klassifizierung unter Verwendung neuronaler Netze klar herauszustellen, habe ich keine Daten aus dem wirklichen Leben verwendet. Stattdessen habe ich künstliche Daten verwendet, bei denen die Eingabe-X-Werte vier beliebige Zahlenwerte ohne besondere Bedeutung sind. Die zu klassifizierende Ausgabe-Y-Variable ist die Farbe, und sie kann einen von drei kategorischen Werten annehmen: rot, grün oder blau. Das in Abbildung 1 dargestellte Programm beginnt mit der Generierung einer Textdatei mit 100 Zeilen künstlicher Daten (zum Beispiel „8,0 5,0 9,0 5,0 grün“), und zeigt dann die ersten vier Zeilen dieser Daten an. Als Nächstes liest das Programm diese Rohdaten in den Speicher ein als Trainingsmatrix mit 80 Zeilen Daten und einer Testmatrix von 20 Zeilen. Beachten, dass auf die Rohdaten zwei Transformationen angewendet werden. Die numerischen Roheingabedaten werden normalisiert, sodass alle Werte zwischen -1,00 und +1,00 liegen, und die Rohausgabedaten (wie „rot“) werden in einen Vektor mit drei Dimensionen kodiert („1,0 0,0 00“).
Abbildung 1 Klassifizierung durch neuronales Netz in Aktion
Abbildung 2: Struktur des neuronalen Netzwerks
Nach dem Erstellen der Trainings- und Testmatrizen erstellt das Demoprogramm ein vollständig verbundenes neuronales Feedforward-Netz mit drei Eingabeneuronen, fünf verborgenen Neuronen für die Berechnung und drei Ausgabeneuronen. Es zeigt sich, dass ein vollständig verknüpftes neuronales 4-5-3-Netzwerk 43 Gewichtungs- und Biaswerte erfordert. Dann analysiert das Klassifizierungsprogramm die Trainingsdaten, um die 43 besten Gewichtungs- und Biaswerte zu finden (diejenigen, die den Klassifizierungsgesamtfehler minimieren). Das Programm verwendet Partikelschwarmoptimierung und Kreuzentropiefehler, um die besten Gewichtungs- und Biaswerte zu ermitteln.
Dann lädt das Klassifizierungsprogramm die besten Gewichtungs- und Biaswerte in das neuronale Netz und bewertet die Vorhersagegenauigkeit des Modells auf den 20 Datenzeilen in der Testmatrix. Beachten Sie, dass die Ausgabe des neuronalen Netzes so angelegt ist, dass sich die drei Ausgabewerte auf 1,0 summieren. In diesem Beispiel sagt das Modell 17 der 20 Testvektoren richtig voraus. Das Bild in Abbildung 2 illustriert, wie das neuronale Netzwerk die Eingabe (-1,00, 1,00, 0,25, -0,50) annimmt und die vorhergesagt Ausgabe (0,9, 0,1, 0,0) generiert, was rot entspricht.
Das Beispielprogramm zeigt, dass fünf Hauptentscheidungen zu treffen sind, wenn neuronale Netze für Klassifizierungen verwendet werden, bei denen die Eingabedaten numerisch und die Ausgabedaten kategorisch sind:
- wie die numerischen Eingabedaten zu normalisieren sind
- wie die kategorischen Ausgabedaten zu kodieren sind
- wie die neuronale Ausgabe im Bereich [0,0, 1,0] zu generieren ist
- wie Fehler beim Training zu messen sind
- wie die Genauigkeit beim Testen zu messen ist
In den folgenden Abschnitten werde ich erklären, dass die im Beispielprogramm getroffenen Entscheidungen Folgende sind:
- eine lineare Umformung auf den numerischen Eingabedaten durchführen
- 1-von-N-Kodierung für kategorische Ausgabedaten verwenden
- eine Softmatrix-Aktivierungsfunktion für die Ausgabeschicht verwenden
- Kreuzentropiefehler verwenden, um die besten Gewichtungen zu bestimmen
- ein „Winner takes All“-Verfahren verwenden, um die Genauigkeit zu bestimmen
Der Programmcode, der den Screenshot in Abbildung 1 generiert hat, ist etwas zu lang, um ihn in diesem Artikel darzustellen, ich konzentriere mich also stattdessen auf die verwenden Algorithmen. Die vollständige Programmquelle ist auf der MSDN-Codedownloadsite unter archive.msdn.microsoft.com/mag201207TestRun verfügbar. Dieser Artikel geht davon aus, dass Sie über fortgeschrittene Programmierkenntnisse und eine grundlegende Kenntnis neuronaler Netze verfügen. Ich erkläre die Grundlagen neuronaler Netze in der Ausgabe von Mai 2012 des MSDN-Magazins (msdn.microsoft.com/magazine/hh975375).
Allgemeine Programmstruktur
Abbildung 3 listet die Programmstruktur des Beispiels auf, das in Abbildung 1 ausgeführt wird. Ich verwendete Visual Studio 2010 zur Erstellung einer einzigen C#-Konsolenanwendung mit der Bezeichnung NeuralClassification. Im Solution Explorer-Fenster benannte ich die Datei Program.cs in den anschaulicheren Namen NeuralClassificationProgram.cs um, wodurch automatisch die Klasse, die die Hauptmethode enthielt, umbenannt wurde. Ich habe die nicht benötigten using-Anweisungen entfernt, die von der Visual Studio-Vorlage generiert worden waren und dem System.IO-Namespace einen Verweis hinzufügten.
Abbildung 3: Struktur des neuronalen Klassifizierungsprogramms
using System;
using System.IO;
namespace NeuralClassification
{
class NeuralClassificationProgram
{
static Random rnd = null;
static void Main(string[] args)
{
try
{
Console.WriteLine("\nBegin Neural network classification\n");
rnd = new Random(159); // 159 makes a nice example
string dataFile = "..\\..\\colors.txt";
MakeData(dataFile, 100);
double[][] trainMatrix = null;
double[][] testMatrix = null;
MakeTrainAndTest(dataFile, out trainMatrix, out testMatrix);
NeuralNetwork nn = new NeuralNetwork(4, 5, 3);
double[] bestWeights = nn.Train(trainMatrix);
nn.SetWeights(bestWeights);
double accuracy = nn.Test(testMatrix);
Console.WriteLine("\nEnd neural network classification\n");
}
catch (Exception ex)
{
Console.WriteLine("Fatal: " + ex.Message);
}
} // Main()
static void MakeData(string dataFile, int numLines) { ... }
static void MakeTrainAndTest(string file, out double[][] trainMatrix,
out double[][] testMatrix) { ... }
}
class NeuralNetwork
{
// Class member fields here
public NeuralNetwork(int numInput, int numHidden,
int numOutput) { ... }
public void SetWeights(double[] weights) { ... }
public double[] ComputeOutputs(double[] currInputs) { ... }
private static double SigmoidFunction(double x) { ... }
private static double[] Softmax(double[] hoSums) { ... }
public double[] Train(double[][] trainMatrix) { ... }
private double CrossEntropy(double[][] trainData,
double[] weights) { ... }
public double Test(double[][] testMatrix) { ... }
}
public class Helpers
{
static Random rnd = new Random(0);
public static double[][] MakeMatrix(int rows, int cols) { ... }
public static void ShuffleRows(double[][] matrix) { ... }
public static int IndexOfLargest(double[] vector) { ... }
public static void ShowVector(double[] vector, int decimals,
bool newLine) { ... }
public static void ShowMatrix(double[][] matrix, int numRows) { ... }
public static void ShowTextFile(string textFile, int numLines) { ... }
}
public class Particle
{
// Class member fields here
public Particle(double[] position, double fitness,
double[] velocity, double[] bestPosition,
double bestFitness) { ... }
public override string ToString() { ... }
}
} // ns
Zusätzlich zu der Klasse, die die Hauptmethode enthält, verfügt das Programm über drei weitere Klassen. Die Klasse NeuralNetwork kapselt ein vollständig verbundenes neuronales Feed-Forward-Netz ein. Die gesamte Kernlogik des Programms ist in dieser Klasse enthalten. Class Helpers enthält sechs Dienstprogrammroutinen. Class Particle definiert ein Partikelobjekt, das vom Partikelschwarmoptimierungs-Algorithmus in der Trainingsmethode der Klasse NeuralNetwork verwendet wird. Ein Kennzeichen von Klassifizierungsprogrammen ist es, dass es viele verschiedene Programmstrukturen gibt; die hier dargestellte Organisation ist nur eine Möglichkeit.
Generieren der Rohdatendatei
In den meisten Klassifizierungsszenarien werden Sie bereits eine Satz Rohdaten festgelegt haben, für diesen Artikel habe ich jedoch Dummy-Rohdaten mit der MakeData-Methode erstellt. So sieht der Prozess in Pseudocode aus:
create 43 arbitrary weights between -2.0 and +2.0
create a 4-5-3 neural network
load weights into the neural network
open a result file for writing
loop 100 times
generate four random inputs x0, x1, x2, x3 between 1.0 and 9.0
compute the y0, y1, y2 neural outputs for the input values
determine largest of y0, y1, y2
if y0 is largest write x0, x1, x2, x3, red
else if y1 is largest write x0, x1, x2, x3, green
else if y2 is largest write x0, x1, x2, x3, blue
end loop
close result file
Das Ziel besteht hier darin, Daten zu erhalten, die mit absolut 100-prozentiger Sicherheit klassifizierbar sind, und nicht zufällige Daten, bei denen nicht klar ist, wie effektiv irgendein Klassifizierungsverfahren wäre. Anders gesagt, ich verwende ein neuronales Netzwerk, um Rohdaten zu erstellen, und dann beginne ich erneut und verwende ein neuronales Netzwerk, um diese Daten zu klassifizieren.
Erstellen der Trainings- und Testmatrizen
Beim Durchführen einer Klassifikationsanalyse mit einem Satz vorhandener Daten besteht ein verbreitetes Verfahren namens Holdout-Überprüfung darin, die Daten in einen größeren Datensatz (oft 80 Prozent) zum Trainieren des neuronalen Netzes und einen kleineren Datensatz (20 Prozent) zum Testen des Modells aufzuteilen. Training bedeutet, die Gewichtungen und Biase des neuronales Netzes zu finden, die Fehlerwerte minimieren. Testen bedeuten, das neuronale Netz mit den besten Gewichtungen zu evaluieren, die während des Training gefunden wurden, unter Verwendung eines Maßes für die Genauigkeit. Hier erstellt die MakeTrainAndTest-Methode Trainings- und Testmatrizen und normalisiert auch die numerischen Eingabedaten und kodiert die numerischen Ausgabedaten. Im Pseudocode funktioniert die Methode so:
determine how many rows to split data into
create a matrix to hold all data
loop
read a line of data
parse each field
foreach numeric input
normalize input to between -1.0 and +1.0
end foreach
encode categorical output using 1-of-N
place normalized and encoded data in matrix
end loop
shuffle matrix
create train and test matrices
transfer first 80% rows of matrix to train, remaining rows to test
Ist die Methodensignatur ist:
static void MakeTrainAndTest(string file, out double[][] trainMatrix,
out double[][] testMatrix)
Der Parameter namens Datei ist der Name der zu erstellenden Rohdatendatei. Die Parameter trainMatrix und testMatrix sind Ausgabeparameter, in die die Ergebnisse platziert werden. Die Methode beginnt mit:
int numLines = 0;
FileStream ifs = new FileStream(file, FileMode.Open);
StreamReader sr = new StreamReader(ifs);
while (sr.ReadLine() != null)
++numLines;
sr.Close(); ifs.Close();
int numTrain = (int)(0.80 * numLines);
int numTest = numLines - numTrain;
Dieser Code zählt die Anzahl der Zeilen in der Rohdatendatei und berechnet dann, wie viele Zeilen 80 Prozent und 20 Prozent der Daten bilden. Hier sind die Prozentsätze hartcodiert; wenn Sie möchten, können Sie sie parametrisieren. Als Nächstes wird eine Matrix, die alle Daten enthält, zugewiesen:
double[][] allData = new double[numLines][];
for (int i = 0; i < allData.Length; ++i)
allData[i] = new double[7];
Es sind keine sieben Spalten vorhanden. eine Spalte für jede der vier numerischen Eingaben und drei Spalten für den 1-von-N-codierten Wert der kategorialen Farbvariable. Erinnern Sie sich, dass das Ziel für dieses Beispiel darin bestand, die Farbe vorherzusagen, die einer von drei kategorischen Werten sein kann: rot, grün oder blau. Codierung mittels der 1-von-N-Technik bedeutet in dieser Situation, dass rot als (1,0, 0,0, 0,0), grün als (0,0, 1,0, 0,0) und blau als (0,0, 0,0, 1,0) kodiert wird. Kategorische Daten müssen numerisch kodiert werden, da neuronale Netze nur numerische Werte direkt verarbeiten können. Es stellt sich heraus, dass die Codierung der Farben durch ein einfaches Verfahren, wie 1 für rot, 2 für grün und 3 für blau eine schlechte Idee wäre. Die Erklärung, warum dies schlecht ist, wäre etwas komplizierter und fällt nicht in den Bereich dieses Artikels.
Eine Ausnahme von der Richtlinie des 1-von-N-Codierens für kategoriale Ausgabedaten besteht darin, dass, wenn nur zwei mögliche Werte vorliegen, wie „männlich“ oder „weiblich“, die 1-von-(N-1)-Codierung verwendet werden kann, bei der ein einziger numerischer Ausgabewert vorliegt, sodass z. B. 0,0 männlich und 1,0 weiblich bedeutet.
Die Codierung wird durch den folgenden Code ausgeführt:
tokens = line.Split(' ');
allData[row][0] = double.Parse(tokens[0]);
allData[row][1] = double.Parse(tokens[1]);
allData[row][2] = double.Parse(tokens[2]);
allData[row][3] = double.Parse(tokens[3]);
for (int i = 0; i < 4; ++i)
allData[row][i] = 0.25 * allData[row][i] - 1.25;
if (tokens[4] == "red") {
allData[row][4] = 1.0;
allData[row][5] = 0.0;
allData[row][6] = 0.0; }
else if (tokens[4] == "green") {
allData[row][4] = 0.0;
allData[row][5] = 1.0;
allData[row][6] = 0.0; }
else if (tokens[4] == "blue") {
allData[row][4] = 0.0;
allData[row][5] = 0.0;
allData[row][6] = 1.0; }
Erinnern Sie sich darin, dass eine Zeile mit Rohdaten so aussieht:
8,0 5,0 9,0 5,0 grün
Die fünf Felder werden mit String.Split analysiert. Die Erfahrung hat gezeigt, dass in den meisten Fällen bessere Ergebnisse erzielt werden, wenn die numerischen Eingabe auf Werte zwischen -1,0 und +1,0 skaliert werden. Jede der ersten vier numerischen Eingaben wird durch multiplizieren mit 0,25 und subtrahieren von 1,25 konvertiert. Erinnern Sie sich daran, dass die numerischen Eingaben in der Dummydatendatei alle zwischen 1,0 und 9,0 liegen. Bei einer echten Klassifizierungsaufgabe müssten Sie die Rohdaten untersuchen und die Minimal- und Maximalwerte bestimmen. Wir möchten, dass -1,0 1,0 und +1,0 9,0 entspricht. Durch eine lineare Umformung finden wir die Steigung (hier 0,25) und den Schnittpunkt (-1,25). Diese Werte können berechnet werden als:
slope = 2 / (max value - min value) = 2 / (9.0 - 1.0) = 0.25
intercept = 1.0 - (slope * max value) = 1 - (0.25 * 9.0) = -1.25
Es gibt viele Alternativen zum Ausführen einer linearen Umformung der numerischen Eingabewerte, das hier dargestellte Verfahren ist jedoch einfach und in den meisten Situationen ein guter Ausgangspunkt.
Nachdem die vier numerischen Eingabewerte umgeformt wurden, wird der Farbwert aus der Rohdatendatei durch 1-von-N-Codierung codiert. Wenn alle Werte aus der Rohdatendatei berechnet und in die allData-Matrix platziert wurden, werden die Zeilen dieser Matrix mit der ShuffleRows-Dienstprogrammmethode in der Helpers-Klasse willkürlich neu angeordnet. Nachdem die Anordnung der Zeilen in allData gemischt wurde, wird den Matrizen trainMatrix und testMatrix ein Raum zugewiesen, dann werden die ersten numTrain-Zeilen von allData in trainMatrix kopiert, und die übrigen numTest-Zeilen von allData werden in testMatrix kopiert.
Eine wichtige Alternative zum Training-Test-Verfahren besteht darin, die Rohdaten in drei Sets einzuteilen: Training, Überprüfung und Test. Die Idee besteht darin, die Trainingsdaten zu verwenden, um den besten Satz neuronaler Netzwerkgewichtungen in Verbindung mit den Überprüfungsdaten zu bestimmen, der verwendet wird, um festzustellen, wann das Training beendet wird. Es gibt noch weitere Verfahren, die als Kreuzvalidierungstechniken zusammengefasst werden.
Die Softmax-Aktivierungsfunktion
Beim Durchführen einer Klassifizierung mit einem neuronalen Netzwerk, bei der die Ausgabevariable kategorisch ist, besteht eine ziemlich komplizierte Beziehung zwischen der Ausgabeaktivierungsfunktion des neuronalen Netzwerks, Berechnungsfehlern während des Trainings und der Berechnung der Vorhersagegenauigkeit des neuronalen Netzwerks. Wenn kategoriale Ausgabedaten (wie Farben mit den werten rot, grün oder blau) mit der 1-von-N-Codierung codiert werden, z. B. (1,0 0,0 0,0) für rot, möchten Sie, dass das neuronale Netzwerk drei numerische Werte ausgibt, damit Sie beim Trainieren des Netzwerks einen Fehler ermitteln können. Sie möchten jedoch nicht, dass drei beliebige numerische Werte ausgegeben werden, da es nicht ganz klar ist, wie ein Fehlerterm zu berechnen ist. Aber nehmen wir an, dass das neuronale Netzwerk drei numerische Werte ausgibt, die alle zwischen 0,0 und 1,0 liegen und die sich zu 1,0 summieren. Dann können die ausgegebenen Werte als Wahrscheinlichkeiten interpretiert werden, was es, wie sich herausstellt, einfach macht, beim Training einen Fehlerterm zu berechnen und beim Testen die Genauigkeit zu berechnen. Die Softmatrix-Aktivierungsfunktion gibt Ausgabewerte in dieser Form aus. Die Softmax-Funktion akzeptiert neuronale Verdeckt-zu-Ausgabe-Summen und gibt die endgültigen neuronalen Ausgabewerte zurück; sie kann folgendermaßen implementiert werden:
private static double[] Softmax(double[] hoSums)
{
double max = hoSums[0];
for (int i = 0; i < hoSums.Length; ++i)
if (hoSums[i] > max) max = hoSums[i];
double scale = 0.0;
for (int i = 0; i < hoSums.Length; ++i)
scale += Math.Exp(hoSums[i] - max);
double[] result = new double[hoSums.Length];
for (int i = 0; i < hoSums.Length; ++i)
result[i] = Math.Exp(hoSums[i] - max) / scale;
return result;
}
Im Prinzip berechnet die Softmax-Funktion einen Skalierungsfaktor, indem die Exp jeder Verdeckt-zu-Ausgabe-Summe genommen und summiert werden, dann wird der Exp jedes Werts durch den Skalierungsfaktor dividiert. Angenommen zum Beispiel, die drei Verdeckt-zu-Ausgabe-Summen sind (2,0, -1,0, 4,0). Der Skalierungsfaktor wäre Exp(2,0) + Exp(-1,0) + Exp(4,0) = 7,39 + 0,37 + 54,60 = 62,36. Die Softmax-Ausgabewerte wären dann Exp(2,0)/62,36, Exp(-1,0)/62,36, Exp(4,0)/62,36) = (0,12, 0,01, 0,87). Beachten Sie, dass die endgültigen Ausgaben alle zwischen 0,0 und 1,0 liegen und sich wirklich zu 1n0 summieren, und weiterhin, dass die größte Verdeckt-zu-Ausgabe-Summe (4,0) die größte Ausgabe/Wahrscheinlichkeit (0,87) hat, und dass das Verhältnis für die zweit- und drittgrößten Werte entsprechend ist.
Unglücklicherweise kann eine naive Implementierung von Softmax oft scheitern, da die Exp-Funktion schnell sehr groß wird und einen arithmetischen Überlauf hervorrufen kann. Die voranstehende Implementierung verwendet die Tatsache, dass Exp(a - b) = Exp(a) / Exp(b), um die Ausgabe auf eine Weise zu berechnen, bei der ein Überlauf vermieden wird. Wenn Sie die Implementierung mit (2,0, -1,0, 4,0) als Eingabe nachverfolgen, erhalten Sie dieselben Ausgaben (0,12, 0,01, 0,87), wie im vorigen Abschnitt erläutert.
Kreuzentropiefehler
Das Wesentliche beim Trainieren eines neuronalen Netzwerks besteht darin, den Satz von Gewichtungen zu finden, der für die Daten im Trainingssatz den geringsten Fehler produziert. Angenommen zum Beispiel, dass (0,75 -0,25 0,25 -0,50 0,00 1,00 0,00) eine Zeile normalisierter, codierter Daten ist. Erinnern Sie sich daran, dass die ersten vier Werte die normalisierten Eingaben sind und die letzten drei Werte grün in 1-von-N-Codierung darstellen. Nehmen Sie jetzt an, dass die Eingaben durch das neuronale Netz hindurchgeführt werden, das mit einem Satz von Gewichtungen geladen wurde, und die Softmax-Ausgabe (0,20 0,70 0,10) ist. Ein traditionelles Verfahren zur Fehlerberechnung für diesen Testvektor ist die Verwendung der Summe der quadrierten Differenz, das wäre in diesem Fall (0,00 - 0,20)^2 + (1,00 - 0,70)^2 + (0,00 - 0,10)^2 = 0,14. Angenommen jedoch, die Softmax-Ausgabe wäre (0,30 0,70 0,00). Sowohl dieser Vektor als auch der vorherige sagen voraus, dass die Ausgabe grün ist, da die Wahrscheinlichkeit von grün 0,70 beträgt. Die Summe der quadrierten Abweichungen für diesen zweiten Vektor beträgt jedoch 0,18, also anders als der erste Fehlerterm. Obwohl die Summe der quadrierten Abweichungen zum Berechnen der Trainingsfehler verwendet werden kann, legen manche Forschungsergebnisse nahe, dass eine alternative Messmethode namens Kreuzentropie vorzuziehen ist.
Im Prinzip wird die Kreuzentropie für einen gegebenen Ausgabevektor v und einen Testvektor t eines neuronalen Netzwerks durch Bestimmen der negativen Summe des Produkts jeder v-Vektorkomponente und der entsprechenden t-Vektorkomponente berechnet. Wie üblich, lässt sich dies am besten anhand eines Beispiels erläutern. Wenn ein Testvektor (0,75 -0,25 0,25 -0,50 0,00 1,00 0,00) und die entsprechende Softmax-Ausgabe des neuronalen Netzwerks (0,20 0,70 0,10) ist, dann ist der Kreuzentropiefehler -1 * (0,00 * Log(0,20)) + (1,00 * Log(0,70)) + (0,00 * Log(0,10)) = -1 * (0 + -0,15 + 0) = 0,15. Beachten Sie, dass alle Terme in der Summe bis auf einen immer null sind, wenn 1-von-N-Codierung verwendet wird. Der Kreuzentropiefehler für den gesamten Trainingssatz kann als die Summe der Kreuzentropie aller Testvektoren oder die durchschnittliche Kreuzentropie jedes Testvektors berechnet werden. Eine Kreuzentropiefehler-Implementierung wird in Abbildung 4 dargestellt.
Abbildung 4:Kreuzentropiefehler
private double CrossEntropy(double[][] trainData,
double[] weights)
{
this.SetWeights(weights);
double sce = 0.0; // sum of cross entropies
for (int i = 0; i < trainData.Length; ++i)
{
double[] currInputs = new double[4];
currInputs[0] = trainData[i][0];
currInputs[1] = trainData[i][1];
currInputs[2] = trainData[i][2];
currInputs[3] = trainData[i][3];
double[] currExpected = new double[3];
currExpected[0] = trainData[i][4];
currExpected[1] = trainData[i][5];
currExpected[2] = trainData[i][6];
double[] currOutputs = this.ComputeOutputs(currInputs);
double currSum = 0.0;
for (int j = 0; j < currOutputs.Length; ++j)
{
if (currExpected[j] != 0.0)
currSum += currExpected[j] * Math.Log(currOutputs[j]);
}
sce += currSum; // accumulate
}
return -sce;
}
Trainieren des neuronalen Netzwerks
Es gibt viele Verfahren, um einen neuronalen Netzwerkklassifikator dafür zu trainieren, den Satz von Gewichtungen zu finden, der am besten den Trainingsdaten entspricht (oder, was das Gleiche ist, der den kleinsten Kreuzentropiefehler ergibt). Auf einer hohen Abstraktionsebene sieht das Trainieren eines neuronalen Netzwerks so aus:
create an empty neural network
loop
generate a candidate set of weights
load weights into neural network
foreach training vector
compute the neural output
compute cross-entropy error
accumulate total error
end foreach
if current weights are best found so far
save current weights
end if
until some stopping condition
return best weights found
Die mit Abstand am weitesten verbreitetste Technik zum Trainieren neuronaler Netzwerke heißt Backpropagation. Diese Technik ist Gegenstand einer großen Anzahl von Forschungsartikeln, sogar so einer so großen Anzahl, dass Sie, wenn Ihnen das Gebiet der Klassifizierung durch neuronale Netzwerke neu ist, leicht zu dem Schluss kommen könnten, dass Backpropagation die einzige Technik ist, die für das Training verwendet wird. Das Einschätzen des besten Satzes von Gewichtungen für ein neuronales Netz ist ein numerisches Minimierungsproblem. Zwei häufige Alternativen zur Verwendung von Backpropagation sind die Verwendung eines genetischen Echtwertalgorithmus (auch evolutionärer Optimierungsalgorithmus genannt) und die Verwendung von Partikelschwarmoptimierung. Jede Einschätzungstechnik hat Stärken und Schwächen. Das in Abbildung 1 dargestellte Programm verwendet Partikelschwarmoptimierung. Ich beschreibe evolutionäre Optimierungsalgorithmen in der Ausgabe des MSDN-Magazins von Juni 2012 (msdn.microsoft.com/magazine/jj133825) und Partikelschwarmoptimierung in der Ausgabe von August 2011 (msdn.microsoft.com/magazine/hh335067).
Es gibt viele Verfahren, um zu bestimmen, wann man das Training eines neuronalen Netzes beenden kann. Obwohl Sie einfach einen Trainingsalgorithmus ausführen können, bis der Kreuzentropiewert sehr nahe bei null liegt und eine fast perfekte Entsprechung anzeigt, besteht die Gefahr, dass die sich ergebenden Gewichtungen zu gut zu den Trainingsdaten passen und dass die Gewichtungen ein neuronales Netzwerk schaffen, das für alle anderen Daten als den Trainingssatz schlecht geeignet ist. Außerdem kann das Trainieren, bis keine Änderung im Kreuzentropiefehler mehr vorliegt, leicht dazu führen, eine Überanpassung zu modellieren. Ein einfaches Verfahren, das auch das vom Beispielprogramm verwendete ist, besteht darin, das Training auf eine begrenzte Anzahl von Wiederholungen zu beschränken. In den meisten Fällen besteht eine viel bessere Taktik zur Vermeidung von Overfitting darin, den Quelldatensatz in Trainings-Überprüfungs-Testsets auszuteilen. Normalerweise verwenden diese drei Datensätze jeweils 60 Prozent, 20 Prozent und 20 Prozent der Quelldaten. Bei dem Verfahren werden Fehler im Trainingssatz berechnet, wie zuvor beschrieben, das Verfahren berechnet jedoch nach jeder Wiederholung in der Hauptschleife den Kreuzentropiefehler am Valdierungsdatensatz. Wenn der Kreuzentropiefehler im Überprüfungsdatensatz beginnt, einen konstanten Fehleranstieg zu zeigen, besteht eine gute Chance, dass der Trainingsalgorithmus begonnen hat, sich zu gut an die Daten anzupassen, und das Training sollte beendet werden. Es gibt viele weitere mögliche Beendigungsverfahren.
Evaluieren des Klassifikators des neuronalen Netzes
Nachdem der Klassifikator des neuronalen Netzes trainiert wurde und einen Satz von besten Gewichtungen und Biasen hervorgebracht hat, besteht der nächste Schritt darin, zu bestimmen, wie genau das resultierende Modell (wobei Modell für das neuronale Netz mit dem besten Gewichtungssatz steht) bei den Testdaten ist. Obwohl Maßwerte wie die Summe der quadrierten Abweichungen oder Kreuzentropiefehler verwendet werden können, besteht ein vernünftiges Maß für die Genauigkeit einfach im Prozentsatz der vom Modell getroffenen richtigen Vorhersagen. Nochmals, es gibt verschiedene Methoden zur Messung der Genauigkeit, ein einfaches Verfahren besteht jedoch darin, das „Winner takes All“-Verfahren zu verwenden. Und wie üblich, lässt sich das Verfahren am besten mit einem Beispiel erklären. Angenommen, ein Testvektor ist (-1,00 1,00 0,25 -0,50 1,00 0,00 0,00), wie im ersten Satz von Vorhersagedaten in Abbildung 1 gezeigt. Mit dem besten Gewichtungssatz generiert das neuronale Netz eine vorhergesagte Softmax-Ausgabe von (0,9 0,1 0,0). Wenn jede Ausgabe als eine Wahrscheinlichkeit interpretiert wird, dann ist die höchste Wahrscheinlichkeit 0,9 und die vorhergesagte Testausgabe kann als (1 0 0) vorgestellt werden, d. h. das Modell trifft die richtige Vorhersage. Anders gesagt, das Winner takes All-Verfahren stellt die Ausgabekomponente des neuronalen Netzwerks mit dem größten Wert fest, macht diese Komponente zu 1 und alle anderen Komponenten zu 0, und vergleicht das Ergebnis mit den tatsächlichen Daten im Trainingsvektor. Im dritten Satz von Genauigkeitsanalysedaten in Abbildung 1 ist der Testvektor (-0,50 0,75 0,25 -0,75 0,0 0,0 1,0). Die tatsächlichen Ausgabedaten sind (0,0 0,0 1,0), was blau entspricht. Die vorhergesagte Ausgabe ist (0,3 0,6 0,1). Die größte Komponente ist die 0,6, daher ist die Modellvorhersage (0 1 0), was grün entspricht. Das Modell hat eine unzutreffende Vorhersage getroffen.
Zusammenfassung
Klassifizierung mit neuronalen Netzwerken ist ein wichtiges, faszinierendes und komplexes Thema. Der hier vorgestellte Beispiel sollte Ihnen eine solide Basis bieten, um mit der Klassifizierung durch neuronale Netzwerke zu experimentieren. In diesem Artikel wird jedoch nur ein sehr spezielles Szenario der Klassifizierung mit neuronalen Netzwerken beschreiben – numerische Eingabevariablen mit einer kategorischen Ausgabevariable – und dies ist nur ein Ausgangspunkt. Andere Szenarien erfordern etwas andere Techniken. Wenn beispielsweise die Eingabedaten eine kategoriale Variable enthalten, könnten Sie erwarten, dass diese mit 1-von-N-Codierung codiert werden, genau wie eine kategoriale Ausgabevariable. In diesem Fall sollten die Eingabedaten jedoch mit der 1-von-(N-1)-Technik codiert werden. Wenn Sie mehr über die Klassifizierung mit neuronalen Netzen erfahren möchten, empfehle ich die sieben FAQs zu neuronalen Netzen, die unter faqs.org verfügbar sind. Die Links zu diesen FAQs ändern sich zwar öfters, sie sollten aber durch Internetrecherche leicht zu finden sein.
Dr. James McCaffrey ist für Volt Information Sciences Inc. tätig. Er leitet technische Schulungen für Softwareentwickler, die auf dem Campus von Microsoft in Redmond, USA arbeiten. Er hat an verschiedenen Microsoft-Produkten mitgearbeitet, unter anderem an Internet Explorer und MSN Search. McCaffrey ist der Autor von „.NET Test Automation Recipes“ (Apress, 2006). Sie erreichen ihn unter jmccaffrey@volt.com oder jammc@microsoft.com.
Unser Dank gilt dem folgenden technischen Experten von Microsoft für die Durchsicht dieses Artikels: Matthew Richardson