/* ahh.h */


/* 역전파 다층 신경망을 구현한 헤더 입니다.*/


//뉴런 구조체 

typedef struct CZ_NURUN

{

        double *weight; //입력 가중치

        double thold;  //임계치 

        double out; //출력값 

        double error_gradient; // 오차기울기 

}NURUN;


typedef struct CZ_ANN 

{

        int layer; //총 층의 개수

        int *nurun_num; //각 층별 뉴런의 개수

        int input_num;     //초기 뉴런의 입력 개수 

        double alpa;

        NURUN **nurun; //전체 뉴런의 가중치 정보 실질적인 뉴런 

}ANN;


//뉴런 초기화 대상, 은닉층개수, 각 층별 뉴런의 개수, 층별 뉴런의 입력개수 

int Init_ANN(struct CZ_ANN *ann,int hidden,int *nurun_num, int input_num);

double Porjection_ANN(struct CZ_ANN *ann,int *input); //정방향연산 

double step(double x);

double sigmoid(double x);

double error_gradient(struct CZ_ANN *ann,int layer, int nurun, double error); //출력층의 오차기울기 

double error(double dst_out, double now_out);          //오차리턴

double error_gradient_for_hidden(struct CZ_ANN *ann,int layer, int nurun); //은닉층의 오차기울기 

double weight_ubdate( struct CZ_ANN *ann,int layer, int nurun, int weight, double input,double dest_out);



double weight_ubdate( struct CZ_ANN *ann,int layer, int nurun, int weight, double input ,double dest_out)

{

       double error = 0;

       error = dest_out - ann->nurun[layer][nurun].out;

       if(layer == ann->layer -1)ann->nurun[layer][nurun].weight[weight] = ann->alpa * input * error_gradient(ann,layer,nurun,error);

       ann->nurun[layer][nurun].weight[weight] = ann->alpa * input * error_gradient_for_hidden(ann,layer,nurun);

       return 0;

}


double error(double dst_out, double now_out){return dst_out - now_out;}

double error_gradient(struct CZ_ANN *ann,int layer, int nurun, double error)

{

       ann->nurun[layer][nurun].error_gradient =  ann->nurun[layer][nurun].out * (1 - ann->nurun[layer][nurun].out) * error;

       return ann->nurun[layer][nurun].error_gradient;

}

double error_gradient_for_hidden(struct CZ_ANN *ann,int layer, int nurun)

{

       double error = 0;

       int cnt =0;

       

       for(cnt=0; cnt < ann->nurun_num[layer+1] ; cnt++)

       error += ann->nurun[layer+1][cnt].error_gradient * ann->nurun[layer+1][cnt].weight[nurun];

        

       return error_gradient(ann,layer,nurun,error);

}


double sigmoid(double x){ return 1/(1+exp((-1)*x)); } 


double Porjection_ANN(struct CZ_ANN *ann,int *input)

{

      int layer,nurun,inp;

      

      for(layer=0; layer < ann->layer;layer++)//층에 접근 

      {

      for(nurun=0; nurun < ann->nurun_num[layer];nurun++)//뉴런에 접근 

      {

        ann->nurun[layer][nurun].out = 0; //선형 가산 

        if(layer==0)for(inp = 0; inp < ann->input_num;inp++) ann->nurun[layer][nurun].out += input[inp]*ann->nurun[layer][nurun].weight[inp];

        else  for(inp = 0; inp < ann->nurun_num[layer-1];inp++)         

        ann->nurun[layer][nurun].out += ann->nurun[layer-1][inp].out*ann->nurun[layer][nurun].weight[inp];

        ann->nurun[layer][nurun].out = sigmoid(ann->nurun[layer][nurun].out - ann->nurun[layer][nurun].thold);

      }

     

      }

      

      return 0; 

}



double step(double x)

{

    if( x < 0 ) return 0;

    else return 1; 

}


int Init_ANN(struct CZ_ANN *ann,int hidden,int *nurun_num, int input_num)

