?? bptrain.java
字號:
package bp;
import structure.*;
/**
* 用BP算法訓練多層神經(jīng)網(wǎng)絡<p>
* 改進型,動量方法<p>
* 由于輸出層激活函數(shù)采用的是sigmoid函數(shù),因此輸出范圍在[0,1]之間<p>
* 因此被逼近的函數(shù)的值域應該在[0,1]
* */
public class BPTrain {
private Net net;
private ReadSample rs;
double[] res;
/**
* 誤差反向傳播訓練
* @param net 待訓練的多層網(wǎng)絡
* */
public void train(Net net){
rs=new ReadSample();
int n =1;
double testErr=0; //神經(jīng)網(wǎng)絡的誤差
double err =Parameter.getInstance().minErr;
this.net =net;
//double[] res;
rs.read();
res=rs.getResult();
do{
testErr=testNet();
if(n%10000==0)
System.out.println(n+"testErr:"+testErr);
if (testErr<err||n>100000) {
Layer outLayer=net.layers[net.layers.length-1];
for(int i=0;i<rs.getRow();i++){
net.compute(rs.getInput()[i]);
//System.out.println("input:"+rs.getInput()[i][0]+" output:"+net.getOutput()[0]+
// " err:"+(net.getOutput()[0]-res[i])+" res:"+res[i]);
}
break;
}
n++;
trainNet();
}while(true);
}
/**
* 測試網(wǎng)絡
* @return 返回所有樣本測試的均方差
* */
private double testNet(){
double testErr=0,e;
double n =rs.getRow(); //樣本數(shù)目
for(int i=0;i<n;i++){
net.compute(rs.getInput()[i]);
testErr+=Math.abs(computeOutErr(res[i]));
}
e=1/n;
return 0.5*e*testErr;
}
/**
* 訓練網(wǎng)絡
* */
private void trainNet(){
for(int i=0;i<rs.getRow();i++){
net.compute(rs.getInput()[i]);
backPropagateNet(res[i]);
adjust(rs.getInput()[i]);
}
}
/**
* 計算每個層的誤差
* */
private void backPropagateNet(double res){
Parameter para=Parameter.getInstance();
int n =para.nodeNum.length-1; //取得輸出層的位置
for(int i=n-1;i>=0;i--){
if(i==n-1) //如果是計算輸出層的誤差
backPropagateLayer(net.layers[i],null,res);
else
backPropagateLayer(net.layers[i],net.layers[i+1],0);
}
}
/**
* 計算某一層的誤差
* @param layer 層
* @param nextLayer 下一層(輸出層是隱層的下一層)
* */
private void backPropagateLayer(Layer layer,Layer nextLayer,double res){
double out;
double err;
double weight; //該層的一個神經(jīng)元到下一層某個神經(jīng)元的連接的權重
if (nextLayer==null){ //計算輸出層的誤差
for(int i=0;i<layer.neurons.length;i++){
out=layer.neurons[i].output;
layer.neurons[i].err=(out-res)*out*(1-out);
}
return;
}
for(int i=0;i<layer.num;i++){ //計算其他層的誤差
err=0;
for(int j=0;j<nextLayer.num;j++){
weight=nextLayer.neurons[j].weight[i];
err+=nextLayer.neurons[j].err*weight;
}
out=layer.neurons[i].output;
layer.neurons[i].err=out*(1-out)*err;
}
}
/**
* 計算輸入一個樣本后的輸出誤差
* <p>可以是多輸出
* */
private double computeOutErr(double res){
double err =0;
int n =Parameter.getInstance()
.nodeNum.length-1; //輸出層的位置
Layer outLayer=net.layers[n-1];
for(int i=0;i<outLayer.neurons.length;i++){
//err+=Math.abs(net.getOutput()[0]-res);
//System.out.println(i+" out:"+net.getOutput()[0]+" res:"+res);
err+=0.5*sqr(outLayer.neurons[i].output-res);
}
return err;
}
/**
* 調(diào)整權值和偏置值
* @param in 當前的輸入
* */
private void adjust(double[] in){
Parameter para =Parameter.getInstance();
double eta =para.eta;
double alpha=para.alpha;
double dw;
Layer layer,lastLayer;
Neuron neuron;
double[] lastLayerOut; //上一層的輸出
for(int i=0;i<net.layers.length;i++){
layer=net.layers[i];
if(i==0){ //當上一層是輸入層
lastLayerOut=in;
}else{
lastLayer=net.layers[i-1];
lastLayerOut=new double[lastLayer.num];
for(int j=0;j<lastLayer.num;j++){
lastLayerOut[j]=lastLayer.neurons[j].output;
}
}
for(int j=0;j<layer.neurons.length;j++){
neuron=layer.neurons[j];
for(int k=0;k<neuron.dweight.length;k++){
dw=eta*neuron.err*lastLayerOut[k]+alpha*neuron.dweight[k];
//System.out.print("調(diào)整前 w"+k+""+j+"="+neuron.weight[k]);
neuron.weight[k]+=-dw;
neuron.dweight[k]=dw;
neuron.bias-=eta*neuron.err;
//System.out.println(" 調(diào)整后 w"+k+""+j+"="+neuron.weight[k]);
}
}
}
}
private double sqr(double n){
return n*n;
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -