Perceptron 학습 알고리즘이 0으로 수렴되지 않음
ANSI C에서의 perceptron 실장은 다음과 같습니다.
#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
파일화하여 3개의 어레이에 값을 로드합니다.x
,y
,outputs
.
다음으로 어떤 이유로 0으로 수렴되지 않는 퍼셉트론 학습 알고리즘이 있습니다.globalError
0)으로 수렴해야 하기 때문에 무한 do while loop이 발생합니다.
작은 트레이닝 세트(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;
}
현재 코드에서 퍼셉트론은 결정 경계의 방향을 성공적으로 학습하지만 이를 번역할 수 없습니다.
y y y y^ ^| - + \\ + | - \\ + +| - +\\ + + | - \\ + + +| - - \\ + | - - \\ +| - - + \\ + | - - \\ + +-------------------------------------------> x이렇게 될 필요가 있어서 꼼짝 못하고 있다
(누군가 지적한 바와 같이, 여기 더 정확한 버전이 있습니다.)
문제는 퍼셉트론이 바이어스 항(즉, 값 1의 입력에 연결된 세 번째 무게 성분)을 가지고 있지 않다는 데 있습니다.
w0 -----x ---->| || f |----> 출력(+1/-1)y ---->| |w1 -----^ w21(표준) ---|
문제를 수정한 방법은 다음과 같습니다.
#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을 사용한 위의 코드 애니메이션으로, 각 반복 시 결정 경계를 보여줍니다.
모든 호출에 재시딩하는 대신 랜덤 제너레이터의 시딩을 메인 시작 부분에 배치하면 도움이 될 수 있습니다.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 어레이에 의존할 필요가 없습니다.
원래 C# 코드는 이것을 p루프 밖에서 실행하는 반면 p루프 내부에서 반복을 늘립니다.printf와 repeating++를 PAUSE 스테이트먼트 전에 p루프 밖으로 이동하는 것이 좋습니다.또, PAUSE 스테이트먼트를 삭제하거나, 로 변경합니다.
if ((iteration % 25) == 0) system("PAUSE");
이러한 모든 변경을 해도 프로그램은 데이터 세트를 사용하여 종료되지 않지만 출력은 더 일관성이 있어 56에서 60 사이의 오차가 발생합니다.
이 데이터셋에서 원래 C# 프로그램을 테스트하는 것은 마지막입니다.이 프로그램도 종료되지 않으면 알고리즘에 문제가 있는 것입니다(데이터셋이 올바르게 보이므로 시각화 코멘트를 참조하십시오).
globalError
0이 되지 않습니다. 말씀하신 대로 0으로 수렴됩니다. 즉, 매우 작아집니다.
다음과 같이 루프를 변경합니다.
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));
»를 maxIterations
★★★★★★★★★★★★★★★★★」maxError
을 사용하다
언급URL : https://stackoverflow.com/questions/1697243/perceptron-learning-algorithm-not-converging-to-0
'programing' 카테고리의 다른 글
정규화된 데이터가 있는 Vuex getter가 반응하지 않음 (0) | 2022.08.15 |
---|---|
상태가 200이고 응답이 있어도 Axios POST는 "Network Error"를 반환한다. (0) | 2022.08.15 |
Vuex - '변환 핸들러 외부의 vuex 저장소 상태를 변환하지 않음' (0) | 2022.08.15 |
C/C++에서 부호 없는 좌회전 전 마스킹이 너무 편집증적인가요? (0) | 2022.08.15 |
프로세스 내부에서 CPU 및 메모리 소비량을 확인하는 방법 (0) | 2022.08.15 |