バックプロパゲーション学習をMATLABとCで

XORを解く

目標

以下のようにXORの非線形分離をすること.

入力1 入力2 出力
0 0 0
1 0 1
0 1 1
1 1 0


最初の雛形

matlabファイル

入力2ユニット出力1ユニットは決まっているので,中間層のユニット数は実行時に変えられるようにしたい.
XORの入力と出力パターンは4通りのみ.
コントロール出来る擬似乱数にしたいので,しょぼくていいのでシードでコントロールできる乱数をつくっちゃいましょう.
もしくはsrand系で.
バイアスニューロンはXORに必須なので,その数も可変にします.
なので,コードを以下のようにしてみた.

kyoshi_input=[0,0; 0,1; 1,0; 1,1];
kyoshi_output=[0,1,1,0];
%bp(kyoshi_input, kyoshi_output, hidden_num,seed,bias_num);
[w1 w2] = bp(kyoshi_input, kyoshi_output, 10, 0.5, 1);
Cコード

を以下のようにする

#include <stdio.h>
#include <math.h>
#include "mex.h"
#define PI 3.1415

int *prdims0, *prdims1, *pldims0, *pldims1;
int pattern, input_num, output_num, hidden_num, i, j, k, randomcount, bias_num;
double *kyoshi_input, *kyoshi_output, *w1, *w2;
double seed;

randomcount=0;

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

void random(){
   double a, b, c, d, e;
   a = seed * PI + 0.5;
   b = a * PI;
   c = b * PI;
   d = c * PI;
   e = d * PI;
   randomcount++;
   if(randomcount%2==0){
       seed = e - (int)e;
   }else{
       seed = -(e - (int)e);
   }
}

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){

   //入力処理
   prdims0 = (int*)mxGetDimensions(prhs[0]);
   pattern = prdims0[0];
   input_num = prdims0[1] + bias_num;
   kyoshi_input = mxGetPr(prhs[0]);
   prdims1 = (int*)mxGetDimensions(prhs[1]);
   output_num = prdims1[0];
   kyoshi_output = mxGetPr(prhs[1]);
   hidden_num = (int)mxGetScalar(prhs[2]) + bias_num;
   seed = (double)mxGetScalar(prhs[3]);
   bias_num = (int)mxGetScalar(prhs[4]);
   printf(" %s%d\n %s%d\n %s%d\n %s%d\n", 
          "pattern:", pattern, 
          "input_num:", input_num, 
          "hidden_num:", hidden_num, 
          "output_num:", output_num,           
          "seed:", seed
          );

   //出力処理
   pldims0 = (int*)mxCalloc(2, sizeof(double));
   pldims0[0] = input_num;
   pldims0[1] = hidden_num;
   plhs[0] = mxCreateNumericArray(2, pldims0, mxDOUBLE_CLASS, mxREAL);
   w1 = mxGetPr(plhs[0]);
   pldims1 = (int*)mxCalloc(1, sizeof(double));
   pldims1[0] = hidden_num;
   plhs[1] = mxCreateNumericArray(1, pldims1, mxDOUBLE_CLASS, mxREAL);
   w2 = mxGetPr(plhs[1]);
   
   //w1と2の初期化    
   for(i=0;i<input_num;i++){
       for(j=0;j<hidden_num;j++){
           random();
           w1[i + j*input_num] = seed;
       }
   }
   for(j=0;j<hidden_num;j++){
       random();
       w2[j]=seed;
   }
   
}

mex後に実行するとちゃんとw1とw2が初期化されていることが分かります