使用iris数据集通过(?)测试,部分测试结果如下
Sample 30 output: [0.9173913048441509 ,0.07218233216540289 ,0.05744858265348781]
Sample 31 output: [0.917292984920966 ,0.07226427474570203 ,0.05751372081755422]
Sample 32 output: [0.918114384748762 ,0.0713477300259459 ,0.0567037735359584]
Sample 33 output: [0.9189481821904941 ,0.07067531962504378 ,0.05611338236094786]
Sample 34 output: [0.9191395178042765 ,0.07041061573734159 ,0.05586669511083175]
Sample 35 output: [0.9172532110788241 ,0.07228931702502635 ,0.05748128484860246]
Sample 36 output: [0.9172752653761954 ,0.07211471985313571 ,0.057250110770381404]
Sample 37 output: [0.9180905113382464 ,0.07134885843883981 ,0.05662172416767537]
Sample 38 output: [0.9172532110788241 ,0.07228931702502635 ,0.05748128484860246]
Sample 39 output: [0.9165688820679151 ,0.07287697667570102 ,0.05794994983627105]
Sample 40 output: [0.9179057763850749 ,0.07162805170331658 ,0.056929321524857794]
Sample 41 output: [0.9178717765050967 ,0.07156232654619624 ,0.05682984883273152]
Sample 42 output: [0.9153313393388919 ,0.07398825937078152 ,0.058912503398660616]
Sample 43 output: [0.9169313882658655 ,0.07253471108301074 ,0.05765933287066486]
Sample 44 output: [0.9181687199702597 ,0.07130231976989787 ,0.056738514755495524]
Sample 45 output: [0.9188397803666218 ,0.0708361637887942 ,0.056398973166296724]
Sample 46 output: [0.9170014434581761 ,0.07243067392965044 ,0.057605319231257564]
Sample 47 output: [0.9185858497855375 ,0.07102838137303531 ,0.0564522737320248]
Sample 48 output: [0.9171664939908034 ,0.07233088463353576 ,0.05751266356066004]
Sample 49 output: [0.9184613071029186 ,0.07109378649317799 ,0.056471769599150436]
Sample 50 output: [0.9176069934031237 ,0.07187964526042434 ,0.057114905318048644]
Sample 51 output: [0.056661448715799256 ,0.9197971680666066 ,0.07034273604934331]
Sample 52 output: [0.05703994046881898 ,0.9193897373001655 ,0.07070184135267996]
Sample 53 output: [0.056972124673542596 ,0.9195511345944515 ,0.07059235324621554]
Sample 54 output: [0.0588559895075485 ,0.9171656902574303 ,0.07268532097165667]
Sample 55 output: [0.057536347679306876 ,0.9188198438194021 ,0.07121395582717005]
Sample 56 output: [0.05817266763576755 ,0.9182205234491182 ,0.07182467026894204]
Sample 57 output: [0.05713037213247033 ,0.9194162321584641 ,0.07071321494288134]
Sample 58 output: [0.058875908321747314 ,0.916832848600374 ,0.07294902583476662]
Sample 59 output: [0.05725757115032023 ,0.9191174308410729 ,0.07096289636406912]
Sample 60 output: [0.058499003167677165 ,0.9176086193746652 ,0.07227789562302502]
使用姿势如下
public class Test {
public static void main(String[] args) {
/*两个隐含层,隐含层4个元素*/
/*目标误差0.009,最大学习次数40000,学习效率0.25,
/*动量因子0.9*/
/*设有两层隐含层*/
BP net = new BP(0.25, 0.9, 1, 0.09, 4000, 2, 4);
net.train();
net.test();
}
}
累计变量的收敛情况
1.1.png
实现代码如下
package BP;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
/*
一个用于分类的BP神经网络
*/
public class BP {
/*********************/
/*对训练样本文件的要求:*/
/*第一行格式为*/
/*输入层神经元个数 输出层神经元个数*/
/*样本值的格式要求为*/
/*样本特征向量 期望输出向量 (空格分开)*/
/*期望输出向量格式:(0 |1.0 )*,只能有一个1.0*/
/*********************/
Scanner scanner;
private final String TRAINING_FILE_PATH = "src/BP/training_samples.txt";
private final String TEST_FILE_PATH = "src/BP/test_samples.txt";
private final String OUTPUT_FILE_PATH = "C:\\Coding\\JFreeChart\\src\\chart_source.txt"; //输出数据用于JFreeChar绘图,绘图代码略
private final String OUTPUT_FILE_PATH_2 = "C:\\Coding\\JFreeChart\\src\\chart_source_2.txt"; //意义同上
private final String OUTPUT_FILE_PATH_3 = "C:\\Coding\\JFreeChart\\src\\chart_source_3.txt"; //意义同上
//private double training_sample_count; //训练样本数
private double eta; //学习因子
private double alpha; //动量因子
private double gain; //sigmoid参数
private double minError; //最小误差
private double outputError;
private long maxTrainingTime; //最大训练次数
private int hiddenLayerCount; //隐含层层数
private int neuronCountHiddenLayer; //假定每个隐含层都有相同的神经元数
private int neuronCountInputLayer; //输入层神经元个数
private int neuronCountOutputLayer; //输出层神经元个数
Layer inputLayer; //输入层
Layer outputLayer; //输出层
ArrayList<Layer> hiddenLayerList; //隐含层
private double[][] wxh; //输入层和第一个隐含层的权值
private double[][][] whh; //隐含层之间的权值
private double[][] why; //隐含层和输出层之间的权值
private double[][] dwxh; //dWeight
private double[][][] dwhh;
private double[][] dwhy;
private double[] target; // target output
/*生成训练好的BP神经网络*/
public BP(double eta, double alpha, double gain, double minError, long maxTrainingTime, int hiddenLayerCount, int neuronCountHiddenLayer) {
this.eta = eta;
this.alpha = alpha;
this.gain = gain;
this.minError = minError;
this.maxTrainingTime = maxTrainingTime;
this.hiddenLayerCount = hiddenLayerCount;
this.neuronCountHiddenLayer = neuronCountHiddenLayer;
try {
/*读取第一行*/
scanner = new Scanner(new File(TRAINING_FILE_PATH));
String input_line = scanner.nextLine();
String[] temp = input_line.split(" ");
neuronCountInputLayer = Integer.parseInt(temp[0]);
neuronCountOutputLayer = Integer.parseInt(temp[1]);
/*分配内存*/
inputLayer = new Layer(neuronCountInputLayer);
outputLayer = new Layer(neuronCountOutputLayer);
hiddenLayerList = new ArrayList<>(hiddenLayerCount);
for (int i = 0; i < hiddenLayerCount; ++i)
hiddenLayerList.add(new Layer(neuronCountHiddenLayer));
wxh = new double[neuronCountInputLayer][neuronCountHiddenLayer];
dwxh = new double[neuronCountInputLayer][neuronCountHiddenLayer];
whh = new double[hiddenLayerCount - 1][neuronCountHiddenLayer][neuronCountHiddenLayer];
dwhh = new double[hiddenLayerCount - 1][neuronCountHiddenLayer][neuronCountHiddenLayer];
why = new double[neuronCountHiddenLayer][neuronCountOutputLayer];
dwhy = new double[neuronCountHiddenLayer][neuronCountOutputLayer];
target = new double[neuronCountOutputLayer];
/*初始化权值和阈值信息*/
for (int i = 0; i < wxh.length; ++i) {
for (int j = 0; j < wxh[0].length; ++j) {
wxh[i][j] = Functions.random(-0.5, 0.5);
}
}
for (int i = 0; i < whh.length; ++i) {
for (int j = 0; j < neuronCountHiddenLayer; ++j) {
for (int k = 0; k < neuronCountHiddenLayer; ++k) {
whh[i][j][k] = Functions.random(-0.5, 0.5);
}
hiddenLayerList.get(i).thresh[j] = Functions.random(-0.5, 0.5);
}
}
for (int i = 0; i < neuronCountOutputLayer; ++i) {
for (int j = 0; j < neuronCountHiddenLayer; ++j) {
why[j][i] = Functions.random(-0.5, 0.5);
}
outputLayer.thresh[i] = Functions.random(-0.5, 0.5);
}
//train();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
/*训练网络*/
public void train() {
String s;
double accumulatedError; //累计
int sample = 1;
try {
FileWriter writer = new FileWriter(new File(OUTPUT_FILE_PATH));
while (true) {
s = scanner.nextLine();
if (s == null) break;
accumulatedError = 0;
/*对单个样本进行训练*/
int turn = 0;
while (true) {
++turn;
outputError = 0;
train(s);
accumulatedError += outputError;
/*去掉后面一项即为去掉评估函数*/
if (turn > maxTrainingTime || outputError < minError)
break;
}
writer.write(sample + " " +accumulatedError + '\n');
++sample;
if (!scanner.hasNextLine()) break;
}
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/*利用文本中的一行信息进行训练*/
private void train (String sample) {
/*实例化输入层数据和该向量对应的*/
String[] temp = sample.split(" ");
for (int i = 0; i < neuronCountInputLayer; ++i)
inputLayer.output[i] = Double.parseDouble(temp[i]);
target = new double[neuronCountOutputLayer];
for (int i = neuronCountInputLayer; i < temp.length; ++i)
target[i - neuronCountInputLayer] = Double.parseDouble(temp[i]);
feedForward();
outputError = 0;
propagateBackward();
updateWeights();
}
/*测试训练完成的神经网络*/
public void test() {
try {
Scanner scanner = new Scanner(new File(TEST_FILE_PATH));
int sample = 30;
while (scanner.hasNextLine()) {
String[] temp = scanner.nextLine().split(" ");
for (int i = 0; i < neuronCountInputLayer; ++i) {
this.inputLayer.output[i] = Double.parseDouble(temp[i]);
}
this.outputError = 0;
feedForward();
++sample;
}
} catch (Exception e) {
e.printStackTrace();
}
}
/*Propagate the inputs forward to compute the outputs*/
private void feedForward() {
/*输入层到第一隐含层*/
Layer firstHiddenLayer = hiddenLayerList.get(0);
for (int i = 0; i < firstHiddenLayer.neuronNumber; ++i) {
double net = 0;
for (int j = 0; j < inputLayer.neuronNumber; ++j) {
net += (inputLayer.output[j] * wxh[j][i]);
}
net -= firstHiddenLayer.thresh[i];
firstHiddenLayer.output[i] = Functions.sigmoid(net, gain);
}
/*计算隐含层之间的输出值,从第二层开始*/
for (int i = 1; i < hiddenLayerCount; ++i) {
Layer thisLayer = hiddenLayerList.get(i);
Layer formerLayer = hiddenLayerList.get(i - 1);
for (int j = 0; j < thisLayer.neuronNumber; ++j) {
double net = 0;
for (int k = 0; k < formerLayer.neuronNumber; ++k) {
net += (formerLayer.output[k] * whh[i-1][k][j]);
}
net -= thisLayer.thresh[j];
thisLayer.output[j] = Functions.sigmoid(net, gain);
}
}
/*最后一层到输出层*/
Layer lastLayer = hiddenLayerList.get(hiddenLayerList.size() - 1);
for (int i = 0; i < outputLayer.neuronNumber; ++i) {
double net = 0;
for (int j = 0; j < lastLayer.neuronNumber; ++j) {
net += (lastLayer.output[j] * why[j][i]);
}
net -= outputLayer.thresh[i];
outputLayer.output[i] = Functions.sigmoid(net, gain);
}
}
/* Propagate deltas backward from output layer to input layer*/
private void propagateBackward () {
/*Computes deltas in the output layer*/
for (int i = 0; i < outputLayer.neuronNumber; ++i) {
double error = target[i] - outputLayer.output[i];
outputLayer.delta[i] = gain
* outputLayer.output[i]
* (1 - outputLayer.output[i])
* error;
this.outputError = (error * error) / 2;
}
/*Computes deltas in the last hidden layer*/
Layer lastLayer = hiddenLayerList.get(hiddenLayerList.size() - 1);
for (int i = 0; i < lastLayer.neuronNumber; ++i) {
double temp = 0;
for (int j = 0; j < outputLayer.neuronNumber; ++j)
temp += (outputLayer.delta[j] * why[i][j]);
lastLayer.delta[i] = (1 - lastLayer.output[i]) * lastLayer.output[i] * temp;
}
/*Computes deltas among the hidden layer*/
for (int i = hiddenLayerList.size() - 2; i >= 0; --i) {
Layer thisLayer = hiddenLayerList.get(i);
Layer sucLayer = hiddenLayerList.get(i + 1);
for (int j = 0; j < thisLayer.neuronNumber; ++j) {
double temp = 0;
for (int k = 0; k < sucLayer.neuronNumber; ++k)
temp += (sucLayer.delta[k] * whh[i][j][k]);
thisLayer.delta[j] = (1 - thisLayer.output[i]) * thisLayer.output[i] * temp;
}
}
}
private void updateWeights() {
/*更新输入层和第一层的权值和阈值*/
Layer firstLayer = hiddenLayerList.get(0);
for (int j = 0; j < firstLayer.neuronNumber; ++j) {
for (int i = 0; i < inputLayer.neuronNumber; ++i) {
wxh[i][j] += (eta * firstLayer.delta[j] * inputLayer.output[i] + alpha * dwxh[i][j]);
dwxh[i][j] = eta * inputLayer.delta[j] * firstLayer.output[i];
}
firstLayer.thresh[j] = eta * firstLayer.delta[j];
}
/*更新隐含层之间的权值和阈值*/
for (int i = 1; i < hiddenLayerList.size(); ++i) {
Layer thisLayer = hiddenLayerList.get(i);
Layer formerLayer = hiddenLayerList.get(i - 1);
for (int j = 0; j < thisLayer.neuronNumber; ++j) {
for (int k = 0; k < formerLayer.neuronNumber; ++k) {
whh[i - 1][k][j] += (eta * thisLayer.delta[j] * formerLayer.output[k] + alpha * dwhh[i - 1][k][j]);
dwhh[i-1][k][j] = eta * thisLayer.delta[j] * formerLayer.output[k];
}
thisLayer.thresh[j] = eta * thisLayer.delta[j];
}
}
/*更新输出层的权值和阈值*/
Layer lastLayer = hiddenLayerList.get(hiddenLayerList.size() - 1);
for (int j = 0; j < outputLayer.neuronNumber; ++j) {
for (int i = 0; i < lastLayer.neuronNumber; ++i) {
why[i][j] += (eta * outputLayer.delta[j] * lastLayer.output[i] + alpha * dwhy[i][j]);
dwhy[i][j] = eta * outputLayer.delta[j] * lastLayer.output[i];
}
outputLayer.thresh[j] = eta * outputLayer.delta[j];
}
}
static class Layer {
int neuronNumber;
double[] output;
double[] delta;
double[] thresh;
public Layer(int neuronNumber) {
this.neuronNumber = neuronNumber;
output = new double[neuronNumber];
delta = new double[neuronNumber];
thresh = new double[neuronNumber];
}
}
}
附用JFreeChart做的参数对累计误差收敛影响的图
[alpha]
1.2.png
[eta]
1.3.png
[gain]
1.4.png
[层数]
1.5.png
网友评论