C++实现神经BP神经网络

时间:2021-10-03 08:38:56

本文实例为大家分享了C++实现神经BP神经网络的具体代码,供大家参考,具体内容如下

BP.h

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#pragma once
#include<vector>
#include<stdlib.h>
#include<time.h>
#include<cmath>
#include<iostream>
using std::vector;
using std::exp;
using std::cout;
using std::endl;
class BP
{
private:
 int studyNum;//允许学习次数
 double h;//学习率
 double allowError;//允许误差
 vector<int> layerNum;//每层的节点数,不包括常量节点1
 vector<vector<vector<double>>> w;//权重
 vector<vector<vector<double>>> dw;//权重增量
 vector<vector<double>> b;//偏置
 vector<vector<double>> db;//偏置增量
 vector<vector<vector<double>>> a;//节点值
 vector<vector<double>> x;//输入
 vector<vector<double>> y;//期望输出
 
 void iniwb();//初始化w与b
 void inidwdb();//初始化dw与db
 double sigmoid(double z);//激活函数
 void forward();//前向传播
 void backward();//后向传播
 double Error();//计算误差
public:
 BP(vector<int>const& layer_num, vector<vector<double>>const & input_a0,
 vector<vector<double>> const & output_y, double hh = 0.5, double allerror = 0.001, int studynum = 1000);
 BP();
 void setLayerNumInput(vector<int>const& layer_num, vector<vector<double>> const & input);
 void setOutputy(vector<vector<double>> const & output_y);
 void setHErrorStudyNum(double hh, double allerror,int studynum);
 void run();//运行BP神经网络
 vector<double> predict(vector<double>& input);//使用已经学习好的神经网络进行预测
 ~BP();
};

BP.cpp

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
#include "BP.h"
BP::BP(vector<int>const& layer_num, vector<vector<double>>const & input,
 vector<vector<double>> const & output_y, double hh, double allerror,int studynum)
{
 layerNum = layer_num;
 x = input;//输入多少个节点的数据,每个节点有多少份数据
 y = output_y;
 h = hh;
 allowError = allerror;
 a.resize(layerNum.size());//有这么多层网络节点
 for (int i = 0; i < layerNum.size(); i++)
 {
 a[i].resize(layerNum[i]);//每层网络节点有这么多个节点
 for (int j = 0; j < layerNum[i]; j++)
  a[i][j].resize(input[0].size());
 }
 a[0] = input;
 studyNum = studynum;
}
 
BP::BP()
{
 layerNum = {};
 a = {};
 y = {};
 h = 0;
 allowError = 0;
}
 
BP::~BP()
{
}
 
void BP::setLayerNumInput(vector<int>const& layer_num, vector<vector<double>> const & input)
{
 layerNum = layer_num;
 x = input;
 a.resize(layerNum.size());//有这么多层网络节点
 for (int i = 0; i < layerNum.size(); i++)
 {
 a[i].resize(layerNum[i]);//每层网络节点有这么多个节点
 for (int j = 0; j < layerNum[i]; j++)
  a[i][j].resize(input[0].size());
 }
 a[0] = input;
}
 
 
void BP::setOutputy(vector<vector<double>> const & output_y)
{
 y = output_y;
}
 
void BP::setHErrorStudyNum(double hh, double allerror,int studynum)
{
 h = hh;
 allowError = allerror;
 studyNum = studynum;
}
 
//初始化权重矩阵
void BP::iniwb()
{
 w.resize(layerNum.size() - 1);
 b.resize(layerNum.size() - 1);
 srand((unsigned)time(NULL));
 //节点层数层数
 for (int l = 0; l < layerNum.size() - 1; l++)
 {
 w[l].resize(layerNum[l + 1]);
 b[l].resize(layerNum[l + 1]);
 //对应后层的节点
 for (int j = 0; j < layerNum[l + 1]; j++)
 {
  w[l][j].resize(layerNum[l]);
  b[l][j] = -1 + 2 * (rand() / RAND_MAX);
  //对应前层的节点
  for (int k = 0; k < layerNum[l]; k++)
  w[l][j][k] = -1 + 2 * (rand() / RAND_MAX);
 }
 }
}
 
 
void BP::inidwdb()
{
 dw.resize(layerNum.size() - 1);
 db.resize(layerNum.size() - 1);
 //节点层数层数
 for (int l = 0; l < layerNum.size() - 1; l++)
 {
 dw[l].resize(layerNum[l + 1]);
 db[l].resize(layerNum[l + 1]);
 //对应后层的节点
 for (int j = 0; j < layerNum[l + 1]; j++)
 {
  dw[l][j].resize(layerNum[l]);
  db[l][j] = 0;
  //对应前层的节点
  for (int k = 0; k < layerNum[l]; k++)
  w[l][j][k] = 0;
 }
 }
}
 
//激活函数
double BP::sigmoid(double z)
{
 return 1.0 / (1 + exp(-z));
}
 
