Realization of simple BP neural network with C + +

Time:2020-10-11

In this paper, we share the specific code of simple BP neural network implemented by C + + for your reference. The specific content is as follows

A simple BP neural network is realized

Using EasyX to display the training process and results graphically

25 samples were used and 10000 times of training were conducted.

The neural network has two inputs and one output

The following figure shows the training effect, data is the input data of training, temp represents the output of the layer, target is the training target, and the large picture on the right is the test result of BP neural network.

The following is the detailed code implementation, mainly or the basic matrix operation.

#include <stdio.h>
#include <stdlib.h>
#include <graphics.h>
#include <time.h>
#include <math.h>

#define uint unsigned short
#define real double

#define threshold (real)(rand() % 99998 + 1) / 100000

//Layers of neural networks
class layer{
private:
 char name[20];
 uint row, col;
 uint x, y;
 real **data;
 real *bias;
public:
 layer(){
 strcpy_s(name, "temp");
 row = 1;
 col = 3;
 x = y = 0;
 data = new real*[row];
 bias = new real[row];
 for (uint i = 0; i < row; i++){
  data[i] = new real[col];
  bias[i] = threshold;
  for (uint j = 0; j < col; j++){
  data[i][j] = 1;
  }
 }
 }
 layer(FILE *fp){
 fscanf_s(fp, "%d %d %d %d %s", &row, &col, &x, &y, name);
 data = new real*[row];
 bias = new real[row];
 for (uint i = 0; i < row; i++){
  data[i] = new real[col];
  bias[i] = threshold;
  for (uint j = 0; j < col; j++){
  fscanf_s(fp, "%lf", &data[i][j]);
  }
 }
 }
 layer(uint row, uint col){
 strcpy_s(name, "temp");
 this->row = row;
 this->col = col;
 this->x = 0;
 this->y = 0;
 this->data = new real*[row];
 this->bias = new real[row];
 for (uint i = 0; i < row; i++){
  data[i] = new real[col];
  bias[i] = threshold;
  for (uint j = 0; j < col; j++){
  data[i][j] = 1.0f;
  }
 }
 }
 layer(const layer &a){
 strcpy_s(name, a.name);
 row = a.row, col = a.col;
 x = a.x, y = a.y;
 data = new real*[row];
 bias = new real[row];
 for (uint i = 0; i < row; i++){
  data[i] = new real[col];
  bias[i] = a.bias[i];
  for (uint j = 0; j < col; j++){
  data[i][j] = a.data[i][j];
  }
 }
 }
 ~layer(){
 //Delete original data
 for (uint i = 0; i < row; i++){
  delete[]data[i];
 }
 delete[]data;
 }
 layer& operator =(const layer &a){
 //Delete original data
 for (uint i = 0; i < row; i++){
  delete[]data[i];
 }
 delete[]data;
 delete[]bias;
 //Reallocate space
 strcpy_s(name, a.name);
 row = a.row, col = a.col;
 x = a.x, y = a.y;
 data = new real*[row];
 bias = new real[row];
 for (uint i = 0; i < row; i++){
  data[i] = new real[col];
  bias[i] = a.bias[i];
  for (uint j = 0; j < col; j++){
  data[i][j] = a.data[i][j];
  }
 }
 return *this;
 }
 layer Transpose() const {
 layer arr(col, row);
 arr.x = x, arr.y = y;
 for (uint i = 0; i < row; i++){
  for (uint j = 0; j < col; j++){
  arr.data[j][i] = data[i][j];
  }
 }
 return arr;
 }
 layer sigmoid(){
 layer arr(col, row);
 arr.x = x, arr.y = y;
 for (uint i = 0; i < x.row; i++){
  for (uint j = 0; j < x.col; j++){
  arr.data[i][j] = 1 / (1 + exp(-data[i][j]));// 1/(1+exp(-z))
  }
 }
 return arr;
 }
 layer operator *(const layer &b){
 layer arr(row, col);
 arr.x = x, arr.y = y;
 for (uint i = 0; i < row; i++){
  for (uint j = 0; j < col; j++){
  arr.data[i][j] = data[i][j] * b.data[i][j];
  }
 }
 return arr;
 }
 layer operator *(const int b){
 layer arr(row, col);
 arr.x = x, arr.y = y;
 for (uint i = 0; i < row; i++){
  for (uint j = 0; j < col; j++){
  arr.data[i][j] = b * data[i][j];
  }
 }
 return arr;
 }
 layer matmul(const layer &b){
 layer arr(row, b.col);
 arr.x = x, arr.y = y;
 for (uint k = 0; k < b.col; k++){
  for (uint i = 0; i < row; i++){
  arr.bias[i] = bias[i];
  arr.data[i][k] = 0;
  for (uint j = 0; j < col; j++){
   arr.data[i][k] += data[i][j] * b.data[j][k];
  }
  }
 }
 return arr;
 }
 layer operator -(const layer &b){
 layer arr(row, col);
 arr.x = x, arr.y = y;
 for (uint i = 0; i < row; i++){
  for (uint j = 0; j < col; j++){
  arr.data[i][j] = data[i][j] - b.data[i][j];
  }
 }
 return arr;
 }
 layer operator +(const layer &b){
 layer arr(row, col);
 arr.x = x, arr.y = y;
 for (uint i = 0; i < row; i++){
  for (uint j = 0; j < col; j++){
  arr.data[i][j] = data[i][j] + b.data[i][j];
  }
 }
 return arr;
 }
 layer neg(){
 layer arr(row, col);
 arr.x = x, arr.y = y;
 for (uint i = 0; i < row; i++){
  for (uint j = 0; j < col; j++){
  arr.data[i][j] = -data[i][j];
  }
 }
 return arr;
 }
 bool operator ==(const layer &a){
 bool result = true;
 for (uint i = 0; i < row; i++){
  for (uint j = 0; j < col; j++){
  if (abs(data[i][j] - a.data[i][j]) > 10e-6){
   result = false;
   break;
  }
  }
 }
 return result;
 }
 void randomize(){
 for (uint i = 0; i < row; i++){
  for (uint j = 0; j < col; j++){
  data[i][j] = threshold;
  }
  bias[i] = 0.3;
 }
 }
 void print(){
 outtextxy(x, y - 20, name);
 for (uint i = 0; i < row; i++){
  for (uint j = 0; j < col; j++){
  COLORREF color = HSVtoRGB(360 * data[i][j], 1, 1);
  putpixel(x + i, y + j, color);
  }
 }
 }
 void save(FILE *fp){
 fprintf_s(fp, "%d %d %d %d %s\n", row, col, x, y, name);
 for (uint i = 0; i < row; i++){
  for (uint j = 0; j < col; j++){
  fprintf_s(fp, "%lf ", data[i][j]);
  }
  fprintf_s(fp, "\n");
 }
 }
 friend class network;
 friend layer operator *(const double a, const layer &b);
};

