TensorFlow.NET introduction to machine learning [5] handwritten digit recognition (MNIST) using neural network

Starting from this article, I finally have to do some serious work. There are preparations ahead. This time we want to solve the classic problem of machine learning, MNIST handwritten numeral recognition.

First, let's introduce the data set. Please first unzip: TF_Net\Asset\mnist_png.tar.gz file

The folder includes two folders: training and validation. The training folder includes 60000 training pictures, and the validation folder includes 10000 evaluation pictures. The pictures are 28 * 28 pixels, which are placed in 0 ~ 9 ten folders respectively.

The overall process of the program is basically the same as the BMI analysis program introduced in the previous article. After all, they are multivariate classification, with several differences.

1. The characteristic data (input) of BMI program is a one-dimensional array, including two numbers. The characteristic data of MNIST is a 28 * 28 two-bit array;

2. There are 3 outputs of BMI program and 10 outputs of MNIST;

 

The network model is constructed as follows:

        private readonly int img_rows = 28;
        private readonly int img_cols = 28;
        private readonly int num_classes = 10;  // total classes
        /// <summary>
        /// Building network model
        /// </summary>     
        private Model BuildModel()
        {
            // Network parameters          
            int n_hidden_1 = 128;    // 1st layer number of neurons.     
            int n_hidden_2 = 128;    // 2nd layer number of neurons.                                
            float scale = 1.0f / 255;

            var model = keras.Sequential(new List<ILayer>
            {
                keras.layers.InputLayer((img_rows,img_cols)),
                keras.layers.Flatten(),
                keras.layers.Rescaling(scale),
                keras.layers.Dense(n_hidden_1, activation:keras.activations.Relu),
                keras.layers.Dense(n_hidden_2, activation:keras.activations.Relu),
                keras.layers.Dense(num_classes, activation:keras.activations.Softmax)
            });

            return model;
        }

Two new methods are used in this network, which need to be explained:

1. Flatten method: it means flattening here. Flatten the 28 * 28 two-dimensional array into a one-dimensional array containing 784 data, because the two-dimensional array cannot be operated;

2. Rescaling} method: multiply each data by a coefficient. Because the data we obtain from the picture is the gray value of each site, and its value range is 0 ~ 255, multiply by a coefficient to reduce the data to less than 1 to avoid overflow during subsequent operations.

 

Others are basically the same as those described in the previous article. All the codes are as follows:

    /// <summary>
    /// Multiple classification is realized by neural network
    /// </summary>
    public class NN_MultipleClassification_BMI
    {
        private readonly Random random = new Random(1);

        // Network parameters
        int num_features = 2; // data features       
        int num_classes = 3;  // total output .

        public void Run()
        {
            var model = BuildModel();
            model.summary();          

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();

            (NDArray train_x, NDArray train_y) = PrepareData(1000);
            model.compile(optimizer: keras.optimizers.Adam(0.001f),
              loss: keras.losses.SparseCategoricalCrossentropy(),
              metrics: new[] { "accuracy" });
            model.fit(train_x, train_y, batch_size: 128, epochs: 300);

            test(model);
        }

        /// <summary>
        /// Building network model
        /// </summary>     
        private Model BuildModel()
        {
            // Network parameters          
            int n_hidden_1 = 64; // 1st layer number of neurons.     
            int n_hidden_2 = 64; // 2nd layer number of neurons.           

            var model = keras.Sequential(new List<ILayer>
            {
                keras.layers.InputLayer(num_features),
                keras.layers.Dense(n_hidden_1, activation:keras.activations.Relu),
                keras.layers.Dense(n_hidden_2, activation:keras.activations.Relu),
                keras.layers.Dense(num_classes, activation:keras.activations.Softmax)
            });

            return model;
        }

        /// <summary>
        /// Load training data
        /// </summary>
        /// <param name="total_size"></param>    
        private (NDArray, NDArray) PrepareData(int total_size)
        {
            float[,] arrx = new float[total_size, num_features];
            int[] arry = new int[total_size];

            for (int i = 0; i < total_size; i++)
            {
                float weight = (float)random.Next(30, 100) / 100;
                float height = (float)random.Next(140, 190) / 100;
                float bmi = (weight * 100) / (height * height);

                arrx[i, 0] = weight;
                arrx[i, 1] = height;

                switch (bmi)
                {
                    case var x when x < 18.0f:
                        arry[i] = 0;
                        break;

                    case var x when x >= 18.0f && x <= 28.0f:
                        arry[i] = 1;
                        break;

                    case var x when x > 28.0f:
                        arry[i] = 2;
                        break;
                }
            }

            return (np.array(arrx), np.array(arry));
        }

        /// <summary>
        /// Consumption model
        /// </summary>      
        private void test(Model model)
        {
            int test_size = 20;
            for (int i = 0; i < test_size; i++)
            {
                float weight = (float)random.Next(40, 90) / 100;
                float height = (float)random.Next(145, 185) / 100;
                float bmi = (weight * 100) / (height * height);

                var test_x = np.array(new float[1, 2] { { weight, height } });
                var pred_y = model.Apply(test_x);

                Console.WriteLine($"{i}:weight={(float)weight} \theight={height} \tBMI={bmi:0.0} \tPred:{pred_y[0].numpy()}");
            }
        }
    }

There are two other points:

1. Because reading pictures is time-consuming, I adopt a method, that is, serialize the read data into a binary file, and deserialize it directly from the binary file next time, which greatly speeds up the processing speed.

2. I did not use the validation image for evaluation, but simply selected 20 samples for testing.

 

[related resources]

Source code: Git: https://gitee.com/seabluescn/tf_not.git

Project Name: NN_MultipleClassification_MNIST

catalog: View tensorflow Net machine learning introduction series directory

Keywords: MNIST

Added by flaquito on Tue, 28 Dec 2021 09:16:09 +0200