使用CNTK实现简单线性回归模型

机器学习和深度学习领域,CNTK(Cognitive Toolkit)是一个强大的工具,它支持多种神经网络模型的构建和训练。尽管CNTK通常用于复杂的神经网络模型,但它同样适用于执行简单的任务,如矩阵乘法和数据集的描述性统计参数计算。本文将展示如何使用CNTK实现一个简单的线性回归模型,该模型仅包含一个神经元和偏置参数,总共只有两个参数:权重(w)和偏置(b)。

使用CNTK来解决如此简单的任务的原因非常直接:通过学习这样的简单模型,可以了解CNTK库的工作原理,并观察到CNTK中的一些不那么显而易见的操作。上述模型可以轻松扩展到逻辑回归模型,只需添加激活函数即可。除了线性回归(代表没有激活函数的神经网络配置)之外,逻辑回归是包含激活函数的最简单的神经网络配置。

假设有一个简单的数据集,它代表一个简单的线性函数。生成的数据集如下表所示:

已经知道所呈现数据集的线性回归参数是:w 和 b,因此希望利用CNTK库来获取这些值,或者至少是接近这些值的参数值。

使用CNTK开发线性回归(LR)模型的任务可以描述为几个步骤:

步骤1:在Visual Studio中创建C#控制台应用程序,更改当前架构,并在解决方案中添加最新的“CNTK.GPU”NuGet包。

步骤2:开始编写代码,添加两个变量:特征和标签。定义训练数据集,通过创建批次来开始。

首先,需要添加一些using语句,并定义计算将发生的设备。通常,如果机器包含NVIDIA兼容的显卡,可以定义CPU或GPU。因此,演示从以下代码片段开始:

using System; using System.Linq; using System.Collections.Generic; using CNTK; namespace LR_CNTK_Demo { class Program { static void Main(string[] args) { // 定义设备 var device = DeviceDescriptor.UseDefaultDevice(); // 定义变量和数据集 Variable x = Variable.InputVariable(new int[] { 1 }, DataType.Float, "input"); Variable y = Variable.InputVariable(new int[] { 1 }, DataType.Float, "output"); // 定义训练数据集 var xValues = Value.CreateBatch(new NDShape(1, 1), new float[] { 1f, 2f, 3f, 4f, 5f }, device); var yValues = Value.CreateBatch(new NDShape(1, 1), new float[] { 3f, 5f, 7f, 9f, 11f }, device); } } }

步骤3:创建一个线性回归网络模型,通过传递输入变量和用于计算的设备。已经讨论过,该模型由一个神经元和一个偏置参数组成。

private static Function createLRModel(Variable x, DeviceDescriptor device) { var initV = CNTKLib.GlorotUniformInitializer(1.0, 1, 0, 1); var b = new Parameter(new NDShape(1, 1), DataType.Float, initV, device, "b"); var W = new Parameter(new NDShape(2, 1), DataType.Float, initV, device, "w"); var Wx = CNTKLib.Times(W, x, "wx"); var l = CNTKLib.Plus(b, Wx, "wx_b"); return l; }

首先,创建初始化器,它将初始化网络参数的初始值。然后,定义偏置和权重参数,并以线性模型的形式将它们组合起来,并返回为Function类型。createModel函数在main方法中被调用。一旦模型创建,可以检查它,并证明模型中只有两个参数。

步骤4:创建Trainer,它将用于训练网络参数w和b。

public Trainer createTrainer(Function network, Variable target) { var lrate = 0.082; var lr = new TrainingParameterScheduleDouble(lrate); var zParams = new ParameterVector(network.Parameters().ToList()); Function loss = CNTKLib.SquaredError(network, target); Function eval = CNTKLib.SquaredError(network, target); var llr = new List(); var msgd = Learner.SGDLearner(network.Parameters(), lr, l); llr.Add(msgd); var trainer = Trainer.CreateTrainer(network, loss, eval, llr); return trainer; }

首先,定义了主神经网络参数的学习率。然后,创建Loss和Evaluation函数。有了这些参数,可以创建SGD学习器。一旦SGD学习器对象被实例化,就通过调用CreateTrainer静态CNTK方法创建trainer,并将其作为函数返回。createTrainer方法在main方法中被调用:

步骤5:训练过程:一旦定义了变量、数据集、网络模型和trainer,就可以开始训练过程。

for (int i = 1; i <= 200; i++) { var d = new Dictionary(); d.Add(x, xValues); d.Add(y, yValues); trainer.TrainMinibatch(d, true, device); var loss = trainer.PreviousMinibatchLossAverage(); var eval = trainer.PreviousMinibatchEvaluationAverage(); if (i % 20 == 0) Console.WriteLine($"It={i}, Loss={loss}, Eval={eval}"); if (i == 200) { var b0_name = paramValues[0].Name; var b0 = new Value(paramValues[0].GetValue()).GetDenseData(paramValues[0]); var b1_name = paramValues[1].Name; var b1 = new Value(paramValues[1].GetValue()).GetDenseData(paramValues[1]); Console.WriteLine($"\nTraining process finished with the following regression parameters:\nb={b0[0][0]}, w={b1[0][0]}\n"); } }

如所见,在仅200次迭代中,回归参数就获得了几乎预期的值。由于训练过程与经典回归参数确定不同,无法获得确切的值。为了估计回归参数,神经网络使用称为随机梯度下降(SGD)的迭代方法。另一方面,经典回归通过最小化最小二乘误差并解决未知数为b和w的系统方程来使用回归分析程序。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485