void BP::forward()
{
 for (int l = 1; l < layerNum.size(); l++)
 {
 for (int i = 0; i < layerNum[l]; i++)
 {
  for (int j = 0; j < x[0].size(); j++)
  {
 
  a[l][i][j] = 0;//第l层第i个节点第j个数据样本
  //计算变量节点乘权值的和
  for (int k = 0; k < layerNum[l - 1]; k++)
   a[l][i][j] += a[l - 1][k][j] * w[l - 1][i][k];
  //加上节点偏置
  a[l][i][j] += b[l - 1][i];
  a[l][i][j] = sigmoid(a[l][i][j]);
  }
 }
 }
}
 
void BP::backward()
{
 int xNum = x[0].size();//样本个数
 //daP第l层da,daB第l+1层da
 vector<double> daP, daB;
 
 
 for (int j = 0; j < xNum; j++)
 {
 //处理最后一层的dw
 daP.clear();
 daP.resize(layerNum[layerNum.size() - 1]);
 for (int i = 0, l = layerNum.size() - 1; i < layerNum[l]; i++)
 {
  daP[i] = a[l][i][j] - y[i][j];
  for (int k = 0; k < layerNum[l - 1]; k++)
  dw[l - 1][i][k] += daP[i] * a[l][i][j] * (1 - a[l][i][j])*a[l - 1][k][j];
  db[l - 1][i] += daP[i] * a[l][i][j] * (1 - a[l][i][j]);
 }
 
 //处理剩下层的权重w的增量Dw
 for (int l = layerNum.size() - 2; l > 0; l--)
 {
  daB = daP;
  daP.clear();
  daP.resize(layerNum[l]);
  for (int k = 0; k < layerNum[l]; k++)
  {
  daP[k] = 0;
  for (int i = 0; i < layerNum[l + 1]; i++)
   daP[k] += daB[i] * a[l + 1][i][j] * (1 - a[l + 1][i][j])*w[l][i][k];
  //dw
  for (int i = 0; i < layerNum[l - 1]; i++)
   dw[l - 1][k][i] += daP[k] * a[l][k][j] * (1 - a[l][k][j])*a[l - 1][i][j];
  //db
  db[l-1][k] += daP[k] * a[l][k][j] * (1 - a[l][k][j]);
  }
 }
 
 }
 
 //计算dw与db平均值
 for (int l = 0; l < layerNum.size() - 1; l++)
 {
 //对应后层的节点
 for (int j = 0; j < layerNum[l + 1]; j++)
 {
  db[l][j] = db[l][j] / xNum;
  //对应前层的节点
  for (int k = 0; k < layerNum[l]; k++)
  w[l][j][k] = w[l][j][k] / xNum;
 }
 }
 
 //更新参数w与b
 for (int l = 0; l < layerNum.size() - 1; l++)
 {
 for (int j = 0; j < layerNum[l + 1]; j++)
 {
  b[l][j] = b[l][j] - h * db[l][j];
  //对应前层的节点
  for (int k = 0; k < layerNum[l]; k++)
  w[l][j][k] = w[l][j][k] - h * dw[l][j][k];
 }
 }
}
 
double BP::Error()
{
 int l = layerNum.size() - 1;
 double temp = 0, error = 0;
 for (int i = 0; i < layerNum[l]; i++)
 for (int j = 0; j < x[0].size(); j++)
 {
  temp = a[l][i][j] - y[i][j];
  error += temp * temp;
 }
 error = error / x[0].size();//求对每一组样本的误差平均
 error = error / 2;
 cout << error << endl;
 return error;
}
 
//运行神经网络
void BP::run()
{
 iniwb();
 inidwdb();
 int i = 0;
 for (; i < studyNum; i++)
 {
 forward();
 if (Error() <= allowError)
 {
  cout << "Study Success!" << endl;
  break;
 }
 backward();
 }
 if (i == 10000)
 cout << "Study Failed!" << endl;
}
 
vector<double> BP::predict(vector<double>& input)
{
 vector<vector<double>> a1;
 a1.resize(layerNum.size());
 for (int l = 0; l < layerNum.size(); l++)
 a1[l].resize(layerNum[l]);
 a1[0] = input;
 for (int l = 1; l < layerNum.size(); l++)
 for (int i = 0; i < layerNum[l]; i++)
 {
  a1[l][i] = 0;//第l层第i个节点第j个数据样本
  //计算变量节点乘权值的和
  for (int k = 0; k < layerNum[l - 1]; k++)
  a1[l][i] += a1[l - 1][k] * w[l - 1][i][k];
  //加上节点偏置
  a1[l][i] += b[l - 1][i];
  a1[l][i] = sigmoid(a1[l][i]);
 }
 return a1[layerNum.size() - 1];
}

验证程序:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include"BP.h"
 
int main()
{
 vector<int> layer_num = { 1, 10, 1 };
 vector<vector<double>> input_a0 = { { 1,2,3,4,5,6,7,8,9,10 } };
 vector<vector<double>> output_y = { {0,0,0,0,1,1,1,1,1,1} };
 
 BP bp(layer_num, input_a0,output_y,0.6,0.001, 2000);
 bp.run();
 for (int j = 0; j < 30; j++)
 {
 vector<double> input = { 0.5*j };
 vector<double> output = bp.predict(input);
 for (auto i : output)
  cout << "j:" << 0.5*j <<" pridict:" << i << " ";
 cout << endl;
 }
 system("pause");
 return 0;
}

输出:

C++实现神经BP神经网络

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/weixin_42333471/article/details/90106465