赞
踩
原文:https://github.com/amace-lzo/top-algorithm-set/wiki/bpnn_BPNeuralNetwork
BP神经网络(Back Propagation Neural Network)是一种基于BP算法的人工神经网络,其使用BP算法进行权值与阈值的调整。在20世纪80年代,几位不同的学者分别开发出了用于训练多层感知机的反向传播算法,David Rumelhart和James McClelland提出的反向传播算法是最具影响力的。其包含BP的两大主要过程,即工作信号的正向传播与误差信号的反向传播,分别负责了神经网络中输出的计算与权值和阈值更新。工作信号的正向传播是通过计算得到BP神经网络的实际输出,误差信号的反向传播是由后往前逐层修正权值与阈值,为了使实际输出更接近期望输出。
(1)工作信号正向传播。输入信号从输入层进入,通过突触进入隐含层神经元,经传递函数运算后,传递到输出层,并且在输出层计算出输出信号传出。当工作信号正向传播时,权值与阈值固定不变,神经网络中每层的状态只与前一层的净输出、权值和阈值有关。若正向传播在输出层获得到期望的输出,则学习结束,并保留当前的权值与阈值;若正向传播在输出层得不到期望的输出,则在误差信号的反向传播中修正权值与阈值。
(2)误差信号反向传播。在工作信号正向传播后若得不到期望的输出,则通过计算误差信号进行反向传播,通过计算BP神经网络的实际输出与期望输出之间的差值作为误差信号,并且由神经网络的输出层,逐层向输入层传播。在此过程中,每向前传播一层,就对该层的权值与阈值进行修改,由此一直向前传播直至输入层,该过程是为了使神经网络的结果与期望的结果更相近。
当进行一次正向传播和反向传播后,若误差仍不能达到要求,则该过程继续下去,直至误差满足精度,或者满足迭代次数等其他设置的结束条件。
第66页
public BPModel trainBP(BPParameter bpParameter, Matrix inputAndOutput) throws Exception {
ActivationFunction activationFunction = bpParameter.getActivationFunction();
int inputCount = bpParameter.getInputLayerNeuronCount();
int hiddenCount = bpParameter.getHiddenLayerNeuronCount();
int outputCount = bpParameter.getOutputLayerNeuronCount();
double normalizationMin = bpParameter.getNormalizationMin();
double normalizationMax = bpParameter.getNormalizationMax();
double step = bpParameter.getStep();
double momentumFactor = bpParameter.getMomentumFactor();
double precision = bpParameter.getPrecision();
int maxTimes = bpParameter.getMaxTimes();
if(inputAndOutput.getMatrixColCount() != inputCount + outputCount){
throw new Exception("神经元个数不符,请修改");
}
默认的激活函数是:sigmoid,而且提供的也只有sigmoid
sigmoid函数也叫Logistic函数,用于隐层神经元输出,取值范围为(0,1),它可以将一个实数映射到(0,1)的区间,可以用来做二分类。在特征相差比较复杂或是相差不是特别大时效果比较好。
Sigmoid函数由下列公式定义
其对x的导数可以用自身表示:
Sigmoid函数的图形如S曲线
// 初始化权值
Matrix weightIJ = initWeight(inputCount, hiddenCount);
Matrix weightJP = initWeight(hiddenCount, outputCount);
// 初始化阈值
Matrix b1 = initThreshold(hiddenCount);
Matrix b2 = initThreshold(outputCount);
// 动量项
Matrix deltaWeightIJ0 = new Matrix(inputCount, hiddenCount);
Matrix deltaWeightJP0 = new Matrix(hiddenCount, outputCount);
Matrix deltaB10 = new Matrix(1, hiddenCount);
Matrix deltaB20 = new Matrix(1, outputCount);
通过上面的BP算法的分析,接下来就更便于理解下面要讨论的动量BP算法了。动量BP算法本质上就是在BP算法的基础上引入了动量因子 n(0~1),引入次因子的优点为使其可以采用较大的学习率,而不会造成学习过程的发散,因为当修正过量时,该算法总是可以使修正量减少,以保持修正方向向着收敛的方向进行。另一方面,动量BP算法总是加速同一梯度方向的修正量。以下则使MOBP的数学模型:
该算法是以前一次的修正结果来影响本次修正量,当前一次的修正量过大时,第二项的符号将与前一次修正量的符号相反(左边小于右边),从而减少本次的修正量,起到减小振荡的作用,反之亦然。可以看出,动量BP算法总是力图使在同一梯度方向上的修正量增加。动量因子 [公式] 越大,同一梯度方向上的动量也越大。
// 截取输入矩阵和输出矩阵
Matrix input = inputAndOutput.subMatrix(0,inputAndOutput.getMatrixRowCount(),0,inputCount);
Matrix output = inputAndOutput.subMatrix(0,inputAndOutput.getMatrixRowCount(),inputCount,outputCount);
// 归一化
Map<String,Object> inputAfterNormalize = MatrixUtil.normalize(input, normalizationMin, normalizationMax);
input = (Matrix) inputAfterNormalize.get("res");
Map<String,Object> outputAfterNormalize = MatrixUtil.normalize(output, normalizationMin, normalizationMax);
output = (Matrix) outputAfterNormalize.get("res");
f2(f1(x1 * w1 + b1)*w2+ b2))
为例int times = 1; double E = 0;//误差 while (times < maxTimes) { /*-----------------正向传播---------------------*/ // 隐含层输入 Matrix jIn = input.multiple(weightIJ); // 扩充阈值 Matrix b1Copy = b1.extend(2,jIn.getMatrixRowCount()); // 加上阈值 jIn = jIn.plus(b1Copy); // 隐含层输出 Matrix jOut = computeValue(jIn,activationFunction); // 输出层输入 Matrix pIn = jOut.multiple(weightJP); // 扩充阈值 Matrix b2Copy = b2.extend(2, pIn.getMatrixRowCount()); // 加上阈值 pIn = pIn.plus(b2Copy); // 输出层输出 Matrix pOut = computeValue(pIn,activationFunction); // 计算误差 Matrix e = output.subtract(pOut); E = computeE(e);//误差 // 判断是否符合精度 if (Math.abs(E) <= precision) { System.out.println("满足精度"); break; }
相当于x1 * w1
相当于把单行的b扩充为n行(n:输入数据的个数)的b,用于构造b1
相当于内层的x1 * w1 + b1
f1(x1 * w1 + b1)
X2 * W2
X2 * W2+ b2
,其中x2 = x1 * w1+ b1f2(X2 * W2 + b2)
公式:1/2 * ( t-a )^2
代码:
/*-----------------反向传播---------------------*/ // J与P之间权值修正量 Matrix deltaWeightJP = e.multiple(step); deltaWeightJP = deltaWeightJP.pointMultiple(computeDerivative(pIn,activationFunction)); deltaWeightJP = deltaWeightJP.transpose().multiple(jOut); deltaWeightJP = deltaWeightJP.transpose(); // P层神经元阈值修正量 Matrix deltaThresholdP = e.multiple(step); deltaThresholdP = deltaThresholdP.transpose().multiple(computeDerivative(pIn, activationFunction)); // I与J之间的权值修正量 Matrix deltaO = e.pointMultiple(computeDerivative(pIn,activationFunction)); Matrix tmp = weightJP.multiple(deltaO.transpose()).transpose(); Matrix deltaWeightIJ = tmp.pointMultiple(computeDerivative(jIn, activationFunction)); deltaWeightIJ = input.transpose().multiple(deltaWeightIJ); deltaWeightIJ = deltaWeightIJ.multiple(step); // J层神经元阈值修正量 Matrix deltaThresholdJ = tmp.transpose().multiple(computeDerivative(jIn, activationFunction)); deltaThresholdJ = deltaThresholdJ.multiple(-step); if (times == 1) { // 更新权值与阈值 weightIJ = weightIJ.plus(deltaWeightIJ); weightJP = weightJP.plus(deltaWeightJP); b1 = b1.plus(deltaThresholdJ); b2 = b2.plus(deltaThresholdP); }else{ // 加动量项 weightIJ = weightIJ.plus(deltaWeightIJ).plus(deltaWeightIJ0.multiple(momentumFactor)); weightJP = weightJP.plus(deltaWeightJP).plus(deltaWeightJP0.multiple(momentumFactor)); b1 = b1.plus(deltaThresholdJ).plus(deltaB10.multiple(momentumFactor)); b2 = b2.plus(deltaThresholdP).plus(deltaB20.multiple(momentumFactor)); } deltaWeightIJ0 = deltaWeightIJ; deltaWeightJP0 = deltaWeightJP; deltaB10 = deltaThresholdJ; deltaB20 = deltaThresholdP; times++; }
以下计算变化量都是根据偏导计算,公式在下图中(公式太难敲了,略)
△w2
=dE/dw2△b2
=dE/db2△w1
=dE/dw1△b1
=dE/db1// BP神经网络的输出 BPModel result = new BPModel(); result.setInputMax((Matrix) inputAfterNormalize.get("max")); result.setInputMin((Matrix) inputAfterNormalize.get("min")); result.setOutputMax((Matrix) outputAfterNormalize.get("max")); result.setOutputMin((Matrix) outputAfterNormalize.get("min")); result.setWeightIJ(weightIJ); result.setWeightJP(weightJP); result.setB1(b1); result.setB2(b2); result.setError(E); result.setTimes(times); result.setBpParameter(bpParameter); System.out.println("循环次数:" + times + ",误差:" + E); return result; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。