开发环境VS2017,CNTK是微软的AI框架,支持用C#进行训练评估.
入门是非常简单的,新建一个 桌面控制台项目 然后安装CNTK框架的Nuget插件
安装成功后,一个CNTK机器学习框架就构建好了.简直不要太简单.虽然框架搞好了,但对于AI算法不是很熟的,刚接触难免摸不着头脑,好在github上面有示例的项目
https://github.com/microsoft/CNTK/tree/master/Examples/TrainingCSharp
仔细研究了一下.发现支持很多算法,抱着先跑通的目的,我先试试逻辑回归算法.看例子上的说明,输入输出都是数组,那么应该是通过神经网络算法通过训练找出输入和输出数据之间的内在联系.比如用于分类,这个逻辑回归还是分为线性和非线性的.
那么我的想法是建立一个用于研究机器学习的分类AI,比如在一个界面设计中会有不同种颜色,试试训练一个AI来判断这些颜色搭配的效果.
输入数组是五种颜色,输出评价.五种颜色分别是 主色,留白色,辅助色,点缀色和文字颜色.在Excel中人工识别一下看看颜色搭配的效果,然后通过VBA输出到txt,再将txt改为批处理调用上面新建的项目的exe,训练AI,最终想法是尝试让AI具备一定的"审美能力".
前文说了使用逻辑回归模型(logistic regression),输入的数据是5种颜色的值,输出的数据是评分(训练).如果训练好了,输入5个数据然后获得评分,评分高的话说明搭配的美观.
那么接下来主要的工作就是准备数据和训练对接的控制台EXE,关于数据准备这里主要使用了EXCEL+VBA这里不介绍.重点是构建控制台EXE.通过批处理bat(本机)或者编写代码调用来调用训练和评估AI.这样使用asp.net可以根据网页请求训练服务器上的AI或者调用AI(尝试过直接把cntk加入web框架中,但cntk必须是X64,有点小问题,理论可行,但我的方法似乎也足够灵活).
1.训练
从外部获取训练数据,共6个分别是5个颜色和一个评分数据.
static public void TrainAndSave(List<float[]> feature_list, List<float[]> label_list)
{
Console.WriteLine($"======== running LogisticRegression{device.Type} ========");
Variable featureVariable = Variable.InputVariable(new int[] { feature_list[0].Length }, DataType.Float);
Variable labelVariable = Variable.InputVariable(new int[] { label_list[0].Length }, DataType.Float);
// Load或build一个逻辑回归模型(load or build a logistic regression model)
Function classifierOutput= CreateModel(featureVariable, numOutputClasses, device);
var loss = CNTKLib.CrossEntropyWithSoftmax(classifierOutput, labelVariable);
var evalError = CNTKLib.ClassificationError(classifierOutput, labelVariable);
// prepare for training
CNTK.TrainingParameterScheduleDouble learningRatePerSample = new CNTK.TrainingParameterScheduleDouble(xxl, 1);
IList<Learner> parameterLearners =
new List<Learner>() { Learner.SGDLearner(classifierOutput.Parameters(), learningRatePerSample) };
var trainer = Trainer.CreateTrainer(classifierOutput, loss, evalError, parameterLearners);
if (File.Exists(trainer_filename))
{
var trasiner = trainer.RestoreFromCheckpoint(trainer_filename);
Console.WriteLine("数据共有"+trasiner.Size().ToString());
}
// 将 两个list 转换为 一维数组
var feature_arr = new float[feature_list.Count * feature_list[0].Length];
var label_arr = new float[feature_list.Count * label_list[0].Length];
for (int i = 0; i < feature_list.Count; i++)
{
for (int j = 0; j < feature_list[0].Length; j++)
{
feature_arr[j * feature_list[0].Length + i] = feature_list[i][j];
}
for (int j = 0; j < label_list[0].Length; j++)
{
label_arr[j * label_list[0].Length + i] = label_list[i][j];
}
}
//Console.WriteLine($"{feature_arr.Length},{label_arr.Length}");
var featureValue = Value.CreateBatch<float>(new int[] { feature_list[0].Length }, feature_arr, device);
var labelValue = Value.CreateBatch<float>(new int[] { label_list[0].Length }, label_arr, device);
bool ischeck = false;
trainer.TrainMinibatch(
new Dictionary<Variable, Value>(){
{ featureVariable, featureValue },
{ labelVariable, labelValue }
},
ischeck,
device);
//classifierOutput.Outputs.ge.Output.ge.pla.Save(filename);
//trainer.RestoreFromCheckpoint(filename);
trainer.SummarizeTrainingProgress();
trainer.SaveCheckpoint(trainer_filename);
classifierOutput.Save(model_filename);
}
CNTK的AI训练一般是批量的(其他框架也是),建立一个model就是AI的模型,一个trainer用于处理训练数据.然后还可以中途保存训练结果.
然后评估的时候先查找这个训练神经节点文件,然后Load以后再对数据进行评估.
if (File.Exists(model_filename))
{
Variable featureVariable = Variable.InputVariable(new int[] { inputDim }, DataType.Float);
Variable labelVariable = Variable.InputVariable(new int[] { numOutputClasses }, DataType.Float);
//Function model = CreateModel(featureVariable, numOutputClasses, device);
Function classifierOutput = CreateModel(featureVariable, numOutputClasses, device);
var loss = CNTKLib.CrossEntropyWithSoftmax(classifierOutput, labelVariable);
var evalError = CNTKLib.ClassificationError(classifierOutput, labelVariable);
CNTK.TrainingParameterScheduleDouble learningRatePerSample = new CNTK.TrainingParameterScheduleDouble(xxl, 1);
IList<Learner> parameterLearners =
new List<Learner>() { Learner.SGDLearner(classifierOutput.Parameters(), learningRatePerSample) };
var trainer = Trainer.CreateTrainer(classifierOutput, loss, evalError, parameterLearners);
if (File.Exists(trainer_filename))
{
var ttt=trainer.RestoreFromCheckpoint(trainer_filename);
//Console.WriteLine("数据共有" + ttt.Size().ToString());
}
var model = trainer.Model();
//Console.WriteLine("加载AI...");
var str_arr = args[1].Split(',');
float[] inputV = new float[str_arr.Length];
for (int k = 0; k < inputV.Length; k++)
{
inputV[k] = Convert.ToSingle(str_arr[k]);
}
var featureinput = Value.CreateBatch<float>(new int[] { inputDim }, inputV, device);
//featureValue = Value.CreateBatch<float>(new int[] { inputDim }, features, device);
var inputDataMap = new Dictionary<Variable, Value>() { { featureVariable, featureinput } };
var outputDataMap = new Dictionary<Variable, Value>() { { model.Output, null } };
//Console.WriteLine("开始评估...");
model.Evaluate(inputDataMap, outputDataMap, device);
//Console.WriteLine("评估完成...");
var outputValue = outputDataMap[model.Output];
IList<IList<float>> actualLabelSoftMax = outputValue.GetDenseData<float>(model.Output);
for (int i = 0; i < actualLabelSoftMax[0].Count; i++)
{
Console.WriteLine(actualLabelSoftMax[0][i]);
}
}
else
{
Console.WriteLine("没找到Model...");
}
在Console控制台exe的入口处通过指示字符串判断输入数据是想要训练还是评估.