BP神经网络拟合sin()

/***************************************
*   Function:
*   神经网络BP算法
*   Lnstree by 2012
****************************************/
#include <math.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <ctype.h>

#define Ni 1   // 输入层神经元 的个数
#define Nm 4   // 隐藏层神经元 的个数
#define No 1   // 输出层神经元 的个数
#define L 100  // 学习的样本个数
#define Enom 0.02  // 确定误差上限,当神经元对待学习样本的拟合度小于该值时
// 可以认为学习结束
#define loopMax 100000 // 确定最大的迭代次数,当迭代达到loopmax时误差之后仍大于Enom时
// 可以认为学习失败
#define e 2.71828

double E;   // 训练每轮迭代误差和
double a, u, n;  // BP 的网络参数
double W1[Ni][Nm], W2[Nm][No];   // 网络连接的权值
double D1[Ni][Nm], D2[Nm][No];   // 每轮对连接权值的修正值
double D11[Ni][Nm], D22[Nm][No]; // 对上一轮的连接权值修正,第一轮为0
double pi[L][Ni], pm[L][Nm], po[L][No];  // 三层神经网络的输入
double T[L][No];   //神经网络的期望输出
double Xm[L][Nm], Xo[L][No]; // 隐层和输出层的神经元输出
double Qm[L][Nm], Qo[L][No]; // 对应各连接的$值
double a1[Ni][Nm],a2[Nm][No];  // 神经网络的学习率

void proceedR();
void Initiate();         // 训练时调用的函数,对神经网络初始话
void proceed();      // 训练时调用的函数,信号正向传播
void forQ();             // 训练时调用函数, 求误差偏导,将误差反传
void amend();       // 训练时调用的函数, 根据误差反向传递结果修改权值

double newa(double a, double D);  // 修改网络学习速率
double cal(double d);    // 计算Signoid函数值
double vcal(double d);   // 计算signoid函数的导数

int main()
{
    long int i;
    int flag;
    char choice;
    for (;;)
    {
        flag = 0;
        Initiate();  // 初始化神经网络

        for (i = 0; i < loopMax; i++)
        {
            proceed();
            if (E < Enom)
            {
                flag = 1;
                break;
            }
            if( i >= loopMax)
   {
    flag = -1;
    break;
   }
            forQ();
            amend();
        }

        if (flag > 0)
        proceedR();
        else
        printf("训练失败");
        for (;;)
        {
            printf("是否继续?");
            scanf("%c", &choice);
            choice = toupper(choice);
            if (choice == 'Y')  break;
            if (choice == 'N') exit(0);
        }
    }
}


// 函数定义
void Initiate()
{
    int i,j,random;
    double x, step;
    int stime;
    long ltime;
    ltime = time(NULL);
    stime = (unsigned)ltime / 2;
    srand(stime);
    a=0.02;
    u = 1;
    n = 1;
    printf("本程序将用于拟合sin()函数。\n\n");

    for (i = 0; i < Nm; i++)
    {
        for (j = 0; j < Ni; j++)
        {
            random = rand()% 100 - 50;
            x = random;
            x = x/ 100;
            W1[j][i] = x;    //  设定初始权值为-0.5~0.5
            D11[j][i] = 0;
            D1[j][i] = 0;
            a1[j][i] = 0.01;
        }
         for (j = 0; j < No; j++)
        {
            random = rand()% 100 - 50;
            x = random;
            x = x/ 100;
            W2[i][j] = x;    //  设定初始权值为-0.5~0.5
            D22[i][j] = 0;
            D2[i][j] = 0;
            a2[i][j] = 0.01;
        }
    }
    step = 1.0 / L;    // 将待训练的区间等分步长为step
    for (i = 0; i < L; i++)
    {
        x = i;
        pi[i][0] = x*step;        // 初始化输入
        T[i][0] = sin(pi[i][0]);  // 期望输出
    }

    printf("初始化成功\n\n下面对神经网络进行训练");
    }
void proceed()
{
 int i, j, k;
 E=0 ;
 for( i=0; i<L; i++ )
 {
  for( j=0; j<Nm; j++ )
  {
   pm[i][j] = 0;
   for( k=0; k<Ni; k++ )
   {
    pm[i][j] = pi[i][k] * W1[k][j] + pm[i][j];
   }
   Xm[i][j] = cal( pm[i][j] );
  }
  for( j=0; j<No; j++)
  {
   po[i][j] = 0;
   for( k=0; k<Nm; k++)
   {
    po[i][j] = Xm[i][k] * W2[k][j] + po[i][j];
   }
   Xo[i][j] = cal( po[i][j] );
      E = E + ( Xo[i][j] - T[i][j] ) * ( Xo[i][j] - T[i][j] ) / 2;
  }
 }
}


