maekawatoshiki
3/8/2015 - 5:04 AM

Hierarchical neural network

Hierarchical neural network

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
using namespace std;
#define NUM_LEARN 20000 //学習の繰り返し回数
#define NUM_SAMPLE 4 //トレーニングデータのサンプル数(ここでは論理回路なので4個、学習1回の中でのループ回数)
#define NUM_INPUT 2 //入力層の数(論理回路の入力)
#define NUM_HIDDEN 5 //中間層の数(適当)
#define NUM_OUTPUT 1 //出力層の数(出力数1個)
#define EPSILON 0.1 //学習時の重み修正定数(η)


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

struct NN
{
	int x[NUM_INPUT];
	int y[NUM_OUTPUT];
};


NN txy[NUM_SAMPLE] = { 0 };
double x[NUM_INPUT+1],h[NUM_HIDDEN+1],y[NUM_OUTPUT];
double w1[NUM_INPUT+1][NUM_HIDDEN],w2[NUM_HIDDEN+1][NUM_OUTPUT];
double h_back[NUM_HIDDEN+1],y_back[NUM_OUTPUT];
//中間、出力の逆伝播量


int main(void){

 	int learn, sample, i, j;
 	double net_input;
	
	srand((unsigned)time(NULL));

	//教師データ(txが入力、tyが出力)
	txy[0].x[0]=0;
	txy[0].x[1]=0;
	txy[0].y[0]=0;
	
	txy[1].x[0]=0;
	txy[1].x[1]=1;
	txy[1].y[0]=1;
	
	txy[2].x[0]=1;
	txy[2].x[1]=0;
	txy[2].y[0]=1;
	
	txy[3].x[0]=1;
	txy[3].x[1]=1;
	txy[3].y[0]=0;

	for(i = 0;i < NUM_INPUT+1; i++)
	  for(j = 0;j < NUM_HIDDEN; j++)
			w1[i][j]= (double)rand() / RAND_MAX;

	for(i = 0;i < NUM_HIDDEN+1; i++)
		for(j = 0;j < NUM_OUTPUT; j++)
			w2[i][j]= (double)rand() / RAND_MAX;

	for(learn = 0; learn < NUM_LEARN; learn++)
	{
		//訓練データに関するループ
		for(sample = 0; sample < NUM_SAMPLE; sample++)
		{
			//順方向の動作
			//訓練データに従って、ネットワークへの入力設定
			for(i = 0;i < NUM_INPUT; i++)
				x[i] = txy[sample].x[i];
	
			//閾値設定x[NUM_INPUT] = 1.0
			x[NUM_INPUT] = (double)1.0;
	
			//隠れ素子の計算
			for( j = 0; j < NUM_HIDDEN;j++)
			{
			 	net_input = 0;
			 	for( i = 0; i < NUM_INPUT+1; i++ )
			 		net_input = net_input + w1[i][j] * x[i];
				//シグモイドの適用
			 	h[j] = sigmoid(net_input);
     			}
	
			//閾値設定h[NUM_HIDDEN] = 1.0
			h[NUM_HIDDEN] = (double)1.0;
	
	
			//出力素子の計算
			for (j = 0; j < NUM_OUTPUT;j++)
			{
      			net_input = 0;
     				for(i = 0;i < NUM_HIDDEN+1; i++)
					net_input = net_input + w2[i][j]*h[i];
				//シグモイドの適用
				y[j]=sigmoid(net_input);
				printf("y > %lf (%d.%d)\n", y[j], txy[sample].x[0], txy[sample].x[1] );
			}
	
			//逆方向の動作
			//出力層素子の逆伝播
			for(j = 0; j < NUM_OUTPUT; j++)
     	 			y_back[j] = ( y[j] - txy[sample].y[j] ) * ( 1.0 - y[j] ) * y[j];
			
			//隠れ層素子の逆伝播
  			for(i = 0; i < NUM_HIDDEN;i++)
			{
				net_input = 0;
				
				for(j = 0; j < NUM_OUTPUT; j++)
					net_input = net_input + w2[i][j] * y_back[j];
	
				h_back[i] = net_input * ((double)1.0 - h[i]) * h[i];
			}
		
			//重みの修正
  			for(i = 0; i < NUM_INPUT+1; i++)
  				for(j = 0; j < NUM_HIDDEN; j++)
					w1[i][j] = w1[i][j] - EPSILON * x[i] * h_back[j];
  			for(i = 0; i < NUM_HIDDEN+1; i++)
  				for(j = 0; j < NUM_OUTPUT; j++)
    					w2[i][j] = w2[i][j] - EPSILON * h[i] * y_back[j];

    		}//訓練データのループ終わり
  
	}//学習データのループ終わり

	for(i = 0;i < NUM_INPUT; i++)
	{
		cin >> x[i];
	}

	//閾値設定x[NUM_INPUT] = 1.0
	 h[NUM_HIDDEN] = x[NUM_INPUT] = (double)1.0;

	//隠れ素子の計算
	for( j = 0; j < NUM_HIDDEN;j++)
	{
	 	net_input = 0;
	 	for(i = 0; i < NUM_INPUT+1; i++)
	 	{
	 		net_input = net_input + w1[i][j] * x[i];
	 	}
		//シグモイドの適用
	 	h[j] = sigmoid(net_input);
     }

	for (j = 0; j < NUM_OUTPUT;j++)
	{
      	net_input = 0;

     		for(i = 0;i < NUM_HIDDEN+1; i++)
			net_input += w2[i][j] * h[i];

		y[j]=sigmoid(net_input);
		printf("y > %lf (%d.%d)\n", y[j], txy[sample].x[0], txy[sample].x[1] );
	}

	return 0;
}