본문 바로가기
재밌게 인공지능을 공부해보자!

딥러닝모델 단순 퍼셉트론 2 ( 학습과정과 코드구현) C,C++

by 토끼여우 2022. 3. 5.
728x90
SMALL
5분동안 열심히(?)만든 퍼셉트론의 학습이미지

저번에 마지막에 쓴 말처럼 선형 분리가 가능한 상태라는 것을 바탕을 깔겠습니다
초평면에 구성하는 매개변수는 W(가중치) b(편향)입니다

입력 데이터를 사용해서 매개변수 W, b를 추청 할 겁니다(구할 겁니다)
그러면 목적을 두겠습니다
목적 : 매개변수 W, b를 구하기

Xi Wi의 집합을 각각 백터로 정의할 수 있습니다
각 가중치를 벡터 W = {W0, W1, W2,...... Wn}

위에 그림을 보면 여러 입력이 보입니다
여러 벡터 중 하나 p 번째의 집합은
Xp = {Xp0, Xp1, Xp2,...... Wpn}
로 정의할 수 있습니다

확실히 딱 지금 모르더라도 걱정하지 말고
감만 어느 정도 이게 이렇게 돼서 이렇게 되는구나라고
감만 잡으면 됩니다

입력을 한 거에서 대응해서 맞는 것을 tp로 줍니다
그럼 위에 그림을 보면
Zp - tp , 즉 Zp와 tp의 차이를 E로 합니다

만약에 차이가 있다면 그 방향으로 w(가중치)를 조금 수정합니다
입력된 벡터는 데이터 수만큼 존재하고 모든 벡터 X0, X1, X2,....... Xp,..... Xn을 차례대로
입력해서 계산을 반복합니다

모든 데이터의 입력이 끝나면 P = 0으로 돌아와서 계산을 계속합니다

w가 변화하지 않게 되는 시점부터 계산을 종료하게 됩니다
수정량이 0 이 될 때입니다

수정량이 0이라는 뜻은 바로 정답 데이터와 차이가 없고 차이가 발생하지
않고 w가 잘 수정됐다는 것입니다

정답 데이터 사인에 차이가 발생하지 않게 정답을 출력하는 퍼셉트론을 구축할 수 있게 모델 구상도가 완성되었습니다

위에 그림을 수식을 나타내면 다음과 같습니다
w <- w + n(tp-Zp) Xp(0 < n <= 1)
(식이 이해가 되지 않는다면 위에 그림을 보면서 정확히는 아니 더라도 감만 어느 정도 잡는 거를 추천드립니다)


tp는 논리 연산이 참(True)일떄 1을 갖고 거짓(False)일 때는 0을 갖습니다 이것을 학습 데이터 또는 트레이닝 데이터라고 말합니다

n은 어느 정도 수정을 할지 제어하는 상수(const)입니다

그리고 이것을 학습 정도를 정한다고 결정돼서 학습률이라고 불립니다
값이 극단적이게 크거나 작지 않은 것을 설정합니다


ex) 학습 데이터가 1이고 최종 출력이 0 일 때는
갱신량은 n( 1 - 0 ) Xp = nXp


ex) 학습 데이터가 1이고 최종 출력이 1 일 때는
갱신량은 n( 1 - 1) Xp = 0
0이 되어 학습되었습니니다


감이 어느 정도 잡혔을 거라 생각합니다

하지만 구하려던 매개변수 W 가 무조건 반드시 1이라고는 할 수 없습니다
왜냐하면 평면을 분리하는 직선에서 입력 데이터에 따라서 여러 개의 초평면(OR, AND, XOR)이 존재하기 때문입니다

미리 준비된 데이터를 이용해서 매개변수를 예측하는 것을 지도 학습이라고 말합니다
또는 모델을 훈련한다고도 말합니다

이제 코드 구현을 하겠습니다
XOR(배타적 논리곱은 저번에 있던 글에 직선이 존재하지 않아서 단순 퍼셉트론에서는 사용을 못한다고 했습니다)

그래서 논리 연산에 AND(논리곱)을 이용하여 C++ 코드로 나타내면

#include <iostream>
#define DATA_NUMS 4 //매크로 변수 DATA_NUMS 4
#define WEIGHT_NUMS 3 //매크로 변수 DATA_WEIGHT 3
using namespace std;
//float(실수) 타입인 dot(점)변수에다가 매개변수에  float 타입 포인터  v1,v2 와 int(정수) 타입 len선언
float dot(float *v1, float *v2, int len)
{
	//실수형 sum을 0 으로 초기화선언
	float sum = 0;
    for (int i = 0; i < len; i++)
    {
    	//지역변수인 sum에다가 v1,v2의 len의 길이에 따라서 인덱스를 올려서 값들을 곱해서 저장
    	sum += v1[i] * v2[i];
     }
    //저장한 sum을 반환합니다
    return sum;
}
float step(float v)
{
	return v > 0 ? 1:0;
}

float forward(float *x,float *w, int len)
{
	float u = dot(x,w,len);
    return step(u);
}

void train(float *w, float *x, float t, float e, int len)
{
	float z = forward(x,w,len);
    for (int j(0); j < len; j++)
    {
    	w[j] += (t - z) * x[j] * e;
    }
}

int main(int argc, char const *argv[])
{
	float e = 0.1; // 학습률
    float x[DATA_NUMS] [WEIGHT_NUMS] = {{1,0,0},{1,0,1},{1,0,1},{1,1,1}}; //밑에 주석 참고
    float t[DATA_NUMS] = {0,0,0,1}; //논리곱(AND)
    //float t[DATA_NUMS] = {0,1,1,1}; //논리합(OR)
    float w[WEIGHT_NUMS] = {0,0,0};  //가중치 0 초기화 작업
  
    int epoch = 10;
    for (int i(0); i < epoch; i++)
    {
		cout << "epoch: " << i << ' ';
        for (int j(0); j < DATA_NUMS; j++)
        {
        	train(w,x[j], t[j], e , WEIGHT_NUMS);
        }
        for (int j(0); j < WEIGHT_NUMS; j++)
        {
        	cout << "w" << j << ":" << w[j] << ' ';
        }
    cout << endl;
    }
    
    for (int i(0); i < DATA_NUMS; i++)
    {
		cout << forward(x[i], w , WEIGHT_NUMS) << ' ';
    }
    cout << endl;
    
    return 0;
}


메인 함수에서 셋째 줄을 보면 논리합, 논리곱, 가중치를 정하는 게 있습니다
실행을 해서 0 0 0 1 이 출력이 되어서 논리곱이 정답이 되어있습니다

코드가 잘 이해가 안 된다면 처음부터 수식을 보면서 코드랑 비교해서 감만 잡으시길 바랍니다
외워봤자 도움이 안 됩니다! 이해부터 하세요!


단순 퍼셉트론은 여기까지입니다!

728x90
LIST