BP人工神经网络的牵线与贯彻亚洲城误乐城ca88网站

神经网络概念与符合领域

神经网络最早的研商是 40 年代心境学家 Mcculloch 和地理学家 Pitts 合作提议的
,他们指出的MP模型拉开了神经网络研究的发端。

神经网络的前进大约经过 3 个级次:1947~1969
年为早期,在那中间数学家们提议了很多神经元模型和读书规则,如 MP
模型、HEBB 学习规则和感知器等;60 年代先前时期至 80
年代先前时期,神经网络控制与总体神经网络研讨一样,处于低潮。在此期间,化学家们做了大量的工作,如
Hopfield
教师对网络引入能量函数的定义,给出了网络的稳定判据,指出了用来联想记忆和优化总计的门路。1984年,Hiton
教师提议 Bol tzman 机模型;1986年 Kumelhart
等人提出误差反向传播神经网络,简称 BP
网络。目前,BP网络已变为广大利用的网络。1987年至今为发展期,在此期间,神经网络受到国际尊重,各种国家都开展商量,形成神经网络发展的另一个高潮。

人工神经网络(ANN)受到生物学的启示是生物神经网络的一种模拟和类似,它从协会、实现机理和效率上模仿生物神经网络。从系统看法看,人工神经元网络是由大量神经元通过极其丰裕和完美的连日而构成的自适应非线性动态系统。人工神经网络,因为生物的就学系统是由相互连接的神经细胞组成的不得了复杂的网络,其中每一个神经元单元有必然数量的实值输入,并暴发单一的实数值输出。1960
年威德罗和霍夫率先把神经网络用于机动控制研讨。神经网络以其独特的布局和处理音讯的不二法门,在很多事实上应用领域中获取了显眼的职能,首要利用如下:自动控制领域、处理组合优化问题、情势识别、图像处理、传感器信号处理、机器人控制、信号处理、卫生保健、医疗、经济、化工领
域、焊接领域、地理领域、数据挖掘、电力系统、交通、军事、矿业、农业和情状等领域。

神经网络基本结构

人工神经网络由神经元模型构成,这种由众多神经元组成的音讯处理网络具有并行分布结构。每个神经元具有单一输出,并且可以与其余神经元连接;存在很多(多重)输出连接格局,每种连接形式对应一个连接权周密。可把
ANN 看成是以处理单元 PE(processing element)
为节点,用加权有向弧(链)相互连接而成的有向图。令来自其余处理单元(神经元)i的音讯为Xi,它们与本处理单元的并行成效强度为
Wi,i=0,1,…,n-1,处理单元的其中阈值为 θ。那么本神经元的输入为:

亚洲城误乐城ca88网站 1

而处理单元的出口为:

亚洲城误乐城ca88网站 2

式中,xi为第 i 个因素的输入,wi 为第 i 个要素与本处理单元的互联权重。f
称为激发函数(activation
function)或效益函数。它控制节点(神经元)的出口。该出口为 1 或 0
取决于其输入之和大于或小于内部阈值 θ。

下图所示神经元单元由两个输入Xi,i=1,2,…,n和一个输出y组成。中间状态由输入信号的权和象征,而输出为:

亚洲城误乐城ca88网站 3

教练网络

神经网络结构被规划到位,有了输入、输出参数后,我们就要对网络开展磨练。神经网络的练习有包括感知器磨炼、delta
规则训练和反向传来算法等教练,其中感知器训练是基础。

感知器和 delta 锻练规则

清楚神经网络的首先步是从对抽象生物神经最先,本文用到的人工神经网络系统是以被誉为感知器的单元为底蕴,如图所示。感知器以一个实数值向量作为输入,统计这一个输入的线性组合,假诺结果超越某个阈值,就输出
1,否则输出 -1,假如 x 从 1 到 n,则感知器统计公式如下:

亚洲城误乐城ca88网站 4

其间每个 wi 是一个实数常量,或称为权值,用来支配输入 xi
对感知器输出的贡献率。特别地,-w0是阈值。

