오늘은 베토벤 교향곡 9번 듣는 세 번째 날~^^*
다양한 악기들이 옹기종기 모여 아름다운 융단을 짜고 있는 아침 볕에 함께 앉아 눈을 감고 몸을 풀고 계셔요~^^* 저는 코딩공부 정리해서 돌아올게요~^^* 쓩우웅~^^*
네~^^* 오늘은, 클래스 Perceptron과 클래스 Point를 함께 연결하여, Point의 this.label을 known answer 알려진 값으로 사용하여 Perceptron을 훈련시켜 보겠습니다.
class Perceptron {
constructor(totalInputs, learningRate) {
this.weights = [];
this.learningConstant = learningRate;
for (let i = 0; i < totalInputs; i++) {
this.weights[i] = random(-1, 1);
}
//1. 모든 입력값에 대하여, 그 입력값을 자신의 가중치로 곱한다.
//1. For every input, multiply that input by its weight.
}
feedforward(inputs) {
let sum = 0;
for (let i = 0; i < this.weights.length; i++) {
sum += inputs[i] * this.weights[i];
}
//2. Sum all of the weighted input
//2. 가중치값이 반영된 입력값을 모두 더한다.
return this.activate(sum);
//총합에 대해 부호를 부여하는 함수 activate()을 호출합니다.
}
activate(sum) {
if (sum > 0) {
return 1;
} else {
return -1;
}
//3. Compute the output of the perceptron based on that sum passed through an activiation function (the sign of the sum)
//3. 총합에 +_부호를 부여하는 활성화 함수를 통과한 총합에 기반하여 perceptron 결과를 계산한다.
}
train(inputs, desired) {
let guess = this.feedforward(inputs);
let error = desired - guess;
for (let i = 0; i < this.weights.length; i++) {
this.weights[i] += error * inputs[i] * this.learningConstant;
}
}
//Supervised Learning 이 이루어 지는 함수입니다.
//1. known answer 알려진 답인 desired를 parameter로 받습니다.
//2. feedforward 함수를 호출하여 input 값을 arguement로 넘겨주며 답을 추측해 보라고 요구합니다.
//3.알려진 답 desired에서 feedforward 함수가 return해 준 추측값 guess를 뺄셈하여 변수 error에 저장합니다.
//4. error값과 input 값과 learningConstatnt 회당 학습률을 곱하여 새로운 가중치값으로 조정합니다.
//5. 이 전체 과정을 반복하면 좋겠지요~^^* 무한 반복함수인 draw()에서 train 함수를 호출하면 될 것 같네요~^^*
}
class Point{
constructor() {
this.x = random(width);
this.y = random(height);
this.label;
if(this.x > this.y) {
this.label = 1;
} else
{this.label = -1;
}
//x = y를 threshold 기준선으로 하여,
//x > y 의 경우 1
//x =< y 의 경우 -1
//판별값 label을 정하겠습니다.
}
show() {
stroke(0);
if (this.label == 1) {
fill(255);
} else{
fill(0);
}
//판별값이 1인 경우 흰색으로 칠합니다.
//판별값이 -1인 경우 검은색으로 칠합니다.
ellipse(this.x, this.y, 8, 8);
}
}
let perceptron;
let points = [];
function setup() {
createCanvas(400, 400);
perceptron = new Perceptron(3, 0.0001);
for (i = 0; i < 100; i++) {
points[i] = new Point();
}
}
function draw() {
background(150);
line(0,0, width, height);
for(i = 0; i < points.length; i++) {
points[i].show();
}
for(i = 0; i < points.length; i++) {
let inputs = [points[i].x, points[i].y];
perceptron.train(inputs,points[i].label);
//point의 위치좌표와 x= y theshold 기준선에 따른 known answer 알려진 값 lable를 argument로 넘겨주며, perceptron의 train 함수를 호출합니다.
}
}
그럼 이제 훈련 결과를 보러 우리 함께 가 볼까요~^^*
네…컴퓨터는 역시 빠른 학습자인 것 같아요… 너무 빠르게 정답에 도달하다 보니, 원래부터 정답이었나??? 의아한 느낌이 들어서요…~^^*
라고 생각해 보려니…
train 결과를 시각적으로 보여주는 단계가 없네요….그래서…,원래 Point만 계속 시각적으로 보여 주는 것 같아요….
훈련 결과가 맞다면, 즉 point의 label 값과 percetron의 guess 값이 같다면 초록색 그렇지 않다면 빨간색으로 표현해 보겠습니다!
class Perceptron {
constructor(totalInputs, learningRate) {
this.weights = [];
this.learningConstant = learningRate;
for (let i = 0; i < totalInputs; i++) {
this.weights[i] = random(-1, 1);
}
//1. 모든 입력값에 대하여, 그 입력값을 자신의 가중치로 곱한다.
//1. For every input, multiply that input by its weight.
}
feedforward(inputs) {
let sum = 0;
for (let i = 0; i < this.weights.length; i++) {
sum += inputs[i] * this.weights[i];
}
//2. Sum all of the weighted input
//2. 가중치값이 반영된 입력값을 모두 더한다.
return this.activate(sum);
//총합에 대해 부호를 부여하는 함수 activate()을 호출합니다.
}
activate(sum) {
if (sum > 0) {
return 1;
} else {
return -1;
}
//3. Compute the output of the perceptron based on that sum passed through an activiation function (the sign of the sum)
//3. 총합에 +_부호를 부여하는 활성화 함수를 통과한 총합에 기반하여 perceptron 결과를 계산한다.
}
train(inputs, desired) {
let guess = this.feedforward(inputs);
if (guess == desired) {
fill(0, 255, 0);
} else {
fill(255, 0, 0);
}
noStroke();
ellipse(inputs[0], inputs[1], 4, 4);
let error = desired - guess;
for (let i = 0; i < this.weights.length; i++) {
this.weights[i] += error * inputs[i] * this.learningConstant;
}
}
//Supervised Learning 이 이루어 지는 함수입니다.
//1. known answer 알려진 답인 desired를 parameter로 받습니다.
//2. feedforward 함수를 호출하여 input 값을 arguement로 넘겨주며 답을 추측해 보라고 요구합니다.
//3.알려진 답 desired에서 feedforward 함수가 return해 준 추측값 guess를 뺄셈하여 변수 error에 저장합니다.
//4. error값과 input 값과 learningConstatnt 회당 학습률을 곱하여 새로운 가중치값으로 조정합니다.
//5. 이 전체 과정을 반복하면 좋겠지요~^^* 무한 반복함수인 draw()에서 train 함수를 호출하면 될 것 같네요~^^*
}
우리…Point의 label 흑/백 Perceptron의 훈련 결과 (guess == label)를 함께 시각적으로 확인해 볼까요~^^*
이상한 것 같아요….
Point의 label과 Perceptron의 guess 값이 일치하면 초록색이 나와야 하는데…그렇다면…모든 동그라미들 내부에 초록색이 칠해져야 하는데…
이상하게도…
x>y 영역은 guess가 모두 틀린 값(빨강)으로 x < y 영역은 guess 가 모두 맞는 값(초록)으로 나오네요…
음….
training이 잘못되고 있는 것 같아요….
오늘 저와 함께 이상한 Perceptron을 발견해 주셔서 감사합니다~^^*
내일 우리 함께 고민을 이어나가 볼까요~^^*
네~^^* 좋아요~^^* 고마워요~^^*
올바르게 guess 추측한다는 것이 생각보다 어렵네요…지금 공부하고 있는 동영상 강의가 p5.js가 아니라 processing 언어로 설명되고 있어서, 제가 p5.js 언어표현으로 비슷하게 바꾸어가며 하고 있는데, 그 과정에서 뭔가 잘못되었을 수도 있을 것 같아요…
앗!!!! 잠시만요!!!! 잘못된 것을 찾아 내었습니다!!!
가중치 값 배열을 만들 때….Point의 x좌표와 Point의 y좌표 값 두 개에 대한 가중치 값이 필요하기 때문에, 배열 구성원은 2개이면 충분할 것 같습니다!!!!
class Perceptron {
constructor(totalInputs, learningRate) {
this.weights = [];
this.learningConstant = learningRate;
for (let i = 0; i < totalInputs; i++) {
this.weights[i] = random(-1, 1);
}
//1. 모든 입력값에 대하여, 그 입력값을 자신의 가중치로 곱한다.
//1. For every input, multiply that input by its weight.
}
feedforward(inputs) {
let sum = 0;
for (let i = 0; i < this.weights.length; i++) {
sum += inputs[i] * this.weights[i];
}
//2. Sum all of the weighted input
//2. 가중치값이 반영된 입력값을 모두 더한다.
return this.activate(sum);
//총합에 대해 부호를 부여하는 함수 activate()을 호출합니다.
}
activate(sum) {
if (sum > 0) {
return 1;
} else {
return -1;
}
//3. Compute the output of the perceptron based on that sum passed through an activiation function (the sign of the sum)
//3. 총합에 +_부호를 부여하는 활성화 함수를 통과한 총합에 기반하여 perceptron 결과를 계산한다.
}
train(inputs, desired) {
let guess = this.feedforward(inputs);
if (guess == desired) {
fill(0, 255, 0);
} else {
fill(255, 0, 0);
}
noStroke();
ellipse(inputs[0], inputs[1], 4, 4);
let error = desired - guess;
for (let i = 0; i < this.weights.length; i++) {
this.weights[i] += error * inputs[i] * this.learningConstant;
}
}
//Supervised Learning 이 이루어 지는 함수입니다.
//1. known answer 알려진 답인 desired를 parameter로 받습니다.
//2. feedforward 함수를 호출하여 input 값을 arguement로 넘겨주며 답을 추측해 보라고 요구합니다.
//3.알려진 답 desired에서 feedforward 함수가 return해 준 추측값 guess를 뺄셈하여 변수 error에 저장합니다.
//4. error값과 input 값과 learningConstatnt 회당 학습률을 곱하여 새로운 가중치값으로 조정합니다.
//5. 이 전체 과정을 반복하면 좋겠지요~^^* 무한 반복함수인 draw()에서 train 함수를 호출하면 될 것 같네요~^^*
}
let perceptron;
let points = [];
function setup() {
createCanvas(400, 400);
perceptron = new Perceptron(2, 0.0001);
for (i = 0; i < 100; i++) {
points[i] = new Point();
}
}
function draw() {
background(150);
stroke(0);
line(0,0, width, height);
for(i = 0; i < points.length; i++) {
points[i].show();
}
for(i = 0; i < points.length; i++) {
let inputs = [points[i].x, points[i].y];
let target = points[i].label;
perceptron.train(inputs,target);
//point의 위치좌표와 x= y theshold 기준선에 따른 known answer 알려진 값 label을 argument로 넘겨주며, perceptron의 train 함수를 호출합니다.
}
}
네!!
inputs 배열은 Point의 x좌표 값과 y 좌표 값을 한 쌍의 구성원으로 가지고 있습니다.
이때, input[0]에는 Point의 x 좌표값이 들어가고 input[1]에는 Point의 y 좌표값이 들어가게 됩니다.
그래서 x좌표 값과 연결된 가중치 값, y좌표 값과 연결된 가중치 값 총 두 개의 가중치 값이 필요하게 됩니다.
그래서 Perceptron을 생성하려고 할 때, totalInputs 갯수를 2개로 지정하여 호출하여야,
<input[0] ~ weight[0]>와 <input[1] ~ weight[1]> 이 서로 짝을 지을 수 있습니다~^^*
오늘 저와 함께 Perceptron이 올바르게 답을 찾아내는 훈련의 결과를 시각적으로 프로그램을 개선해 주셔서 감사합니다~^^*
와우!!! 벌써 점심시간이 되어가네요!!! 매우 흥미진진한 아침시간을 저와 함께 보내 주셔서 감사합니다~~~!!!
근데요~~ 이건 뭘까요~~ Guess What~~^^* 우리도 perceptron이 되어 볼까요~~^^*
Perceptron의 매력을 담뿍 느낀 아침이었습니다~^^* 쉽지 않지만 재미있는 Perceptron!
너무너무 창의적이고 재미있지만 매우 어려운 안무를 해내었을 때의 성취감!이 지금 우리가 느끼고 있는 감정인가요~~^^*
오늘도 보람찬 하루 보내시고요!
뿌듯한 마음 안고 깊은 밤 코~^^* 하시기 바래요~^^*
네~^^* 꿈은 이루어 집니다~^^*
댓글 남기기