用java实现三层BP神经网络算法

20 篇文章 0 订阅
18 篇文章 0 订阅

首先大家了解一下BP神经网络,如下:

BP(back propagation)神经网络是1986年由Rumelhart和McClelland为首的科学家提出的概念,是一种按照误差逆向传播算法训练的多层前馈神经网络,是目前应用最广泛的神经网络。

人工神经网络无需事先确定输入输出之间映射关系的数学方程,仅通过自身的训练,学习某种规则,在给定输入值时得到最接近期望输出值的结果。作为一种智能信息处理系统,人工神经网络实现其功能的核心是算法。BP神经网络是一种按误差反向传播(简称误差反传)训练的多层前馈网络,其算法称为BP算法,它的基本思想是梯度下降法,利用梯度搜索技术,以期使网络的实际输出值和期望输出值的误差均方差为最小。

基本BP算法包括信号的前向传播和误差的反向传播两个过程。即计算误差输出时按从输入到输出的方向进行,而调整权值和阈值则从输出到输入的方向进行。正向传播时,输入信号通过隐含层作用于输出节点,经过非线性变换,产生输出信号,若实际输出与期望输出不相符,则转入误差的反向传播过程。误差反传是将输出误差通过隐含层向输入层逐层反传,并将误差分摊给各层所有单元,以从各层获得的误差信号作为调整各单元权值的依据。通过调整输入节点与隐层节点的联接强度和隐层节点与输出节点的联接强度以及阈值,使误差沿梯度方向下降,经过反复学习训练,确定与最小误差相对应的网络参数(权值和阈值),训练即告停止。此时经过训练的神经网络即能对类似样本的输入信息,自行处理输出误差最小的经过非线形转换的信息。

现在我们开始用java实现,如下:

首先定义BP神经网络的基本信息类,用来保存权重和动量因子等等。

public class BPNet {
	
        //分别是输入节点,隐藏节点,输出节点数量
	private int input_node_num;
	private int hide_node_num;
	private int output_node_num;
	
        //记录各层节点数据
	private double[] input_nodes;
	private double[] hide_nodes;
	private double[] output_nodes;
	
        //记录权重矩阵
	private DenseMatrix64F input_weights;
	private DenseMatrix64F output_weights;
	
	//记录动量因子矩阵
	private DenseMatrix64F input_momentums;
	private DenseMatrix64F output_momentums;

BPNet(int input_node_num,int hide_node_num,int output_node_num){
		
		this.input_node_num = input_node_num + 1;
		this.hide_node_num = hide_node_num;
		this.output_node_num = output_node_num;
		
		this.input_nodes =  initVector(this.input_node_num,1);
		this.hide_nodes = initVector(this.hide_node_num,1);
		this.output_nodes = initVector(this.output_node_num,1);
		
		this.input_weights = new DenseMatrix64F(this.input_node_num,this.hide_node_num);
		this.output_weights = new DenseMatrix64F(this.hide_node_num,this.output_node_num); 
		this.input_momentums = new DenseMatrix64F(this.input_node_num,this.hide_node_num);
		this.output_momentums = new DenseMatrix64F(this.hide_node_num,this.output_node_num); 
		
		for(int i=0;i<input_node_num;i++)
			for(int j=0;j<hide_node_num;j++)
				this.input_weights.set(i, j, rand(-0.5,0.5));
		
		for(int i=0;i<hide_node_num;i++)
			for(int j=0;j<output_node_num;j++)
				this.output_weights.set(i, j, rand(-1,1));
		
		this.input_momentums.zero();
		this.output_momentums.zero();
		
		
	}
}

然后是随机数生成器,作为权重矩阵调节使用

private double rand(double a,double b) {
		
		Random r = new Random();
		
		 return (b-a)*r.nextDouble() + a;
	}

sigmoid方法实现

private double sigmoid(double src) {
		return 1.0 / ( 1 + Math.exp(-src));
	}

输入数据处理


private void InputDatas(double[]  inputs) {

                //输入层
		for(int i=0;i<this.input_node_num-1;i++)
			this.input_nodes[i] = inputs[i];

                //隐藏层
		for(int i=0;i<this.hide_node_num;i++) {
			double tmp = 0;
			for(int j=0;j<this.input_node_num;j++) {
				tmp+=this.input_nodes[j] * this.input_weights.get(j,i);
			}
			this.hide_nodes[i]=sigmoid(tmp);
		}
		
                //输出层
		for(int i=0;i<this.output_node_num;i++) {
			double tmp = 0;
			for(int j=0;j<this.hide_node_num;j++) {
				tmp+=this.hide_nodes[j] * this.output_weights.get(j, i);
			}
			this.output_nodes[i]=sigmoid(tmp);
		}
		

	}

然后是BP算法的核心处理更新权重和动量因子,并返回误差均方差

private double BackPropagate(double[] targets,double N,double M) {
		
		 double[] output_deltas = new double[output_node_num];
		 
		 for(int i=0;i<output_node_num;i++) {
			 output_deltas[i] = this.output_nodes[i] * (targets[i]-this.output_nodes[i]);
		 }
		 
		 double[] hidden_deltas = new double[hide_node_num];
		 
		 for(int i=0;i<this.hide_node_num;i++) {
			double tmp = 0;
			for(int j=0;j<this.output_node_num;j++) {
				tmp+=output_deltas[j] * this.output_weights.get(i,j);
			}
			hidden_deltas[i]=this.hide_nodes[i]*tmp;
		 }
		 
		 for(int i=0;i<this.hide_node_num;i++) {
			for(int j=0;j<this.output_node_num;j++) {
			    double change = output_deltas[j]*this.hide_nodes[i];
			    this.output_weights.set(i, j, this.output_weights.get(i,j)+N*change + M*this.output_momentums.get(i,j));
			    this.output_momentums.set(i, j, change);
			}
		 }
		 
		 for(int i=0;i<this.input_node_num;i++) {
			for(int j=0;j<this.hide_node_num;j++) {
			    double change = hidden_deltas[j]*this.input_nodes[i];
			    this.input_weights.set(i, j, this.input_weights.get(i,j)+N*change + M*this.input_momentums.get(i,j));
			    this.input_momentums.set(i, j, change);
			}
		 }

		 double error = 0;
		 
		 for(int i=0;i<targets.length;i++) {
			 error += 0.5*Math.pow((targets[i]-this.output_nodes[i]),2);
		 }

		 return error;
	}

训练数据方法

private void TrainData(double[][] patterns,double[][] labels,int iterations,double N,double M) {
		
		for(int i=0;i<iterations;i++) {
			double error = 0.0;
			
			for(int j=0;j<patterns.length;j++) {
				this.InputDatas(patterns[j]);
				error+=this.BackPropagate(labels[j], N, M);
			}
			
			if(i % 100 == 0) {
				System.out.println("diff:"+error);
			}
		}
	
	}

现在开始测试进行2万次迭代

double[][] datas = {{0,0},{0.1,0.1},{0,0.9},{0,1},{0.9,0.1},{1,0},{1,1},{0.9,0.9}};
		double[][] labels = {{0},{0},{1},{1},{1},{1},{0},{0}};
		
		BPNet bp = new BPNet(2,5, 1);
		
		bp.TrainData(datas, labels, 20000,0.5,0.1);
		
		for(int i=0;i<datas.length;i++) {
	        bp.InputDatas(datas[i]);
	        System.out.println(bp.getOutput_nodes()[0]);
		}

可以看到误差从一开始的1.19收敛到了小于0.001,如下图:

对原数据测试,全部正确

  • 2
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路边草随风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值