固然当教练样例线性可分时,感知器法则可以成功地找到一个权向量,但若是样例不是线性可分时它将无法消灭,因而众人设计了另一个磨练法则来摆平那一个不足,这一个训练规则叫做
delta
规则。感知器磨炼规则是基于这样一种思路–权周到的调动是由目的和出口的差分方程表明式决定。而
delta
规则是基于梯度降落这样一种思路。这一个纷繁的数学概念可以举个简单的例子来表示。从给定的几点来看,向南的这条路径比向东这条更陡些。向东就像从悬崖上掉下来,不过向南就是顺着一个多少倾斜的斜坡下来,向西象登一座陡峭的山,而北方则到了平整,只要逐步的游荡就可以了。所以你要物色的是到达平地的兼具途径将官陡峭的总数减弱到微小的路线。在权周密的调整中,神经网络将会找到一种将误差缩减到微小的权全面的分配形式。这一部分大家不做详细介绍,如有需要我们可参考相关的人为智能书籍。

反向传播算法

人工神经网络学习为上学实数值和向量值函数提供了一种实际的格局,对于连续的和离散的性质都可以拔取。并且对训练多少中的噪声具有很好的健壮性。反向传播算法是最广大的网络学习算法。这是我们所知用来磨练神经网络很常见的主意,反向传播算法是一种具有很强学习能力的系统,结构相比较简单,且易于编程。

鲁梅尔哈特(哈特(Hart))(Rumelhart)和Mike莱兰(Meclelland)于 1985 年发展了 BP
网络学习算法,实现了明斯基的多层网络设想。BP网络不仅涵盖输入节点和出口节点,而且蕴藏一层或多层隐(层)节点。输入信号先向前传递到隐藏节点,经过功用后,再把潜伏节点的出口新闻传送到输出节点,最后交给输出结果。节点的鼓舞函数一般拔取S 型函数。

反向传播(back-propagation,BP)算法是一种总括单个权值变化引起网络性能变化值的较为简单的法门。由于BP算法过程包含从出口节点开端,反向地向第一隐含层(即最相仿输入层的隐含层)传播由总误差引起的权值修正,所以称为”反向传播”。反向传播特性与所求解问题的特性和所作细节采取有极为密切的涉及。

对于由一文山会海规定的单元互连形成的多层网络,反向传播算法可用来读书这么些多层网络的权值。它利用梯度下降方法总括最小化网络输出值和目的值之间的误差平方,因为我们要考虑多少个出口单元的网络,而不是像从前只考虑单个单元,所以我们要重新总结误差E,以便对所有网络出口的误差求和:

亚洲城误乐城ca88网站 5

Outpus 是网络出口单元的集结,tkd 和 okd 是与训练样例 d 和第 k
个出口单元的有关输出值.

反向传播算法的一个喜人特性是:它可以在网络之中的隐藏层发现有用的高中级表示:

1.练习样例仅包含网络输入和出口,权值调节的过程可以擅自地安装权值,来定义任何隐藏单元表示,这么些藏身单元表示在使误差E达到最刻钟最可行。

2.指点反向传来算法定义新的隐藏层特征,那些特征在输入中没有显明表示出来,但能捕捉输入实例中与上学目的函数最相关的特性

反向传播磨练神经元的算法如下:

亚洲城误乐城ca88网站 6

C++简单实现与测试

以下C++代码实现了BP网络,通过8个3位二进制样本对应一个梦想输出,磨炼BP网络,最后磨练好的网络可以将输入的三位二进制数对应输出一位十进制数。

亚洲城误乐城ca88网站 7亚洲城误乐城ca88网站 8View Code

//将三位二进制数转为一位十进制数

#include <iostream>
#include <cmath>
using namespace std;

#define  innode 3  //输入结点数
#define  hidenode 10//隐含结点数
#define  outnode 1 //输出结点数
#define  trainsample 8//BP训练样本数

class BpNet
{
public:
    void train(double p[trainsample][innode ],double t[trainsample][outnode]);//Bp训练
    double p[trainsample][innode];     //输入的样本
    double t[trainsample][outnode];    //样本要输出的

    double *recognize(double *p);//Bp识别

    void writetrain(); //写训练完的权值
    void readtrain(); //读训练好的权值,这使的不用每次去训练了,只要把训练最好的权值存下来就OK

    BpNet();
    virtual ~BpNet();

public:
    void init();
    double w[innode][hidenode];//隐含结点权值
    double w1[hidenode][outnode];//输出结点权值
    double b1[hidenode];//隐含结点阀值
    double b2[outnode];//输出结点阀值

    double rate_w; //权值学习率(输入层-隐含层)
    double rate_w1;//权值学习率 (隐含层-输出层)
    double rate_b1;//隐含层阀值学习率
    double rate_b2;//输出层阀值学习率

    double e;//误差计算
    double error;//允许的最大误差
    double result[outnode];// Bp输出
};

BpNet::BpNet()
{
    error=1.0;
    e=0.0;

    rate_w=0.9;  //权值学习率(输入层--隐含层)
    rate_w1=0.9; //权值学习率 (隐含层--输出层)
    rate_b1=0.9; //隐含层阀值学习率
    rate_b2=0.9; //输出层阀值学习率
}

BpNet::~BpNet()
{

}

void winit(double w[],int n) //权值初始化
{
  for(int i=0;i<n;i++)
    w[i]=(2.0*(double)rand()/RAND_MAX)-1;
}

void BpNet::init()
{
    winit((double*)w,innode*hidenode);
    winit((double*)w1,hidenode*outnode);
    winit(b1,hidenode);
    winit(b2,outnode);
}

void BpNet::train(double p[trainsample][innode],double t[trainsample][outnode])
{
    double pp[hidenode];//隐含结点的校正误差
    double qq[outnode];//希望输出值与实际输出值的偏差
    double yd[outnode];//希望输出值

    double x[innode]; //输入向量
    double x1[hidenode];//隐含结点状态值
    double x2[outnode];//输出结点状态值
    double o1[hidenode];//隐含层激活值
    double o2[hidenode];//输出层激活值

    for(int isamp=0;isamp<trainsample;isamp++)//循环训练一次样品
    {
        for(int i=0;i<innode;i++)
            x[i]=p[isamp][i]; //输入的样本
        for(int i=0;i<outnode;i++)
            yd[i]=t[isamp][i]; //期望输出的样本

        //构造每个样品的输入和输出标准
        for(int j=0;j<hidenode;j++)
        {
            o1[j]=0.0;
            for(int i=0;i<innode;i++)
                o1[j]=o1[j]+w[i][j]*x[i];//隐含层各单元输入激活值
            x1[j]=1.0/(1+exp(-o1[j]-b1[j]));//隐含层各单元的输出
            //    if(o1[j]+b1[j]>0) x1[j]=1;
            //else x1[j]=0;
        }

        for(int k=0;k<outnode;k++)
        {
            o2[k]=0.0;
            for(int j=0;j<hidenode;j++)
                o2[k]=o2[k]+w1[j][k]*x1[j]; //输出层各单元输入激活值
            x2[k]=1.0/(1.0+exp(-o2[k]-b2[k])); //输出层各单元输出
            //    if(o2[k]+b2[k]>0) x2[k]=1;
            //    else x2[k]=0;
        }

        for(int k=0;k<outnode;k++)
        {
            qq[k]=(yd[k]-x2[k])*x2[k]*(1-x2[k]); //希望输出与实际输出的偏差
            for(int j=0;j<hidenode;j++)
                w1[j][k]+=rate_w1*qq[k]*x1[j];  //下一次的隐含层和输出层之间的新连接权
        }

        for(int j=0;j<hidenode;j++)
        {
            pp[j]=0.0;
            for(int k=0;k<outnode;k++)
                pp[j]=pp[j]+qq[k]*w1[j][k];
            pp[j]=pp[j]*x1[j]*(1-x1[j]); //隐含层的校正误差

            for(int i=0;i<innode;i++)
                w[i][j]+=rate_w*pp[j]*x[i]; //下一次的输入层和隐含层之间的新连接权
        }

        for(int k=0;k<outnode;k++)
        {
            e+=fabs(yd[k]-x2[k])*fabs(yd[k]-x2[k]); //计算均方差
        }
        error=e/2.0;

        for(int k=0;k<outnode;k++)
            b2[k]=b2[k]+rate_b2*qq[k]; //下一次的隐含层和输出层之间的新阈值
        for(int j=0;j<hidenode;j++)
            b1[j]=b1[j]+rate_b1*pp[j]; //下一次的输入层和隐含层之间的新阈值
    }
}

