#include <stdio.h>
#include <math.h>
#include <stdlib.h>
/* 層の定義 */
#define R 3 /* 層の数 */
#define N1 2 /* 入力層のユニット数 */
#define NR 1 /* 出力層のユニット数 */
#define MAX_N 5 /* 層中の最大ユニット数 */
int n[R]={N1, 2, NR}; /* 各層のユニット数 */
typedef struct {
double w[MAX_N][MAX_N];
double theta[MAX_N];
double output[MAX_N];
double delta[MAX_N];
/* モーメント法 */
double w_t1[MAX_N][MAX_N];
double theta_t1[MAX_N];
} LayerRec;
LayerRec L[R];
/* 教師データの定義 */
#define P 4 /* 教師データの数 */
typedef struct {
double x[N1];
double t[NR];
} TeachData;
TeachData T[P]={ /* XOR */
0, 0, 0,
0, 1, 1,
1, 0, 1,
1, 1, 0,
};
/* 学習時の定数の定義 */
#define EPSILON 1.0e-3 /* 学習を停止する許容誤差 */
#define INIT_W 0.5 /* 結合荷重の初期乱数の範囲 */
#define INIT_THETA 1.0 /* 閾値の初期乱数の範囲 */
#define ETA_W 0.5 /* 結合荷重の学習係数 */
#define ETA_THETA 1.0 /* 閾値の学習係数 */
/* モーメント法 */
#define ALPHA_MIN 0.2 /* モーメント法の例 0.2 */
#define ALPHA_MAX 0.9
#define ALPHA_DELTA 0.001 /* 修正モーメント法の例 0.001 */
double Alpha;
#define f(u) (1/(1+exp(-(u))))
#define f_dash(o) (o*(1.0-o))
#define rnd() (2.0*(double)rand()/RAND_MAX-1.0)
/* [-1, 1] の乱数 */
#define square(x) ((x)*(x))
#define BeginTable() printf(" t E w1-11 w1-12 θ1-1 w1-21 w1-22 θ1-2 w2-11 w2-12 θ2-1\n")
#define BeginResultTable() printf(" p x1 x2 tp o\n")
#define EndTable() printf("\n")
#define BeginRow()
#define EndRow() printf("\n")
#define PrintValue(v) printf("%5g ", v)
/* ニューラルネットワークの初期化 */
Initialize()
{
int i, j, k;
for(k=1; k<R; k++)
for(i=0; i<n[k]; i++) {
for(j=0; j<n[k-1]; j++) {
L[k].w[i][j]=INIT_W*rnd();
L[k].w_t1[i][j]=0;
}
L[k].theta[i]=INIT_THETA*rnd();
L[k].theta_t1[i]=0;
}
}
/* 入力→出力 */
Forward(int p)
{
int i, j, k;
double u;
k=0;
for(i=0; i<n[k]; i++)
L[k].output[i]=T[p].x[i];
for(k=1; k<R; k++)
for(i=0; i<n[k]; i++) {
u=0.0;
for(j=0; j<n[k-1]; j++)
u+=L[k].w[i][j]*L[k-1].output[j];
u-=L[k].theta[i];
L[k].output[i]=f(u);
}
}
/* 出力→入力 */
Backward(int p)
{
int i, j, k, l;
double delta;
k=R-1;
for(i=0; i<n[k]; i++)
L[k].delta[i]= -(T[p].t[i]-L[k].output[i])*f_dash(L[k].output[i]);
/* 中間層の誤差 */
for(k=R-2; k>=1; k--)
for(i=0; i<n[k]; i++) {
delta=0.0;
for(l=0; l<n[k+1]; l++)
delta+=L[k+1].w[l][i]*L[k+1].delta[l];
L[k].delta[i]=delta*f_dash(L[k].output[i]);
}
}
/* 学習 */
Learn()
{
int i, j, k;
double delta;
for(k=R-1; k>=1; k--)
for(i=0; i<n[k]; i++) {
for(j=0; j<n[k-1]; j++) {
delta=-ETA_W*L[k].delta[i]*L[k-1].output[j]+Alpha*L[k].w_t1[i][j];
L[k].w[i][j]+=delta;
L[k].w_t1[i][j]=delta;
}
delta=ETA_THETA*L[k].delta[i]+Alpha*L[k].theta_t1[i];
L[k].theta[i]+=delta;
L[k].theta_t1[i]=delta;
}
}
/* 誤差関数 */
double MSE()
{
int i, k, p;
double E;
k=R-1; /* 出力層 */
E=0.0;
for(p=0; p<P; p++) {
Forward(p);
for(i=0; i<n[k]; i++)
E+=square(T[p].t[i]-L[k].output[i]);
}
return(E/P);
}
/* ニューラルネットワークの表示 */
PrintNetwork()
{
int i, j, k;
for(k=1; k<R; k++) {
for(i=0; i<n[k]; i++) {
for(j=0; j<n[k-1]; j++)
PrintValue(L[k].w[i][j]);
PrintValue(L[k].theta[i]);
}
}
}
Test(int p)
{
int i, k;
BeginRow();
PrintValue((double)p);
Forward(p);
k=0;
for(i=0; i<n[k]; i++)
PrintValue(L[k].output[i]);
k=R-1;
for(i=0; i<n[k]; i++)
PrintValue(T[p].t[i]);
for(i=0; i<n[k]; i++)
PrintValue(L[k].output[i]);
EndRow();
}
main()
{
int p, loop;
double E;
BeginTable();
Initialize();
E=MSE();
Alpha=ALPHA_MIN;
for(loop=0; E>EPSILON; loop++) {
if(loop%100==0) {
BeginRow();
PrintValue((double)loop);
PrintValue(E);
PrintNetwork();
EndRow();
}
for(p=0; p<P; p++) {
Forward(p); /* 出力の計算 */
Backward(p); /* 誤差逆伝播 */
Learn(); /* 各層の学習 */
}
E=MSE();
if(Alpha<ALPHA_MAX)
Alpha+=ALPHA_DELTA;
}
BeginRow();
PrintValue((double)loop);
PrintValue(E);
PrintNetwork();
EndRow();
EndTable();
/* テスト結果の出力 */
BeginResultTable();
for(p=0; p<P; p++)
Test(p);
EndTable();
}