BP神经网络的基础介绍见:http://blog.csdn.net/fengbingchun/article/details/50274471,这里主要以公式推导为主。

BP神经网络又称为误差反向传播网络,其结构例如以下图。

这样的网络实质是一种前向无反馈网络,具有结构清晰、易实现、计算功能强大等特点。

BP神经网络有一个输入层。一个输出层。一个或多个隐含层。每一层上包括了若干个节点。每个节点代表一个神经元,同一层上各节点之间无不论什么耦合连接关系,层间各神经元之间实现全连接,即后一层(如输入层)的每个神经元与前一层(如隐含层)的每个神经元实现全连接。网络依照监督学习的方式学习,当信息被输入网络后神经元受到刺激。激活值从输入层依次经过各隐含层节点。最后在输出层的各节点获得网络的输入响应。

BP神经网络的基本思想:BP神经网络的学习採用误差反向传播算法。BP算法是一种有监督的学习方法。其主要思想是把整个学习过程分为正向传播、反向(逆向)传播和记忆训练三个部分。正向传播时,输入样本从输入层输入。经各隐含层处理后传向输出层,每一层神经元的状态仅仅影响下一层神经元的状态。

假设在输出层得不到期望的输出。则转入误差的反向传播阶段。将输出误差以某种形式通过隐含层向输入层反传,并将误差分摊给各层的全部单元,从而获得各层单元的误差信号并将其作为修正各单元权值的根据。这样的网络的信号正向传播与误差反向传播是重复交替进行的,权值的不断调整就是网络的记忆训练过程。

网络的记忆训练过程一直进行到网络趋向收敛,即输出误差达到要求的标准。

三层BP神经网络的学习算法:为了使BP网络具有某种功能,完毕某项任务。必须调整层间连接权值和节点阈值,使全部样品的实际输出和期望输出之间的误差稳定在一个较小的值之内。三层BP网络学习过程主要由四部分组成:(1)、输入模式顺传播(输入模式由输入层经隐含层向输出层传播计算);(2)、输出误差逆传播(输出的误差由输出层经隐含层传向输入层);(3)、循环记忆训练(模式顺传播与误差逆传播的计算过程重复交替循环进行);(4)、学习结果判别(判定全局误差是否趋向极小值或是否已达到设定的最大迭代次数)。

(1)、输入模式顺传播:这一过程主要是利用输入模式求出它所相应的实际输出。

确定输入向量Xk

式中,k=1,2,…,m;m是学习模式对数(训练模式对数)。n是输入层单元数。

确定期望输出向量Yk

式中,k=1,2,…,m;m是学习模式对数(训练模式对数)。q为输出层单元数。

计算隐含层各神经元的激活值sj

式中,n是输入层单元数。wij是输入层至隐含层的连接权值。θj是隐含层单元的阈值;j=1,2…p。p是隐含层单元数。

激活函数採用s型函数:

计算隐含层j单元的输出值:将上面的激活值即公式(3)代入激活函数即公式(4)中可得隐含层j单元的输出值:

阈值θj在学习过程中与权值wij一样也不断地被修正。

计算输出层第t个单元的激活值ot

计算输出层第t个单元的实际输出值ct

式中,wjt是隐含层至输出层的权值;θt是输出层单元阈值;j=1,2…p,p是隐含层单元数;xj为隐含层第j个节点的输出值。f是s型激活函数。t=1,2…,q。q为输出层单元数。

利用以上各公式就能够计算出一个输入模式的顺传播过程。

(2)、输出误差的逆传播:在第一步的模式顺传播计算中得到了网络的实际输出值,当这些实际的输出值与希望的输出值不一样或者误差大于所限定的数值时,就要对网络进行校正。

这里的校正是从前往后进行的。所以叫做误差逆传播,计算时是从输出层到隐含层,再从隐含层到输入层。

输出层的校正误差:

式中,t=1,2,…,q。q是输出层单元数。k=1,2,…,m,m是训练(学习)模式对数;ytk是希望输出;ctk是实际输出;f(.)是对输出函数的导数。

