🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
这次先上 运行“结果”: ``` 训练次数 误差 0 16.519723 500 0.135468 1000 0.105337 1500 0.082751 2000 0.076986 2500 0.073428 3000 0.070383 3500 0.067702 4000 0.065119 4500 0.062573 5000 0.060117 5500 0.057829 6000 0.055517 6500 0.053316 7000 0.051277 6*3=:17.721119 检验 训练“BP网络”训练的 成果: 3.200000*6=:19.920839 4.300000*8=:35.636405 6.000000*8=:49.607321 2.100000*7=:15.587592 4.300000*8=:35.636405 ``` 结果说明: “BP神经网络”学习乘法……成果是, TA学的是那个意思(精度一般般)…… 但就像小动物,能猜个大概其……也是一种进步。 二、 再上 C的 程序代码 和 注释: ``` // 在微软VS-C++2017调试运行通过-ConA1neuron20200310a.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #define _CRT_SECURE_NO_WARNINGS #include "pch.h" #include <iostream> #include <stdio.h> #include <time.h> #include <math.h> #include <stdlib.h> #define Error001Precision 0.05 //误差允许精度 #define Display01Frequency 500 //显示训练次数的频次//频率 #define Data 820 //Data 用来表示已经知道的数据样本的数量,也就是训练样本的数量 #define In 2 //In 表示对于每个样本有多少个输入变量 #define Out 1 #define Neuron 45 //Neuron 表示神经元的数量 #define TrainC 20000 //TrainC 来表示训练的次数 #define A 0.2 //在具体实现对误差修改中,我们再加上学习率,并且对先前学习到的修正误差量进行继承,直白的说就是都乘上一个0到1之间的数,具体的见如下实现参考代码 #define B 0.4 #define a 0.2 #define b 0.3 double d_in[Data][In]; // ,d_in[Data][In] 存储 Data 个样本,每个样本的 In 个输入 double d_out[Data][Out]; //d_out[Data][Out] 存储 Data 个样本,每个样本的 Out 个输出。 double w[Neuron][In];//w[Neuron][In] 表示某个输入对某个神经元的权重 double o[Neuron]; //数组 o[Neuron] 记录的是神经元通过激活函数对外的输出, , double v[Out][Neuron];//v[Out][Neuron] 来表示某个神经元对某个输出的权重; double Maxin[In], Minin[In], Maxout[Out], Minout[Out]; double OutputData[Out];//OutputData[Out] 存储BP神经网络的输出。 double dv[Out][Neuron], dw[Neuron][In]; //与之对应的保存它们两个修正量的数组 dw[Neuron][In] 和 dv[Out][Neuron] double e01ErrorPrecision; //误差 void writeTest() { FILE *fp1, *fp2; double r1, r2; int i; srand((unsigned)time(NULL)); if ((fp1 = fopen("D:\\in.txt", "w")) == NULL) { printf("can not open the in file\n"); exit(0); } if ((fp2 = fopen("D:\\out.txt", "w")) == NULL) { printf("can not open the out file\n"); exit(0); } for (i = 0; i < Data; i++) { r1 = rand() % 1000 / 100.0; r2 = rand() % 1000 / 100.0; fprintf(fp1, "%lf %lf\n", r1, r2); fprintf(fp2, "%lf \n", r1*r2); //训练 bp网络学习乘法! r1 + r2); } fclose(fp1); fclose(fp2); } void readData() { FILE *fp1, *fp2; int i, j; if ((fp1 = fopen("D:\\in.txt", "r")) == NULL) { printf("can not open the in file\n"); exit(0); } for (i = 0; i < Data; i++) for (j = 0; j < In; j++) fscanf(fp1, "%lf", &d_in[i][j]); fclose(fp1); if ((fp2 = fopen("D:\\out.txt", "r")) == NULL) { printf("can not open the out file\n"); exit(0); } for (i = 0; i < Data; i++) for (j = 0; j < Out; j++) fscanf(fp1, "%lf", &d_out[i][j]); fclose(fp2); } void initBPNework() { int i, j; //第01步,先:找到数据最小、最大值: for (i = 0; i < In; i++) { Minin[i] = Maxin[i] = d_in[0][i]; for (j = 0; j < Data; j++) { Maxin[i] = Maxin[i] > d_in[j][i] ? Maxin[i] : d_in[j][i]; Minin[i] = Minin[i] < d_in[j][i] ? Minin[i] : d_in[j][i]; } } //找输出数据的最小、最大值: for (i = 0; i < Out; i++) { Minout[i] = Maxout[i] = d_out[0][i]; for (j = 0; j < Data; j++) { Maxout[i] = Maxout[i] > d_out[j][i] ? Maxout[i] : d_out[j][i]; Minout[i] = Minout[i] < d_out[j][i] ? Minout[i] : d_out[j][i]; } } //第02:归一化处理 for (i = 0; i < In; i++) for (j = 0; j < Data; j++) d_in[j][i] = (d_in[j][i] - Minin[i] + 1) / (Maxin[i] - Minin[i] + 1); for (i = 0; i < Out; i++) for (j = 0; j < Data; j++) d_out[j][i] = (d_out[j][i] - Minout[i] + 1) / (Maxout[i] - Minout[i] + 1); //第03:初始化神经元 for (i = 0; i < Neuron; ++i) for (j = 0; j < In; ++j) { w[i][j] = rand()*2.0 / RAND_MAX - 1; dw[i][j] = 0; } for (i = 0; i < Neuron; ++i) for (j = 0; j < Out; ++j) { v[j][i] = rand()*2.0 / RAND_MAX - 1; dv[j][i] = 0; } } //BP神经网络 //函数 computO(i) 负责的是通过BP神经网络的机制对样本 i 的输入,预测其输出。回想BP神经网络的基本模型(详情见 基本模型)对应的公式(1)还有 激活函数对应的公式(2): void computO(int var) { int i, j; double sum, y; for (i = 0; i < Neuron; ++i) { sum = 0; for (j = 0; j < In; ++j) sum += w[i][j] * d_in[var][j]; o[i] = 1 / (1 + exp(-1 * sum)); } for (i = 0; i < Out; ++i) { sum = 0; for (j = 0; j < Neuron; ++j) sum += v[i][j] * o[j]; OutputData[i] = sum; } } //函数 backUpdate(i) 负责的是将预测输出的结果与样本真实的结果进行比对,然后对神经网络中涉及到的权重进行修正,也这是BP神经网络实现的关键所在。如何求到对于 w[Neuron][In] 和 v[Out][Neuron] 进行修正的误差量便是关键所在!误差修正量的求法在基本模型一文中数学分析部分有解答,具体问题具体分析,落实到我们设计的这个BP神经网络上来说,需要得到的是对w[Neuron][In] 和 v[Out][Neuron] 两个数据进行修正误差,误差量用数据结构 dw[Neuron][In] 和 dv[Out][Neuron] 来进行存储 void backUpdate(int var) { int i, j; double t; for (i = 0; i < Neuron; ++i) { t = 0; for (j = 0; j < Out; ++j) { t += (OutputData[j] - d_out[var][j])*v[j][i]; dv[j][i] = A * dv[j][i] + B * (OutputData[j] - d_out[var][j])*o[i]; v[j][i] -= dv[j][i]; } for (j = 0; j < In; ++j) { dw[i][j] = a * dw[i][j] + b * t*o[i] * (1 - o[i])*d_in[var][j]; w[i][j] -= dw[i][j]; } } } double result(double var1, double var2) { int i, j; double sum, y; var1 = (var1 - Minin[0] + 1) / (Maxin[0] - Minin[0] + 1); var2 = (var2 - Minin[1] + 1) / (Maxin[1] - Minin[1] + 1); for (i = 0; i < Neuron; ++i) { sum = 0; sum = w[i][0] * var1 + w[i][1] * var2; o[i] = 1 / (1 + exp(-1 * sum)); } sum = 0; for (j = 0; j < Neuron; ++j) sum += v[0][j] * o[j]; return sum * (Maxout[0] - Minout[0] + 1) + Minout[0] - 1; } void writeNeuron() { FILE *fp1; int i, j; if ((fp1 = fopen("D:\\neuron.txt", "w")) == NULL) { printf("can not open the neuron file\n"); exit(0); } for (i = 0; i < Neuron; ++i) for (j = 0; j < In; ++j) { fprintf(fp1, "%lf ", w[i][j]); } fprintf(fp1, "\n\n\n\n"); for (i = 0; i < Neuron; ++i) for (j = 0; j < Out; ++j) { fprintf(fp1, "%lf ", v[j][i]); } fclose(fp1); } void trainNetwork() //训练 { int i, c01Count = 0;// c01Count训练次数 计数 int j; do //do110 { e01ErrorPrecision = 0; for (i = 0; i < Data; ++i) { computO(i); for (j = 0; j < Out; ++j) e01ErrorPrecision += fabs((OutputData[j] - d_out[i][j]) / d_out[i][j]); backUpdate(i); } if (0 == c01Count % Display01Frequency) //1000) //20) //if220 { printf("%d %lf\n", c01Count, e01ErrorPrecision / Data); }//if220 c01Count++; } while (c01Count<TrainC && e01ErrorPrecision / Data> Error001Precision); // 0.05);// 1); // 0.01); //do110 }//训练-End int main() { std::cout << "Hello World!\n"; writeTest(); readData(); initBPNework(); trainNetwork(); printf("%d*%d=:%lf \n",6,3, result(6, 3)); printf("%f*%d=:%lf \n",3.2, 6, result(3.2, 6)); printf("%f*%d=:%lf \n",4.3,8, result(4.3, 8)); printf("%f*%d=:%lf \n",6.0,8, result(6, 8)); printf("%f*%d=:%lf \n",2.1,7, result(2.1, 7)); printf("%f*%d=:%lf \n",4.3,8, result(4.3, 8)); writeNeuron(); return 0; }// // ``` 再运行一次, 训练BP网络学会“乘法”: ``` 训练次数 误差 8500 0.081898 9000 0.079318 9500 0.075935 10000 0.071483 10500 0.066695 11000 0.063684 11500 0.062921 12000 0.062295 12500 0.062092 13000 0.061443 13500 0.060544 14000 0.059567 14500 0.058434 15000 0.057286 15500 0.056034 16000 0.054670 16500 0.053297 17000 0.051820 17500 0.050263 检验“BP网络”训练的成果: 6*3=:16.459228 3.200000*6=:18.756765 4.300000*8=:33.943728 6.000000*8=:47.677582 2.100000*7=:14.412758 4.300000*8=:33.943728 ```