上次用MATLAB做的,這次嘗試用C寫了下,有待改進!
#include <stdio.h>
#include <math.h>
double daoshu(double p)//求導數函數
{
double d;
d = 1/p;
return d;
}
int main(int argc,char argv[])
{
int n;
double P[10] = {4,11,23,34,47,58,62,71,89,97},D[10],OUT[10];//10個樣本
for(n=0;n<10;n++)//目標結果:D=1/P
{
D[n] = daoshu(P[n]);
}
double w11 = 1,w12 = 1,w13 = 1,w21 = 1,w22 = 1,w23 = 1;//初始權值
double v11,v12,v13,v2,y1,y2,y3,O;//加權和v,各層輸出y,O
int T = 0, epoch = 0;//週期T,輸入樣本次數epoch
double E = 0,Ee = 0,e = 0;//平均方差E,方差e
double Eta = 0.5,Delta11,Delta12,Delta13,Delta2;//步長Eta,梯度Delta
while(epoch==0||(0.5*0.1*Ee>0.00001&&T<200))//開始訓練;誤差較大繼續訓練,週期較少繼續訓練
{
Ee = 0;//誤差和歸零
for(n=0;n<10;n++)
{
//隱層加權求和
v11 = w11*P[n];
v12 = w12*P[n];
v13 = w13*P[n];
//隱層輸出
y1 = 1/(exp(-v11)+1);
y2 = 1/(exp(-v12)+1);
y3 = 1/(exp(-v13)+1);
//輸出層加權求和
v2 = w21*y1+w22*y2+w23*y3;
//輸出層輸出
O = 1/(exp(-v2)+1);
//輸出層誤差
e = D[n]-O;
//樣本方差累計
Ee = Ee+0.5*pow(e,2);
//輸出層梯度
Delta2 = e*O*(1-O);
//輸出層權值更新
w21 = w21+Eta*Delta2*y1;
w22 = w22+Eta*Delta2*y2;
w23 = w23+Eta*Delta2*y3;
//隱層梯度
Delta11 = y1*(1-y1)*(Delta2*(w21+w22+w23));
Delta12 = y2*(1-y2)*(Delta2*(w21+w22+w23));
Delta13 = y3*(1-y3)*(Delta2*(w21+w22+w23));
//隱層權值更新
w11 = w11+Eta*Delta11*P[n];
w12 = w12+Eta*Delta12*P[n];
w13 = w13+Eta*Delta13*P[n];
//樣本輸入數加一
epoch++;
}
//週期數加一
T++;
//平均方差
E = 0.5*0.1*Ee;
if(T<200)
printf("T = %d;E = %f\n",T,E);
}
//輸出訓練結果
printf("E = %e\n epoch = %d T = %d\n w11 = %f w12 = %f w13 = %f w21 = %f w22 = %f w23 = %f\n\n",E,epoch,T,w11,w12,w13,w21,w22,w23);
//仿真樣本
double Q[10] = {5,10,20,30,40,50,60,70,80,90};
for(n=0;n<10;n++)
{
D[n] = daoshu(Q[n]);
}
printf("Q: ");
for(n=0;n<10;n++)
{
printf("%f ",Q[n]);
}
printf("\n\n");
//目標結果
printf("D: ");
for(n=0;n<10;n++)
{
printf("%f ",D[n]);
}
printf("\n\n");
//仿真
for(n=0;n<10;n++)
{
v11 = w11*P[n];
v12 = w12*P[n];
y1 = 1/(exp(-v11)+1);
y2 = 1/(exp(-v12)+1);
v2 = w21*y1+w22*y2;
OUT[n] = 1/(exp(-v2)+1);
}
//仿真結果
printf("O: ");
for(n=0;n<10;n++)
{
printf("%f ",OUT[n]);
}
printf("\n");
getchar();
}