void forQ()
{
 int i,j,k;
 for( i=0; i<L; i++ )
 {
  for( j=0; j<No; j++)
  {
   Qo[i][j] = ( T[i][j] - Xo[i][j] )* vcal( Xo[i][j] );
  }
  for(j=0; j<Nm; j++)
  {
   Qm[i][j]=0;
   for( k=0; k<No; k++)
   {
    Qm[i][j] = Qo[i][k] * W2[j][k] + Qm[i][j];
   }
   Qm[i][j] = Qm[i][j] * vcal( Xm[i][j] );
  }
 }
 }

void amend()
{
 int i,j,k;
 double D;
 for( i=0; i<Nm; i++)
 {
  for( j=0; j<Ni; j++)
  {
   D1[j][i]=0;
  }
  for( j=0; j<No; j++)
  {
   D2[i][j]=0;
  }
 }
 for( i=0; i<Ni; i++)
 {
  for( j=0; j<Nm; j++)
  {
   for( k=0; k<L; k++)
   {
    D1[i][j] = Qm[k][j] * pi[k][j] + D1[i][j];
   }
             D = D1[i][j] * D11[i][j]  ;//为D11付初值
    a1[i][j] = newa( a1[i][j] , D );  // a 付初值
    W1[i][j] = W1[i][j] + a1[i][j] * ( n * D1[i][j] + ( 1 - n ) * D11[i][j] );
    D11[i][j] = D1[i][j];
  }
 }
    for( i=0; i<Nm; i++)
 {
  for( j=0; j<No; j++)
  {
   for( k=0; k<L; k++)
   {
    D2[i][j] = Qo[k][j] * Xm[k][i] + D2[i][j];
   }
   D = D2[i][j] * D22[i][j]  ;//为D11付初值
            a2[i][j] = newa( a2[i][j] , D );
   W2[i][j] = W2[i][j] + a2[i][j] * ( n * D2[i][j] + ( 1 - n ) * D22[i][j] );
   D22[i][j] = D2[i][j];
  }
 }
}
void proceedR()
{
    int i,j;
    float x;
    double input, output;
    char choice;
    for(;;)
    {
        for (;;)
        {
            printf("在此输入需要计算的值(0,1):");
            scanf("%f", &x);
            input = (double) x;

            if ((input >= 0.0) && (input <= 1))
            {
                break;
            }

            printf("请输入0,1的值!\n");
            for (;;)
            {
                printf("是否继续(Y/N):");
                scanf("%c", &choice);
                choice = toupper(choice);
                if (choice == 'y')  break;
                if (choice == 'N') exit(0);
            }
        }

        for (i = 0; i < Nm; i++)
        {
            pm[0][i] = 0;
            for (j = 0; j < Ni; j++)
            {
                pm[0][i] = input * W1[j][i] + pm[0][i];

            }
             Xm[0][i] = cal(pm[0][i]);
        }

        for (i = 0; i < No; i++)
        {
            po[0][i] = 0;
            for (j= 0; j < Nm; j++)
            {
                po[0][i] = Xm[0][j] * W2[j][i] + po[0][i];
            }
        }
        output = cal (po[0][0]);
        printf("输入的%20f 对应的结果 %f\n", input, output);
        printf("输入的%20f 正常的的结果 %f\n",input, sin(input));
    }
}
// S型激励函数
double cal(double d)
{
    d = -(d * u);
    d = exp(d);
    d = 1/(1 + d);
    return d;
}

// S型激励函数的导数
double vcal(double d)
{
    return u*d*(1 - d);
}

double newa(double a, double D)
{
    if (D > 0)
    {
        if (a <= 0.04)
        {
            a = a*2;
        }
        else
        {
            a = 0.08;
        }
    }
    else if (D < 0)
    {
        if (a >= 0.02)
        {
            a = a/2;
        }
        else
        {
            a = 0.01;
        }
    }

    return a;
}


注:该程序参考C语言编程百例,不错的一本书,有兴趣可以看看。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值