basic neural network in C

profileJack Jonshen
Framework.zip

Framework/.DS_Store

__MACOSX/Framework/._.DS_Store

Framework/data_loading.cpp

#include "header_file.h" int ReverseInt(int i) { unsigned char ch1, ch2, ch3, ch4; ch1 = i & 255; ch2 = (i >> 8) & 255; ch3 = (i >> 16) & 255; ch4 = (i >> 24) & 255; return((int)ch1 << 24) + ((int)ch2 << 16) + ((int)ch3 << 8) + ch4; } //Load MNIST images function void Loading_Mnist_images(string filename, vector<cv::Mat> &images) { ifstream file(filename, ios::in | ios::binary); if (file.is_open() == false) { cout << "open mnist image file error!" << endl; return; } else if (file.is_open() == true) { int magic_number = 0; int number_of_images = 0; int n_rows = 0; int n_cols = 0; //load sizeof(magic_number) to magic_number file.read((char*)&magic_number, sizeof(magic_number)); magic_number = ReverseInt(magic_number); //load number_of_images file.read((char*)&number_of_images, sizeof(number_of_images)); number_of_images = ReverseInt(number_of_images); //Find image Height file.read((char*)&n_rows, sizeof(n_rows)); n_rows = ReverseInt(n_rows); //Find image Width file.read((char*)&n_cols, sizeof(n_cols)); n_cols = ReverseInt(n_cols); cout << "Total number of images are: " << number_of_images << endl; // read image and save to images for (int i = 0; i < number_of_images; ++i) { //cv::Mat current_image = cv::Mat::zeros(n_rows, n_cols, CV_8UC1); cv::Mat current_image = cv::Mat::zeros(1,n_rows* n_cols, CV_8UC1); int current_index = 0; for (int r = 0; r < n_rows; ++r) { for (int c = 0; c < n_cols; ++c) { unsigned char temp = 0; file.read((char*)&temp, sizeof(temp)); /*current_image.at<uchar>(r, c) = (int)temp;*/ current_image.at<uchar>(current_index) = (int)temp; current_index++; } } images.push_back(current_image); } } } // Load Mnist label function void Load_Mnist_Label(string filename, vector<int> &labels) { ifstream file(filename, ios::in | ios::binary); if (file.is_open()) { int magic_number = 0; int number_of_labels = 0; file.read((char*)&magic_number, sizeof(magic_number)); magic_number = ReverseInt(magic_number); file.read((char*)&number_of_labels, sizeof(number_of_labels)); number_of_labels = ReverseInt(number_of_labels); cout << "Total number of labels are: " << number_of_labels << endl; for (int i = 0; i < number_of_labels; ++i) { unsigned char current_label = 0; file.read((char*)&current_label, sizeof(current_label)); labels.push_back(current_label); } } } // Give a name for each images function string GetImageName(int number, int arr[]) { string str1, str2; for (int i = 0; i < 10; i++) { if (number == i) { arr[i]++; char ch1[10]; sprintf(ch1, "%d", arr[i]); str1 = std::string(ch1); if (arr[i] < 10) { str1 = "0000" + str1; } else if (arr[i] < 100) { str1 = "000" + str1; } else if (arr[i] < 1000) { str1 = "00" + str1; } else if (arr[i] < 10000) { str1 = "0" + str1; } break; } } char ch2[10]; sprintf(ch2, "%d", number); str2 = std::string(ch2); str2 = str2 + "_" + str1; return str2; } // writing training images to train image folder void WritingTrainingIimage(vector<cv::Mat> &train_images_vector, vector<int> &train_labels_vector) { /******************************* writing training images to train image folder **************************************/ int train_count_digits[10]; for (int i = 0; i < 10; i++) train_count_digits[i] = 0; string save_train_images_path = "train_images/"; //path for train images for (int i = 0; i < train_images_vector.size(); i++) { int number = train_labels_vector[i]; string image_name = GetImageName(number, train_count_digits); image_name = save_train_images_path + image_name + ".jpg"; cv::imwrite(image_name, train_images_vector[i].reshape(0,28)); if (i % 5000 == 0) { cout << "Saving " << i << " images" << endl; } if (i == 10) { cout << "10 images are written into train images folder. If you want to continuou to write image, click Y then click Enter. Else click N then click Enter. " << std::endl; char training_button; cin >> training_button; if (training_button == 'y') { cout << "Continue to write image" << endl; continue; } else { cout << "Stop to write image" << endl; break; } } } } // writing testing images to test image folder void WritingTestingIimage(vector<cv::Mat> &test_images_vector, vector<int> &test_labels_vector) { /******************************* writing testinging image to test image folder **************************************/ int test_count_digits[10]; for (int i = 0; i < 10; i++) test_count_digits[i] = 0; string save_test_images_path = "test_images/"; //path for test images for (int i = 0; i < test_images_vector.size(); i++) { int number = test_labels_vector[i]; string image_name = GetImageName(number, test_count_digits); image_name = save_test_images_path + image_name + ".jpg"; cv::imwrite(image_name, test_images_vector[i].reshape(0, 28)); if (i % 5000 == 0) { cout << "Saving " << i << " images" << endl; } if (i == 10) { cout << "10 images are written into test images folder. If you want to continuou to write image, click Y then click Enter. Else click N then click Enter. " << std::endl; char testing_button; cin >> testing_button; if (testing_button == 'y') { cout << "Continue to write image" << endl; continue; } else { cout << "Stop to write image" << endl; break; } } } }

