文章目录
- 前言
- 一、VS2022+CNTK环境搭建
- 二、逻辑回归代码构建
- 1.逻辑回归构建
- 2.训练数据的生成
- 3.模型训练
- 三、效果展示
前言
本文基于CNTK实现逻辑回归二分类,并以之前的不同,本次使用C#实现,不适用python,python版的CNTK比较简单,而且python版的cntk个人感觉没什么必要,毕竟是微软的框架因此本人强迫症犯了,所以使用C#实现CNTK
环境版本:
Visualstudio 2022
C# .net4.6
cntk 2.7
cuda 10.1
一、VS2022+CNTK环境搭建
首先把CNTK的需要的dll解压出来,可直接从此处免费下载:
CNTK安装
然后再项目上引入dll,如图:
二、逻辑回归代码构建
1.逻辑回归构建
从网上对逻辑回归的图的解释,可以使用CNTK很容易就可以构建逻辑回归的结构
private static Function CreateLinearModel(Variable input, int outputDim, DeviceDescriptor device)
{int inputDim = input.Shape[0];var weightParam = new Parameter(new int[] { outputDim, inputDim }, DataType.Float, 1, device, "w");var biasParam = new Parameter(new int[] { outputDim }, DataType.Float, 0, device, "b");return CNTKLib.Times(weightParam, input) + biasParam;
}
这里的可以简单的理解为y=kx+b的结构。
2.训练数据的生成
这里主要是每次训练的时候会生成一批数据,首先对输入批次/输出批次构建数组,然后使用随机数种子,生成一批数据,服从高斯分布随机数,注意这里的mean和std
private static double GenerateGaussianNoise(double mean, double stdDev, Random random)
{double u1 = 1.0 - random.NextDouble();double u2 = 1.0 - random.NextDouble();double stdNormalRandomValue = Math.Sqrt(-2.0 * Math.Log(u1)) * Math.Sin(2.0 * Math.PI * u2);return mean + stdDev * stdNormalRandomValue;}private static void GenerateRawDataSamples(int sampleSize, int inputDim, int numOutputClasses, out float[] features, out float[] oneHotLabels){Random random = new Random(0);features = new float[sampleSize * inputDim];oneHotLabels = new float[sampleSize * numOutputClasses];for (int sample = 0; sample < sampleSize; sample++){int label = random.Next(numOutputClasses);for (int i = 0; i < numOutputClasses; i++){oneHotLabels[sample * numOutputClasses + i] = label == i ? 1 : 0;}for (int i = 0; i < inputDim; i++){features[sample * inputDim + i] = (float)GenerateGaussianNoise(3, 1, random) * (label + 1);}}}
3.模型训练
static void Main(string[] args)
{//设置逻辑回归的输入和输出的量,三入二出,因逻辑回归基本是二分类,因此这里输出的是2int inputDim = 3;int numOutputClasses = 2;//使用GPU模块var device = DeviceDescriptor.GPUDevice(0);//设置输入输出Variable featureVariable = Variable.InputVariable(new int[] { inputDim }, DataType.Float);Variable labelVariable = Variable.InputVariable(new int[] { numOutputClasses }, DataType.Float);//网络结构的构建及损失计算,这里使用CNTK的Softmaxvar classifierOutput = CreateLinearModel(featureVariable, numOutputClasses, device);var loss = CNTKLib.CrossEntropyWithSoftmax(classifierOutput, labelVariable);var evalError = CNTKLib.ClassificationError(classifierOutput, labelVariable);//学习率的设置TrainingParameterScheduleDouble learningRatePerSample = new TrainingParameterScheduleDouble(0.02, 1);IList<Learner> parameterLearners = new List<Learner>() { Learner.SGDLearner(classifierOutput.Parameters(), learningRatePerSample) };//构建训练迭代器var trainer = Trainer.CreateTrainer(classifierOutput, loss, evalError, parameterLearners);//训练批次int minibatchSize = 64;int numMinibatchesToTrain = 10000;int updatePerMinibatches = 10;// 循环训练for (int minibatchCount = 0; minibatchCount < numMinibatchesToTrain; minibatchCount++){Value features, labels;GenerateValueData(minibatchSize, inputDim, numOutputClasses, out features, out labels, device);trainer.TrainMinibatch(new Dictionary<Variable, Value>() { { featureVariable, features }, { labelVariable, labels } }, device);PrintTrainingProgress(trainer, minibatchCount, updatePerMinibatches);}Console.ReadLine();
}