码迷,mamicode.com
首页 > 其他好文 > 详细

BP神经网络

时间:2014-06-05 02:40:25      阅读:261      评论:0      收藏:0      [点我收藏+]

标签:c   style   class   blog   code   a   

神经网络常用于机器学习中的分类,常用的分类算法有:朴素贝叶斯,遗传算法,神经网络,支持向量机等。

 

在互联网发达的今天,有很多东西需要进行分类,在分类之前,我们常常是有一些数据,找出这些数据符合什么样的

模型,然后根据这些已有数据来预测将来,神经网络就是用来进行这种数据建模的。

 

神经网络一般情况是有bubuko.com,布布扣个输入,有bubuko.com,布布扣个输出,在输入层和输出层之间通常还有若干个隐含层。实际上,在1989年

Robert Hecht-Nielsen证明了对于任何闭区间内的一个连续函数都可以用一个隐含层的BP网络来逼近,因而一个

3层的BP网络就可以完成任意的bubuko.com,布布扣维到bubuko.com,布布扣维的映射。

 

在BP(Back Propagation)神经网络中,输入层和输出层的节点个数都是确定的,那么隐含层的节点应该设置为

少才是最合适的呢?

 

实际上,隐含层的节点个数的多少是对神经网络的性能有影响的,有一个经验公式如下:

 

     bubuko.com,布布扣

 

其中,bubuko.com,布布扣为隐含层的节点个数,bubuko.com,布布扣为输入层的节点个数,bubuko.com,布布扣为输出层的节点个数,bubuko.com,布布扣为1~10之间的调节常数。

 

 

BP神经网络的原理

 

简单来说,BP神经网络分为3层,输入层,隐含层,输出层。每层之间每两个节点之间都有一个权值bubuko.com,布布扣,每一个节

点都有一个阀值bubuko.com,布布扣,并且还有一个激活函数bubuko.com,布布扣,每一个神经元的模型如下:

 

                                    bubuko.com,布布扣

 

 

BP神经网络在正常训练过程中,分为两个步骤反复调整:

   (1)工作信号正向传递子过程        

   (2)误差信号反向传递子过程

 

BP神经网络算法基本流程如下:

 

   (1)构造初始神经网络,随机初始化神经网络的权值和阀值。

   (2)对于训练样本集中的每一个样本,输入到神经网络,计算每个神经元的输出。

   (3)利用能量函数计算神经网络对于该样本的能量值,计算每个神经元节点所产生的误差,反向传递该误差,

        修正各个权值和阀值。

   (4)重复(2)和(3),直到算法终止条件成立退出。

 

在上述算法流程中,每个神经元的数学公式为:

 

    bubuko.com,布布扣

 

激活函数一般选择S型激活函数。

 

BP神经网络代码:

#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>

using namespace std;

const double A = 30.0;
const double B = 10.0;
const int MAX = 500;            //最大训练次数
const double COEF = 0.0035;     //网络的学习效率
const double BCOEF = 0.001;     //网络的阀值调整效率
const double ERROR = 0.002;     //网络训练中允许的误差
const double ACCURACY = 0.0005; //网络要求精度

int cnt, t;
double differ,is;

double sample[41][4]=
{
    {0,0,0,0},
    {5,1,4,19.020},
    {5,3,3,14.150},
    {5,5,2,14.360},
    {5,3,3,14.150},
    {5,3,2,15.390},
    {5,3,2,15.390},
    {5,5,1,19.680},
    {5,1,2,21.060},
    {5,3,3,14.150},
    {5,5,4,12.680},
    {5,5,2,14.360},
    {5,1,3,19.610},
    {5,3,4,13.650},
    {5,5,5,12.430},
    {5,1,4,19.020},
    {5,1,4,19.020},
    {5,3,5,13.390},
    {5,5,4,12.680},
    {5,1,3,19.610},
    {5,3,2,15.390},
    {1,3,1,11.110},
    {1,5,2,6.521},
    {1,1,3,10.190},
    {1,3,4,6.043},
    {1,5,5,5.242},
    {1,5,3,5.724},
    {1,1,4,9.766},
    {1,3,5,5.870},
    {1,5,4,5.406},
    {1,1,3,10.190},
    {1,1,5,9.545},
    {1,3,4,6.043},
    {1,5,3,5.724},
    {1,1,2,11.250},
    {1,3,1,11.110},
    {1,3,3,6.380},
    {1,5,2,6.521},
    {1,1,1,16.000},
    {1,3,2,7.219},
    {1,5,3,5.724}
};

double b[4][10],bc[4][10];
double w[4][10][10],wc[4][10][10];
double netin[4][10],o[4][10],d[4][10];

//计算NN网络隐含层和输出层的输出
void NetworkOut(int m,int n)
{
    int k = 2;
    //隐含层各节点的输出
    for(int i=1; i<=m; i++) //m为隐含层结点的个数
    {
        netin[k][i] = 0;
        for(int j=1; j<=3; j++) //隐含层的每个结点均有3个输入变量
            netin[k][i] += o[k-1][j] * w[k][j][i];
        netin[k][i] -= b[k][i];
        o[k][i] = A / (1 + exp(-netin[k][i] / B));
    }

    k = 3;
    //输出层各节点的输出
    for(int i=1; i<=n; i++)
    {
        netin[k][i] = 0;
        for(int j=1; j<=m; j++)
            netin[k][i] += o[k-1][j] * w[k][j][i];
        netin[k][i] -= b[k][i];
        o[k][i] = A / (1 + exp(-netin[k][i] / B));
    }
}

