项目:奇偶识别
将一个int型整数转化为32位二进制数作为BP人工神经网络的输入(例如,整数2为10前面加30个0,这32个数字分别为32个输入),0或1作为输出层的输出(该数为偶数,则预期输出d为0;该数为奇数,则预期输出d为1),以这样的模型(32个输入,隐含层16个神经元,输出层1个神经元,学习率参数r的值为0.1)训练1000个回合(训练一回合=训练一次训练集,训练一回合后,打乱训练集,再进行下一回合的训练),然后对测试集进行测试并统计奇偶识别率。
训练集:1000个随机整数和1000个预期输出
测试集:10000个随机整数
注:这里的神经网络模型写的是关于二分类的问题,没有写通用的神经网络类
反向传播,随机梯度下降。
神经网络类:
import java.util.Arrays;
public class NeuralNetworks {
int input_n; // 输入层结点数
double[][] w1; // w1[0] 为偏置的权重
int hidden_n; // 隐藏层结点数
double[] hidden_layer; // 隐藏层
double[][] w2; // w2[0] 为偏置的权重
int output_n; // 输出层结点数
double[] y; // 输出层
double alpha; // 学习率
double b; // 偏置
public NeuralNetworks(int input_n, int hidden_n, int output_n, double alpha, double b) {
this.input_n = input_n;
this.hidden_n = hidden_n;
this.output_n = output_n;
this.alpha = alpha;
this.b = b;
initial();
}
// 初始化
private void initial() {
this.w1 = new double[input_n + 1][hidden_n];
this.hidden_layer = new double[this.hidden_n];
this.w2 = new double[hidden_n + 1][output_n];
this.y = new double[output_n];
initial_w(w1);
initial_w(w2);
}
// 初始化权重
private void initial_w(double[][] w) {
for (int i = 0; i < w.length; i++) {
for (int j = 0; j < w[0].length; j++) {
w[i][j] = Math.random();
}
}
}
// 训练模型
public void train(double[] input_x, double[] t_y) {
calculate_y(input_x); // 计算输出层
double[] y_error = calculate_y_error(t_y); // 计算输出层误差
double[] hidden_error = calculate_hidden_error(y_error); // 计算隐藏层误差
reNewWeight(this.hidden_layer, this.w2, y_error); // 更新隐藏层到输出层权重
reNewWeight(input_x, this.w1, hidden_error); // 更新输入层到隐藏层权重
}
// 预测
public void predict(double[] x) {
calculate_y(x);
System.out.println(Arrays.toString(this.y));
if (this.y[0] < 0.5) {
System.out.println("偶数!!!");
} else {
System.out.println("奇数!!!");
}
}
// 更新权重
private void reNewWeight(double[] in, double[][] w, double[] error) {
// 更新结点权重
for (int i = 1; i < w.length; i++) {
for (int j = 0; j < w[0].length; j++) {
w[i][j] += (this.alpha * error[j] * in[i - 1]);
}
}
// 更新偏置的权重
for (int j = 0; j < w[0].length; j++) {
w[0][j] += (this.alpha * error[j] * this.b);
}
}
// 计算隐藏层误差
private double[] calculate_hidden_error(double[] y_error) {
double sum;
double[] hidden_error = new double[this.hidden_n];
for (int i = 0; i < this.hidden_n; i++) {
sum = 0;
for (int j = 0; j < this.output_n; j++) {
sum += (y_error[j] * this.w2[i + 1][j]);
}
hidden_error[i] = sum * this.hidden_layer[i] * (1 - this.hidden_layer[i]);
}
return hidden_error;
}
// 计算输出层误差
private double[] calculate_y_error(double[] t_y) {
double[] y_error = new double[this.output_n];
for (int i = 0; i < output_n; i++) {
y_error[i] = (t_y[i] - this.y[i]) * this.y[i] * (1 - this.y[i]);
}
return y_error;
}
// 计算输出层值
private void calculate_y(double[] input_x) {
calculate_layer(input_x, this.w1, this.hidden_layer); // 计算隐藏层值
calculate_layer(this.hidden_layer, this.w2, this.y); // 计算输出层值
}
// 计算该层的输出值
private void calculate_layer(double[] in, double[][] w, double[] out) {
double z;
for (int i = 0; i < w[0].length; i++) {
z = w[0][i] * this.b;
for (int j = 1; j < w.length; j++) {
z += (w[j][i] * in[j - 1]);
}
out[i] = 1 / (1 + Math.exp(-z)); // sigmoid函数
}
}
}
主类:
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Random random = new Random();
NeuralNetworks bp = new NeuralNetworks(32,16,1,0.1,1);
double[] t_y = new double[1];
double[] x;
ArrayList<Integer> train_datas = new ArrayList<>();
// 随机生成训练集
for(int i=0;i<1000;i++){
train_datas.add(random.nextInt());
}
// 训练模型
for(int k=0;k<1000;k++){
for(int i=0;i<train_datas.size();i++){
t_y[0] = (train_datas.get(i) & 1); // 预期输出
x = get_x(train_datas.get(i));
bp.train(x,t_y);
}
}
System.out.println("训练完成!!!");
Scanner in = new Scanner(System.in);
int k;
System.out.print("输入数字识别奇偶(输入0结束):");
while((k = in.nextInt()) != 0){
x = get_x(k);
bp.predict(x);
System.out.print("输入数字识别奇偶(输入0结束):");
}
in.close();
}
// 将10进制转换成2进制
public static double[] get_x(int num){
double[] x = new double[32];
for(int i=31;i>=0;i--){
x[i] = (num & 1);
num >>>= 1;
}
return x;
}
}