double *BpNet::recognize(double *p)
{
    double x[innode]; //输入向量
    double x1[hidenode]; //隐含结点状态值
    double x2[outnode]; //输出结点状态值
    double o1[hidenode]; //隐含层激活值
    double o2[hidenode]; //输出层激活值

    for(int i=0;i<innode;i++)
        x[i]=p[i];

    for(int j=0;j<hidenode;j++)
    {
        o1[j]=0.0;
        for(int i=0;i<innode;i++)
            o1[j]=o1[j]+w[i][j]*x[i]; //隐含层各单元激活值
        x1[j]=1.0/(1.0+exp(-o1[j]-b1[j])); //隐含层各单元输出
        //if(o1[j]+b1[j]>0) x1[j]=1;
        //    else x1[j]=0;
    }

    for(int k=0;k<outnode;k++)
    {
        o2[k]=0.0;
        for(int j=0;j<hidenode;j++)
            o2[k]=o2[k]+w1[j][k]*x1[j];//输出层各单元激活值
        x2[k]=1.0/(1.0+exp(-o2[k]-b2[k]));//输出层各单元输出
        //if(o2[k]+b2[k]>0) x2[k]=1;
        //else x2[k]=0;
    }

    for(int k=0;k<outnode;k++)
    {
        result[k]=x2[k];
    }
    return result;
}

void BpNet::writetrain()
{
    FILE *stream0;
    FILE *stream1;
    FILE *stream2;
    FILE *stream3;
    int i,j;
    //隐含结点权值写入
    if(( stream0 = fopen("w.txt", "w+" ))==NULL)
    {
        cout<<"创建文件失败!";
        exit(1);
    }
    for(i=0;i<innode;i++)
    {
        for(j=0;j<hidenode;j++)
        {
            fprintf(stream0, "%f\n", w[i][j]);
        }
    }
    fclose(stream0);

    //输出结点权值写入
    if(( stream1 = fopen("w1.txt", "w+" ))==NULL)
    {
        cout<<"创建文件失败!";
        exit(1);
    }
    for(i=0;i<hidenode;i++)
    {
        for(j=0;j<outnode;j++)
        {
            fprintf(stream1, "%f\n",w1[i][j]);
        }
    }
    fclose(stream1);

    //隐含结点阀值写入
    if(( stream2 = fopen("b1.txt", "w+" ))==NULL)
    {
        cout<<"创建文件失败!";
        exit(1);
    }
    for(i=0;i<hidenode;i++)
        fprintf(stream2, "%f\n",b1[i]);
    fclose(stream2);

    //输出结点阀值写入
    if(( stream3 = fopen("b2.txt", "w+" ))==NULL)
    {
        cout<<"创建文件失败!";
        exit(1);
    }
    for(i=0;i<outnode;i++)
        fprintf(stream3, "%f\n",b2[i]);
    fclose(stream3);

}

