Microsoft Infer.NET使用手册1

最近这段时间沉迷机器学习,神经网络无法自拔,偶然又想到了曾经找到过的Infer.NET, 可以被我信仰的语言–C#可以完美调用,感觉功能也挺强大的,但是由于拿到一个API第一反应肯定是懵逼:“这tm都是什么鬼玩意儿”,“官方教程在说什么?”, 没错我也是这样,所以这两天一直在研究,虽然感觉微软可能已经不重视这个东西了,但个人感觉作为一个较为轻量级的深度学习框架功能也算是强大的了,不过完全比不上google的tensorflow就是了。

这篇文章主要还是讲一下Infer.NET的详细用法,看不懂官方的同学可以来这边看一下,我们首先还是讲一下贝叶斯分类器,和官方教程中要做的差不多,但这里会更详细。

首先,第一步,在VS 2015中新建一个C#控制台项目:N4R)`QAR3)SRYF}4PPEH

然后,第二步,下载Infer.NET,官方地址:http://infernet.azurewebsites.net/ ,应该会下载下来一个压缩包,有源码也有bin,但在开发过程中我们主要会用到的应该就是bin里的东西

(OQ~JJ$6YXXPD]LWR~J$O$Y[I$UTI)BQD0UWJI7C)1JXPV

然后,在你的VS里,导入这几个ss1

然后点击“浏览”

ss3ss2

也就是说导入所有除了FSharp以外的dll库文件。

(顺带一提,NuGet程序包里也有Infer.NET,但是那个不提供learners的所有API,所以建议还是从官网下载手动导入)

 

假如,教育局希望能写一个程序,通过学生的语数英科四门成绩判断他是不是一个好学生(应试教育害人,雾( ̄▽ ̄)”),为了让祖国的花朵被削的更狠,而又不用费太多力气,教育局决定实用一部分的样本(sample)学生的成绩(也就是特性,feature)先由老师们判断他是不是好学生(好学生也就是标签,label),剩下的任务由程序来判断是不是好学生。

接下来,就让我们开始编写代码吧!

那么,开始咯,先定义一个类叫做Student,包涵两个属性:

[code lang=”CSharp”]

public string name;     //学生的名字
public Vector c_m_s_e;   //语数英科成绩, Vector需要引用MicrosoftResearch.Infer.Maths。
[/code]

然后构造函数为:

[code lang=”CSharp”]
public Student(string Name, Vector FourSubjects)
{
name = Name;
c_m_s_e = FourSubjects;
}
[/code]

再加个其实没什么意义的小东西:

[code lang=”CSharp”]
public static Vector getGrades(double chinese, double english, double math, double science)
{
return Vector.FromArray(chinese,english,math,science);
}
[/code]

Student类,完成。

接下来,再新建一个类,作为分类器的映射(mapping),叫做StudentClassifier,然后先引用:

[code lang=”CSharp”]
using MicrosoftResearch.Infer.Learners.Mappings;
using MicrosoftResearch.Infer.Maths;
[/code]

并让这个类实现 IClassifierMapping这个接口,好了,然后在我们开始下一步之前,有必要先介绍一下IClassifierMapping,这可是重点知识哦

首先,介绍一下这个接口的四个泛型参数<in TInstanceSource, TInstance, in TLabelSource, out TLabel, out TFeatures>,首先,第一个,instanceSource,就是在训练分类器是输入的一组数据的类型,这个类型代表了分类器所有的实例数据源的类型,一般来说我们训练一组数据的时候会选择将InstanceSource定义为一个集合类型的接口,比如IList<T>,或IEnumerable<T>,因为这个类型代表了所有实例数据源的总和,而T一般就是单个实例的类型,那么Instance也就可以被定义为T,当然也可以将Instance定义为一个int,作为InstanceSource的index。而后面两个,LabelSource,和Label也就是同样的道理了,他们作为标签的类型,一般也就是bool(二项分类)或int,string(多项分类)了,说明一下,标签就是分类器将实例分类的结果,即使标签,输入的标签,也就是作为分类结果的训练数据咯。最后一个,feature,feature就是特征,即为分类器将instance分类的标准,分类的根据,这个物体的特征更偏向与哪一种feature,便将其分类为那一类。

IClassifierMapping作为较为简单的一种分类器映射,它具有4个需要实现的方法,这四个方法的作用就是让分类器获取实例,特征,以及标签的。这四个方法分别是:

[code lang=”CSharp”]
IEnumerable<TLabel>; GetClassLabels(TInstanceSource instanceSource = default(TInstanceSource), TLabelSource labelSource = default(TLabelSource));
[/code]

这个方法用于获取标签的种类,比如我们这里给学生的标签只有两类:好学生和坏学生,那类型就是bool,即返回一个bool[]数组,包涵{true,false},不过在多项分类的地方,应该返回一个字符串或整数数组。

[code lang=”CSharp”]
TFeatures GetFeatures(TInstance instance, TInstanceSource instanceSource = default(TInstanceSource));
[/code]

这个方法用于从instance获取特征,在这里必须写明白如何才能让分类器从instance和instanceSource中获取特征这个属性,在这里,我们给学生的特征只有四门成绩这个Vector,而如果instance是学生,那么只需要写return instance.c_m_s_e即可