layer operator *(const double a, const layer &b){
 layer arr(b.row, b.col);
 arr.x = b.x, arr.y = b.y;
 for (uint i = 0; i < arr.row; i++){
 for (uint j = 0; j < arr.col; j++){
  arr.data[i][j] = a * b.data[i][j];
 }
 }
 return arr;
}

//Neural network
class network{
 int iter;
 double learn;
 layer arr[3];
 layer data, target, test;
 layer& unit(layer &x){
 for (uint i = 0; i < x.row; i++){
  for (uint j = 0; j < x.col; j++){
  x.data[i][j] = i == j ? 1.0 : 0.0;
  }
 }
 return x;
 }
 layer grad_sigmoid(layer &x){
 layer e(x.row, x.col);
 e = x*(e - x);
 return e;
 }
public:
 network(FILE *fp){
 fscanf_s(fp, "%d %lf", &iter, &learn);
 //Input data
 data = layer(fp);
 for (uint i = 0; i < 3; i++){
  arr[i] = layer(fp);
  //arr[i].randomize();
 }
 target = layer(fp);
 //Test data
 test = layer(2, 40000);
 for (uint i = 0; i < test.col; i++){
  test.data[0][i] = ((double)i / 200) / 200.0f;
  test.data[1][i] = (double)(i % 200) / 200.0f;
 }
 }
 void train(){
 int i = 0;
 char str[20];
 data.print();
 target.print();
 for (i = 0; i < iter; i++){
  sprintf_s(str, "Iterate:%d", i);
  outtextxy(0, 0, str);
  //Forward propagation
  layer l0 = data;
  layer l1 = arr[0].matmul(l0).sigmoid();
  layer l2 = arr[1].matmul(l1).sigmoid();
  layer l3 = arr[2].matmul(l2).sigmoid();
  //Display output results
  l1.print();
  l2.print();
  l3.print();
  if (l3 == target){
  break;
  }
  //Back propagation
  layer l3_delta = (l3 - target ) * grad_sigmoid(l3);
  layer l2_delta = arr[2].Transpose().matmul(l3_delta) * grad_sigmoid(l2);
  layer l1_delta = arr[1].Transpose().matmul(l2_delta) * grad_sigmoid(l1);
  //Gradient descent method
  arr[2] = arr[2] - learn * l3_delta.matmul(l2.Transpose());
  arr[1] = arr[1] - learn * l2_delta.matmul(l1.Transpose());
  arr[0] = arr[0] - learn * l1_delta.matmul(l0.Transpose());
 }
 sprintf_s(str, "Iterate:%d", i);
 outtextxy(0, 0, str);
 //Test output
 // selftest();
 }
 void selftest(){
 //Testing
 layer l0 = test;
 layer l1 = arr[0].matmul(l0).sigmoid();
 layer l2 = arr[1].matmul(l1).sigmoid();
 layer l3 = arr[2].matmul(l2).sigmoid();
 setlinecolor(WHITE);
 //Testing例
 for (uint j = 0; j < test.col; j++){
  Colorref color = hsvtorgb (360 * L3. Data [0] [J], 1, 1); // output color
  putpixel((int)(test.data[0][j] * 160) + 400, (int)(test.data[1][j] * 160) + 30, color);
 }
 //Standard example
 for (uint j = 0; j < data.col; j++){
  COLORREF color = HSVtoRGB(360 *  target.data [0] [J], 1, 1); // output color
  setfillcolor(color);
  fillcircle((int)(data.data[0][j] * 160) + 400, (int)(data.data[1][j] * 160) + 30, 3);
 }
 line(400, 30, 400, 230);
 line(400, 30, 600, 30);
 }
 void save(FILE *fp){
 fprintf_s(fp, "%d %lf\n", iter, learn);
 data.save(fp);
 for (uint i = 0; i < 3; i++){
  arr[i].save(fp);
 }
 target.save(fp);
 }
};
#include "network.h"

void main(){
 FILE file;
 FILE *fp = &file;
 //Read status
 fopen_s(&fp, "Text.txt", "r");
 network net(fp);
 fclose(fp);
 initgraph(600, 320);
 net.train();
 //Save status
 fopen_s(&fp, "Text.txt", "w");
 net.save(fp);
 fclose(fp);
 getchar();
 closegraph();
}

The above code was implemented in early 2016, which is very crude and not conducive to extension. Three years later, I revisited the back propagation algorithm and refactored the code above.

Recently, referring to the description of the back propagation algorithm in the book “deep learning”, I realized the neural network framework based on the back propagation algorithm with C + +: GitHub: neural network. The framework supports tensor operations such as convolution, pooling and upsampling. In addition to the traditional stacked network model, it also implements the automatic derivation algorithm based on computational graph, and there are still some bugs. It is expected to support the construction of convolutional neural networks and implement some gradient based optimization algorithms introduced in the book “deep learning”.

Welcome interested students to put forward valuable suggestions here.

The above is the whole content of this article, I hope to help you in your study, and I hope you can support developeppaer more.