隐含层各单元的校正误差:

式中,t=1,2,…,q。q是输出层单元数。j=1,2,…,p; p是隐含层单元数;k=1,2,…,m,m是训练(学习)模式对数。

对于输出层至隐含层连接权和输出层阈值的校正量:

式中,bjk是隐含层j单元的输出。dtk是输出层的校正误差;j=1,2…,p。t=1,2,…,q;k=1,2,…,m; α>0(输出层至隐含层学习率)。

隐含层至输入层的校正量:

式中,ejk是隐含层j单元的校正误差;xik是标准输入,i=1,2,…,n ,n是输入层单元数;0<β<1(隐含层至输入层学习率)。

(3)、循环记忆训练:为使网络的输出误差趋向于极小值,对于BP网输入的每一组训练模式,一般要经过数百次甚至上万次的循环记忆训练,才干使网络记住这一模式。这样的循环记忆实际上就是重复重复上面介绍的输入模式顺传播和输出误差逆传播。

(4)、学习结果的判别:当每次循环记忆训练结束后,都要进行学习结果的判别。判别的目的主要是检查输出误差是否已经小到能够同意的程度。

假设小到能够同意的程度,就能够结束整个学习过程。否则还要继续进行循环训练。

确定隐含层节点数:一般有3个经验公式:

式中,m为要设置的隐含层节点数。n为输入层节点数;l为输出层节点数。α为1至10之间的常数。

下面依照上面的公式实现的BP,通过MNIST库測试,识别率能够达到96.5%以上。

BP.hpp:

  1. #ifndef _BP_HPP_
  2. #define _BP_HPP_
  3.  
  4. namespace ANN {
  5.  
  6. #define num_node_input_BP 784 //输入层节点数
  7. #define width_image_BP 28 //归一化图像宽
  8. #define height_image_BP 28 //归一化图像高
  9. #define num_node_hidden_BP 120 //隐含层节点数
  10. #define num_node_output_BP 10 //输出层节点数
  11. #define alpha_learning_BP 0.8 //输出层至隐含层学习率
  12. #define beta_learning_BP 0.6 //隐含层至输入层学习率
  13. #define patterns_train_BP 60000 //训练模式对数(总数)
  14. #define patterns_test_BP 10000 //測试模式对数(总数)
  15. #define iterations_BP 10000 //最大训练次数
  16. #define accuracy_rate_BP 0.965 //要求达到的准确率
  17.  
  18. class BP {
  19. public:
  20. BP();
  21. ~BP();
  22.  
  23. void init(); //初始化,分配空间
  24. bool train(); //训练
  25. int predict(const int* data, int width, int height); //预測
  26. bool readModelFile(const char* name); //读取已训练好的BP model
  27.  
  28. protected:
  29. void release(); //释放申请的空间
  30. bool saveModelFile(const char* name); //将训练好的model保存起来,包括各层的节点数,权值和阈值
  31. bool initWeightThreshold(); //初始化,产生[-1, 1]之间的随机小数
  32. bool getSrcData(); //读取MNIST数据
  33. void calcHiddenLayer(const int* data); //计算隐含层输出
  34. void calcOutputLayer(); //计算输出层输出
  35. void calcAdjuctOutputLayer(const int* data); //计算输出层校正误差
  36. void calcAdjuctHiddenLayer(); //计算隐含层校正误差
  37. float calcActivationFunction(float x); //计算激活函数,对数S形函数
  38. void updateWeightThresholdOutputLayer(); //更新输出层至隐含层权值和阈值
  39. void updateWeightThresholdHiddenLayer(const int* data); //更新隐含层至输入层权值和阈值
  40. float test(); //训练完一次计算一次准确率
  41.  
  42. private:
  43. float weight1[num_node_input_BP][num_node_hidden_BP]; //输入层至隐含层连接权值
  44. float weight2[num_node_hidden_BP][num_node_output_BP]; //隐含层至输出层连接权值
  45. float threshold1[num_node_hidden_BP]; //隐含层阈值
  46. float threshold2[num_node_output_BP]; //输出层阈值
  47. float output_hiddenLayer[num_node_hidden_BP]; //顺传播。隐含层输出值
  48. float output_outputLayer[num_node_output_BP]; //顺传播,输出层输出值
  49. float adjust_error_outputLayer[num_node_output_BP]; //逆传播,输出层校正误差
  50. float adjust_error_hiddenLayer[num_node_hidden_BP]; //逆传播,隐含层校正误差
  51.  
  52. int* data_input_train; //原始标准输入数据,训练
  53. int* data_output_train; //原始标准期望结果,训练
  54. int* data_input_test; //原始标准输入数据,測试
  55. int* data_output_test; //原始标准期望结果,測试
  56. };
  57.  
  58. }
  59.  
  60. #endif //_BP_HPP_

BP.cpp:

  1. #include <assert.h>
  2. #include <time.h>
  3. #include <iostream>
  4. #include <fstream>
  5. #include <algorithm>
  6. #include <windows.h>
  7.  
  8. #include "BP.hpp"
  9.  
  10. namespace ANN {
  11.  
  12. BP::BP()
  13. {
  14. data_input_train = NULL;
  15. data_output_train = NULL;
  16. data_input_test = NULL;
  17. data_output_test = NULL;
  18. }
  19.  
  20. BP::~BP()
  21. {
  22. release();
  23. }
  24.  
  25. void BP::release()
  26. {
  27. if (data_input_train) {
  28. delete[] data_input_train;
  29. }
  30. if (data_output_train) {
  31. delete[] data_output_train;
  32. }
  33. if (data_input_test) {
  34. delete[] data_input_test;
  35. }
  36. if (data_output_test) {
  37. delete[] data_output_test;
  38. }
  39. }
  40.  
  41. bool BP::initWeightThreshold()
  42. {
  43. srand(time(0) + rand());
  44.  
  45. for (int i = 0; i < num_node_input_BP; i++) {
  46. for (int j = 0; j < num_node_hidden_BP; j++) {
  47. weight1[i][j] = -1 + 2 * ((float)rand()) / RAND_MAX; //[-1, 1]
  48. }
  49. }
  50.  
  51. for (int i = 0; i < num_node_hidden_BP; i++) {
  52. for (int j = 0; j < num_node_output_BP; j++) {
  53. weight2[i][j] = -1 + 2 * ((float)rand()) / RAND_MAX;
  54. }
  55. }
  56.  
  57. for (int i = 0; i < num_node_hidden_BP; i++) {
  58. threshold1[i] = -1 + 2 * ((float)rand()) / RAND_MAX;
  59. }
  60.  
  61. for (int i = 0; i < num_node_output_BP; i++) {
  62. threshold2[i] = -1 + 2 * ((float)rand()) / RAND_MAX;
  63. }
  64.  
  65. return true;
  66. }
  67.  
  68. static int reverseInt(int i)
  69. {
  70. unsigned char ch1, ch2, ch3, ch4;
  71. ch1 = i & 255;
  72. ch2 = (i >> 8) & 255;
  73. ch3 = (i >> 16) & 255;
  74. ch4 = (i >> 24) & 255;
  75. return((int)ch1 << 24) + ((int)ch2 << 16) + ((int)ch3 << 8) + ch4;
  76. }
  77.  
  78. static void readMnistImages(std::string filename, int* data_dst, int num_image)
  79. {
  80. std::ifstream file(filename, std::ios::binary);
  81. assert(file.is_open());
  82.  
  83. int magic_number = 0;
  84. int number_of_images = 0;
  85. int n_rows = 0;
  86. int n_cols = 0;
  87. file.read((char*)&magic_number, sizeof(magic_number));
  88. magic_number = reverseInt(magic_number);
  89. file.read((char*)&number_of_images, sizeof(number_of_images));
  90. number_of_images = reverseInt(number_of_images);
  91. assert(number_of_images == num_image);
  92. file.read((char*)&n_rows, sizeof(n_rows));
  93. n_rows = reverseInt(n_rows);
  94. file.read((char*)&n_cols, sizeof(n_cols));
  95. n_cols = reverseInt(n_cols);
  96. assert(n_rows == height_image_BP && n_cols == width_image_BP);
  97.  
  98. for (int i = 0; i < number_of_images; ++i) {
  99. for (int r = 0; r < n_rows; ++r) {
  100. for (int c = 0; c < n_cols; ++c) {
  101. unsigned char temp = 0;
  102. file.read((char*)&temp, sizeof(temp));
  103. //data_dst[i * num_node_input_BP + r * n_cols + c] = (int)temp; //formula[1]
  104. if (temp > 128) {
  105. data_dst[i * num_node_input_BP + r * n_cols + c] = 1;
  106. } else {
  107. data_dst[i * num_node_input_BP + r * n_cols + c] = 0;
  108. }
  109. }
  110. }
  111. }
  112. }
  113.  
  114. static void readMnistLabels(std::string filename, int* data_dst, int num_image)
  115. {
  116. std::ifstream file(filename, std::ios::binary);
  117. assert(file.is_open());
  118.  
  119. int magic_number = 0;
  120. int number_of_images = 0;
  121. file.read((char*)&magic_number, sizeof(magic_number));
  122. magic_number = reverseInt(magic_number);
  123. file.read((char*)&number_of_images, sizeof(number_of_images));
  124. number_of_images = reverseInt(number_of_images);
  125. assert(number_of_images == num_image);
  126.  
  127. for (int i = 0; i < number_of_images; ++i) {
  128. unsigned char temp = 0;
  129. file.read((char*)&temp, sizeof(temp));
  130. data_dst[i * num_node_output_BP + temp] = 1; //formula[2]
  131. }
  132. }
  133.  
  134. bool BP::getSrcData()
  135. {
  136. assert(data_input_train && data_output_train && data_input_test && data_output_test);
  137.  
  138. std::string filename_train_images = "D:/Download/MNIST/train-images.idx3-ubyte";
  139. std::string filename_train_labels = "D:/Download/MNIST/train-labels.idx1-ubyte";
  140. readMnistImages(filename_train_images, data_input_train, patterns_train_BP);
  141. /*unsigned char* p = new unsigned char[784];
  142. memset(p, 0, sizeof(unsigned char) * 784);
  143. for (int j = 0, i = 59998 * 784; j< 784; j++, i++) {
  144. p[j] = (unsigned char)data_input_train[i];
  145. }
  146. delete[] p;*/
  147. readMnistLabels(filename_train_labels, data_output_train, patterns_train_BP);
  148. /*int* q = new int[10];
  149. memset(q, 0, sizeof(int) * 10);
  150. for (int j = 0, i = 59998 * 10; j < 10; j++, i++) {
  151. q[j] = data_output_train[i];
  152. }
  153. delete[] q;*/
  154.  
  155. std::string filename_test_images = "D:/Download/MNIST/t10k-images.idx3-ubyte";
  156. std::string filename_test_labels = "D:/Download/MNIST/t10k-labels.idx1-ubyte";
  157. readMnistImages(filename_test_images, data_input_test, patterns_test_BP);
  158. readMnistLabels(filename_test_labels, data_output_test, patterns_test_BP);
  159.  
  160. return true;
  161. }
  162.  
  163. void BP::init()
  164. {
  165. data_input_train = new int[patterns_train_BP * num_node_input_BP];
  166. memset(data_input_train, 0, sizeof(int) * patterns_train_BP * num_node_input_BP);
  167. data_output_train = new int[patterns_train_BP * num_node_output_BP];
  168. memset(data_output_train, 0, sizeof(int) * patterns_train_BP * num_node_output_BP);
  169. data_input_test = new int[patterns_test_BP * num_node_input_BP];
  170. memset(data_input_test, 0, sizeof(int) * patterns_test_BP * num_node_input_BP);
  171. data_output_test = new int[patterns_test_BP * num_node_output_BP];
  172. memset(data_output_test, 0, sizeof(int) * patterns_test_BP * num_node_output_BP);
  173.  
  174. initWeightThreshold();
  175. getSrcData();
  176. }
  177.  
  178. float BP::calcActivationFunction(float x)
  179. {
  180. return 1.0 / (1.0 + exp(-x)); //formula[4] formula[5] formula[7]
  181. }
  182.  
  183. void BP::calcHiddenLayer(const int* data)
  184. {
  185. for (int i = 0; i < num_node_hidden_BP; i++) {
  186. float tmp = 0;
  187. for (int j = 0; j < num_node_input_BP; j++) {
  188. tmp += data[j] * weight1[j][i];
  189. }
  190.  
  191. tmp -= threshold1[i]; //formula[3]
  192. output_hiddenLayer[i] = calcActivationFunction(tmp);
  193. }
  194. }
  195.  
  196. void BP::calcOutputLayer()
  197. {
  198. for (int i = 0; i < num_node_output_BP; i++) {
  199. float tmp = 0;
  200. for (int j = 0; j < num_node_hidden_BP; j++) {
  201. tmp += output_hiddenLayer[j] * weight2[j][i];
  202. }
  203.  
  204. tmp -= threshold2[i]; //formula[6]
  205. output_outputLayer[i] = calcActivationFunction(tmp);
  206. }
  207. }
  208.  
  209. void BP::calcAdjuctOutputLayer(const int* data)
  210. {
  211. for (int i = 0; i < num_node_output_BP; i++) {
  212. adjust_error_outputLayer[i] = (data[i] - output_outputLayer[i]) *
  213. output_outputLayer[i] * (1.0 - output_outputLayer[i]); //formula[8], f'(x)= f(x)*(1. - f(x))
  214. }
  215. }
  216.  
  217. void BP::calcAdjuctHiddenLayer()
  218. {
  219. for (int i = 0; i < num_node_hidden_BP; i++) {
  220. float tmp = 0;
  221. for (int j = 0; j < num_node_output_BP; j++) {
  222. tmp += weight2[i][j] * adjust_error_outputLayer[j];
  223. }
  224.  
  225. adjust_error_hiddenLayer[i] = tmp * (output_hiddenLayer[i] * (1.0 - output_hiddenLayer[i])); //formula[9]
  226. }
  227. }
  228.  
  229. void BP::updateWeightThresholdOutputLayer()
  230. {
  231. for (int i = 0; i < num_node_output_BP; i++) {
  232. for (int j = 0; j < num_node_hidden_BP; j++) {
  233. weight2[j][i] += (alpha_learning_BP * adjust_error_outputLayer[i] * output_hiddenLayer[j]); //formula[10]
  234. }
  235.  
  236. threshold2[i] += (alpha_learning_BP * adjust_error_outputLayer[i]); //formula[11]
  237. }
  238. }
  239.  
  240. void BP::updateWeightThresholdHiddenLayer(const int* data)
  241. {
  242. for (int i = 0; i < num_node_hidden_BP; i++) {
  243. for (int j = 0; j < num_node_input_BP; j++) {
  244. weight1[j][i] += (beta_learning_BP * adjust_error_hiddenLayer[i] * data[j]); //formula[12]
  245. }
  246.  
  247. threshold1[i] += (beta_learning_BP * adjust_error_hiddenLayer[i]); //formula[13]
  248. }
  249. }
  250.  
  251. float BP::test()
  252. {
  253. int count_accuracy = 0;
  254.  
  255. for (int num = 0; num < patterns_test_BP; num++) {
  256. int* p1 = data_input_test + num * num_node_input_BP;
  257. calcHiddenLayer(p1);
  258. calcOutputLayer();
  259.  
  260. float max_value = -9999;
  261. int pos = -1;
  262.  
  263. for (int i = 0; i < num_node_output_BP; i++) {
  264. if (output_outputLayer[i] > max_value) {
  265. max_value = output_outputLayer[i];
  266. pos = i;
  267. }
  268. }
  269.  
  270. int* p2 = data_output_test + num * num_node_output_BP;
  271. if (p2[pos] == 1) {
  272. count_accuracy++;
  273. }
  274. Sleep(1);
  275. }
  276.  
  277. return (count_accuracy * 1.0 / patterns_test_BP);
  278. }
  279.  
  280. bool BP::saveModelFile(const char* name)
  281. {
  282. FILE* fp = fopen(name, "wb");
  283. if (fp == NULL) {
  284. return false;
  285. }
  286.  
  287. int num_node_input = num_node_input_BP;
  288. int num_node_hidden = num_node_hidden_BP;
  289. int num_node_output = num_node_output_BP;
  290. fwrite(&num_node_input, sizeof(int), 1, fp);
  291. fwrite(&num_node_hidden, sizeof(int), 1, fp);
  292. fwrite(&num_node_output, sizeof(int), 1, fp);
  293. fwrite(weight1, sizeof(weight1), 1, fp);
  294. fwrite(threshold1, sizeof(threshold1), 1, fp);
  295. fwrite(weight2, sizeof(weight2), 1, fp);
  296. fwrite(threshold2, sizeof(threshold2), 1, fp);
  297.  
  298. fflush(fp);
  299. fclose(fp);
  300.  
  301. return true;
  302. }
  303.  
  304. bool BP::readModelFile(const char* name)
  305. {
  306. FILE* fp = fopen(name, "rb");
  307. if (fp == NULL) {
  308. return false;
  309. }
  310.  
  311. int num_node_input, num_node_hidden, num_node_output;
  312.  
  313. fread(&num_node_input, sizeof(int), 1, fp);
  314. assert(num_node_input == num_node_input_BP);
  315. fread(&num_node_hidden, sizeof(int), 1, fp);
  316. assert(num_node_hidden == num_node_hidden_BP);
  317. fread(&num_node_output, sizeof(int), 1, fp);
  318. assert(num_node_output == num_node_output_BP);
  319. fread(weight1, sizeof(weight1), 1, fp);
  320. fread(threshold1, sizeof(threshold1), 1, fp);
  321. fread(weight2, sizeof(weight2), 1, fp);
  322. fread(threshold2, sizeof(threshold2), 1, fp);
  323.  
  324. fflush(fp);
  325. fclose(fp);
  326.  
  327. return true;
  328. }
  329.  
  330. int BP::predict(const int* data, int width, int height)
  331. {
  332. assert(data && width == width_image_BP && height == height_image_BP);
  333.  
  334. const int* p = data;
  335. calcHiddenLayer(p);
  336. calcOutputLayer();
  337.  
  338. float max_value = -9999;
  339. int ret = -1;
  340.  
  341. for (int i = 0; i < num_node_output_BP; i++) {
  342. if (output_outputLayer[i] > max_value) {
  343. max_value = output_outputLayer[i];
  344. ret = i;
  345. }
  346. }
  347.  
  348. return ret;
  349. }
  350.  
  351. bool BP::train()
  352. {
  353. int i = 0;
  354. for (i = 0; i < iterations_BP; i++) {
  355. std::cout << "iterations : " << i;
  356.  
  357. float accuracyRate = test();
  358. std::cout << ", accuray rate: " << accuracyRate << std::endl;
  359. if (accuracyRate > accuracy_rate_BP) {
  360. saveModelFile("bp.model");
  361. std::cout << "generate bp model" << std::endl;
  362. break;
  363. }
  364.  
  365. for (int j = 0; j < patterns_train_BP; j++) {
  366. int* p1 = data_input_train + j * num_node_input_BP;
  367. calcHiddenLayer(p1);
  368. calcOutputLayer();
  369.  
  370. int* p2 = data_output_train + j * num_node_output_BP;
  371. calcAdjuctOutputLayer(p2);
  372. calcAdjuctHiddenLayer();
  373.  
  374. updateWeightThresholdOutputLayer();
  375. int* p3 = data_input_train + j * num_node_input_BP;
  376. updateWeightThresholdHiddenLayer(p3);
  377. }
  378. }
  379.  
  380. if (i == iterations_BP) {
  381. saveModelFile("bp.model");
  382. std::cout << "generate bp model" << std::endl;
  383. }
  384.  
  385. return true;
  386. }
  387.  
  388. }

