65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 中的深度学习:Keras.NET 中的硬币识别,第二部分

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2020 年 11 月 6 日

CPOL

3分钟阅读

viewsIcon

13719

downloadIcon

308

在本文中,我们将研究使用 Keras.NET 实现的用于硬币识别的 CNN。

首先,让我们从 Nuget 包管理器下载 Keras.NET 包。 我们可以在工具 > Nuget 包管理器中找到 Nuget 包管理器。 Keras.NET 依赖于 Numpy.NET 和 pythonnet_netstandard 包。 如果它们没有安装,让我们继续安装它们。

重要的是要指出,Keras.NET 需要在您的操作系统中安装 Python 2.7-3.7 版本。 它还需要安装 Python 库 Numpy 和 TensorFlow。 在此示例中,我们使用了 Python 3.7 64 位。

如果您在执行本文中的代码时遇到任何问题,请尝试在 ConsoleApplication 中执行 main 方法时在开始时运行以下代码一次。 此代码将设置您需要的环境变量,以便找到所有 DLL

private static void SetupPyEnv()
        {
            string envPythonHome = @"C:\Users\arnal\AppData\Local\Programs\Python\Python37\";
            string envPythonLib = envPythonHome + "Lib\\;" + envPythonHome + @"Lib\site-packages\";
            Environment.SetEnvironmentVariable("PYTHONHOME", envPythonHome, EnvironmentVariableTarget.Process);
            Environment.SetEnvironmentVariable("PATH", envPythonHome + ";" + envPythonLib + ";" + Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Machine), EnvironmentVariableTarget.Process);
            Environment.SetEnvironmentVariable("PYTHONPATH", envPythonLib, EnvironmentVariableTarget.User);
           
            PythonEngine.PythonHome = envPythonHome;
            PythonEngine.PythonPath = Environment.GetEnvironmentVariable("PYTHONPATH");
        }

现在我们将看到使用 Keras.NET 创建用于硬币识别的 CNN 是多么容易和透明。 以下类显示了包含模型所有逻辑的 Cnn 类。

public class Cnn
    {
        private DataSet _dataset;
        private Sequential _model;

        public Cnn(DataSet dataset)
        {
            _dataset = dataset;
            _model = new Sequential();
        }

        public void Train()
        {
            // Build CNN model
            _model.Add(new Conv2D(32, kernel_size: (3, 3).ToTuple(),
                                 padding: Settings.PaddingMode,
                                 input_shape: new Shape(Settings.ImgWidth, Settings.ImgHeight, Settings.Channels)));
            _model.Add(new Activation(Settings.ActivationFunction));
            _model.Add(new Conv2D(32, (3, 3).ToTuple()));
            _model.Add(new Activation(Settings.ActivationFunction));
            _model.Add(new MaxPooling2D(pool_size: (2, 2).ToTuple()));
            _model.Add(new Dropout(0.25));

            _model.Add(new Conv2D(64, kernel_size: (3, 3).ToTuple(),
                                padding: Settings.PaddingMode));
            _model.Add(new Activation(Settings.ActivationFunction));
            _model.Add(new Conv2D(64, (3, 3).ToTuple()));
            _model.Add(new Activation(Settings.ActivationFunction));
            _model.Add(new MaxPooling2D(pool_size: (2, 2).ToTuple()));
            _model.Add(new Dropout(0.25));

            _model.Add(new Flatten());
            _model.Add(new Dense(Settings.FullyConnectedNodes));
            _model.Add(new Activation(Settings.ActivationFunction));
            _model.Add(new Dropout(0.5));
            _model.Add(new Dense(_dataset.NumberClasses));
            _model.Add(new Softmax());
            
            _model.Compile(loss: Settings.LossFunction,
              optimizer: Settings.Optimizer, 
              metrics: new string[] { Settings.Accuracy });
            
            _model.Fit(_dataset.TrainX, _dataset.TrainY,
                          batch_size: Settings.BatchSize,
                          epochs: Settings.Epochs,
                          validation_data: new NDarray[] { _dataset.ValidationX, _dataset.ValidationY });

            var score = _model.Evaluate(_dataset.ValidationX, _dataset.ValidationY, verbose: 0);
            Console.WriteLine("Test loss:" + score[0]);
            Console.WriteLine("Test accuracy:" + score[1]);
        }

        public NDarray Predict(string imgPath)
        {
            NDarray x = Utils.Normalize(imgPath);
            x = x.reshape(1, x.shape[0], x.shape[1], x.shape[2]);
            return _model.Predict(x);
        }
    }

我们可以看到,我们首先有一个构造函数,我们在其中接收数据集(在本系列的第二篇文章中导入和处理),并创建存储在私有变量 _model 中的 Sequential 类的新实例。 什么是 Sequential? 它是一个空模型,使我们能够堆叠图层,这正是我们需要的。

然后,在 Train 方法中,我们首先按照上一篇文章中介绍的架构创建我们的图层堆栈,然后编译模型并调用 fit 方法开始训练。 使用的损失函数是 categorical_crossentropy。 什么是损失函数? 它是我们用来优化学习过程的函数,也就是说,我们要么最小化它,要么最大化它。 负责最小化损失函数的是优化器——一种改变网络的权重和学习率以最小化损失的算法。

最后,使用验证数据集评估模型。 另一种方法是 Predict,顾名思义,它预测新传入数据的标签。 此方法应在训练完成后调用。 启动训练短语非常简单,只需运行以下操作即可

var cnn = new Cnn(dataSet);
cnn.Train();

让我们看看在本系列中我们正在经历的硬币识别问题中,在训练期间获得的结果

我们可以看到,我们在训练期间能够达到 100% 的准确率。

对于预测方法,其输出将是一个 NDarray,其中包含对象或图像属于用于训练 CNN 的其中一个类的概率。

那么,什么样的架构需要 GPU 而不是 CPU 呢? 例如,AlexNet 架构包括五个卷积层和三个完全连接的层,以及池化层和激活层。 由于其复杂性,这种类型的深度 CNN 在 GPU 上表现更好。 一般规则是,您添加的图层越多,权重的计算就越复杂。

在了解了如何编写自己的 CNN 之后,我们将进入预训练模型的领域。 更多相关内容请参见下一篇文章

© . All rights reserved.