Back Propagation Algorithm

这个Java程序实现了Back Propagation(BP)神经网络算法,包括数据加载、样本集划分、初始化权重、训练和测试过程。它计算sigmoid函数、均方误差,并进行权重更新以优化网络性能。

以前写的算法。(数据集见图)


package BP;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Random;
import java.util.TreeSet;

public class BackPropagation {

public class Sample//样本
{
private double[] attributes=new double[4];//样本属性值
private int label;//样本标签
Sample(double[] attributes,int label)//构造函数
{
for(int i=0;i<this.attributes.length;i++)
{
this.attributes[i]=attributes[i];
}
this.label= label;
}

public int getLabel()//获取样本标签
{
return this.label;
}

public double[] getAttributes()//返回样本的属性组
{
return this.attributes;
}

public double compute(double[] weights)//计算该样本属性与对应的权值的乘积和
{
int i;
double num=0;
for (i = 0; i < weights.length - 1; i++) 
{
num += weights[i] * this.attributes[i];
}
num -= weights[weights.length - 1] * 1;// 偏置
return num;
}

public void show()//输出样本的属性和标签
{
int i;
for(i=0;i<this.attributes.length;i++)
{
System.out.printf(this.attributes[i]+"  ");
}
System.out.println(this.label);
}
}

public double compute(double[] d,double[] weights)//计算两个数组的乘积和
{
int i;
double num=0;
for (i = 0; i < weights.length - 1; i++)
{
num += d[i]*weights[i];
}
num -= weights[weights.length - 1] * 1;// 偏置
return num;
}

//计算sigmoid函数的输出值
public double sigmoid(double x)
{
return 1.0/(1.0+Math.exp((-1.0)*x));
}

//初始化权值,随机产生0~1之间的数
public void init_weight(double[][] ih_weights,double[] ho_weights) 
{
int i,j;
Random r = new Random();
for(i=0;i<ih_weights.length;i++)//初始化输入层到隐藏层的权值
{
for(j=0;j<ih_weights[0].length;j++)
{
ih_weights[i][j]= r.nextInt(10)/10.0;
}
}
for (i = 0; i < ho_weights.length; i++)//初始化隐藏层到输出层的权值
{
ho_weights[i]= r.nextInt(10)/10.0;
}
}


//加载数据集
public void load_datas(String filename,ArrayList<Sample> sampleSet,int num_features)
{
String line;//记录从数据集中读取的行数据
String[] s ;//存储从数据集中读出的行数据分割后的样本属性和标签
double[] attributes=new double[num_features];//存储每个样本的属性值
FileReader fr =null;
BufferedReader bufr = null ;
try
{
fr = new FileReader("f:\\" +filename);
bufr= new BufferedReader(fr);
//读取训练样本
while((line = bufr.readLine())!=null)
{
s = line.split(",");
for(int i=0;i<num_features;i++)
{
attributes[i]=Double.parseDouble(s[i]);
}
sampleSet.add(new Sample(attributes,Integer.parseInt(s[4].trim())));
}
}
catch(IOException e){}
finally
{
try
{
if(bufr!=null)
bufr.close();
}
catch(IOException e){}
}
}

