反向传播神经网络(BP网络)介绍及Java实现
2017-04-01 21:03
281 查看
在之前的文章中我简单展望过人工智能。并提出过神经网络是一个核心技术,今天我就要介绍神经网络的经典算法反向传播神经网络(Backpropagation Neural Network)。
BP网络由DE Rumelhart, GE Hinton等于1986年提出(值得注意的是GE Hinton也是深度学习的奠基人),它是最经典的一个神经网络算法。神经网络是一组连接的输入/输出神经元,每个连接都有相对应的权重。如图,是一个典型的多层前馈(multilayer feed-forward)神经网络结构。它由一个输入层、一个输出层和多个隐藏层组成。在给出输入后,经过层层网络,最后得到一个输出。而神经网络算法本质就是找为各连接找出合适的权值。
算法中的终止条件可以是到达一定的迭代次数或到达一定的准确度。可以看出算法本身并不复杂,后面要讲的推导也不会比高等数学的题难推,就是几个数学公式比较复杂。可是算法却有十分神奇的能力,所以有机会一定把数学学好。
E(w⃗ )=12∑d∈D∑k∈outputs(tkd−okd)2
所以我们的目的是使误差值最小。那么如何使该误差函数取的最小值,通过计算E关于w的导数,列方程使所有导数都为零?显然是不可行的。所以我们要利用计算机的计算能力去一步步逼近最小值,这里用的方法就是梯度下降(Gradient descend),即朝着梯度下降的方向逐步偏移。
误差函数:
正式推导前先明确几个标记,可以使后面推导更简洁:
输出单元的误差:
隐藏单元的误差:
可以看出误差更新的过程是从后往前传播,所以算法的名字为反向传播算法
BP网络由DE Rumelhart, GE Hinton等于1986年提出(值得注意的是GE Hinton也是深度学习的奠基人),它是最经典的一个神经网络算法。神经网络是一组连接的输入/输出神经元,每个连接都有相对应的权重。如图,是一个典型的多层前馈(multilayer feed-forward)神经网络结构。它由一个输入层、一个输出层和多个隐藏层组成。在给出输入后,经过层层网络,最后得到一个输出。而神经网络算法本质就是找为各连接找出合适的权值。
网络计算过程
在讨论BP算法前,还是先明确一下,在上面的网络中得到权值后,具体的计算过程到底是怎么回事。首先明确,上图中的输入层其实是我们要分类的样本的各特征,而隐藏层和输出层每个圆圈都代表了一个sigmoid单元。如下图所示,sigmoid的计算过程为:首先得到各输入与常数1的和net=∑ni=0wixi,然后用sigmoid函数计算输出out=σ(net)=11+e−net。这便是单各单元的计算方式,而整个网络便是前一层作为输入与后一层的每各单元连接,计算出各单元的输出后,再把这一层做为输入传递到后一层。。。算法过程
下面先给出BP神经网络的算法过程算法中的终止条件可以是到达一定的迭代次数或到达一定的准确度。可以看出算法本身并不复杂,后面要讲的推导也不会比高等数学的题难推,就是几个数学公式比较复杂。可是算法却有十分神奇的能力,所以有机会一定把数学学好。
算法推导
梯度下降
可以从上面的算法过程看出,BP算法其实就是不断根据输出与实际值的误差来更新各连接权值。那么什么样的权值是最好的,我们中学应该都学过最小二乘法,即每一个输出与实际值差值的平方的和最小,即误差函数最小。在BP网络中,误差这样定义:E(w⃗ )=12∑d∈D∑k∈outputs(tkd−okd)2
所以我们的目的是使误差值最小。那么如何使该误差函数取的最小值,通过计算E关于w的导数,列方程使所有导数都为零?显然是不可行的。所以我们要利用计算机的计算能力去一步步逼近最小值,这里用的方法就是梯度下降(Gradient descend),即朝着梯度下降的方向逐步偏移。
迭代方法推导
在正式推导前我先说明:其实BP算法有两中形式:标准形和随机梯度下降方法。这一点刚开始也让我疑惑了很久:为什么上面每一个样例都要迭代一次?不是应该一次扫一遍数据库,计算出总误差再迭代吗?后面那种其实就是标准形式的梯度下降方法,可是这样计算量大,收敛的速度慢。而每一个样例都迭代速度快,而且还可以避免陷入局部最优。下面我介绍的就是随机梯度下降方式的推导过程。可以看出这种方式的误差函数和上面那个有区别。但后面推导过程其实非常相似。误差函数:
正式推导前先明确几个标记,可以使后面推导更简洁:
输出单元的误差:
隐藏单元的误差:
可以看出误差更新的过程是从后往前传播,所以算法的名字为反向传播算法
Java实现
算法理解起来可能比较困难,但是整体过程并不复杂,用Java实现,总代码不会超过100行即可实现,但是代码也比较绕,理解起来也会费点劲。下面给出我的实现,或者可以下载我的整个工程,我这个项目是用BPNN做手写体识别,最后效果并不好,不过算法本身是正确的,我用它做过习题。public double layer[][];//store the output of every unit public double layerErr[][];//store the error of every unit public double layerWeight[][][];//store weights public double layerWeightDelta[][][];//store number of weights adjust public double mobp;// momentum rate public double rate;// adjust steps length /** * initialize the BPNN * @param layernum units number of every layer * @param rate adjust steps length * @param mobp momentum rate */ public BpNN(int[] layernum,double rate,double mobp){ this.rate=rate; this.mobp=mobp; layer=new double[layernum.length][]; layerErr=new double[layernum.length][]; layerWeight=new double[layernum.length][][]; layerWeightDelta=new double[layernum.length][][]; for(int l=0;l<layernum.length;l++){ layer[l]=new double[layernum[l]]; layerErr[l]=new double[layernum[l]]; // layerWeight[l]=new double[layernum[l]+1][]; // layerWeightDelta[l]=new double[layernum[l]+1][]; if(l+1<layernum.length){ layerWeight[l]=new double[layernum[l]+1][layernum[l+1]]; layerWeightDelta[l]=new double[layernum[l]+1][layernum[l+1]]; for(int x=0;x<layernum[l]+1;x++){ for(int y=0;y<layernum[l+1];y++){ layerWeight[l][x][y]=0.1; } } } } } /** * compute the output from front to back * @param in input vector * @return output vector * */ public double[] compute(double[] in){ for(int l=1;l<layer.length;l++){ for(int j=0;j<layer[l].length;j++){ double z=layerWeight[l-1][layer[l-1].length][j];//constant multiply weights for(int x=0;x<layer[l-1].length;x++){ layer[l-1][x]=l==1?in[x]:layer[l-1][x]; z+=layerWeight[l-1][x][j]*layer[l-1][x]; } layer[l][j]=1/(1+Math.exp(-z)); } } return layer[layer.length-1]; } /** * update weight from back to front * @param tar target values (instances) */ public void updateWeight(double[] tar){ int l=layer.length-1; for(int y=0;y<layer[l].length;y++){ layerErr[l][y]=layer[l][y]*(1-layer[l][y])*(tar[y]-layer[l][y]); } while(l-->0){ for(int j=0;j<layerErr[l].length;j++){ double z=0; for(int i=0;i<layerErr[l+1].length;i++){ z+=l>0?layerErr[l+1][i]*layerWeight[l][j][i]:0;//0 layer is input layer, need not calculate error layerWeightDelta[l][j][i]=mobp*layerWeightDelta[l][j][i]+rate*layerErr[l+1][i]*layer[l][j];//delta weight with momentum layerWeight[l][j][i]+=layerWeightDelta[l][j][i];//update weight of units if(j==layerErr[l].length-1){//update weights of constant layerWeightDelta[l][j+1][i]=mobp*layerWeightDelta[l][j+1][i]+rate*layerErr[l+1][i]; layerWeight[l][j+1][i]+=layerWeightDelta[l][j+1][i]; } } layerErr[l][j]=z*layer[l][j]*(1-layer[l][j]);//compute error } } } public void train(double[] in, double[] tar) { compute(in); updateWeight(tar); } public double[][][] getWeight(){ return layerWeight; } public void setWeight(double[][][] weight){ layerWeight=weight; }
相关文章推荐
- 【计算机网络】关于三种网络通信模式以及java中三种通信方式的实现介绍
- Java中网络IO的实现方式(BIO、NIO、AIO)介绍
- Java 实现 BP 神经网络完成 Iris 数据分类
- Java实现ANN神经网络之BP代码参考
- Java HelloWorld实现及Java运行原理介绍
- 定时器的实现、java定时器Timer和Quartz介绍与Spring中定时器的配置
- java网络编程----------Socket实现客户端和服务器的连接
- BP网络之C#实现
- Java网络请求(get/post)工具类实现的两种方式
- java搜索---网络爬虫实现
- Java网络编程:实现HTTP断点续传下载工具(附源代码)
- Java新一代网络编程模型AIO原理及Linux系统AIO介绍
- 用JAVA实现汉字转拼音缩写(两种方式介绍)
- 读书笔记-java网络编程-6URL和URI-HTTP协议和cookie的java实现
- 神经网络(BP)算法Python实现及简单应用
- 详解 BP 神经网络基本原理及 C 语言实现
- java 通过网络唤醒实现远程开机
- java代码实现访问网络外部接口并获取数据的工具类
- 定时器的实现、java定时器介绍与Spring中定时器的配置
- JAVA 上加密算法的实现用例,MessageDigest介绍