Perceptron l'apprentissage de l'algorithme ne converge pas vers 0
Voici mon perceptron mise en œuvre de la norme ANSI C:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
float randomFloat()
{
srand(time(NULL));
float r = (float)rand() / (float)RAND_MAX;
return r;
}
int calculateOutput(float weights[], float x, float y)
{
float sum = x * weights[0] + y * weights[1];
return (sum >= 0) ? 1 : -1;
}
int main(int argc, char *argv[])
{
//X, Y coordinates of the training set.
float x[208], y[208];
//Training set outputs.
int outputs[208];
int i = 0; //iterator
FILE *fp;
if ((fp = fopen("test1.txt", "r")) == NULL)
{
printf("Cannot open file.\n");
}
else
{
while (fscanf(fp, "%f %f %d", &x[i], &y[i], &outputs[i]) != EOF)
{
if (outputs[i] == 0)
{
outputs[i] = -1;
}
printf("%f %f %d\n", x[i], y[i], outputs[i]);
i++;
}
}
system("PAUSE");
int patternCount = sizeof(x) / sizeof(int);
float weights[2];
weights[0] = randomFloat();
weights[1] = randomFloat();
float learningRate = 0.1;
int iteration = 0;
float globalError;
do {
globalError = 0;
int p = 0; //iterator
for (p = 0; p < patternCount; p++)
{
//Calculate output.
int output = calculateOutput(weights, x[p], y[p]);
//Calculate error.
float localError = outputs[p] - output;
if (localError != 0)
{
//Update weights.
for (i = 0; i < 2; i++)
{
float add = learningRate * localError;
if (i == 0)
{
add *= x[p];
}
else if (i == 1)
{
add *= y[p];
}
weights[i] += add;
}
}
//Convert error to absolute value.
globalError += fabs(localError);
printf("Iteration %d Error %.2f %.2f\n", iteration, globalError, localError);
iteration++;
}
system("PAUSE");
} while (globalError != 0);
system("PAUSE");
return 0;
}
L'ensemble de la formation, je suis en utilisant: Ensemble De Données
J'ai supprimé toutes pertinence de code. Fondamentalement, ce qu'il fait maintenant, il lit test1.txt
fichier et charges des valeurs pour les trois tableaux: x
, y
, outputs
.
Puis il y a une perceptron algorithme d'apprentissage qui, pour une raison quelconque, ne converge pas vers 0 (globalError
devrait converger vers 0) et donc j'obtiens une infinie boucle do while.
Lorsque j'utilise un petit ensemble de formation (5 points), cela fonctionne assez bien. Toute idée d'où pourrait être le problème?
J'ai écrit cet algorithme très similaire à ce C# algorithme du Perceptron:
EDIT:
Voici un exemple avec un plus petit ensemble de formation:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
float randomFloat()
{
float r = (float)rand() / (float)RAND_MAX;
return r;
}
int calculateOutput(float weights[], float x, float y)
{
float sum = x * weights[0] + y * weights[1];
return (sum >= 0) ? 1 : -1;
}
int main(int argc, char *argv[])
{
srand(time(NULL));
//X coordinates of the training set.
float x[] = { -3.2, 1.1, 2.7, -1 };
//Y coordinates of the training set.
float y[] = { 1.5, 3.3, 5.12, 2.1 };
//The training set outputs.
int outputs[] = { 1, -1, -1, 1 };
int i = 0; //iterator
FILE *fp;
system("PAUSE");
int patternCount = sizeof(x) / sizeof(int);
float weights[2];
weights[0] = randomFloat();
weights[1] = randomFloat();
float learningRate = 0.1;
int iteration = 0;
float globalError;
do {
globalError = 0;
int p = 0; //iterator
for (p = 0; p < patternCount; p++)
{
//Calculate output.
int output = calculateOutput(weights, x[p], y[p]);
//Calculate error.
float localError = outputs[p] - output;
if (localError != 0)
{
//Update weights.
for (i = 0; i < 2; i++)
{
float add = learningRate * localError;
if (i == 0)
{
add *= x[p];
}
else if (i == 1)
{
add *= y[p];
}
weights[i] += add;
}
}
//Convert error to absolute value.
globalError += fabs(localError);
printf("Iteration %d Error %.2f\n", iteration, globalError);
}
iteration++;
} while (globalError != 0);
//Display network generalisation.
printf("X Y Output\n");
float j, k;
for (j = -1; j <= 1; j += .5)
{
for (j = -1; j <= 1; j += .5)
{
//Calculate output.
int output = calculateOutput(weights, j, k);
printf("%.2f %.2f %s\n", j, k, (output == 1) ? "Blue" : "Red");
}
}
//Display modified weights.
printf("Modified weights: %.2f %.2f\n", weights[0], weights[1]);
system("PAUSE");
return 0;
}
- Petite suggestion: Sortie après "Impossible d'ouvrir le fichier" ou au moins d'initialiser les tableaux avec quelque chose dans ce cas.
- BTW, le jeu de données semble valide - mis en ligne une rapide n'dirty POV-Ray de visualisation: img175.imageshack.us/img175/7135/pointtest.png
- Pourquoi voulez-vous assumer l'erreur d'aller à 0? Droit maintenant, le globalError est calculé comme le journal de la perte, qui doit être réduite au minimum, mais pas de zéro. Si vos données est voulu par la conception séparable alors le 0-1 perte pourrait frapper 0 (même si ce n'est de nouveau pas certain à cause de la stochasticité de la descente de gradient).
- Je ne suis pas vraiment bon en maths, mais il devrait converger vers 0 si les deux ensembles de points sont lineary séparables. J'ai aussi vérifié un article de Wikipédia à propos de Perceptron et mon algorithme semble être correct. J'ai ajouté un exemple avec un petit ensemble de formation ci-dessous, vous pouvez vérifier la façon dont il devrait fonctionner.
- C/C++ Perceptron: sourceforge.net/projects/ccperceptron
- La suite lib pourrait vous aider: sourceforge.net/projects/c-c-neural-networks
Vous devez vous connecter pour publier un commentaire.
Dans votre code actuel, le perceptron avec succès apprend le sens de la décision de la frontière, MAIS est incapable de traduire il.
(comme quelqu'un l'a souligné, voici une version plus précise)
Le problème réside dans le fait que votre perceptron a pas de biais terme, soit un tiers du poids du composant connecté à une entrée de valeur 1.
Voici comment j'ai résolu le problème:
... avec la sortie suivante:
Et voici un court métrage d'animation de le code ci-dessus à l'aide de MATLAB, montrant la décision de la frontière à chaque itération:
y = ax + c
est l'équation de la ligne de séparation. Comment puis-je obtenira
etc
constantes de poids de appris perceptron?w0*x + w1*y + w2 = 0
oùw_i
le poids appris (poids des composants connectés à l'x/y entrées + le biais, reportez-vous au schéma au début du post). Évidemment, vous pouvez réorganiser les conditions pour être de la forme y=ax+bif (outputs[i] == 0) outputs[i] = -1;
est retiré?calculateOutput
retourne -1 ou +1, que j'ai gardé à partir du code original. La classe de la cible à l'origine, dataset fichier est codé comme 0/1, d'où la nécessité de remplacer le 0 à -1.Il pourrait aider si vous mettez le semis du générateur aléatoire au début de votre principal à la place de réensemencement sur chaque appel à
randomFloat
, c'est à direQuelques petites erreurs que j'ai repéré dans votre code source:
Mieux de changer ce
de sorte que vous n'avez pas à compter sur votre x tableau de la bonne taille.
Vous augmentez itérations à l'intérieur de la boucle p, alors qu'à l'origine le code C# est-ce à l'extérieur de la p de la boucle. Mieux déplacer le printf et l'itération++ à l'extérieur de la boucle p avant la PAUSE de l'instruction aussi j'aimerais supprimer l'instruction de PAUSE ou changer pour
Même à faire tous ces changements, votre programme ne fonctionne toujours pas mettre fin à l'utilisation de votre ensemble de données, mais la production est plus cohérente, en donnant une erreur oscillant quelque part entre 56 et 60.
La dernière chose que vous pouvez essayer est de tester l'original programme C# sur ce jeu de données, si elle aussi n'est pas arrêter, il y a quelque chose de mal avec l'algorithme (parce que votre dataset semble correct, voir ma visualisation commentaire).
globalError
ne deviendra pas zéro, il convergent pour de zéro, comme vous l'avez dit, c'est à dire qu'il va devenir très faible.Changer votre boucle comme tel:
Donner
maxIterations
etmaxError
valeurs applicables à votre problème.