用Tensorflow.net实现手写数字识别

Python版的手写数字识别例子很多,但是将python tensorflow编写的模型变成APP,比较简单的一种方法是将其打包成exe(大小要5~6G),然后作为子程序与其它语言编写的主界面程序直接通过控制台命令通信。这种方式虽然简单,但是有两个缺点:python部分子程序太大,而且作为子程序会被杀毒软件当成木马删掉,因此对不太熟悉电脑的用户使用比较麻烦。
另外一直方法是将python tensorflow训练好的模型转换成pb格式,然后在其它主界面程序中写模型调用代码,这种方式比较麻烦,难度系数也大。
最方便简单的一种方法就是使用tensorflow.net版(https://github.com/SciSharp)编写APP,这样神经网络部分代码和界面等部分程序代码可以合成一个整体,编译后的exe也不大。
本代码是基于SciSharp社区中的例子代码(SciSharp\SciSharp-Stack-Examples\src\TensorFlowNET.Examples\ImageProcessing\DigitRecognitionCNN.cs)改编而来。SciSharp社区中的例子代码直接用公共网上的mnist数据集进行训练。由于mnist数据集将所有图片合成在一个文件,不方便追加训练。本代码用minist数据集分解后存储于0~9个文件夹中的图片进行训练,因此可以方便的进行追加,或者用于其它符号图片的分类。

  1. 本代码主要改动之一是,在PrepareData()函数中读取0~9个文件夹中的图片并准备训练数据集。

    public override void PrepareData()
    {
        //Directory.CreateDirectory("image_classification_cnn_v1");
        //var loader = new MnistModelLoader();
        //mnist = loader.LoadAsync(".resources/mnist", oneHot: true, showProgressInConsole: true).Result;
    
        List<NDArray> x_list = new List<NDArray>();
        List<NDArray> y_list = new List<NDArray>(); 
        //load train
        string[] folders = Directory.GetDirectories("image_classification_cnn_v1\\train_image");
        for (int i = 0; i < folders.Length; i++)
        {
            string[] files = Directory.GetFiles(folders[i]);
            for (int j = 0; j < files.Length; j++)
            {
                NDArray x = np.empty(784, np.ubyte);
                x = cv2.imread(files[j], SharpCV.IMREAD_COLOR.IMREAD_GRAYSCALE);
                x_list.Add(x);
                NDArray y = np.empty(10, np.float32);
                y[i] = 1f;
                y_list.Add(y);
            }
        }
        x_train = np.zeros((x_list.Count, 784), np.ubyte);
        y_train = np.zeros((y_list.Count, 10), np.float32);
        for(int i = 0; i < x_list.Count; i++)
        {
            x_train[i] = x_list[i];
            y_train[i] = y_list[i];
        }
        (x_train, y_train) = Reformat(x_train, y_train);
        
        //load valid
        folders = Directory.GetDirectories("image_classification_cnn_v1\\valid_image");
        x_list.Clear();
        y_list.Clear();
        for (int i = 0; i < folders.Length; i++)
        {
            string[] files = Directory.GetFiles(folders[i]);
            for (int j = 0; j < files.Length; j++)
            {
                NDArray x = np.empty(784, np.ubyte);
                x = cv2.imread(files[j], SharpCV.IMREAD_COLOR.IMREAD_GRAYSCALE);
                x_list.Add(x);
                NDArray y = np.empty(10, np.float32);
                //for (int k = 0; k < 10; k++)
                //    y[k] = 0f;
                y[i] = 1f;
                y_list.Add(y);
            }
        }
        x_valid = np.zeros((x_list.Count, 784), np.ubyte);
        y_valid = np.zeros((y_list.Count, 10), np.float32);
        for (int i = 0; i < x_list.Count; i++)
        {
            x_valid[i] = x_list[i];
            y_valid[i] = y_list[i];
        }
        (x_valid, y_valid) = Reformat(x_valid, y_valid);
    
    
        //(x_valid, y_valid) = Reformat(mnist.Validation.Data, mnist.Validation.Labels);
        //(x_test, y_test) = Reformat(mnist.Test.Data, mnist.Test.Labels);
    
        print("Size of:");
        print($"- Training-set:\t\t{len(x_train)}");
        print($"- Validation-set:\t{len(x_valid)}");
    
        // generate labels
        var labels = range(0, 10).Select(x => x.ToString());
        File.WriteAllLines(@"image_classification_cnn_v1\labels.txt", labels);
    
    }
    

首先通过代码

NDArray x = np.empty(784, np.ubyte);
 x = cv2.imread(files[j], SharpCV.IMREAD_COLOR.IMREAD_GRAYSCALE);

将图片导成(28,28)的NDArray,当所有图片导入到List x_list后,再通过代码

for(int i = 0; i < x_list.Count; i++)
    {
        x_train[i] = x_list[i];
        y_train[i] = y_list[i];
    }
    (x_train, y_train) = Reformat(x_train, y_train);

将List x_list转换成NDArray x_train,其中x_train是一个(60000,28,28,1)的NDArray,60000是图片的个数。

  1. 本代码另一个主要改动是,在Predict()函数中增加了对28*28的黑底图片进行手写数字的识别。

    public override void Predict()
    {
        // predict image
        var wizard = new ModelWizard();
        var task = wizard.AddImageClassificationTask<CNN>(new TaskOptions
        {
            LabelPath = @"image_classification_cnn_v1\labels.txt",
            ModelPath = @"image_classification_cnn_v1\saved_model.pb"
        });
    
        NDArray input = np.empty(784, np.ubyte);
        input = cv2.imread("image_classification_cnn_v1\\test_image\\0_2.jpg", SharpCV.IMREAD_COLOR.IMREAD_GRAYSCALE);
        Shape shape = new Shape(1, 28, 28, 1);
        NDArray newinput = input.reshape(shape);
        newinput = newinput.astype(TF_DataType.TF_FLOAT);
        var result = task.Predict(newinput); 
        string ss = result.Label;
    
        //var input = x_valid["0:1"]; 
        //long output = np.argmax(y_test[0]);
        //Debug.Assert(result.Label == output.ToString());
    
        //input = x_test["1:2"];
        //result = task.Predict(input);
        //output = np.argmax(y_test[1]);
        //Debug.Assert(result.Label == output.ToString());
    
    }
    

首先通过代码

NDArray input = np.empty(784, np.ubyte);
input = cv2.imread("image_classification_cnn_v1\\test_image\\0_2.jpg",
SharpCV.IMREAD_COLOR.IMREAD_GRAYSCALE);

将图片导成(28,28)的NDArray,然后再通过

Shape shape = new Shape(1, 28, 28, 1);
NDArray newinput = input.reshape(shape);
newinput = newinput.astype(TF_DataType.TF_FLOAT);

将input转换为(1, 28, 28, 1)且为TF_FLOAT类型的NDArray,接下来直接输入task.Predict()函数就可以预测啦。
4. 整个文件代码如下:

using SciSharp.Models;
using SciSharp.Models.ImageClassification;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Tensorflow;
using Tensorflow.NumPy;
using static Tensorflow.Binding;
using static SharpCV.Binding;
using Tensorflow.Keras.Metrics;
using System.Collections.Generic;

namespace TensorFlowNET.Examples
{
/// <summary>
/// Convolutional Neural Network classifier for Hand Written Digits
/// CNN architecture with two convolutional layers, followed by two fully-connected layers at the end.
/// Use Stochastic Gradient Descent (SGD) optimizer. 
/// https://www.easy-tensorflow.com/tf-tutorials/convolutional-neural-nets-cnns/cnn1
/// </summary>
public class DigitRecognitionCNN : SciSharpExample, IExample
{
    //Datasets<MnistDataSet> mnist;



    float accuracy_test = 0f;

    NDArray x_train, y_train;
    NDArray x_valid, y_valid;
    //NDArray x_test, y_test;

    public ExampleConfig InitConfig()
        => Config = new ExampleConfig
        {
            Name = "MNIST CNN (Graph)",
            Enabled = true
        };

    public bool Run()
    {
        PrepareData();
        Train();
        //Test();
        Predict();

        return accuracy_test > 0.95;
    }

    public override void Train()
    {
        // using wizard to train model
        var wizard = new ModelWizard();
        var task = wizard.AddImageClassificationTask<CNN>(new TaskOptions
        {
            InputShape = (28, 28, 1),
            NumberOfClass = 10,
        });
        task.SetModelArgs(new ConvArgs
        {
            NumberOfNeurons = 128
        });
        task.Train(new TrainingOptions
        {
            Epochs = 50,
            TrainingData = new FeatureAndLabel(x_train, y_train),
            ValidationData = new FeatureAndLabel(x_valid, y_valid)
        });
    }

    //public override void Test()
    //{
    //    var wizard = new ModelWizard();
    //    var task = wizard.AddImageClassificationTask<CNN>(new TaskOptions
    //    {
    //        ModelPath = @"image_classification_cnn_v1\saved_model.pb"
    //    });
    //    var result = task.Test(new TestingOptions
    //    {
    //        TestingData = new FeatureAndLabel(x_test, y_test)
    //    });
    //    accuracy_test = result.Accuracy;
    //}

    public override void Predict()
    {
        // predict image
        var wizard = new ModelWizard();
        var task = wizard.AddImageClassificationTask<CNN>(new TaskOptions
        {
            LabelPath = @"image_classification_cnn_v1\labels.txt",
            ModelPath = @"image_classification_cnn_v1\saved_model.pb"
        });

        NDArray input = np.empty(784, np.ubyte);
        input = cv2.imread("image_classification_cnn_v1\\test_image\\0_2.jpg", SharpCV.IMREAD_COLOR.IMREAD_GRAYSCALE);
        Shape shape = new Shape(1, 28, 28, 1);
        NDArray newinput = input.reshape(shape);
        newinput = newinput.astype(TF_DataType.TF_FLOAT);
        var result = task.Predict(newinput); 
        string ss = result.Label;

        //var input = x_valid["0:1"]; 
        //long output = np.argmax(y_test[0]);
        //Debug.Assert(result.Label == output.ToString());

        //input = x_test["1:2"];
        //result = task.Predict(input);
        //output = np.argmax(y_test[1]);
        //Debug.Assert(result.Label == output.ToString());
    }

    public override void PrepareData()
    {
        //Directory.CreateDirectory("image_classification_cnn_v1");
        //var loader = new MnistModelLoader();
        //mnist = loader.LoadAsync(".resources/mnist", oneHot: true, showProgressInConsole: true).Result;

        List<NDArray> x_list = new List<NDArray>();
        List<NDArray> y_list = new List<NDArray>(); 
        //load train
        string[] folders = Directory.GetDirectories("image_classification_cnn_v1\\train_image");
        for (int i = 0; i < folders.Length; i++)
        {
            string[] files = Directory.GetFiles(folders[i]);
            for (int j = 0; j < files.Length; j++)
            {
                NDArray x = np.empty(784, np.ubyte);
                x = cv2.imread(files[j], SharpCV.IMREAD_COLOR.IMREAD_GRAYSCALE);
                x_list.Add(x);
                NDArray y = np.empty(10, np.float32);
                y[i] = 1f;
                y_list.Add(y);
            }
        }
        x_train = np.zeros((x_list.Count, 784), np.ubyte);
        y_train = np.zeros((y_list.Count, 10), np.float32);
        for(int i = 0; i < x_list.Count; i++)
        {
            x_train[i] = x_list[i];
            y_train[i] = y_list[i];
        }
        (x_train, y_train) = Reformat(x_train, y_train);
        
        //load valid
        folders = Directory.GetDirectories("image_classification_cnn_v1\\valid_image");
        x_list.Clear();
        y_list.Clear();
        for (int i = 0; i < folders.Length; i++)
        {
            string[] files = Directory.GetFiles(folders[i]);
            for (int j = 0; j < files.Length; j++)
            {
                NDArray x = np.empty(784, np.ubyte);
                x = cv2.imread(files[j], SharpCV.IMREAD_COLOR.IMREAD_GRAYSCALE);
                x_list.Add(x);
                NDArray y = np.empty(10, np.float32);
                //for (int k = 0; k < 10; k++)
                //    y[k] = 0f;
                y[i] = 1f;
                y_list.Add(y);
            }
        }
        x_valid = np.zeros((x_list.Count, 784), np.ubyte);
        y_valid = np.zeros((y_list.Count, 10), np.float32);
        for (int i = 0; i < x_list.Count; i++)
        {
            x_valid[i] = x_list[i];
            y_valid[i] = y_list[i];
        }
        (x_valid, y_valid) = Reformat(x_valid, y_valid);


        //(x_valid, y_valid) = Reformat(mnist.Validation.Data, mnist.Validation.Labels);
        //(x_test, y_test) = Reformat(mnist.Test.Data, mnist.Test.Labels);

        print("Size of:");
        print($"- Training-set:\t\t{len(x_train)}");
        print($"- Validation-set:\t{len(x_valid)}");

        // generate labels
        var labels = range(0, 10).Select(x => x.ToString());
        File.WriteAllLines(@"image_classification_cnn_v1\labels.txt", labels);
    }

    /// <summary>
    /// Reformats the data to the format acceptable for convolutional layers
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    private (NDArray, NDArray) Reformat(NDArray x, NDArray y)
    {
        var (unique_y, _) = np.unique(np.argmax(y, 1));
        var (img_size, num_ch, num_class) = ((int)np.sqrt(x.shape[1]).astype(np.int32), 1, len(unique_y));
        var dataset = x.reshape((x.shape[0], img_size, img_size, num_ch)).astype(np.float32);
        //y[0] = np.arange(num_class) == y[0];
        //var labels = (np.arange(num_class) == y.reshape(y.shape[0], 1, y.shape[1])).astype(np.float32);
        return (dataset, y);
    }
}
}

运行结果如下图所示:
在这里插入图片描述

代码链接:
链接:https://pan.baidu.com/s/1Fn7zZHri5u5DhV0EupEZCw
提取码:a1b2

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: c是英文字母表中的第三个字母。它可以用来表示很多不同的事物和概念。首先,c可以表示华氏温度单位。在华氏温度系统中,0°F表示冰的融点,32°F表示水的冰点,而100°F表示人体正常体温。另外,c也是“克(gram)”的缩写。克是国际通用的质量单位,用于测量物体的重量。例如,一颗苹果的重量可以用克来表示。此外,c也代表光速。根据爱因斯坦的相对论理论,光在真空中的速度是恒定的,即299,792,458米每秒,简称299,792,458m/s或c。光速是一个非常重要的物理常数,对于许多科学研究和实验都起着重要的作用。最后,c还可以表示一些其他的概念,例如在计算机编程中,C语言是一种广泛使用的编程语言;在音乐中,C调是一个音调的名称,表示中央C音;在化学中,C是碳元素的化学符号。总的来说,c是一个多功能的字母,用来表示温度、质量、光速和其他各种不同的概念。 ### 回答2: c是拉丁字母表中的第三个字母,也是英文字母表中的第三个字母。在大写形式下,c的形状类似于一个弯曲的「C」,而在小写形式下,c的形状则更像一个「c」。c在英语中有着重要的语言学功能,常常用作辅音字母。但在某些语言中,c也可以作为元音字母使用。 在英语中,c通常发出/ k /的音,例如「cat」(猫)、「car」(汽车)和「cup」(杯子)。在其他一些语言中,c可以发出/ s /的音,例如西班牙语的「ciudad」(城市)和法语的「commerce」(商业)。在某些情况下,c可以发出/ch/的音,例如英语单词「church」(教堂)。 c还可以作为一个字母缩写或符号的代表。例如,在化学术语中,c代表光速(c = 299,792,458米/秒),这是光在真空中传播的速度。此外,c还可以表示一些常见的度量单位,如摄氏度(Celsius)和克(gram)。 总而言之,c是一个重要且多功能的字母,它在拉丁字母表和英文字母表中拥有确定的位置,并在不同的语言和领域中发挥着不同的作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值