__MACOSX/Framework/._data_loading.cpp

Framework/header_file.h

#include <iostream> #include <fstream> #include <vector> #include <string> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; int ReverseInt(int i); //Load MNIST images function void Loading_Mnist_images(string filename, vector<cv::Mat> &images); // Load Mnist label function void Load_Mnist_Label(string filename, vector<int> &labels); // Give a name for each images function string GetImageName(int number, int arr[]); // writing training images to train image folder void WritingTrainingIimage(vector<cv::Mat> &train_images_vector, vector<int> &train_labels_vector); // writing testing images to test image folder void WritingTestingIimage(vector<cv::Mat> &test_images_vector, vector<int> &test_labels_vector);

__MACOSX/Framework/._header_file.h

Framework/main.cpp

Framework/main.cpp


#include   "header_file.h"
#include   "Net.h"
#include   "utilis.h"

#define  MODE  1   // 0 - training mode;  1 - testing mode
#define  IMAGE_NUMBER  3000
#define  LOSS_THRESHOLD  50

using   namespace  std ;
using   namespace  cv ;

/************************** Implementation Here *******************/

/********** Function 1:  Backpropogation for training use *************************/
//apply the back-propogation algorithm as described in the class
//Hint: use loop to update the parameraters interatively. The number of interations should be equal to the number of samples. In this case, it should be "image_used_to_train"
void  backPropogation ( const   Mat   & traing_img ,   const   Mat   & training_label ,   Mat   & theta_1 ,   Mat   & theta_2 ,   Mat   & bias_1 ,   Mat   & bias_2 )
{
     //Input Parameters
     //traing_img: the images use for training, it has 784 rows and IMAGE_NUMBER columns. Each column represents an image.
     //training_label: the corresponding labels for "training_img". It has 10 rows and IMAGE_NUMBER column.
    
     //theta_1 and theta_2: they are actually the output. You need to use the training data to iteratively update the these two matrices.
    
     //bias_1 and bias_2: simlilary, they are the output. You need to use the training data to iteratively update the these two matrices.
    
    


}


/********** Function 2:  Prediction for testing use  *************************/
//Use the parameters learned (theta_1, theta_2) to compute the input sample "sample_image"

//Hint: You can use the matrix based multiplication to compute the last layer's values. Then pick up the maximum one as the final output.
void  numPrediction ( const   Mat   & sample_img ,   const   Mat   & theta_1 ,   const   Mat   & theta_2 ,   const   Mat   & bias_1 ,   const   Mat   & bias_2 ,   int   & predicted_number )
{
     //Input Parameters
     //sample_img: the input image for number prediction. Its dimension is 784x1
     //theta_1 and theta_2 are the learned parameters
     //bias_1 and bias_2 are the learned parameters
     //predicted_number: the output result. You need to find the neuron with the maximum output from the last layer. So the predicted_number will be the index of that neuron
    
    
}


/*********************  End of Implementation  *********************/