void BpNet::readtrain()
{
    FILE *stream0;
    FILE *stream1;
    FILE *stream2;
    FILE *stream3;
    int i,j;

    //隐含结点权值读出
    if(( stream0 = fopen("w.txt", "r" ))==NULL)
    {
        cout<<"打开文件失败!";
        exit(1);
    }
    float  wx[innode][hidenode];
    for(i=0;i<innode;i++)
    {
        for(j=0;j<hidenode;j++)
        {
            fscanf(stream0, "%f", &wx[i][j]);
            w[i][j]=wx[i][j];
        }
    }
    fclose(stream0);

    //输出结点权值读出
    if(( stream1 = fopen("w1.txt", "r" ))==NULL)
    {
        cout<<"打开文件失败!";
        exit(1);
    }
    float  wx1[hidenode][outnode];
    for(i=0;i<hidenode;i++)
    {
        for(j=0;j<outnode;j++)
        {
            fscanf(stream1, "%f", &wx1[i][j]);
            w1[i][j]=wx1[i][j];
        }
    }
    fclose(stream1);

    //隐含结点阀值读出
    if(( stream2 = fopen("b1.txt", "r" ))==NULL)
    {
        cout<<"打开文件失败!";
        exit(1);
    }
    float xb1[hidenode];
    for(i=0;i<hidenode;i++)
    {
        fscanf(stream2, "%f",&xb1[i]);
        b1[i]=xb1[i];
    }
    fclose(stream2);

    //输出结点阀值读出
    if(( stream3 = fopen("b2.txt", "r" ))==NULL)
    {
        cout<<"打开文件失败!";
        exit(1);
    }
    float xb2[outnode];
    for(i=0;i<outnode;i++)
    {
        fscanf(stream3, "%f",&xb2[i]);
        b2[i]=xb2[i];
    }
    fclose(stream3);
}


//输入样本
double X[trainsample][innode]= {
    {0,0,0},{0,0,1},{0,1,0},{0,1,1},{1,0,0},{1,0,1},{1,1,0},{1,1,1}
    };
//期望输出样本
double Y[trainsample][outnode]={
    {0},{0.1429},{0.2857},{0.4286},{0.5714},{0.7143},{0.8571},{1.0000}
    };

int main()
{
    BpNet bp;
    bp.init();
    int times=0;
    while(bp.error>0.0001)
    {
        bp.e=0.0;
        times++;
        bp.train(X,Y);
        cout<<"Times="<<times<<" error="<<bp.error<<endl;
    }
    cout<<"trainning complete..."<<endl;
    double m[innode]={1,1,1};
    double *r=bp.recognize(m);
    for(int i=0;i<outnode;++i)
       cout<<bp.result[i]<<" ";
    double cha[trainsample][outnode];
    double mi=100;
    double index;
    for(int i=0;i<trainsample;i++)
    {
        for(int j=0;j<outnode;j++)
        {
            //找差值最小的那个样本
            cha[i][j]=(double)(fabs(Y[i][j]-bp.result[j]));
            if(cha[i][j]<mi)
            {
                mi=cha[i][j];
                index=i;
            }
        }
    }
    for(int i=0;i<innode;++i)
       cout<<m[i];
    cout<<" is "<<index<<endl;
    cout<<endl;
    return 0;
}

亚洲城误乐城ca88网站,参考文献

神经网络介绍——利用反向传播算法的形式学习
http://www.ibm.com/developerworks/cn/linux/other/l-neural/index.html

人为智能 Java 坦克机器人体系: 神经网络,上部
http://www.ibm.com/developerworks/cn/java/j-lo-robocode3/index.html

人造智能 Java 坦克机器人系列: 神经网络,下部
http://www.ibm.com/developerworks/cn/java/j-lo-robocode4/

利用 Python 构造神经网络–Hopfield 网络可以重构失真的图案并排除噪声
http://www.ibm.com/developerworks/cn/linux/l-neurnet/

提供一个Matlab的BP神经网络的根底材料
http://www.cnblogs.com/galaxyprince/archive/2010/12/20/1911157.html

codeproject上的一个落实,作者曾经提交好三种样式的使用例子
http://www.codeproject.com/KB/recipes/aforge_neuro.aspx