{

    int cnt, cnt2,cnt3; 

    

    ann->alpa = 0.01;

    ann->layer=hidden+1; //출력층의 개수를 포함

    

    ann->nurun_num = (int*)malloc(sizeof(int)*ann->layer);

    

    

    //층별 뉴런 정보 할당 

    for(cnt=0;cnt<ann->layer;cnt++) ann->nurun_num[cnt] = nurun_num[cnt];

    ann->input_num = input_num;     //초기입력개수 할당 

         

    ann->nurun = (NURUN**)malloc(sizeof(NURUN)*ann->layer);//레이어 할당

    for(cnt=0;cnt < ann->layer;cnt++) ann->nurun[cnt] = (NURUN*)malloc(sizeof(NURUN)*ann->nurun_num[cnt]);//뉴런할당

    

    

    for(cnt=0;cnt < ann->layer;cnt++)for(cnt2=0;cnt2 < ann->nurun_num[cnt];cnt2++)

    if(cnt == 0)ann->nurun[cnt][cnt2].weight = (double*)malloc(sizeof(double)*ann->input_num);//촉수할당

    else ann->nurun[cnt][cnt2].weight = (double*)malloc(sizeof(double)*ann->nurun_num[cnt-1]);//하층뉴런의 입력개수는 상층뉴런의 개수와 동일 

    

    

    //초기 가중치 할당 

    for(cnt=0;cnt < ann->layer;cnt++)for(cnt2=0;cnt2 < ann->nurun_num[cnt];cnt2++)

    if(cnt==0)for(cnt3=0;cnt3<ann->input_num;cnt3++)ann->nurun[cnt][cnt2].weight[cnt3] = 1;//입력측의 가중치는 생각하지 말자.. 

    else for(cnt3=0;cnt3<ann->nurun_num[cnt-1];cnt3++)ann->nurun[cnt][cnt2].weight[cnt3] = cnt2;

    

    return 0;

}


/* main.c */

#include <stdio.h>

#include <stdlib.h>

#include <math.h>

#include "ann.h"


int main()

{

    ANN ann; //뉴런 생성 

    int hidden = 1;

    int nurun_num[2] = {2,1};

    int input_num = 2; 

    int input[4][2] = {0,0,0,1,1,0,1,1};

    

    int cnt, cnt2, cnt3;

    

    

    //뉴런 초기화 

    Init_ANN(&ann,hidden,nurun_num,input_num);

    

      

    

    ann.nurun[0][0].thold = 7.3061;

    ann.nurun[0][1].thold = 2.8441;

    ann.nurun[1][0].thold = 4.5589;

    

    

    ann.nurun[0][0].weight[0] = 4.7621;

    ann.nurun[0][0].weight[1] = 4.7618;

    ann.nurun[0][1].weight[0] = 6.3917;

    ann.nurun[0][1].weight[1] = 6.3917;

    ann.nurun[1][0].weight[0] = -10.3788;

    ann.nurun[1][0].weight[1] = 9.7691;

    

    int a =0;

    printf("다층 신경망 Xor 학습\n");

    for(a=0;a<4;a++)

{


    Porjection_ANN(&ann,input[a]); //뉴런에 입력을 넣어 연산을 본다. 

    

    /*

    for(cnt=0;cnt < ann.layer;cnt++)

    {

     for(cnt2=0;cnt2 < ann.nurun_num[cnt];cnt2++)

     {     

       printf("출력 : %lf ",ann.nurun[cnt][cnt2].out);

       printf(" ");

     }

     printf("\n");

    

    }*/

    

    for(cnt2=0;cnt2 < ann.nurun_num[ann.layer-1];cnt2++)

     {     

       printf("\n입력 : %d Xor %d ",input[a][0],input[a][1]);

       printf("출력 : %lf ",ann.nurun[ann.layer-1][cnt2].out);

       printf("판정 : %lf ",step(ann.nurun[ann.layer-1][cnt2].out - 0.5));

     }

     printf("\n");


}

    printf("\n");

    system("pause");

    return 0;



폴더 정리하다 발견한 거 투척.

좀 오래전에 만들다 던졌던 것 같은데, 다층신경망이랍시고 만든 다음에 역전파 만들려다가 귀찮아서 때려침 -_-;;

덕분에 신경망인데 학습을 못하는 장애를 가진 코드 가 탄생 ㅋㅋ


어릴때의 나는 지금보다 똑똑했던 것 같다 ㅠ