//计算NN网络的反向传播误差
void CalcInvError(int m,int n)
{
    t = cnt - 1;
    d[3][1] = (o[3][1] - sample[t][3]) * (A / B) * exp(-netin[3][1] / B) / pow(1 + exp(-netin[3][1] / B), 2);
    //隐含层的误差
    int k = 2;
    for(int i=1; i<=m; i++)
    {
        double tmp = 0;
        for(int j=1; j<=n; j++)
            tmp += w[k+1][i][j] * d[k+1][j];
        d[k][i] = tmp * (A / B) * exp(-netin[k][i] / B) / pow(1 + exp(-netin[k][i] / B), 2);
    }
}

//计算网络权值W的调整量
void Calcwc(int m,int n)
{
    int k = 3;
    //输出层与隐含层之间的权值调整
    for(int i=1; i<=m; i++)
        for(int j=1; j<=n; j++)
            wc[k][i][j] = -COEF * d[k][j] * o[k-1][i] + 0.5 * wc[k][i][j];
    k = 2;
    //输入层与隐含层之间的权值调整
    for(int i=1; i<=m; i++)
        for(int j=1; j<=n; j++)
            wc[k][i][j] = -COEF * d[k][j] * o[k-1][i] + 0.5 * wc[k][i][j];
}

//计算网络阀值的调整量
void Calcbc(int m,int n)
{
    for(int i=1; i<=m; i++)
        bc[2][i] = BCOEF * d[2][i];
    for(int i=1; i<=n; i++)
        bc[3][i] = BCOEF * d[3][i];
}

//调整网络权值
void ChangeWeight(int m,int n)
{
    for(int i=1; i<=3; i++)
    {
        for(int j=1; j<=m; j++)
        {
            //为了保证较好的鲁棒性,计算权值时乘惯性系数0.9
            w[2][i][j] = 0.9 * w[2][i][j] + wc[2][i][j];
            //printf("w[2][%d][%d] = %lf\n",i,j,w[2][i][j]);
        }
    }
    for(int i=1; i<=m; i++)
    {
        for(int j=1; j<=n; j++)
        {
            w[3][i][j] = 0.9 * w[3][i][j] + wc[3][i][j];
            // printf("w[3][%d][%d] = %lf\n",i,j,w[3][i][j]);
        }
    }
}

//调整网络阀值
void Changeb(int m,int n)
{
    for(int i=1; i<=m; i++)
        b[2][i] += bc[2][i];
    for(int i=1; i<=n; i++)
        b[3][i] += bc[3][i];
}

//清除网络权值变化量和网络阀值变化量
void Clear()
{
    memset(wc,0,sizeof(wc));
    memset(bc,0,sizeof(bc));
}

double Random()
{
    int t = 100;
    t += rand() % 400;
    return t / 5000.0;
}

//初始化网络权值
void Init()
{
    srand(time(0));
    for(int i=0; i<4; i++)
    {
        for(int j=0; j<10; j++)
        {
            b[i][j] = Random();    //初始化网络阀值
            for(int k=0; k<10; k++)
                w[i][j][k] = Random();  //初始化网络权值
        }
    }
}

//计算网络单个样本误差
void CalcDiffer()
{
    t = cnt - 1;
    differ = 0.5 * (o[3][1] - sample[t][3]) * (o[3][1] - sample[t][3]);
}

void CalcList()
{
    is = 0;
    for(int i=0; i<=19; i++)
    {
        o[1][1] = sample[i][0];
        o[1][2] = sample[i][1];
        o[1][3] = sample[i][2];
        NetworkOut(8,1);
        is += (o[3][1] - sample[i][3]) * (o[3][1] - sample[i][3]);
    }
    is /= 20;
}

//训练网络
void trainNN()
{
    Init();
    for(int time=1; time<=MAX; time++)
    {
        cnt = 0;
        while(cnt <= 40)
        {
            o[1][1] = sample[cnt][0];
            o[1][2] = sample[cnt][1];
            o[1][3] = sample[cnt][2];
            cnt++;
            Clear();
            NetworkOut(8,1);
            CalcDiffer();
            while(differ > ERROR)
            {
                CalcInvError(8,1);
                Calcwc(8,1);
                Calcbc(8,1);
                ChangeWeight(8,1);
                Changeb(8,1);
                NetworkOut(8,1);
                CalcDiffer();
            }
        }
        printf("This is %d times trainning NN...\n",time);
        CalcList();
        printf("is == %lf\n\n\n",is);
        if(is < ACCURACY) break;
    }
}

int main()
{
    printf("Please wait for the trainning NN...\n\n");
    trainNN();
    printf("The trainning complete!\n");

    char ch = 'y';
    while(ch == 'Y' || ch == 'y')
    {
        printf("Please input the data to be tested!\n");
        for(int i=1; i<=3; i++)
        {
            double x;
            scanf("%lf",&x);
            o[1][i] = x;
        }
        NetworkOut(8,1);
        double ans = o[3][1];
        printf("The answer is %lf\n",ans);
        printf("Still test? [Yes] or [No]\n");
        ch = getchar();
    }
    return 0;
}


 

 

BP神经网络,布布扣,bubuko.com

BP神经网络

标签:c   style   class   blog   code   a   

原文地址:http://blog.csdn.net/acdreamers/article/details/27183751

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!