2014년 11월 8일 토요일

MBP 사용 XOR 학습하기

앞에서 다른 툴을 사용할때 대부분 XOR예제를 들었습니다.
이번에도 XOR로 예제를 할껀데요, Multi-layer이므로 hidden을 2개 2개 연결하는 전체 layer를 4개가 되도록 만들겠습니다.
이미 다른 툴에서도 같은 방식으로 테스트 하였습니다.




빨간색으로 표시된 부분에 node형태를 기록합니다. 2-2-2-1 을 적어주면 자동으로 아래와 같은 신경망이 생기게 됩니다.

학습 데이터는 CSV 파일로 입력하면 되는데 ","로 구별되게 만들면 됩니다. excel 로 만들거나 open office 또는 직접만들면 됩니다.

x1,x2,y
0,0,0
1,0,1
0,1,1
1,1,0

train data를 선택하고 가중치 값을 randomize 설정합니다. 일반적으로 -0.5~0.5 구간으로 설정하고 train 버튼을 누릅니다.


해당 결과를 C언어로 생성하면 다음과 같다

/**
 Generated by Multiple Back-Propagation Version 2.2.4
 Multiple Back-Propagation can be freely obtained at http://dit.ipg.pt/MBP
*/

#include <math.h>
/**
 inputs  - should be an array of 2 element(s), containing the network input(s).
 outputs - should be an array of 1 element(s), that will contain the network output(s).
 Note : The array inputs will also be changed.Its values will be rescaled between -1 and 1.
*/
void test1(double * inputs, double * outputs) {
 double mainWeights[] = {-3.432557344436646, 3.249020814895630, 3.257052659988403, 2.534264326095581, 2.839271068572998, 2.841655492782593, -2.028863191604614, -5.165799140930176, 4.703624248504639, 0.984100341796875, 1.948586821556091, -2.196990251541138, -2.397869348526001, 8.108511924743652, -3.533092021942139};
 double * mw = mainWeights;
 double hiddenLayer1outputs[2];
 double hiddenLayer2outputs[2];
 int c;

 inputs[0] = -1.0 + (inputs[0] - 0.000000000000000) / 0.500000000000000;
 inputs[1] = -1.0 + (inputs[1] - 0.000000000000000) / 0.500000000000000;
 hiddenLayer1outputs[0] = *mw++;
 for(c = 0; c < 2; c++) hiddenLayer1outputs[0] += *mw++ * inputs[c];
 hiddenLayer1outputs[0] = 1.0 / (1.0 + exp(-hiddenLayer1outputs[0]));
 hiddenLayer1outputs[1] = *mw++;
 for(c = 0; c < 2; c++) hiddenLayer1outputs[1] += *mw++ * inputs[c];
 hiddenLayer1outputs[1] = 1.0 / (1.0 + exp(-hiddenLayer1outputs[1]));
 hiddenLayer2outputs[0] = *mw++;
 for(c = 0; c < 2; c++) hiddenLayer2outputs[0] += *mw++ * hiddenLayer1outputs[c];
 hiddenLayer2outputs[0] = 1.0 / (1.0 + exp(-hiddenLayer2outputs[0]));
 hiddenLayer2outputs[1] = *mw++;
 for(c = 0; c < 2; c++) hiddenLayer2outputs[1] += *mw++ * hiddenLayer1outputs[c];
 hiddenLayer2outputs[1] = 1.0 / (1.0 + exp(-hiddenLayer2outputs[1]));
 outputs[0] = *mw++;
 for(c = 0; c < 2; c++) outputs[0] += *mw++ * hiddenLayer2outputs[c];
 outputs[0] = 1.0 / (1.0 + exp(-outputs[0]));
 outputs[0] = 0.000000000000000 + (outputs[0] - 0.000000) * 1.000000000000000;
}

위 소스를 java로 변경하여 테스트 해보았습니다.
public class MBPtest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  
  double []inputs = new double [2];
  double []outputs = new double [1];
  inputs[0]=0d;
  inputs[1]=0d;
  test1(inputs,outputs);
  System.out.println("test1 : 0 0 "+outputs[0]);

  inputs[0]=0d;
  inputs[1]=1d;
  test1(inputs,outputs);
  System.out.println("test1 : 0 1 "+outputs[0]);

  inputs[0]=1d;
  inputs[1]=0d;
  test1(inputs,outputs);
  System.out.println("test1 : 1 0 "+outputs[0]);

  inputs[0]=1d;
  inputs[1]=1d;
  test1(inputs,outputs);
  System.out.println("test1 : 1 1 "+outputs[0]);
 }
 public static void test1(double []inputs, double []outputs) {
  double mainWeights[] = {-3.432557344436646, 3.249020814895630, 3.257052659988403, 2.534264326095581, 2.839271068572998, 2.841655492782593, -2.028863191604614, -5.165799140930176, 4.703624248504639, 0.984100341796875, 1.948586821556091, -2.196990251541138, -2.397869348526001, 8.108511924743652, -3.533092021942139};
  double [] mw = mainWeights;
  int mwindex = 0;
  double []hiddenLayer1outputs = new double[2];
  double []hiddenLayer2outputs = new double[2];
  int c;

  inputs[0] = -1.0 + (inputs[0] - 0.000000000000000) / 0.500000000000000;
  inputs[1] = -1.0 + (inputs[1] - 0.000000000000000) / 0.500000000000000;
  hiddenLayer1outputs[0] = mw[mwindex++];
  for(c = 0; c < 2; c++) hiddenLayer1outputs[0] += mw[mwindex++] * inputs[c];
  hiddenLayer1outputs[0] = 1.0 / (1.0 + Math.exp(-hiddenLayer1outputs[0]));
  hiddenLayer1outputs[1] = mw[mwindex++];
  for(c = 0; c < 2; c++) hiddenLayer1outputs[1] += mw[mwindex++] * inputs[c];
  hiddenLayer1outputs[1] = 1.0 / (1.0 + Math.exp(-hiddenLayer1outputs[1]));
  hiddenLayer2outputs[0] = mw[mwindex++];
  for(c = 0; c < 2; c++) hiddenLayer2outputs[0] += mw[mwindex++] * hiddenLayer1outputs[c];
  hiddenLayer2outputs[0] = 1.0 / (1.0 + Math.exp(-hiddenLayer2outputs[0]));
  hiddenLayer2outputs[1] = mw[mwindex++];
  for(c = 0; c < 2; c++) hiddenLayer2outputs[1] += mw[mwindex++] * hiddenLayer1outputs[c];
  hiddenLayer2outputs[1] = 1.0 / (1.0 + Math.exp(-hiddenLayer2outputs[1]));
  outputs[0] = mw[mwindex++];
  for(c = 0; c < 2; c++) outputs[0] += mw[mwindex++] * hiddenLayer2outputs[c];
  outputs[0] = 1.0 / (1.0 + Math.exp(-outputs[0]));
  outputs[0] = 0.000000000000000 + (outputs[0] - 0.000000) * 1.000000000000000;
 }
}


결과는 아래와 같이 나왔습니다.

test1 : 0 0 0.022113442375209617
test1 : 0 1 0.9805543032118464
test1 : 1 0 0.980571510242402
test1 : 1 1 0.018783890881570123
굉장히 편한 도구입니다. 대부분의 학습은 속도가 느리기 때문에 해당 툴을 CUDA를 이용해서 학습 후 결과만 받아서, 사용하는 곳에서는 그 결과를 이용해서 구현하면 되기 때문에 모바일 환경에서도 쉽게 구현할 수 있을것 같습니다.



댓글 없음:

댓글 쓰기