BP神经网络实现(Java代码)

神经网络的原理虽然理解起来不难,但是要是想实现它,还是需要做一些工作的,并且有很多细节性的东西需要注意。通过参阅各种相关资料,以及参考网络上已有的资源,自己写了一个含有一个隐含层,且只能有一个输出单元的简单的BP网络,经过测试,达到了预期的效果。

需要说明的是,神经网络的每个输入都在[0,1]中,输出也在[0,1]中,在使用神经网络解决实际问题的时候,还需要对实际问题的输入输出进行归一化处理。另外,尽量不要使得神经网络的输入或输出接近于0或1,这样会影响拟合效果。

我用正弦函数进行了一次测试,效果如图所示:


以下是相关的代码:

1.神经网络代码

package pkg1;

import java.util.Scanner;

/*
 * 
 */
public class TestNeuro {

	private int INPUT_DIM=1;
	private int HIDDEN_DIM=20;
	private double LEARNING_RATE=0.05;
	double [][] input_hidden_weights=new double[INPUT_DIM][HIDDEN_DIM];
	double [] hidden_output_weights=new double[HIDDEN_DIM];
	double[] hidden_thresholds=new double[HIDDEN_DIM];
	double output_threshold;
	
	public static void main(String[]args){
		Scanner in=new Scanner(System.in);
		TestNeuro neuro=new TestNeuro(1,5);
		neuro.initialize();
		for(int i=0;i<10000;i++){
			double[] input=new double[1];
			input[0]=Math.random();
			double expectedOutput=input[0]*input[0];
			//System.out.println("input : "+input[0]+"\t\texpectedOutput : "+expectedOutput);
			//System.out.println("predict before training : "+neuro.predict(input));
			neuro.trainOnce(input, expectedOutput);
			//System.out.println("predict after training : "+neuro.predict(input));
			//in.next();
		}
		while(true){
			//neuro.printLinks();
			double[] input=new double[1];
			input[0]=in.nextDouble();
			double expectedOutput=in.nextDouble();
			System.out.println("predict before training : "+neuro.predict(input));
			neuro.trainOnce(input, expectedOutput);
			System.out.println("predict after training : "+neuro.predict(input));
			
		}
	}
	
	public TestNeuro(int input_dimension,int hidden_dimension){
		this.INPUT_DIM=input_dimension;
		this.HIDDEN_DIM=hidden_dimension;
		this.initialize();
	}
	
	
	/**
	 * 打印出本神经元网络各层之间的连接权重,以及各个神经元上的阈值的信息。
	 */
	void print(){
		System.out.println("隐含层阈值:");
		for(int i=0;i<HIDDEN_DIM;i++){
			System.out.print(hidden_thresholds[i]+" ");
		}System.out.println();
		System.out.println("输出层阈值:");
		System.out.println(output_threshold);
		
		System.out.println("连接权重:*********************");
		System.out.println("输入层与隐含层的连接");
		for(int i=0;i<INPUT_DIM;i++){
			for(int j=0;j<HIDDEN_DIM;j++){
				System.out.print(input_hidden_weights[i][j]+" ");
			}System.out.println();
		}
		System.out.println("隐含层到输出层的连接");
		for(int i=0;i<HIDDEN_DIM;i++){
			System.out.print(hidden_output_weights[i]+" ");
		}System.out.println();
		System.out.println("*********************************");
	}
	
	/**
	 * 初始化,对所有的权值产生一个(0,1)之间的随机double型值
	 */
	void initialize(){
		
		//输入层到隐含层的连接权重
		for(int i=0;i<INPUT_DIM;i++){
			for(int j=0;j<HIDDEN_DIM;j++){
				input_hidden_weights[i][j]=Math.random();
			}
		}
		//隐含层到输出层的连接权重
		for(int i=0;i<HIDDEN_DIM;i++){
			hidden_output_weights[i]=Math.random();
		}
		//隐含层的阈值
		for(int i=0;i<HIDDEN_DIM;i++){
			hidden_thresholds[i]=Math.random();
		}
		//输出层的阈值
		output_threshold=Math.random();
	}
	
	/**
	 * 激励函数
	 * @param x
	 * @return
	 */
	double function(double x){
		return 1/(1+Math.pow(Math.E, -x));
	}
	
	/**
	 * 给定一个输入,进行预测
	 * @param input
	 * @return
	 */
	double predict(double[]input){
		double[] hiddenValues=new double[HIDDEN_DIM];
		for(int i=0;i<hiddenValues.length;i++){
			double sum=0;
			for(int j=0;j<input.length;j++){
				sum+=input[j]*input_hidden_weights[j][i];
			}
			sum+=hidden_thresholds[i];//再加上本神经元的阈值
			hiddenValues[i]=function(sum);
		}
		
		
		double sum=0;
		for(int i=0;i<HIDDEN_DIM;i++){
			sum+=hiddenValues[i]*hidden_output_weights[i];
		}
		sum+=output_threshold;//输出层神经元的阈值
		return function(sum);
	}
	
