本文实现的是对张军等编写的《计算智能》第二章中的2.4.3引用举例的code实现。
图一
图二
import java.util.Scanner;
public class Bp {
private int InputLayer = 3; //输入层
private int HiddenLayer = 2; //隐含层
private int OutputLayer = 1; //输出层
private double LearningRate = 0.9; //学习率
private double ExpectedValue = 1; //预期值
double [][] Input_Hidden_weights = new double [InputLayer][HiddenLayer]; //输入层到隐含层的权重
double [][] Hidden_Output_weights = new double [HiddenLayer][OutputLayer]; //隐含层到输出层的权重
double [] Hidden_polarization = new double[HiddenLayer]; //隐含层的偏置
double [] Output_polarization = new double[OutputLayer]; //输出层的偏置
double [] HiddenInputValues = new double[HiddenLayer]; //隐含层的输入值
double [] HiddenOutputValues = new double[HiddenLayer]; //隐含层的输出值
double [] OutputInputValues = new double[OutputLayer]; //输出层的输入值
double [] OutputOutputValues = new double[OutputLayer]; //输出层的输出值
double [] ErrorHiddenValues = new double[HiddenLayer]; //隐含层的误差值
double [] ErrorOutputValues = new double[OutputLayer]; //输出层的误差值
double [][] Adjustment_Input_Hidden_weights = new double [InputLayer][HiddenLayer]; //调整输入层到隐含层的权重
double [][] Adjustment_Hidden_Output_weights = new double [HiddenLayer][OutputLayer]; //调整隐含层到输出层的权重
double [] Adjustment_Hidden_polarization = new double [HiddenLayer]; //调整隐含层的偏置
double [] Adjustment_Output_polarization = new double [OutputLayer]; //调整输出层的偏置
//一、初始化网络权重和偏置
void initialize(){
Scanner in = new Scanner(System.in);
//(1)输入层到隐含层的连接权重
System.out.println("请输入输出层到隐含层的连接权重:");
for (int i = 0 ; i < InputLayer ; i++ ){
for ( int j = 0 ; j < HiddenLayer; j++ ){
Input_Hidden_weights[i][j]= in.nextDouble();
}
}
//(2)隐含层到输出层的连接权重
System.out.println("请输入隐含层到输出层的连接权重:");
for (int i = 0 ; i < HiddenLayer ; i++ ){
for ( int j = 0 ; j < OutputLayer; j++ ){
Hidden_Output_weights[i][j]= in.nextDouble();
}
}
//(3)隐含层的偏置
System.out.println("请输入隐含层的偏置:");
for (int i = 0 ; i < HiddenLayer ; i++ ){
Hidden_polarization[i] = in.nextDouble();
}
//(4)输出层的偏置
System.out.println("请输入输出层的偏置:");
for (int i = 0 ; i < OutputLayer ; i++ ){
Output_polarization[i] = in.nextDouble();
}
System.out.println("*********************************");
}
//二、创建激活函数
double ActivationFunction(double x){
return 1/( 1 + Math.pow(Math.E,-x));
}
//三、向前传播输入(前馈型网络)
void Forward( double[] TrainingSamples ){
//隐含层的总输入和输出
for(int i = 0; i < HiddenInputValues.length ; i++ ){
double OutputSumTemp = 0; //临时存放数据
for(int j = 0; j < TrainingSamples.length; j++ ){
OutputSumTemp += TrainingSamples[j]*Input_Hidden_weights[j][i];
}
HiddenInputValues[i]= OutputSumTemp + Hidden_polarization[i];
System.out.println("神经元"+(i+4)+"的总输入:");
System.out.println(HiddenInputValues[i]);
HiddenOutputValues[i] = ActivationFunction(HiddenInputValues[i]);
System.out.println("神经元"+(i+4)+"的总输出:");
System.out.println(HiddenOutputValues[i]);
}
//输出层的总输入和输出
for( int i = 0 ; i < OutputLayer ; i++ ){
double OutputSumTemp = 0; //临时存放数据
for(int j = 0; j < HiddenLayer ; j++ ){
OutputSumTemp += HiddenOutputValues[j]*Hidden_Output_weights[j][i];
}
OutputInputValues[i]= OutputSumTemp + Output_polarization[i];
System.out.println("神经元"+(i+6)+"的总输入:");
System.out.println(OutputInputValues[i]);
OutputOutputValues[i] = ActivationFunction(OutputInputValues[i]);
System.out.println("神经元"+(i+6)+"的总输出:");
System.out.println(OutputOutputValues[i]);
}
System.out.println("*********************************");
}
//三、反向误差传播
void BackWard(){
//输出层的误差
for(int i = 0 ; i < OutputLayer ; i++ ){
ErrorOutputValues[i] = OutputOutputValues[i]*( 1 - OutputOutputValues[i])*( ExpectedValue - OutputOutputValues[i] );
System.out.println("神经元"+(i+6)+"的误差:");
System.out.println(ErrorOutputValues[i]);
}
//隐含层的误差
for(int i = HiddenLayer - 1 ; i >= 0 ; i-- ){
double ErrorTemp = 0; //临时存放数据
for(int j = 0 ; j < OutputLayer ; j++ ){
ErrorTemp = HiddenOutputValues[i]*( 1-HiddenOutputValues[i])*ErrorOutputValues[j]*Hidden_Output_weights[i][j];
}
ErrorHiddenValues[i] = ErrorTemp;
System.out.println("神经元"+(i+4)+"的误差:");
System.out.println(ErrorHiddenValues[i]);
}
System.out.println("*********************************");
}
//四、网络连接权重和偏置的调整
void Adjustment(double[] TrainingSamples){
//(1)调整隐含层到输出层的权重值
System.out.println("调整隐含层到输出层的连接权重:");
for(int i = 0 ; i < HiddenLayer ; i++ ){
double TempWeights = 0; //临时存放数据
for(int j = 0 ; j < OutputLayer ; j++ ){
TempWeights = Hidden_Output_weights[i][j]+LearningRate*ErrorOutputValues[j]*HiddenOutputValues[i];
Adjustment_Hidden_Output_weights[i][j] = TempWeights;
System.out.println(Adjustment_Hidden_Output_weights[i][j]);
}
}
//(2)调整输入层到隐含层的权重值
System.out.println("调整输入层到隐含层的权重值:");
for(int i = 0 ; i < InputLayer ; i++ ){
double TempWeights = 0; //临时存放数据
for(int j = 0 ; j < HiddenLayer; j++ ){
TempWeights = Input_Hidden_weights[i][j]+LearningRate*ErrorHiddenValues[j]*TrainingSamples[i];
Adjustment_Input_Hidden_weights[i][j] = TempWeights;
System.out.println(Adjustment_Input_Hidden_weights[i][j]);
}
}
//(3)调整输出层的偏置
System.out.println("调整输出层的偏置:");
for(int i = 0; i < OutputLayer; i++ ){
Adjustment_Output_polarization[i] = Output_polarization[i] + LearningRate * ErrorOutputValues[i];
System.out.println(Adjustment_Output_polarization[i]);
}
//(4)调整隐含层的偏置
System.out.println("调整隐含层的偏置:");
for(int i = HiddenLayer - 1 ; i >= 0; i-- ){
Adjustment_Hidden_polarization[i] = Hidden_polarization[i] + LearningRate * ErrorHiddenValues[i];
System.out.println(Adjustment_Hidden_polarization[i]);
}
}
//五、判断结束
void Judge(){
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Bp bpnn = new Bp();
bpnn.initialize();
double[] TrainData = {1,0,1};
bpnn.Forward(TrainData);
bpnn.BackWard();
//如果误差不在容忍的范围内则进行调整
bpnn.Adjustment(TrainData);
}
}
运行截图:
注意点:
这个code实现的是一次计算,由于判断函数没有去实现。书中对判断结束描述如下:对于每个样本,如果最终的输出误差小于可接受的范围或者迭代次数t达到了一定的阈值,则选取下一个样本,转到步骤二继续执行;否则,迭代次数加1,然后向步骤2继续使用当前样本训练。
参考资料:
(1)woodbean – BP神经网络实现(Java代码):http://blog.csdn.net/woodbean/article/details/7175378
(2)ACdreamers – BP神经网络:http://blog.csdn.net/acdreamers/article/details/44657439
(3)https://zhidao.baidu.com/question/320522363.html
(4)http://www.cnblogs.com/hesi/p/7218602.html
(5)刀客123 – BP神经网络的数据分类 : http://blog.csdn.net/dingyahui123/article/details/72809153?locationNum=1&fps=1
(6)zhc0822 – BP神经网络的Java实现 : http://fantasticinblur.iteye.com/blog/1465497