头文件
1 #pragma once 2 3 #include <iostream> 4 #include <cmath> 5 #include <vector> 6 #include <stdlib.h> 7 #include <time.h> 8 9 using namespace std; 10 11 #define innode 2 //输入结点数 12 #define hidenode 4 //隐含结点数 13 #define hidelayer 1 //隐含层数 14 #define outnode 1 //输出结点数 15 #define learningRate 0.9//学习速率,alpha 16 17 // --- -1~1 随机数产生器 --- 18 inline double get_11Random() // -1 ~ 1 19 { 20 return ((2.0*(double)rand()/RAND_MAX) - 1); 21 } 22 23 // --- sigmoid 函数 --- 24 inline double sigmoid(double x) 25 { 26 double ans = 1 / (1+exp(-x)); 27 return ans; 28 } 29 30 // --- 输入层节点。包含以下分量:--- 31 // 1.value: 固定输入值; 32 // 2.weight: 面对第一层隐含层每个节点都有权值; 33 // 3.wDeltaSum: 面对第一层隐含层每个节点权值的delta值累积 34 typedef struct inputNode 35 { 36 double value; 37 vector<double> weight, wDeltaSum; 38 }inputNode; 39 40 // --- 输出层节点。包含以下数值:--- 41 // 1.value: 节点当前值; 42 // 2.delta: 与正确输出值之间的delta值; 43 // 3.rightout: 正确输出值 44 // 4.bias: 偏移量 45 // 5.bDeltaSum: bias的delta值的累积,每个节点一个 46 typedef struct outputNode // 输出层节点 47 { 48 double value, delta, rightout, bias, bDeltaSum; 49 }outputNode; 50 51 // --- 隐含层节点。包含以下数值:--- 52 // 1.value: 节点当前值; 53 // 2.delta: BP推导出的delta值; 54 // 3.bias: 偏移量 55 // 4.bDeltaSum: bias的delta值的累积,每个节点一个 56 // 5.weight: 面对下一层(隐含层/输出层)每个节点都有权值; 57 // 6.wDeltaSum: weight的delta值的累积,面对下一层(隐含层/输出层)每个节点各自积累 58 typedef struct hiddenNode // 隐含层节点 59 { 60 double value, delta, bias, bDeltaSum; 61 vector<double> weight, wDeltaSum; 62 }hiddenNode; 63 64 // --- 单个样本 --- 65 typedef struct sample 66 { 67 vector<double> in, out; 68 }sample; 69 70 // --- BP神经网络 --- 71 class BpNet 72 { 73 public: 74 BpNet(); //构造函数 75 void forwardPropagationEpoc(); // 单个样本前向传播 76 void backPropagationEpoc(); // 单个样本后向传播 77 // 更新 weight, bias 78 void training (static vector<sample> sampleGroup, double threshold); 79 // 神经网络预测 80 void predict (vector<sample>& testGroup); 81 // 设置学习样本输入 82 void setInput (static vector<double> sampleIn); 83 // 设置学习样本输出 84 void setOutput(static vector<double> sampleOut); 85 86 public: 87 double error; 88 inputNode* inputLayer[innode];// 输入层(仅一层) 89 outputNode* outputLayer[outnode];// 输出层(仅一层) 90 // 隐含层(可能有多层) 91 hiddenNode* hiddenLayer[hidelayer][hidenode]; 92 };
主程序:main
1 #include "BP.h" 2 3 int main() 4 { 5 BpNet testNet; 6 7 // 学习样本 8 vector<double> samplein[4]; 9 vector<double> sampleout[4]; 10 samplein[0].push_back(0); samplein[0].push_back(0); sampleout[0].push_back(0); 11 samplein[1].push_back(0); samplein[1].push_back(1); sampleout[1].push_back(1); 12 samplein[2].push_back(1); samplein[2].push_back(0); sampleout[2].push_back(1); 13 samplein[3].push_back(1); samplein[3].push_back(1); sampleout[3].push_back(0); 14 sample sampleInOut[4]; 15 for (int i = 0; i < 4; i++) 16 { 17 sampleInOut[i].in = samplein[i]; 18 sampleInOut[i].out = sampleout[i]; 19 } 20 vector<sample> sampleGroup(sampleInOut, sampleInOut + 4); 21 testNet.training(sampleGroup, 0.0001); 22 23 // 测试数据 24 vector<double> testin[4]; 25 vector<double> testout[4]; 26 testin[0].push_back(0.1); testin[0].push_back(0.2); 27 testin[1].push_back(0.15); testin[1].push_back(0.9); 28 testin[2].push_back(1.1); testin[2].push_back(0.01); 29 testin[3].push_back(0.88); testin[3].push_back(1.03); 30 sample testInOut[4]; 31 for (int i = 0; i < 4; i++) testInOut[i].in = testin[i]; 32 vector<sample> testGroup(testInOut, testInOut + 4); 33 34 // 预测测试数据,并输出结果 35 testNet.predict(testGroup); 36 for (int i = 0; i < testGroup.size(); i++) 37 { 38 for (int j = 0; j < testGroup[i].in.size(); j++) 39 cout << testGroup[i].in[j] << " "; 40 cout << "-- prediction :"; 41 for (int j = 0; j < testGroup[i].out.size(); j++) 42 cout << testGroup[i].out[j] << " "; 43 cout << endl; 44 } 45 46 system("pause"); 47 return 0; 48 }
源程序:bp.cpp
1 #include "BP.h" 2 3 using namespace std; 4 5 BpNet::BpNet() 6 { 7 srand((unsigned)time(NULL)); // 随机数种子 8 error = 100.f; // error初始值,极大值即可 9 10 // 初始化输入层 11 for (int i = 0; i < innode; i++) 12 { 13 inputLayer[i] = new inputNode(); 14 for (int j = 0; j < hidenode; j++) 15 { 16 inputLayer[i]->weight.push_back(get_11Random()); 17 inputLayer[i]->wDeltaSum.push_back(0.f); 18 } 19 } 20 21 // 初始化隐藏层 22 for (int i = 0; i < hidelayer; i++) 23 { 24 if (i == hidelayer - 1) 25 { 26 for (int j = 0; j < hidenode; j++) 27 { 28 hiddenLayer[i][j] = new hiddenNode(); 29 hiddenLayer[i][j]->bias = get_11Random(); 30 for (int k = 0; k < outnode; k++) 31 { 32 hiddenLayer[i][j]->weight.push_back(get_11Random()); 33 hiddenLayer[i][j]->wDeltaSum.push_back(0.f); 34 } 35 } 36 } 37 else 38 { 39 for (int j = 0; j < hidenode; j++) 40 { 41 hiddenLayer[i][j] = new hiddenNode(); 42 hiddenLayer[i][j]->bias = get_11Random(); 43 for (int k = 0; k < hidenode; k++) 44 { 45 hiddenLayer[i][j]->weight.push_back(get_11Random()); 46 } 47 } 48 } 49 } 50 51 // 初始化输出层 52 for (int i = 0; i < outnode; i++) 53 { 54 outputLayer[i] = new outputNode(); 55 outputLayer[i]->bias = get_11Random(); 56 } 57 } 58 59 void BpNet::forwardPropagationEpoc() 60 { 61 // forward propagation on hidden layer 62 for (int i = 0; i < hidelayer; i++) 63 { 64 if (i == 0) 65 { 66 for (int j = 0; j < hidenode; j++) 67 { 68 double sum = 0.f; 69 for (int k = 0; k < innode; k++) 70 { 71 sum += inputLayer[k]->value * inputLayer[k]->weight[j]; 72 } 73 sum += hiddenLayer[i][j]->bias; 74 hiddenLayer[i][j]->value = sigmoid(sum); 75 } 76 } 77 else 78 { 79 for (int j = 0; j < hidenode; j++) 80 { 81 double sum = 0.f; 82 for (int k = 0; k < hidenode; k++) 83 { 84 sum += hiddenLayer[i-1][k]->value * hiddenLayer[i-1][k]->weight[j]; 85 } 86 sum += hiddenLayer[i][j]->bias; 87 hiddenLayer[i][j]->value = sigmoid(sum); 88 } 89 } 90 } 91 92 // forward propagation on output layer 93 for (int i = 0; i < outnode; i++) 94 { 95 double sum = 0.f; 96 for (int j = 0; j < hidenode; j++) 97 { 98 sum += hiddenLayer[hidelayer-1][j]->value * hiddenLayer[hidelayer-1][j]->weight[i]; 99 } 100 sum += outputLayer[i]->bias; 101 outputLayer[i]->value = sigmoid(sum); 102 } 103 } 104 105 void BpNet::backPropagationEpoc() 106 { 107 // backward propagation on output layer 108 // -- compute delta 109 for (int i = 0; i < outnode; i++) 110 { 111 double tmpe = fabs(outputLayer[i]->value-outputLayer[i]->rightout); 112 error += tmpe * tmpe / 2; 113 114 outputLayer[i]->delta 115 = (outputLayer[i]->value-outputLayer[i]->rightout)*(1-outputLayer[i]->value)*outputLayer[i]->value; 116 } 117 118 // backward propagation on hidden layer 119 // -- compute delta 120 for (int i = hidelayer - 1; i >= 0; i--) // 反向计算 121 { 122 if (i == hidelayer - 1) 123 { 124 for (int j = 0; j < hidenode; j++) 125 { 126 double sum = 0.f; 127 for (int k=0; k<outnode; k++) 128 { 129 sum += outputLayer[k]->delta * hiddenLayer[i][j]->weight[k]; 130 } 131 hiddenLayer[i][j]->delta 132 = sum * (1 - hiddenLayer[i][j]->value) * hiddenLayer[i][j]->value; 133 } 134 } 135 else 136 { 137 for (int j = 0; j < hidenode; j++) 138 { 139 double sum = 0.f; 140 for (int k=0; k<hidenode; k++) 141 { 142 sum += hiddenLayer[i + 1][k]->delta * hiddenLayer[i][j]->weight[k]; 143 } 144 hiddenLayer[i][j]->delta 145 = sum * (1 - hiddenLayer[i][j]->value) * hiddenLayer[i][j]->value; 146 } 147 } 148 } 149 150 // backward propagation on input layer 151 // -- update weight delta sum 152 for (int i = 0; i < innode; i++) 153 { 154 for (int j = 0; j < hidenode; j++) 155 { 156 inputLayer[i]->wDeltaSum[j] += inputLayer[i]->value * hiddenLayer[0][j]->delta; 157 } 158 } 159 160 // backward propagation on hidden layer 161 // -- update weight delta sum & bias delta sum 162 for (int i = 0; i < hidelayer; i++) 163 { 164 if (i == hidelayer - 1) 165 { 166 for (int j = 0; j < hidenode; j++) 167 { 168 hiddenLayer[i][j]->bDeltaSum += hiddenLayer[i][j]->delta; 169 for (int k = 0; k < outnode; k++) 170 { 171 hiddenLayer[i][j]->wDeltaSum[k] += hiddenLayer[i][j]->value * outputLayer[k]->delta; 172 } 173 } 174 } 175 else 176 { 177 for (int j = 0; j < hidenode; j++) 178 { 179 hiddenLayer[i][j]->bDeltaSum += hiddenLayer[i][j]->delta; 180 for (int k = 0; k < hidenode; k++) 181 { 182 hiddenLayer[i][j]->wDeltaSum[k] += hiddenLayer[i][j]->value * hiddenLayer[i+1][k]->delta; 183 } 184 } 185 } 186 } 187 188 // backward propagation on output layer 189 // -- update bias delta sum 190 for (int i = 0; i < outnode; i++) outputLayer[i]->bDeltaSum += outputLayer[i]->delta; 191 } 192 193 void BpNet::training(static vector<sample> sampleGroup, double threshold) 194 { 195 int sampleNum = sampleGroup.size(); 196 197 while(error > threshold) 198 //for (int curTrainingTime = 0; curTrainingTime < trainingTime; curTrainingTime++) 199 { 200 cout << "training error: " << error << endl; 201 error = 0.f; 202 // initialize delta sum 203 for (int i = 0; i < innode; i++) inputLayer[i]->wDeltaSum.assign(inputLayer[i]->wDeltaSum.size(), 0.f); 204 for (int i = 0; i < hidelayer; i++){ 205 for (int j = 0; j < hidenode; j++) 206 { 207 hiddenLayer[i][j]->wDeltaSum.assign(hiddenLayer[i][j]->wDeltaSum.size(), 0.f); 208 hiddenLayer[i][j]->bDeltaSum = 0.f; 209 } 210 } 211 for (int i = 0; i < outnode; i++) outputLayer[i]->bDeltaSum = 0.f; 212 213 for (int iter = 0; iter < sampleNum; iter++) 214 { 215 setInput(sampleGroup[iter].in); 216 setOutput(sampleGroup[iter].out); 217 218 forwardPropagationEpoc(); 219 backPropagationEpoc(); 220 } 221 222 // backward propagation on input layer 223 // -- update weight 224 for (int i = 0; i < innode; i++) 225 { 226 for (int j = 0; j < hidenode; j++) 227 { 228 inputLayer[i]->weight[j] -= learningRate * inputLayer[i]->wDeltaSum[j] / sampleNum; 229 } 230 } 231 232 // backward propagation on hidden layer 233 // -- update weight & bias 234 for (int i = 0; i < hidelayer; i++) 235 { 236 if (i == hidelayer - 1) 237 { 238 for (int j = 0; j < hidenode; j++) 239 { 240 // bias 241 hiddenLayer[i][j]->bias -= learningRate * hiddenLayer[i][j]->bDeltaSum / sampleNum; 242 243 // weight 244 for (int k = 0; k < outnode; k++) 245 { hiddenLayer[i][j]->weight[k] -= learningRate * hiddenLayer[i][j]->wDeltaSum[k] / sampleNum; } 246 } 247 } 248 else 249 { 250 for (int j = 0; j < hidenode; j++) 251 { 252 // bias 253 hiddenLayer[i][j]->bias -= learningRate * hiddenLayer[i][j]->bDeltaSum / sampleNum; 254 255 // weight 256 for (int k = 0; k < hidenode; k++) 257 { hiddenLayer[i][j]->weight[k] -= learningRate * hiddenLayer[i][j]->wDeltaSum[k] / sampleNum; } 258 } 259 } 260 } 261 262 // backward propagation on output layer 263 // -- update bias 264 for (int i = 0; i < outnode; i++) 265 { outputLayer[i]->bias -= learningRate * outputLayer[i]->bDeltaSum / sampleNum; } 266 } 267 } 268 269 void BpNet::predict(vector<sample>& testGroup) 270 { 271 int testNum = testGroup.size(); 272 273 for (int iter = 0; iter < testNum; iter++) 274 { 275 testGroup[iter].out.clear(); 276 setInput(testGroup[iter].in); 277 278 // forward propagation on hidden layer 279 for (int i = 0; i < hidelayer; i++) 280 { 281 if (i == 0) 282 { 283 for (int j = 0; j < hidenode; j++) 284 { 285 double sum = 0.f; 286 for (int k = 0; k < innode; k++) 287 { 288 sum += inputLayer[k]->value * inputLayer[k]->weight[j]; 289 } 290 sum += hiddenLayer[i][j]->bias; 291 hiddenLayer[i][j]->value = sigmoid(sum); 292 } 293 } 294 else 295 { 296 for (int j = 0; j < hidenode; j++) 297 { 298 double sum = 0.f; 299 for (int k = 0; k < hidenode; k++) 300 { 301 sum += hiddenLayer[i-1][k]->value * hiddenLayer[i-1][k]->weight[j]; 302 } 303 sum += hiddenLayer[i][j]->bias; 304 hiddenLayer[i][j]->value = sigmoid(sum); 305 } 306 } 307 } 308 309 // forward propagation on output layer 310 for (int i = 0; i < outnode; i++) 311 { 312 double sum = 0.f; 313 for (int j = 0; j < hidenode; j++) 314 { 315 sum += hiddenLayer[hidelayer-1][j]->value * hiddenLayer[hidelayer-1][j]->weight[i]; 316 } 317 sum += outputLayer[i]->bias; 318 outputLayer[i]->value = sigmoid(sum); 319 testGroup[iter].out.push_back(outputLayer[i]->value); 320 } 321 } 322 } 323 324 void BpNet::setInput(static vector<double> sampleIn) 325 { 326 for (int i = 0; i < innode; i++) 327 inputLayer[i]->value = sampleIn[i]; 328 } 329 330 void BpNet::setOutput(static vector<double> sampleOut) 331 { 332 for (int i = 0; i < outnode; i++) 333 outputLayer[i]->rightout = sampleOut[i]; 334 }