퍼셉트론 학습 알고리즘이 0으로 수렴되지 않음
다음은 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;
}
내가 사용중인 교육 세트 : 데이터 세트
관련없는 코드를 모두 제거했습니다. 기본적으로는 지금 무엇을이 읽고 test1.txt
그것에서 세 개의 배열에 파일을로드 값을 : x
, y
, outputs
.
그런 다음 어떤 이유로 인해 0으로 수렴하지 않는 (0으로 수렴해야 함) 퍼셉트론 학습 알고리즘 이 globalError
있으므로 무한 do while 루프를 얻습니다.
더 작은 훈련 세트 (예 : 5 점)를 사용하면 꽤 잘 작동합니다. 문제가 될 수있는 아이디어가 있습니까?
이 알고리즘을이 C # Perceptron 알고리즘 과 매우 유사하게 작성했습니다 .
편집하다:
다음은 더 작은 학습 세트를 사용한 예입니다.
#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;
}
현재 코드에서 퍼셉트론 은 결정 경계의 방향을 성공적으로 학습하지만 번역 할 수 없습니다 .
yy ^ ^ | -+ \\ + | -\\ + + | -+ \\ + + | -\\ + + + | --\\ + | --\\ + | --+ \\ + | --\\ + + ---------------------> x --------------------> x 이렇게 붙어 있어야 할 필요가 있습니다.
(누군가 지적했듯이 여기에 더 정확한 버전이 있습니다 )
문제는 퍼셉트론에 바이어스 항 , 즉 값 1의 입력에 연결된 세 번째 가중치 성분 이 없다는 사실에 있습니다 .
w0 ----- x ----> | | | f | ----> 출력 (+ 1 / -1) y ----> | | w1 ----- ^ w2 1 (바이어스) --- |
다음은 문제를 해결 한 방법입니다.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define LEARNING_RATE 0.1
#define MAX_ITERATION 100
float randomFloat()
{
return (float)rand() / (float)RAND_MAX;
}
int calculateOutput(float weights[], float x, float y)
{
float sum = x * weights[0] + y * weights[1] + weights[2];
return (sum >= 0) ? 1 : -1;
}
int main(int argc, char *argv[])
{
srand(time(NULL));
float x[208], y[208], weights[3], localError, globalError;
int outputs[208], patternCount, i, p, iteration, output;
FILE *fp;
if ((fp = fopen("test1.txt", "r")) == NULL) {
printf("Cannot open file.\n");
exit(1);
}
i = 0;
while (fscanf(fp, "%f %f %d", &x[i], &y[i], &outputs[i]) != EOF) {
if (outputs[i] == 0) {
outputs[i] = -1;
}
i++;
}
patternCount = i;
weights[0] = randomFloat();
weights[1] = randomFloat();
weights[2] = randomFloat();
iteration = 0;
do {
iteration++;
globalError = 0;
for (p = 0; p < patternCount; p++) {
output = calculateOutput(weights, x[p], y[p]);
localError = outputs[p] - output;
weights[0] += LEARNING_RATE * localError * x[p];
weights[1] += LEARNING_RATE * localError * y[p];
weights[2] += LEARNING_RATE * localError;
globalError += (localError*localError);
}
/* Root Mean Squared Error */
printf("Iteration %d : RMSE = %.4f\n",
iteration, sqrt(globalError/patternCount));
} while (globalError > 0 && iteration <= MAX_ITERATION);
printf("\nDecision boundary (line) equation: %.2f*x + %.2f*y + %.2f = 0\n",
weights[0], weights[1], weights[2]);
return 0;
}
... 다음 출력으로 :
Iteration 1 : RMSE = 0.7206
Iteration 2 : RMSE = 0.5189
Iteration 3 : RMSE = 0.4804
Iteration 4 : RMSE = 0.4804
Iteration 5 : RMSE = 0.3101
Iteration 6 : RMSE = 0.4160
Iteration 7 : RMSE = 0.4599
Iteration 8 : RMSE = 0.3922
Iteration 9 : RMSE = 0.0000
Decision boundary (line) equation: -2.37*x + -2.51*y + -7.55 = 0
다음은 MATLAB을 사용한 위 코드의 짧은 애니메이션이며 각 반복에서 결정 경계 를 보여줍니다 .
당신이 행해져 Yout 주 시작시 무작위 생성기의 파종을 넣어 대신에 모든 호출에 시드 경우는 도움이 될 수도 randomFloat
, 즉
float randomFloat()
{
float r = (float)rand() / (float)RAND_MAX;
return r;
}
// ...
int main(int argc, char *argv[])
{
srand(time(NULL));
// X, Y coordinates of the training set.
float x[208], y[208];
소스 코드에서 발견 한 몇 가지 작은 오류 :
int patternCount = sizeof(x) / sizeof(int);
이것을 더 잘 변경하십시오.
int patternCount = i;
따라서 올바른 크기를 갖기 위해 x 배열에 의존 할 필요가 없습니다.
You increase iterations inside the p loop, whereas the original C# code does this outside the p loop. Better move the printf and the iteration++ outside the p loop before the PAUSE statement - also I'd remove the PAUSE statement or change it to
if ((iteration % 25) == 0) system("PAUSE");
Even doing all those changes, your program still doesn't terminate using your data set, but the output is more consistent, giving an error oscillating somewhere between 56 and 60.
The last thing you could try is to test the original C# program on this dataset, if it also doesn't terminate, there's something wrong with the algorithm (because your dataset looks correct, see my visualization comment).
globalError
will not become zero, it will converge to zero as you said, i.e. it will become very small.
Change your loop like such:
int maxIterations = 1000000; //stop after one million iterations regardless
float maxError = 0.001; //one in thousand points in wrong class
do {
//loop stuff here
//convert to fractional error
globalError = globalError/((float)patternCount);
} while ((globalError > maxError) && (i<maxIterations));
Give maxIterations
and maxError
values applicable to your problem.
참고URL : https://stackoverflow.com/questions/1697243/perceptron-learning-algorithm-not-converging-to-0
'programing' 카테고리의 다른 글
'jquery-ui'파일을 찾을 수 없습니다. (0) | 2020.11.26 |
---|---|
부모에서 자식으로 이벤트를 내보내는 방법은 무엇입니까? (0) | 2020.11.26 |
외부 CSS의 범위를 특정 요소로만 제한 하시겠습니까? (0) | 2020.11.25 |
gRPC (HTTP / 2)가 HTTP / 2를 사용하는 REST보다 빠릅니까? (0) | 2020.11.25 |
Java enum 및 추가 클래스 파일 (0) | 2020.11.25 |