int  main ( int  argc ,   char   ** argv )   {
    
/******************** Parameters to be learned  ******************/
     Mat  theta_1 ;   //The matrix between layer 1 and layer 2
     Mat  theta_2 ;   //The matrix between layer 2 and layer 3
     Mat  bias_1 ;   //The vector for layer 1
     Mat  bias_2 ;   //The vector for layer 2
    
    theta_1 . create ( 100 ,   784 ,  CV_32FC1 );   //initialize the matrix with 100x784 dimension
    theta_2 . create ( 10 ,   100 ,  CV_32FC1 );    //initialize the matrix with 10x100 dimension
    bias_1 . create ( 100 ,   1 ,  CV_32FC1 );   //initialize the bias matrix with 100x1
    bias_2 . create ( 10 ,   1 ,  CV_32FC1 );   //initialize the bias matrix with 10x1

/*************************  Load training data *************************/
     //train_images 784 x 60000
    vector < cv :: Mat >  train_images_vector ;
     Loading_Mnist_images ( "train-images.idx3-ubyte" ,  train_images_vector );

     //train_labels = 10 x 60000;
    vector < int >  train_labels_vector ;
     Load_Mnist_Label ( "train-labels.idx1-ubyte" ,  train_labels_vector );


///************************* Load testing data *************************/
//  //test_images 784 x 10000;
    vector < cv :: Mat >  test_images_vector ;
     Loading_Mnist_images ( "t10k-images.idx3-ubyte" ,  test_images_vector );

     //train_labels 10 x 10000;
    vector < int >  test_labels_vector ;
     Load_Mnist_Label ( "t10k-labels.idx1-ubyte" ,  test_labels_vector );

     // Check
     if   ( test_images_vector . size ()   !=  test_labels_vector . size ())   {
        cout  <<   "parse MNIST test file error"   <<  endl ;
     }



if ( MODE  ==   0 )
{
     /************************* Prepare for training data *************************/
     int  image_used_to_train  =  IMAGE_NUMBER ;
     Mat  training_data_mat  =   Mat :: zeros ( 784 ,  image_used_to_train ,  CV_32FC1 );
     Mat  training_data_label  =   Mat :: zeros ( 10 , image_used_to_train ,  CV_32FC1 );

     // initialize image matrix and label matrix
     for   ( int  i  =   0 ;  i  <  image_used_to_train ;  i ++ )
     {
         Mat   GrayImage ,   BinaryImage ;
         //Get the data
        train_images_vector [ i ]. copyTo ( GrayImage );
         //Convert the data to BinaryImage 
        threshold ( GrayImage ,   BinaryImage ,   1 ,   1 ,  CV_THRESH_BINARY );
        cv :: transpose ( BinaryImage ,   BinaryImage );
         BinaryImage . copyTo ( training_data_mat . col ( i ));
        training_data_label . at < float > ( train_labels_vector [ i ], i )   =   1 ;
     }


     /************************* training ****************************/
     //Randomly assign values to initialize the two matrices: theta_1, theta_2
    cv :: randu ( theta_1 ,   0.0 ,   1.0 );   //initial all the parameters between [0, 1]
    cv :: randu ( theta_2 ,   0.0 ,   1.0 );
    

     //call the back-propogation to get the paraterms update
    backPropogation ( training_data_mat ,  training_data_label ,  theta_1 ,  theta_2 ,  bias_1 ,  bias_2 );
    
    
    
     /***************** Save the matrices to local files ****************/
     FileStorage  fs1 ( "theta_1.xml" ,   FileStorage :: WRITE );
     FileStorage  fs2 ( "theta_2.xml" ,   FileStorage :: WRITE );
    fs1  <<   "theta_1"   <<  theta_1 ;
    fs2  <<   "theta_2"   <<  theta_2 ;
    fs1 . release ();
    fs2 . release ();

    
    
}
else
{
     ///************************* Prepare for testing data *************************/
     int  image_used_to_test  =   1 ;
     Mat  testing_data_mat  =   Mat :: zeros ( 784 ,  image_used_to_test ,  CV_32FC1 );
     Mat  testing_data_label  =   Mat :: zeros ( 10 ,  image_used_to_test ,  CV_32FC1 );
    
     // load the model from files
     FileStorage  fs1 ( "theta_1.xml" ,   FileStorage :: READ );
     FileStorage  fs2 ( "theta_2.xml" ,   FileStorage :: READ );
    fs1 [ "theta_1" ]   >>  theta_1 ;
    fs2 [ "theta_2" ]   >>  theta_2 ;
    fs1 . release ();
    fs2 . release ();
    

     // Using mouse to get image
     Draw_number ();
     Mat   Draw_image   =  imread ( "MouseDraw.jpg" );
    resize ( Draw_image ,   Draw_image ,   Size ( 28 ,   28 ),   0 ,   0 ,  INTER_LINEAR );
    cvtColor ( Draw_image ,   Draw_image ,  CV_BGR2GRAY );
    threshold ( Draw_image ,   Draw_image ,   150 ,   1 ,  THRESH_BINARY_INV );
     //cout << Draw_image << endl;
     Mat  sample_image ;
     Draw_image . reshape ( 0 ,   784 ). copyTo ( sample_image );
    sample_image . convertTo ( sample_image ,  CV_32FC1 );
    
  
     /*********************  Forward Prediction:  *********************/
    
    
     int  number  =   0 ;   //Initially set to 0, you will update during the forward prediction
    
    numPrediction ( sample_image ,  theta_1 ,  theta_2 ,  bias_1 ,  bias_2 ,  number );
    
    
    printf ( "Output the predicted number: \n" );
    cout  <<  number << endl ;
}
     char  a ;
     //cin >> a;
    
     return   0 ;

}