[code lang=”CSharp”]
IEnumerable<TInstance>; GetInstances(TInstanceSource instanceSource);
[/code]

这个倒是有点复杂,一般来说,只需要返回InstanceSource就可以了,不过如果你所填写的InstanceSource不是一个集合类型或者instanceSource是集合但集合的泛型参数与Instance不一样,那么则需要自寻方法使用yield return语句将你希望作为instance的所有元素迭代入返回值中了。

[code lang=”CSharp”]
TLabel GetLabel(TInstance instance, TInstanceSource instanceSource = default(TInstanceSource), TLabelSource labelSource = default(TLabelSource));
[/code]

这个方法用于通过instance,instanceSource获取label,也就是对应这个instance的label,比如学生就是instance,而他的label(好或坏)的位置也就是输入的labelSource数组的位置。

好了好了,那么这个接口也差不多讲完了,让我们开始下一步吧。

这一步,我们就来玩♂玩这个接口,首先,定义所有泛型参数,由于我们的实例都是学生,所以在InstanceSource这个我们肯定将其定义为IList<Student>,然后自然Instance的类型就是Student了。接下来,labelSource和label的类型也如法炮制,不过对于这个我们没有定义什么特别的label类型,也完全不需要,所以只需要定义为IList<bool>和bool就行了,也就是说让bool作为label的类型,好学生就是true,坏学生就是false,很明确吧。最后,feature,我们会用到一个比较特别的类,Vector,这个类是一个很标准的向量,也是Infer.NET提供的类,因此这个类也会被特殊对待,你可以将这里的Vector理解为一个double[]数组,但其实在概念上也稍有不同,不过不影响,只要在这里填上Vector就好了,它可以代表四门科目的成绩。

好了下面废话也不用说太多了,函数定义就直接放代码应该也都能理解

[code lang=”CSharp”]
class StudentClassifier : IClassifierMapping<IList<Student>, Student, IList<bool>, bool, Vector>
{
public IEnumerable<bool> GetClassLabels(IList<Student> instanceSource = null, IList<bool> labelSource = null)
{
return new bool[] { true, false };
}

public Vector GetFeatures(Student instance, IList<Student> instanceSource = null)
{
return instance.c_m_s_e;
}

public IEnumerable<Student> GetInstances(IList<Student> instanceSource)
{
return instanceSource;
}

public bool GetLabel(Student instance, IList<Student> instanceSource = null, IList<bool> labelSource = null)
{
return instance.good;
}
}
[/code]

那么,这些工作完成之后,就是真正激动人心的时刻了,我们回到Program类里,先引用一下需要的命名空间:

[code lang=”CSharp”]
using MicrosoftResearch.Infer.Learners;
[/code]

再在Main函数中实例化我们的StudentClassifier :

[code lang=”CSharp”]
StudentClassifier classifier = new StudentClassifier();
[/code]

然后再来实例化一台贝叶斯(被我妈称为“被噎死”)分类器:

[code lang=”CSharp”]
var classMachine = BayesPointMachineClassifier.CreateBinaryClassifier(classifier);
[/code]

之后准备好需要的数据

[code lang=”CSharp”]
List<Student> students = new List&lt;Student&gt;()
{ new Student("Derek",Student.getGrades(70,85,88,66)),
new Student("老大",Student.getGrades(80,85,90,70)),
new Student("Edward",Student.getGrades(83,77,56,47))
};

List<bool> labels = new List<bool>() { true, true, false };
[/code]

然后students就是InstanceSource,labels就是LabelSource,那么就让我们开始训练分类器吧!

[code lang=”CSharp”]
classMachine.Train(students, labels);
[/code]

没错就这么简单。。。好了接下来直接接着往下写,测试其在用那些数据训练后根据特征预测的能力:

[code lang=”CSharp”]
Student someone = new Student("somebody", Student.getGrades(90, 80, 92, 70));
bool isGoodStudent = classMachine.Predict(someone);
System.Console.WriteLine(isGoodStudent);
[/code]

program类中所以代码应该是这样的:

[code lang=”CSharp”]
using System.Collections.Generic;
using MicrosoftResearch.Infer.Learners;
namespace InfernetTutorial
{
class Program
{
static void Main(string[] args)
{
StudentClassifier classifier = new StudentClassifier();
var classMachine = BayesPointMachineClassifier.CreateBinaryClassifier(classifier);
List<Student> students = new List&lt;Student&gt;()
{ new Student("Derek",Student.getGrades(70,85,88,66)),
new Student("老大",Student.getGrades(80,85,90,70)),
new Student("Edward",Student.getGrades(83,77,56,47))
};

List&lt;bool&gt; labels = new List<bool>() { true, true, false };
classMachine.Train(students, labels);
Student someone = new Student("somebody", Student.getGrades(90, 80, 92, 70));
bool isGoodStudent = classMachine.Predict(someone);
System.Console.WriteLine(isGoodStudent);

}
}
}
[/code]

然后大家运行一下,看看分类器认为他到底是好学生还是坏学生吧!

P.S.:其实经本人亲自测试,这里提供给分类器的数据并不好,大家可以再尝试其他的方式来玩玩这个东西。

No Comments

Add your comment

Translate/繁简转换