    //将原始数据集划分为训练集和测试集
public void divid_dataSet(ArrayList<Sample> sampleSet,ArrayList<Sample> trainSet,ArrayList<Sample> testSet)
{
ArrayList<Sample> posSet = new ArrayList<Sample>();// 正样本集
ArrayList<Sample> negSet = new ArrayList<Sample>();// 负样本集
int pos = 0;// 正样本个数
int neg = 0;// 负样本个数
int train_instances = 0;// 训练样本个数
int train_instances_pos = 0;// 训练集中正 个数
int i=0;
Iterator<Sample> it_sampleSet= sampleSet.iterator();

Collections.shuffle(sampleSet);//打乱原始数据集,重新随机排列
while(it_sampleSet.hasNext())//迭代遍历原始样本集,计算其中正,负样本数目
{
Sample s=it_sampleSet.next();
if(s.getLabel()==1)
{
posSet.add(s);//标签为1的样本加入正样本集
pos++;
}
else
{
negSet.add(s);//标签为0的样本加入负样本集
neg++;
}
}

train_instances =(int)(sampleSet.size()*0.8);//取原始数据集的80%作为训练集
train_instances_pos = (int)(train_instances * ((pos*(1.0)) / (pos + neg)));//采用分层抽样,获取训练集中相应的正样本数

i=0;
Iterator<Sample> it_posSet= posSet.iterator();
while(it_posSet.hasNext())//迭代遍历正样本集
{
Sample s= it_posSet.next();
if (i< train_instances_pos) {// 选择正样本加入训练集
trainSet.add(s);
i++;
}
else// 选择正样本加入测试集
{
testSet.add(s);
}
}

i=0;
Iterator<Sample> it_negSet= negSet.iterator();
while(it_negSet.hasNext())//迭代遍历负样本集
{
Sample s= it_negSet.next();
if (i < train_instances - train_instances_pos) {// 选择负样本加入训练集
trainSet.add(s);
i++;
}
else// 选择负样本加入测试集
{
testSet.add(s);
}
}
}

//均方误差
public double E_mean(double[][] ih_weights,double[] ho_weights, ArrayList<Sample> trainSet,int num_hiden_neuron,double threshold,double alpha)
{
int i,flag;
Sample s;
double E=0,d,num=0;
double[] hiden=new double[num_hiden_neuron];//存储隐藏层的输出
Iterator<Sample> it_trainSet=trainSet.iterator();
while(it_trainSet.hasNext())//迭代遍历训练集样本
{
num=0;
s=it_trainSet.next();//当前训练样本
for(i=0;i<num_hiden_neuron;i++)//计算隐藏层每个神经元的决策值
{
d=compute(s.getAttributes(),ih_weights[i]);
hiden[i]= sigmoid(d);
}
num +=compute(hiden,ho_weights);//计算输出层的输入乘积和
d=sigmoid(num);//计算输出层的决策值
if(d>=threshold)
flag=1;
else
flag=0;
E +=Math.pow(flag-s.getLabel(), 2);
}
return E/2.0;

}
//训练 ,参数序列依次为:                    输入层到隐藏层的权值数组,                    隐藏层到输出层的权值数组                                                                    训练集                                         隐藏层神经元个数                                      阈值                                          学习参数
public void train(double[][] ih_weights,double[] ho_weights, ArrayList<Sample> trainSet,int num_hiden_neuron,double threshold,double alpha)
{
int i,j;
Sample s;
double gradient_o,gradient_h,d,num=0;//gradient_o是输出层的梯度项,gradient_h是隐藏层的梯度项
double[] hiden=new double[num_hiden_neuron];//存储隐藏层的输出
while(true)
{
Iterator<Sample> it_trainSet=trainSet.iterator();
while(it_trainSet.hasNext())//迭代遍历训练集样本
{
num=0;
s=it_trainSet.next();//当前训练样本
for(i=0;i<num_hiden_neuron;i++)//计算隐藏层每个神经元的决策值
{
d=compute(s.getAttributes(),ih_weights[i]);//计算乘积和
hiden[i]= sigmoid(d);
}
num +=compute(hiden,ho_weights);//计算输出层的输入乘积和
d=sigmoid(num);//计算输出层的决策值

// if(d>=threshold)
// flag=1;
// else
// flag=0;

//if(flag!=s.getLabel())//样本的实际预测输出与真实标签不一致时,调整权值
//{
gradient_o=d*(1-d)*(s.getLabel()-d);//计算输出层的梯度项
for(i=0;i<hiden.length;i++)//调整隐藏层到输出层的权重
{
ho_weights[i] +=alpha*gradient_o*hiden[i];
}
ho_weights[ho_weights.length-1] -=alpha*ho_weights[ho_weights.length-1];//调整偏置

for(i=0;i<hiden.length;i++)//调整输入层到隐藏层的权重
{
gradient_h=hiden[i]*(1-hiden[i])*ho_weights[i]*gradient_o;//计算隐藏层的梯度项
for(j=0;j<ih_weights[0].length-1;j++)
{
ih_weights[i][j] +=alpha*gradient_h*s.attributes[j];
}
ih_weights[i][j] -=alpha*gradient_h;//调整偏置
}
//}
}
//均方误差小于trainSet.size()*0.0005,循环停止,即错误率小于1%时终止
if(E_mean(ih_weights,ho_weights,trainSet,num_hiden_neuron,threshold,alpha)<trainSet.size()*0.005)
break;
}
}

//测试  参数序列依次为:                                   输入层到隐藏层的权值数组,                      隐藏层到输出层的权值数组                                                                    测试集                                         隐藏层神经元个数                                      阈值                                          学习参数
public double[] test(double[][] ih_weights,double[] ho_weights, ArrayList<Sample> testSet,int num_hiden_neuron,double threshold,double alpha)throws IOException
{
double tp=0,fp=0,tn=0,fn=0;//分类结果混淆矩阵的4个值
double[] perform=new double[4];//存储分类结果混淆矩阵的4个值
double d,num=0;
Sample s;
int i,flag;
double[] hiden=new double[num_hiden_neuron];//存储隐藏层的每个神经元的值
BufferedWriter bufw = new BufferedWriter(new FileWriter("D:\\ROC.txt"));//将样本的决策值和真实标签写入文件,在matlab中画ROC
Iterator<Sample> it_testSet=testSet.iterator();
 
while(it_testSet.hasNext())//迭代遍历测试集
{
num=0;
s=it_testSet.next();//当前测试集的样本
for(i=0;i<num_hiden_neuron;i++)//计算隐藏层每个神经元的决策值
{
d=compute(s.getAttributes(),ih_weights[i]);
hiden[i]= sigmoid(d);
}

num +=compute(hiden,ho_weights);//计算乘积和
d=sigmoid(num);
bufw.write(s.getLabel()+"  "+d);
bufw.newLine();
if(d>=threshold)
flag=1;
else
flag=0;

if(s.getLabel()==1)
   {
    if(flag==1)
    tp++;
    else
    fn++;
   }
   if(s.getLabel()==0)
   {
    if(flag==1)
    fp++;
    else
    tn++;
   }
          }
   bufw.close();
perform[0]=tp;
perform[1]=fp;
perform[2]=tn;
perform[3]=fn;
return perform;

}


