[转]在C#中像PYTHON一样编写TENSORFLOW机器学习代码

2022-03-03 14:15
50
0
添加收藏

 

机器学习是一个令人激动人心的领域,一直有新的技术突破。研究人员不断推动机器智能的提升,教机器如何听说读写——这些曾经是我们人类专属的技能。机器学习的首选语言是Python,最受欢迎的库是Google的TensorFlow。几乎所有的代码示例都是用Python编写的,并且依赖于TensorFlow和NumPy库。对于C#和.NET的开发人员来说,我们在面临着一个严峻的选择:要么学习Python,要么使用NET机器学习库,并从头开始精心编写我们自己的C#代码

 

事实上,这就是我在机器学习课程中常用的策略。我研究了许多使用Keras和TensorFlow的Python代码,然后我从头开始编写自己的C#代码,使用原生的CNTK和ML.NET库代替。这种方法很有效,但它也有一些缺点:

 

  • 我的学生习惯于.NET,这些编码技巧不容易转移到Python。
  • CNTK和ML.NET不支持某些TensorFlow功能,因此我必须使用Python代码向C#开发人员演示它们。

 

我一直在努力在.NET中编写机器学习库,模仿Python的API和编码风格,如NativeKerasKerasSharp,但这些项目不再处于积极开发的阶段。我一直在寻找一个全面的.NET库,它完全模仿了如何用Python编写机器学习代码,终于我发现了她——SciSharpSciSharp正在为数据科学,机器学习和人工智能构建一个.NET开源生态系统,其理念是C#机器学习代码应该像对应的Python代码一样尽可能地语法,与编程的感觉。

 

看看下面的例子 - 这是TensorFlow中的简单线性回归演示。 Python代码在左侧,相应的C#代码在右侧:

右边的代码看起来像Python,但它是实际的C#代码。 它使用一个名为TesorFlow.NET的包装器在幕后调用真正的TensorFlow库。请注意,我们已经有了TensorFlow包装器; 几年前,Xamarin创始人米格尔大神建造了优秀的TensorFlowSharp。 但是,他的库只暴露了低级别的TensorFlow API。 相比之下,SciSharp库神奇地暴露了所有TensorFlow,包括高级图形构建功能。

 

TensorFlow在很大程度上依赖于NumPy,这是一个高性能的Python数学库,可以在内存中处理非常大的数据数组。 因此,SciSharp团队开发了自己的版本NumSharp,这是NumPy到C#的端口。

NumSharp遵循与原始NumPy完全相同的编码风格。 使用左侧的Python代码和右侧的相应C#代码查看此示例:同样,右边的代码遵循与Python相同的语法约定和API样式,但它实际上是C#代码。

 

SciSharp团队在这里取得了一项重大成就。 使用TensorFlow.NET和NumSharp,我们实际上可以使用Python代码示例,将它们复制并粘贴到C#文件中,然后只需稍作修改即可运行它们——这为.NET开发人员打开了完整的机器学习生态系统。

 

我决定采用SciSharp。查看以下说明,以便在C#中启动并运行您自己的TensorFlow代码。我将构建一个简单的线性回归演示,它适合一些样本数据的回归线。

 

让我们开始吧。以下是在.NET Core中设置新控制台项目的方法:

 

$ dotnet new console -o LinearRegression$ cd LinearRegression

 

 

接下来,我需要安装我需要的软件包:

 

$ dotnet add package TensorFlow.NET

 

 

就这样简单!这将安装TensorFlow.NET包,它也将自动拉入NumSharp。该软件包还安装了Microsoft.ML.TensorFlow.Redist,它是本机TensorFlow库的跨平台安装程序。这将在Windows,Linux和OS / X上为您设置一切。

 

现在我准备开始编码了。这是Program.cs的上半部分应该是这样的:

 