__MACOSX/Framework/._main.cpp

Framework/t10k-images.idx3-ubyte

__MACOSX/Framework/._t10k-images.idx3-ubyte

Framework/t10k-labels.idx1-ubyte

__MACOSX/Framework/._t10k-labels.idx1-ubyte

Framework/train-images.idx3-ubyte

__MACOSX/Framework/._train-images.idx3-ubyte

Framework/train-labels.idx1-ubyte

__MACOSX/Framework/._train-labels.idx1-ubyte

Framework/utilis.h

#include "header_file.h" // Mouse callback function void on_mouse(int event, int x, int y, int flags, void* param) { static bool s_bMouseLButtonDown = false; static CvPoint s_cvPrePoint = cvPoint(0, 0);//set the orignal switch (event)// call event { case CV_EVENT_LBUTTONDOWN:// left button down s_bMouseLButtonDown = true; s_cvPrePoint = cvPoint(x, y); break; case CV_EVENT_LBUTTONUP://left button on s_bMouseLButtonDown = false; break; case CV_EVENT_MOUSEMOVE:// mouse is moving if (s_bMouseLButtonDown) { CvPoint cvCurrPoint = cvPoint(x, y);// save the point cvLine((IplImage*)param, s_cvPrePoint, cvCurrPoint, CV_RGB(0, 200, 0), 8);// connect two points s_cvPrePoint = cvCurrPoint;// set current point as the orignal point cvShowImage("Draw_Board", (IplImage*)param); } break; } } void Draw_number() { const int MAX_WIDTH = 140, MAX_HEIGHT = 140; const char *pstrSaveImageName = "MouseDraw.jpg"; IplImage *pSrcImage = cvCreateImage(cvSize(MAX_WIDTH, MAX_HEIGHT), IPL_DEPTH_8U, 3); cvSet(pSrcImage, CV_RGB(255, 255, 255)); // set the image as wight cvNamedWindow("Draw_Board", CV_WINDOW_AUTOSIZE); cvShowImage("Draw_Board", pSrcImage); cvSetMouseCallback("Draw_Board", on_mouse, (void*)pSrcImage); int c; do { c = cvWaitKey(0); if(c == 'd' || c == 'D') break; switch ((char)c) { case 'r': cvSet(pSrcImage, CV_RGB(255, 255, 255)); cvShowImage("Draw_Board", pSrcImage); break; case 's': cvSaveImage(pstrSaveImageName, pSrcImage); cout << "Image saved. Please click ESC to close the window." << endl; break; } } while (c > 0 && c != 27); cvDestroyWindow("Draw_Board"); cvReleaseImage(&pSrcImage); }

__MACOSX/Framework/._utilis.h