test.cpp:

  1. #include <iostream>
  2. #include "BP.hpp"
  3. #include <opencv2/opencv.hpp>
  4.  
  5. int test_BP();
  6.  
  7. int main()
  8. {
  9. test_BP();
  10. std::cout << "ok!" << std::endl;
  11. }
  12.  
  13. int test_BP()
  14. {
  15. //1. bp train
  16. ANN::BP bp1;
  17. bp1.init();
  18. bp1.train();
  19.  
  20. //2. bp predict
  21. ANN::BP bp2;
  22. bool flag = bp2.readModelFile("bp.model");
  23. if (!flag) {
  24. std::cout << "read bp model error" << std::endl;
  25. return -1;
  26. }
  27.  
  28. int target[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
  29. std::string path_images = "../../../../test-images/";
  30.  
  31. int* data_image = new int[width_image_BP * height_image_BP];
  32.  
  33. for (int i = 0; i < 10; i++) {
  34. char ch[15];
  35. sprintf(ch, "%d", i);
  36. std::string str;
  37. str = std::string(ch);
  38. str += ".jpg";
  39. str = path_images + str;
  40.  
  41. cv::Mat mat = cv::imread(str, 2 | 4);
  42. if (!mat.data) {
  43. std::cout << "read image error" << std::endl;
  44. return -1;
  45. }
  46.  
  47. if (mat.channels() == 3) {
  48. cv::cvtColor(mat, mat, cv::COLOR_BGR2GRAY);
  49. }
  50.  
  51. if (mat.cols != width_image_BP || mat.rows != height_image_BP) {
  52. cv::resize(mat, mat, cv::Size(width_image_BP, height_image_BP));
  53. }
  54.  
  55. memset(data_image, 0, sizeof(int) * (width_image_BP * height_image_BP));
  56.  
  57. for (int h = 0; h < mat.rows; h++) {
  58. uchar* p = mat.ptr(h);
  59. for (int w = 0; w < mat.cols; w++) {
  60. if (p[w] > 128) {
  61. data_image[h* mat.cols + w] = 1;
  62. }
  63. }
  64. }
  65.  
  66. int ret = bp2.predict(data_image, mat.cols, mat.rows);
  67. std::cout << "correct result: " << i << ", actual result: " << ret << std::endl;
  68. }
  69.  
  70. delete[] data_image;
  71.  
  72. return 0;
  73. }

train结果例如以下图所看到的:

predict结果例如以下图所看到的,測试图像是从MNIST test集合中选取的:

GitHub:https://github.com/fengbingchun/NN

BP神经网络公式推导及实现(MNIST)的更多相关文章

  1. Python实现bp神经网络识别MNIST数据集

    title: "Python实现bp神经网络识别MNIST数据集" date: 2018-06-18T14:01:49+08:00 tags: [""] cat ...

  2. BP神经网络的公式推导

    如果感觉自己看不懂,那就看看我博客的梯度下降法,博文最后的感知机也算最简单的BP神经网络吧,用的也是反馈(w,b):典型梯度下降法 BP网络的结构 BP网络的结构如下图所示,分为输入层(Input), ...

  3. BP神经网络原理及python实现

    [废话外传]:终于要讲神经网络了,这个让我踏进机器学习大门,让我读研,改变我人生命运的四个字!话说那么一天,我在乱点百度,看到了这样的内容: 看到这么高大上,这么牛逼的定义,怎么能不让我这个技术宅男心 ...

  4. 【机器学习】BP神经网络实现手写数字识别

    最近用python写了一个实现手写数字识别的BP神经网络,BP的推导到处都是,但是一动手才知道,会理论推导跟实现它是两回事.关于BP神经网络的实现网上有一些代码,可惜或多或少都有各种问题,在下手写了一 ...

  5. 神经网络中的BP神经网络和贝叶斯

    1 贝叶斯网络在地学中的应用 1 1.1基本原理及发展过程 1 1.2 具体的研究与应用 4 2 BP神经网络在地学中的应用 6 2.1BP神经网络简介 6 2.2基本原理 7 2.3 在地学中的具体 ...

  6. BP神经网络在python下的自主搭建梳理

    本实验使用mnist数据集完成手写数字识别的测试.识别正确率认为是95% 完整代码如下: #!/usr/bin/env python # coding: utf-8 # In[1]: import n ...

  7. 机器学习(4):BP神经网络原理及其python实现

    BP神经网络是深度学习的重要基础,它是深度学习的重要前行算法之一,因此理解BP神经网络原理以及实现技巧非常有必要.接下来,我们对原理和实现展开讨论. 1.原理  有空再慢慢补上,请先参考老外一篇不错的 ...

  8. 基于BP神经网络的简单字符识别算法自小结(C语言版)

    本文均属自己阅读源代码的点滴总结.转账请注明出处谢谢. 欢迎和大家交流.qq:1037701636 email:gzzaigcn2009@163.com 写在前面的闲话: 自我感觉自己应该不是一个非常 ...

  9. 三.BP神经网络

    BP神经网络是包含多个隐含层的网络,具备处理线性不可分问题的能力.以往主要是没有适合多层神经网络的学习算法,,所以神经网络的研究一直处于低迷期. 20世纪80年代中期,Rumelhart,McClel ...

随机推荐

  1. c++中六种构造函数的实现以及9中情况下,构造函数的调用过程

    六种构造函数的实现代码例如以下: #include<iostream> using namespace std; //c++中六种默认的构造函数 class Test { public: ...

  2. Anders Hejlsberg 和 Erich Gamma

    Anders Hejlsberg 和 Erich Gamma 大概半年前,我写了一篇名叫<有点软文>的文章,深情并茂地告诉大家,我司其实隐藏着很多牛人巨擘.有些人是身怀屠龙技,但是大家不认 ...

  3. SQL 锁 lock

    http://www.cnblogs.com/huangxincheng/p/4292320.html 关于sql 中的锁. 1 排他锁 sql中在做 insert update delete 会存在 ...

  4. 完全背包模板 51Nod 1101

    N元钱换为零钱,有多少不同的换法?币值包括1 2 5分,1 2 5角,1 2 5 10 20 50 100元. 例如:5分钱换为零钱,有以下4种换法: 1.5个1分 2.1个2分3个1分 3.2个2分 ...

  5. CSS Loading 特效

    全页面遮罩效果loading css: .loading_shade { position: fixed; left:; top:; width: 100%; height: 100%; displa ...

  6. JDBC连接池C3P0

    连接池 1)传统方式找DriverManager要连接.数目是有限的. 2)传统方式的close().并没有将Connection重用.仅仅是切断应用程序和数据库的桥梁,即无发送到SQL命令到数据库端 ...

  7. Day3下午解题报告

    预计分数:20+40+30=90 实际分数:40+90+60=190 再次人品爆发&&手感爆发&&智商爆发 谁能告诉我为什么T1数据这么水.. 谁能告诉我为什么T2数据 ...

  8. 有点坑爹的GDALComputeRasterMinMax函数

    作者:朱金灿 来源:http://blog.csdn.net/clever101 GDALComputeRasterMinMax函数是gdal库为了求取指定波段的极值而提供的接口.最近看了这个接口的源 ...

  9. call、apply、bind 区别

    1.为什么要用 call .apply? 为了 改变方法里面的属性而不去改变原来的方法 function fruits() {} fruits.prototype = { color: "r ...

  10. 模板 Fail树

    fail树就是将Trie图的Fail指针反指,从而生成一棵树,这个树的性质是:子节点对应字符串为以当前串为后缀,而子节点为原串的前缀,前缀的后缀就是嵌套在原串中的子串. 模板:BZOJ3172 Des ...