 public void evaluation( double tp,double fp,double tn,double fn)//算法性能表示
{
double accuracy = (tp + tn) / (tp + tn + fp + fn);
double specificity = tn / (fp + tn);
double precision = tp / (tp + fp);
double recall = tp / (tp + fn);
double sensitivity = tp / (tp + fn);
double mcc = (tp * tn - fp * fn)
/ Math.sqrt((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn));
double f1 = (2 * precision * recall) / (precision + recall);
System.out
.println("*********************************Result*****************************************");
System.out
.println("TP=" + tp + ",FP=" + fp + ",TN=" + tn + ",FN=" + fn);
System.out.println("Accuracy=" + accuracy + ",Specificity="
+ specificity);
System.out.println("Precision=" + precision + ",Recall=" + recall);
System.out.println("Sensitivity=" + sensitivity + ",MCC=" + mcc);
System.out.println("F1-measure=" + f1);
System.out
.println("********************************************************************************");
}
 
    public void showWeights(double[][] ih_weights,double[] ho_weights,int num_hiden_neuron)
    {
    System.out.printf("\n");
System.out
.println("*******************************输入层到隐层权值***************************************");
for(int i=0;i<num_hiden_neuron;i++)
{
for(int j=0;j<ih_weights[0].length;j++)
{
System.out.printf(ih_weights[i][j]+"  ");
}
System.out.printf("\n");
}
System.out
.println("********************************************************************************");

System.out.printf("\n");
System.out
.println("*******************************隐层到输出层权值***************************************");
for(int k=0;k<num_hiden_neuron+1;k++)
{
System.out.printf(ho_weights[k]+"  ");
}
System.out.printf("\n");
System.out
.println("********************************************************************************");
    }
 
public static void main(String[] args)throws IOException
{
BackPropagation bp =new BackPropagation();
ArrayList<Sample>  sampleSet= new ArrayList<Sample>();//原始样本集
ArrayList<Sample>  trainSet= new ArrayList<Sample>();//训练样本集
ArrayList<Sample>  testSet= new ArrayList<Sample>();//测试样本集
   int num_features= 4;//样本特征数目
   int num_hiden_neuron=4;//隐藏层神经元的个数
   double[][] ih_weights = new double[num_hiden_neuron][num_features+1];//存储输入层到隐藏层权值,+1为偏置
double[] ho_weights = new double[num_hiden_neuron+1];//存储隐藏层到输出层权值,+1为偏置
double alpha=0.02;//学习参数
   double threshold=0.5;//阈值
   
   
   bp.load_datas("dataSet.txt",sampleSet,num_features);//加载数据集
bp.divid_dataSet(sampleSet,trainSet,testSet);//将原始数据集划分为训练集和测试集
bp.init_weight(ih_weights,ho_weights);//初始化权值
bp.train(ih_weights,ho_weights,trainSet,num_hiden_neuron,threshold,alpha);
double[] perform=bp.test(ih_weights,ho_weights,testSet,num_hiden_neuron,threshold,alpha);
bp.evaluation(perform[0],perform[1],perform[2],perform[3]);
bp.showWeights(ih_weights,ho_weights,num_hiden_neuron);//打印权值
}


}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值