using System;using NumSharp;using Tensorflow;using static Tensorflow.Python; namespace LinearRegression{    /// <summary>    /// The main program class    /// </summary>    public class Program    {        /// <summary>        /// The main program entry point        /// </summary>        /// <param name="args">The command line arguments</param>        public static void Main(string[] args)        {            // load the data            var dataX = np.array(                3.3f, 4.4f, 5.5f, 6.71f, 6.93f, 4.168f, 9.779f, 6.182f, 7.59f, 2.167f,                7.042f, 10.791f, 5.313f, 7.997f, 5.654f, 9.27f, 3.1f);            var dataY = np.array(                1.7f, 2.76f, 2.09f, 3.19f, 1.694f, 1.573f, 3.366f, 2.596f, 2.53f, 1.221f,                2.827f, 3.465f, 1.65f, 2.904f, 2.42f, 2.94f, 1.3f);            var samples = dataX.shape[0];             // the rest of the code goes here...        }    }}

 

 

这是一个简单的.NET Core控制台应用程序。 请注意使用训练数据设置NumPy数组的np.array方法。 shape [0]调用检索数组的长度,就像在Python中一样。现在我将在TensorFlow中设置一个简单的线性回归模型:

 

此代码调用tf.placeholder来设置模型输入和输出:X表示输入数据,Y表示输出数据。
以下两个调用tf.Variable设置权重和偏差模型变量。 这些变量组合成一个模型如下:
在这里插入图片描述

 

读者会发现这只是线性回归的等式。 TensorFlow将在训练期间调整W和b变量以找到完美的回归线。
最后,代码在损失变量中设置了一个损失函数。 损失函数是一种表达式,其值在训练期间需要最小化。 我将使用均方误差或MSE:
在这里插入图片描述
这只是模型预测与实际值之差的平方和。接下来,我将训练这个模型1000次:

 

// use these training parametersvar epochs = 1000;var learningRate = 0.01f;var displayEvery = 50; // use a gradient descent optimizervar optimizer = tf.train.GradientDescentOptimizer(learningRate).minimize(loss); // train the modelvar init = tf.global_variables_initializer();with(tf.Session(), sess => {    sess.run(init);     // run training epochs    Console.WriteLine("Training model...");    for (int epoch = 0; epoch < epochs; epoch++)    {        foreach (var (x, y) in zip<float>(dataX, dataY))        {            sess.run(optimizer,                 new FeedItem(X, x),                new FeedItem(Y, y));        }         // display intermittent results        if ((epoch + 1) % displayEvery == 0)        {            var lossValue = sess.run(loss, new FeedItem(X, dataX), new FeedItem(Y, dataY));            Console.WriteLine($"  epoch: {epoch + 1}\tMSE = {lossValue}\tW = {sess.run(W)}\tb = {sess.run(b)}");        }    }     // show final training loss    var trainingLoss = sess.run(loss,        new FeedItem(X, dataX),        new FeedItem(Y, dataY));    Console.WriteLine($"  Final MSE = {trainingLoss}");     // the rest of the code goes here...});

 

 

代码设置GradientDescentOptimizer以最小化损失函数,并使用tf.Session()启动TensorFlow会话。TensorFlow中的所有内容都需要调用tf.run()来执行。所以我首先设置了一个global_variables_initializer来初始化模型,然后运行它。然后我运行优化器1000个时期来训练模型,每50个时期我运行损失函数并显示中间训练损失。循环完成后,我再次运行损失功能并显示最终的训练损失。

 

我现在有一个训练有素的好模型,是时候在一些新数据上测试这个模型:

 

// load validation datavar testDataX = np.array(6.83f, 4.668f, 8.9f, 7.91f, 5.7f, 8.7f, 3.1f, 2.1f);var testDataY = np.array(1.84f, 2.273f, 3.2f, 2.831f, 2.92f, 3.24f, 1.35f, 1.03f);var validationSamples = testDataX.shape[0]; // validate the modelConsole.WriteLine("Validating model...");var validationLoss = tf.reduce_sum(tf.pow(model - Y, 2.0f)) / validationSamples;var lossValue2 = sess.run(validationLoss, new FeedItem(X, testDataX), new FeedItem(Y, testDataY));Console.WriteLine($"  Validation loss = {lossValue2}");

 

 

代码调用np.array来设置新的验证数据,并设置一个新的validationLoss函数来在验证期间计算MSE。然后它在验证数据上运行此损失函数,并在控制台上显示验证丢失。就是这样。这是TensorFlow中的完整线性回归演示。
此代码将在所有主要操作系统上运行 - Windows,Linux和OS / X.您可以在控制台上运行代码,如下所示:

 

$ dotnet run

 

 

或者通过点击F5在Visual Studio Code中。这是在最新版本的VS Code中在我的Mac上运行的应用程序:

这是在终端的命令行上运行的相同应用程序:

 


经过1000个训练时期后,我最终损失了0.1548。完全训练的模型在验证数据上的损失为0.1572。

 

这是一个最初用Python编写的TensorFlow线性回归演示,现在移植到C#,只有很少的语法更改。
有数千个类似的代码示例,现在它们都可供C#开发人员访问。

 

你意如何?准备好开始用TensorFlow.NET和NumSharp编写C#机器学习应用了吗?

 

作者:Mark Farragher
英文版地址:https://medium.com/machinelearningadvantage/run-tensorflow-machine-learning-code-in-c-with-almost-no-changes-77f7b629389

全部评论