Hi,
zu Neuronalen Netzen fällt mir immer wieder
http://www.20q.net/ ein...
Zurück zum Thema:
Maschinelles Lernen/Mustererkennung/Künstliche Intelligenz ist ein großes Themengebiet, und die zugrundeliegende Mathematik teilweise wirklich heftig. Ohne eine fundierte Ausbildung auf den Gebieten wirst du dir (sehr) schwer tun.
Ich versuche trotzdem mal meinen Senf in verständlicher Form dazuzugeben, und auch das letzte Beispiel zu kommentieren, vielleicht hilft es dir ja weiter:
Wie es auch schon im Code steht ist ein wesentlicher Aspekt der Mustererkennung die Klassifizierung eines unbekannten Samples (das Sample ist hier eine Zahl). Mögliche Klassen sind dabei "gerade" und "ungerade". Die Klassifizierung wird nun erreicht, indem das unbekannte Sample mit Trainingsdaten (hier steckt das Lernen drinnen) verglichen wird, wobei die Trainingsdaten in einem "Lernprozess" natürlich schon in die möglichen Klassen unterteilt worden sein müssen. Für den Lernprozess (aka Training des Modells) gibt es verschiedene Möglichkeiten, da es im Code um überwachtes Lernen geht, werde ich nur auf diese Technik näher eingehen:
Nehmen wir als Trainingsdaten die Zahlen {2,4,6,101,103,105} an.
PHP:
int TrainingData[] = {2,4,6,101,103,105};
Dann werden diese Zahlen vom Benutzer (überwachtes Lernen, z.B. mit einer Ja/Nein-Abfrage) in die entsprechenden Klassen eingeteilt. Also: Class1= {2,4,6} und Class2={101,103,105}
PHP:
// Generische Trainingsfunktion.
// Class1 enthält danach alle Elemente aus TrainingData die zu Klasse1 gehören und Class2 enthält alle Elemente aus TrainingData die zu Klasse2 gehören.
// Die Methode allokiert Speicher für Class1 und Class2.
// Hoffe ich hab mich nicht mit den Pointern vertan...
void TrainModel(int *TrainingData, unsinged int *LengthClass1, int **Class1, unsigned int *LengthClass2, int **Class2);
unsigned int LengthClass1;
unsigned int LengthClass2;
int *Class1;
int *Class2;
TrainModel(TrainingData, &LengthClass1, &Class1, &LengthClass2, &Class2);
Als nächstes muss ein neues Sample (wie oben gesagt) mit den Trainingsdaten verglichen werden. Das wird erreicht indem für jedes Sample (egal ob Trainingssample oder unbekanntes Sample) ein Merkmal (engl. Feature) berechnet wird. Dieses Merkmal sollte möglichst stellvertretend für die Klasse des Samples sein. Für jede Trainingsklasse (Class1 und Class2) kann das entsprechende Merkmal z.B. ermittelt werden, indem für jedes Element der Klasse das Merkmal berechnet wird, und die Merkmale dann gemittelt werden.
PHP:
// Generische Merkmalsberechnung
int ComputeFeature(int Sample);
// Berechnet das Merkmal für eine Klasse
int ComputeClassFeature(unsigned int Length, int *Class)
{
int ClassFeature = 0;
for ( unsigned int i = 0; i < Length; i++ )
ClassFeature += ComputeFeature(Class[i]);
ClassFeature /= (float)Length;
return ClassFeature;
}
und nun der eigentliche Vergleich von einem neuem, unbekannten Sample mit den Trainingsklassen
PHP:
// Generischer Klassifikator.
// Die ID der Klasse wird zurückgegeben: 0 für gerade, 1 für ungerade
unsigned int Classify(int FeatureOfNewSample, int Class1Feature, int Class2Feature);
// Zahl einlesen
int NumberToClassify;
printf("Please enter number to classify: ");
scanf("%d",&NumberToClassify);
printf("\n");
// Merkmale von Trainingsklassen und neuem Sample berechnen
int ClassFeature1 = ComputeClassFeature(LengthClass1, Class1);
int ClassFeature2 = ComputeClassFeature(LengthClass2, Class2);
int NewSampleFeature = ComputeFeature(NumberToClassify);
// Klasse berechnen
unsigned int ClassID = Classify(NewSampleFeature, ClassFeature1, ClassFeature2);
// Klasse ausgeben
printf("Die Zahl %d ist ", NumberToClassify);
if ( ClassID == 0 )
printf("gerade\n");
else
printf("ungerade\n");
Das ist nun im Prinzip der Grundaufbau eines jeden Mustererkennungssystems/Klassifikator. Das kann man natürlich auf eine beliebige Anzahl von Klassen erweitern, letzendlich kann man aber alles auf eine binäre Entscheidungsregel zurückführen. Viel wichtiger sind die "generischen Funktionen" die in meinen Code-snippets vorkommen, und hier wirds entweder einfach oder richtig komplex. Letzteres lassen wir mal aus, bei Fragen gibts gerne einen Nachschub...
1.
Trainingsfunktion:
PHP:
// Generische Trainingsfunktion.
// Class1 enthält danach alle Elemente aus TrainingData die zu Klasse1 gehören und Class2 enthält alle Elemente aus TrainingData die zu Klasse2 gehören.
// Die Methode allokiert Speicher für Class1 und Class2.
// Hoffe ich hab mich nicht mit den Pointern vertan...
void TrainModel(int *TrainingData, unsinged int LengthClass1, int **Class1, unsigned int LengthClass2, int **Class2);
Da gibts nicht viel zu sagen: Den TrainingData-Array traversieren, und den Benutzer entscheiden lassen. Speicher Anforderungen natürlich nicht vergessen!
2.
Klassifikator:
Der einfachste Ansatz ist einfach die "Distanz" des Features des neuen Samples zu den bestehenden Klassen zu berechnen und die Klasse zu wählen, die die geringste Distanz aufweist
PHP:
unsigned int Classify(int FeatureOfNewSample, int Class1Feature, int Class2Feature)
{
if ( abs(FeatureOfNewSample-Class1Feature) < abs(FeatureOfNewSample-Class2Feature )
return 0;
else
return 1;
}
2.
Merkmalsberechnung/Merkmalsbestimmung
PHP:
// Generische Merkmalsberechnung
int ComputeFeature(int Sample);
Tja, was ist das Merkmal der Klassen? Zu Klasse1 sollen gerade, zu Klasse2 ungerade Zahlen gehören. Imho gibt es kein bessers Merkmal als Modulo. Schluss aus. Deswegen ist dieses Beispiel (gerade oder ungerade) gänzlich ungeeignet, da der eigentliche Klassifikator bereits in C integriert ist

Somit hätten wir
PHP:
int ComputeFeature(int Sample)
{
return Sample % 2;
}
Ich möchte trotzdem noch etwas anmerken was dir für andere Arbeiten auf diesem Gebiet hilfreich sein kann:
Wir hatten die Trainingsdaten {2,4,6,101,103,105} und die gelernten Klassen Class1= {2,4,6} und Class2={101,103,105}. Diese Klassen sind wunderbar getrennt, und auf den ersten Blick ist sogar nicht die Division mit Rest DAS entscheidende Merkmal sondern der (absolute) Wert:
PHP:
int ComputeFeature(int Sample)
{
return abs(Sample);
}
Somit hätten wir als Merkmal für Class1=4 und für Class2=103. Wenn du dir den Klassifikator von oben (Distanz zu den Klassen ansiehst) hoffe ich, dass es dir klar ist, dass bei der Klassifikation der Zahl 11 alles schiefläuft!
So, das war lange

. Hoffe mal es sind keine zu schlimmen Fehler drinnen.
P.S:
Das Code-Beispiel von dir halte ich nicht für ein richtiges Neuronales Netz, bzw. es ist so trivial, dass ich es nicht als solches erkenne...