	/**
	 * 进行一次训练
	 * @param input
	 * @param expectedOutput
	 */
	void trainOnce(double[] input, double expectedOutput){
		double[] hiddenValues=new double[HIDDEN_DIM];
		double[] hiddenParams=new double[HIDDEN_DIM];
		
		for(int i=0;i<hiddenValues.length;i++){
			double sum=0;
			for(int j=0;j<input.length;j++){
				sum+=input[j]*input_hidden_weights[j][i];
			}
			sum+=hidden_thresholds[i];//
			hiddenValues[i]=function(sum);
			hiddenParams[i]=sum;
		}
		
		double sum=0;
		for(int i=0;i<HIDDEN_DIM;i++){
			sum+=hiddenValues[i]*hidden_output_weights[i];
		}
		sum+=output_threshold;//
		double outputValue=function(sum);
		double outputParam=sum;
		//System.out.println("实际输出");
		
		/*
		 * 调整权值和阈值
		 */
		
		for(int i=0;i<input.length;i++){
			double factor=(expectedOutput-outputValue)*outputValue*(1-outputValue)*LEARNING_RATE*input[i];
			for(int j=0;j<HIDDEN_DIM;j++){
				double delta=factor*hidden_output_weights[j]*hiddenValues[j]*(1-hiddenValues[j]);
				//System.out.println("输入层到隐含层连接的权重调整:delta = "+delta+"\t\t weight = "+input_hidden_weights[i][j]);
				input_hidden_weights[i][j]+=delta;
			}
		}
		double factor=(expectedOutput-outputValue)*outputValue*(1-outputValue)*LEARNING_RATE;
		for(int i=0;i<hidden_thresholds.length;i++){
			double delta=factor*hidden_output_weights[i]*hiddenValues[i]*(1-hiddenValues[i]);
			hidden_thresholds[i]+=delta;
		}
		
		//System.out.println("hidden_output_weights : "+hidden_output_weights.length);
		for(int i=0;i<hidden_output_weights.length;i++){
			//w+=(exp-act)*df/dw
			//df/dw=x(1-x)*hiddenj
			double delta=factor*hiddenValues[i];
			//System.out.println("隐含层到输出层连接的权值调整:delta = "+delta+"\t\t weight = "+hidden_output_weights[i]);
			hidden_output_weights[i]+=delta;
			
		}
		double delta=(expectedOutput-outputValue)*outputValue*(1-outputValue)*LEARNING_RATE;
		output_threshold+=delta;
		if(Math.abs(outputValue-expectedOutput)>0.1){
			//System.out.println(input[0]+"\t\t"+outputValue+"\t\t"+expectedOutput);
		}
		

		
	}
	
}


2.测试代码


package pkg1;

import java.awt.Graphics;
import java.util.Scanner;

import javax.swing.JFrame;

public class DisplayNeuro extends javax.swing.JPanel{

	public static final int SIDE_LENGTH=200;
	
	TestNeuro neuro;//=new TestNeuro();
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		DisplayNeuro dn=new DisplayNeuro();
		JFrame jFrame=new JFrame();
		jFrame.setBounds(100, 100, 300, 300);
		jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jFrame.add(dn);
		jFrame.setVisible(true);
		
		TestNeuro neuro=new TestNeuro(1,20);
		dn.neuro=neuro;
		Scanner in=new Scanner(System.in);
		dn.repaint();
		for(int i=0;i<100000000;i++){
			double[] input=new double[1];
			input[0]=Math.random()/2+0.25;
			double expectedOutput=(Math.sin(3.14*(input[0]-0.25)*2*4)+1)/8*3+0.125;
			//System.out.println("input : "+input[0]+"\t\texpectedOutput : "+expectedOutput);
			//System.out.println("predict before training : "+neuro.predict(input));
			neuro.trainOnce(input, expectedOutput);
			//System.out.println("predict after training : "+neuro.predict(input));
			
			if(i%100000==0){
			
				System.out.println("input please ");
				//in.next();
				//neuro.initialize();
				dn.repaint();
			}
			
		}
	}
	
	
	@Override
	public void paint(Graphics arg0) {
		// TODO Auto-generated method stub
		super.paint(arg0);
		
		for(double x=0.25;x<0.75;x+=0.005){
			double[] input=new double[1];
			input[0]=x;
			double y=neuro.predict(input);
			arg0.fillRect((int)(x*SIDE_LENGTH), (int)((1-y)*SIDE_LENGTH), 1, 1);
		}
		
		
	}
	

}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值