ML.NET案例详解:在.NET下使用机器学习API实现化学分子式数据格式的判定

半年前写过一篇类似的文章,题目是:《在.NET中使用机器学习API(ML.NET)实现化学分子式数据格式的判定》,在该文中,我介绍了化学分子式数据格式的基本知识,同时给出了一个案例,展示了如何在.NET/.NET Core中,使用微软开源的ML.NET框架,通过机器学习,实现化学分子式数据格式的预测。

时隔半年,ML.NET有了很大的发展。在阅读我之前那篇文章的时候,或许还会对给出的案例代码有些疑问,ML.NET经过几个版本的更新之后,API的设计变得更为合理易用,所开放的接口也越来越多(比如,新版本的ML.NET中,对机器学习引擎的OutputSchema进行了完全开放,开发者可以根据自己的需要进行调用),因此,本文就再一次回到这个话题并进行更为详细的介绍,用新版本的ML.NET重新实现化学分子式数据格式的判定。

有关化学分子式的相关知识,在这里也就不多说了,直接看代码实现部分。

准备数据

我们的数据仍然是一个CSV文件,通过逗号分隔,文件包含两个字段:结构式数据(ChemicalStructure),以及该结构式数据的类型(Type),以下是这个文件的部分片段,注意,在这个文件中,我们没有定义CSV头,不过这不重要,只要记得在后面的代码实现中,将这个设置体现出来就可以了。


[O-]C(CCCCCCCCCCCCCCCCC)=O.[Na+],SMILES
O=C(C1)N(C2[C@@]3(CC4)[C@](N4C5)([H])C[C@@]6([H])C5=CCOC1[C@]62[H])C7=C3C=CC=C7.O[N+]([O-])=O,SMILES
O=C1CC2C(C3[C@]45C(C=CC=C6)=C6N31)C(CC4N(CC5)C7)C7=CCO2.OS(O)(=O)=O.O=C8CC9C(C%10[C@@]%11%12C(C=CC=C%13)=C%13N%108)C(CC%11N(CC%12)C%14)C%14=CCO9,SMILES
C=CC1=CC=CC=C1,SMILES
N=C(OC)CCCCCCC(OC)=N.Cl.Cl,SMILES
NC(CCC(N)=O)=O,SMILES
O=C(O)C1(N(CCOC)CCOC)CCC(C)CC1,SMILES
CN(C)C(C)CC(C1=CC=CC=C1)(C(CC)=O)C2=CC=CC=C2,SMILES
NCC1(CCC(CCC)CC1)N(C)CC2=COC=C2,SMILES
AAADceByOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAACBThgAYCCAMABAAIAACQCAAAAAAAAAAAAAEIAAACABQAgAAHAAAFIAAQAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==,BASE64_CDX
AAADceByOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAACAAACBThgAYCCAMABgAIAACQCAAAAAAAAAAAAAEIAAACABQAgAAHQAAFIAAQAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==,BASE64_CDX
AAADccBCIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAQCAAACBThgAYCAABAAgAAAAAAAAAAAAAAAAAAAIAAAAACEAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==,BASE64_CDX
AAADccBjgAAAAAAAAAAAAAAAAAAAAWAAAAAsAAAAAAAAAFgB+AAAHAAQAAAACAjBFwQH8L9MEACgAQZhZACAgC0REKABUCAoVBCASABASEAUBAgIAALAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==,BASE64_CDX
AAADceB7uAAAAAAAAAAAAAAAAAAAAAAAAAAwQIAAAAAAAACBAAAAHgAQCAAADCjBmAYxyIPAAgCoAiXS/ACCAAElAgAJiIGIZMiKYDLA1bGUYQhslgLYyce8rwCeCAAAAAAAAAAQAAAAAAAAAAAAAAAAAA==,BASE64_CDX
OC1=C(C2=C(C=C1)C[C@@]3([C@]45[H])[H])O[C@]([C@@]52CCN3C)([C@H](CC4)OC)[H],SMILES
OC1=C(O2)C([C@]([C@]2(C)C(CC3)=O)(CCN4C)[C@]3([H])[C@H]4C5)=C5C=C1,SMILES
........

注意:你不需要将这些数据复制下来,本文结尾会给出源代码,其中包含了这个完整的数据文件。

实现过程

可以基于.NET Framework 4.6.1或者.NET Core创建一个新的控制台应用程序,在这个控制台应用程序上,添加对ML.NET NuGet包的引用。实现的第一步就是定义我们的样本数据对象。根据上面的CSV文件结构,我们可以设计如下的类:


public class ChemicalData
{
    [Column("0")]
    public string ChemicalStructure;
    [Column("1")]
    public string Type;
}

这个类非常简单,仅仅是针对CSV文件两个列的映射。接下来,我们需要定义用于保存预测结果的数据对象,该对象不仅会用来保存预测结果值,而且还会提供基于不同分类的可信度得分(Score):


public class ChemicalDataPrediction
{
    [ColumnName("PredictedLabel")]
    public string Type;
    public float[] Score;
}

OK,到这里我们基本上已经清楚我们的机器学习应用场景了:我们在使用Multi-class Classification对化学结构式数据进行分类。在机器学习的应用过程中,了解应用场景是非常重要的。然后,回到Main函数,实现如下代码:


static void Main(string[] args)
{
    // 创建机器学习上下文实例
    var mlContext = new MLContext();
    // 从data.txt读入样本数据
    var dataView = mlContext.Data.ReadFromTextFile("data.txt", new TextLoader.Arguments
    {
        Separators = new char[] { ',' }, // 逗号分隔
        HasHeader = false, // 文件中不包含CSV头信息
        Column = new[] {
            new TextLoader.Column("ChemicalStructure", DataKind.Text, 0),  // 化学结构式数据字段
            new TextLoader.Column("Type", DataKind.Text, 1)  // 化学结构式数据类型字段
        }
    });
    // 创建机器学习管道,指定我们需要使用CSV文件中的Type字段进行标记并分类
    var pipeline = mlContext.Transforms.Conversion.MapValueToKey("Label", "Type")
         
        // 指定将由ChemicalStructure字段提供特征信息
        .Append(mlContext.Transforms.Text.FeaturizeText("Features", "ChemicalStructure"))
        // 选择机器学习算法
        .Append(mlContext.MulticlassClassification.Trainers.LogisticRegression())
        // 计算结果将输出到由PredictedLabel所标记的对象字段上
        .Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabel"));
    // 基于样本数据和所选择的管道选项,进行模型训练,并返回模型
    var model = pipeline.Fit(dataView);
    // 创建预测引擎
    var engine = model.CreatePredictionEngine<ChemicalData, ChemicalDataPrediction>(mlContext);
    // 对给定的测试数据进行预测,并输出测试结果
    var sample = new ChemicalData { ChemicalStructure = "NC(C(N)=O)=O" };
    var prediction = engine.Predict(sample);
    Console.WriteLine(prediction.Type);
}

代码非常简单,有几个点说明一下:

  • 新的ML.NET需要创建MLContext对象,所有的机器学习工作都会依赖于这个上下文

  • 通过MapValueToKey方法来指定读入数据的哪个字段是用来进行分类标记的,这个Label是ML.NET的一个保留字段名,在模型训练的时候会找到由Label所标记的字段进行计算

  • Features也是ML.NET的一个保留字段名,它指定了哪个(或哪些)字段将提供特征数据

  • PredictedLabel也是ML.NET的保留字段名,它指定了计算结果应该输出到哪个对象字段中

直接运行程序,可以看到,程序毫无悬念地输出了正确结果:

640?wx_fmt=png

可信度得分的获取

在上面的代码中,如果我们将断点设置在最后一句Console.WriteLine方法上,然后调试程序,查看prediction的数值,会发现,各个分类的可信度已经在Score字段里了:

640?wx_fmt=png

可问题是,我如何知道某个得分到底是属于哪个分类呢?在ML.NET 0.6之前的版本,在训练好的模型对象上,会有一个TryGetScoreLabelNames的扩展方法,它能够返回可信度得分的分类名称,顺序和Score数组的顺序一致。但从ML.NET 0.6开始,这个扩展方法已经没有了,但这并不是说ML.NET变得更弱了,相反,新版本中直接将OutputSchema对象暴露出来,开发者可以自己实现所需的方法。下面的代码展示了如何基于预测引擎的OutputSchema来获取各个分类的名称,以及所对应的可信度得分:


static void Main(string[] args)
{
    // ...
    // 接上文代码
     
    var outputSchema = engine.OutputSchema;
    TryGetScoreLabelNames(outputSchema, out var names);
    var confidences = new Dictionary<string, float>();
    for (var idx = 0; idx < names.Length; idx++)
    {
        confidences.Add(names[idx], prediction.Score[idx]);
    }
    Console.WriteLine(JsonConvert.SerializeObject(
        new
        {
            Label = prediction.Type,
            Confidences = confidences
        },
        Formatting.Indented));
}
static bool TryGetScoreLabelNames(Schema outputSchema, out string[] names, string scoreColumnName = DefaultColumnNames.Score)
{
    names = (string[])null;
    var scoreColumn = outputSchema.GetColumnOrNull(scoreColumnName);
    var slotNames = new VBuffer<ReadOnlyMemory<char>>();
    scoreColumn.Value.GetSlotNames(ref slotNames);
    names = new string[slotNames.Length];
    var num = 0;
    foreach (var denseValue in slotNames.DenseValues())
    {
        names[num++] = denseValue.ToString();
    }
    return true;
}

再次执行程序,可以看到,我们已经可以输出各个分类的可信度得分了:

640?wx_fmt=png

预测失误

现在我们做个试验,将最后用于测试的数据从SMILES换成INCHI,比如:

1
var sample = new ChemicalData { ChemicalStructure = "InChI=1S/ClH/h1H/p-1" };

然后再次运行程序,结果发现,我们本想得到INCHI的输出,却仍然得到SMILES的结果,只不过SMILES的可信度降低了,InChi的可信度升高了:

640?wx_fmt=png

这个问题主要是因为我们所提供的用于训练的样本数据还不够多,如果训练数据量大,并且干扰比较小的话,得到的预测结果就会更准确。因此,在实践机器学习的过程中,保证训练数据的纯净度和数据量是非常重要的,这也就是为什么目前机器学习的项目中,在数据清洗这一步中有着相当大的投入。回到我们的案例,让我们在样本CSV文件中多加一些InChi数据,来帮助机器学习得到更精确的结果:


"InChI=1/C2H6O/c1-2-3/h3H,2H2,1H3",InChi
"InChI=1/C6H8O6/c7-1-2(8)5-3(9)4(10)6(11)12-5/h2,5,7-10H,1H2/t2-,5+/m0/s1",InChi
"InChI=1S/C6H8O6/c7-1-2(8)5-3(9)4(10)6(11)12-5/h2,5,7-10H,1H2/t2-,5+/m0/s1",InChi
"InChI=1S/CH4/h1H4",InChi
"InChI=1S/C2H6/c1-2/h1-2H3",InChi
"InChI=1S/C2H6O/c1-2-3/h3H,2H2,1H3",InChi
"InChI=1S/C3H7NO2/c1-2(4)3(5)6/h2H,4H2,1H3,(H,5,6)/t2-/m0/s1",InChi
"InChI=1S/ClH/h1H/p-1",InChi
"InChI=1S/C6H7NO/c1-5-3-2-4-7-6(5)8/h2-4H,1H3,(H,7,8)",InChi
"InChI=1S/CH2N2/c1-3-2/h1H2",InChi
"InChI=1S/C7H5N3O/c11-7-5-3-1-2-4-6(5)8-10-9-7/h1-4H,(H,8,9,11)",InChi
"InChI=1S/C8H6N2O/c11-8-6-3-1-2-4-7(6)9-5-10-8/h1-5H,(H,9,10,11)",InChi
"InChI=1S/C2H6N2O/c1-4(2)3-5/h1-2H3",InChi
"InChI=1S/C9H8N2O/c1-6-10-8-5-3-2-4-7(8)9(12)11-6/h2-5H,1H3,(H,10,11,12)",InChi
"InChI=1S/C6H8O/c1-2-3-4-5-6-7/h2-6H,1H3/b3-2+,5-4+",InChi

再次运行程序,我们已经可以得到正确的输出了(虽然它仍然认为有31%的可能性是SMILES):

640?wx_fmt=png

模型的保存与使用

我们可以用下面的代码将训练好的模型保存到本地ZIP文件中,以便今后直接在项目中使用:


using (var fs = new FileStream("ml_model.zip", FileMode.Create, FileAccess.Write, FileShare.Write))
{
    mlContext.Model.Save(model, fs);
}

然后使用下面的代码,读入保存的模型,并进行新的预测:


var mlContext2 = new MLContext();
ITransformer loadedModel;
using (var stream = new FileStream("ml_model.zip", FileMode.Open, FileAccess.Read, FileShare.Read))
{
    loadedModel = mlContext2.Model.Load(stream);
    var engine2 = loadedModel.CreatePredictionEngine<ChemicalData, ChemicalDataPrediction>(mlContext2);
    var pred = engine2.Predict(new ChemicalData { ChemicalStructure = "c1ccccc1" });
    Console.WriteLine(pred.Type);
}

总结

本文再一次介绍了如何使用微软开源的ML.NET框架,实现化学结构式数据格式的预测和判定。本文对使用ML.NET的整个流程进行了详细完整的介绍,但只演示了Multi-class Classification的应用场景。其它应用场景其实也大同小异,开发人员需要根据实际情况进行选择。通过ML.NET产生的训练模型是可以序列化到ZIP文件的,因此,模型可以方便地重用。ML.NET支持.NET Core,因此,基于docker和ASP.NET Core实现机器学习的RESTful API也是轻而易举的事情,本文就不继续深入了。

源代码下载

请 下载本文案例的源代码http://sunnycoding.cn/archives/ML_ChemStructure_Demo.zip

原文地址:http://sunnycoding.cn/2019/02/22/categorize-chemical-structure-using-ml-net-advanced/

.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com
640?wx_fmt=jpeg


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317106.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构之线段树合并——永无乡,Lomsat gelral,Tree Rotations,Tree Rotations Escape Through Leaf

文章目录[HNOI2012]永无乡Lomsat gelral「POI2011 R2 Day2」旋转树木 Tree RotationsEscape Through Leaf线段树合并与 fhq-treap合并很类似&#xff0c;也是将两个不同根的线段树暴力合并至于时间复杂度&#xff0c;线段树合并一次是可以达到O(n)O(n)O(n)的&#xff0c;但是大…

吉特仓储管理系统--开源2018年源码

应该说今天过完&#xff0c;这个年就算真正意义上的过完了&#xff0c;没有想到的是又是在出差的路上写这样的文章。废话也不多说&#xff0c;写这篇文章主要的目的是想将去年吉特仓储管理系统开发的一个版本源代码开放出来&#xff0c;供各位开发者阅读使用。github 源代码地址…

自定义Visual Studio.net Extensions 开发符合ABP vnext框架代码生成插件[附源码]

介绍我很早之前一直在做mvc5 scaffolder的开发功能做的已经非常完善,使用代码对mvc5的项目开发效率确实能成倍的提高,就算是刚进团队的新成员也能很快上手,如果你感兴趣 可以参考 http://neozhu.github.io/MVC5-Scaffolder/#/ https://github.com/neozhu/MVC5-Scaffolder但是m…

洛谷P1650:田忌赛马(贪心)

解析 其实并不简单的一道题。 是刘汝佳老师的例题&#xff0c;搜到之后按照讲的策略写了一发。 &#xff08;由于这个策略并不完全正确&#xff0c;就不展开讲了&#xff09; 好啊&#xff01; 可是感觉讲的策略特别对&#xff0c;为什么呢&#xff1f; 原因在于&#xff0…

EFCore Lazy Loading + Inheritance = 干净的数据表 (二)

前言本篇是上一篇EFCore Lazy Loading Inheritance 干净的数据表 &#xff08;一&#xff09; 【献给处女座的DB First程序猿】 前菜 的续篇。这一篇才是真的为处女座的DB First程序猿准备的正餐。继续上一篇的话题&#xff0c;我们希望用EFCore&#xff0c;且继续使用与逻辑…

我们为什么要搞长沙.NET技术社区?

某种意义上讲&#xff0c;长沙和中国大部分内地城市一样&#xff0c;都是互联网时代的灯下黑。没有真正意义上的互联网公司&#xff0c;例如最近发布的中国互联网企业一百强中没有一家湖南或者长沙的公司就是明证。然而长沙并非没有互联网人&#xff0c;在麓谷几十万计的IT 从业…

在ASP.NET Core中使用EPPlus导入出Excel文件

这篇文章说明了如何使用EPPlus在ASP.NET Core中导入和导出.xls/.xlsx文件&#xff08;Excel&#xff09;。在考虑使用.NET处理excel时&#xff0c;我们总是寻找第三方库或组件。使用Open Office Xml格式&#xff08;xlsx&#xff09;读取和写入Excel 2007/2010文件的最流行的.n…

月旦评 之 DevOps招贤令2019 - 没有人比我们更懂DevOps

公元164-182年间&#xff0c;汝南平舆的许氏兄弟于每月初一品评人物&#xff0c;褒贬时政&#xff0c;被称为“月旦评”。所谓“子治世之能臣&#xff0c;乱世之奸雄也”这句许邵评价曹操的话也是来自于“月旦评”&#xff1b;时间一下子来到了2019年&#xff0c;DevOps招贤令再…

HDU - 2204 Eddy‘s爱好(尚未完全解决)

HDU - 2204 Eddy’s爱好 题意&#xff1a; 给你一个正整数N&#xff0c;确定在1到N之间有多少个可以表示成M^K&#xff08;K>1)的数 题解&#xff1a; 参考题解&#xff1a; 我们先举例找找规律 1~10以内2的次方有多少个&#xff1f;有121,224,329,一共三个&#xff0c;…

EF Core中避免贫血模型的三种行之有效的方法(翻译)

[Paul Hiles: 3 ways to avoid an anemic domain model in EF Core &#xff1a;https://www.devtrends.co.uk/blog/3-ways-to-avoid-an-anemic-domain-model-in-ef-core]1.引言在使用ORM中&#xff08;比如Entity Framework&#xff09;贫血领域模型十分常见 。本篇文章将先探…

Saving Beans HDU - 3037(卢卡斯定理)

Saving Beans HDU - 3037&#xff08;卢卡斯定理&#xff09; 题意&#xff1a; 他们想知道有多少种方法可以在n树中保存不超过m个bean&#xff08;它们是相同的&#xff09;。 现在他们求助于你&#xff0c;你应该给他们答案。 结果可能非常巨大; 你应该输出模p的结果&…

我们为什么要搞长沙.NET技术社区(三)

我们为什么要搞长沙.NET技术社区&#xff08;三&#xff09; 小饭局搞事情先从饭局开始是中华民族的优良传统。昨天晚餐时间&#xff0c;长沙 .net 技术社区的主要发起人员进行了一番小聚&#xff0c;同时也作为一个非正式会议&#xff0c;对社区发展进行了探讨。从介绍自己对于…

【招聘(北京)】北森测评招聘 .NET 架构师、高级工程师

工作职责公司核心产品的迭代需求分析设计开发。公司核心产品的线上维护和性能调优。对初中级技术人员培养和质量把关。编写软件设计和技术文档。任职资格为人正直、诚信、责任心强&#xff0c;能承受较大工作压力。强烈的目标导向意识&#xff0c;逻辑思维清晰&#xff0c;执行…

网络流模型与技巧总结

文章目录前言常见基本模型最大匹配、最小点覆盖和最大独立集构造最小点覆盖最大点权匹配最小路径覆盖不可重覆盖可重覆盖最大权闭合子图建图技巧利用拆点进行限流利用断边表示决策利用虚点表示组合关系链状模型用链表示时间轴用链表示偏序关系形式的选取限制通过拆点描述先后顺…

卢卡斯定理 Lucas

参考文章 详细定义内容看这个参考文章 结论&#xff1a; 模板&#xff1a; Lucas函数&#xff1a; long long Lucas(long long n,long long m){if(m0) return 1;return Lucas(n/p,m/p)*C(n%p,m%p)%p; }组合数函数&#xff1a; 此处求逆元的用的bp-2 long long C(long long…

VS 2019 要来了,是时候了解一下 C# 8.0 新功能

近日&#xff0c;微软发布了 Visual Studio 2019 的发布日期&#xff0c;2019 年 4 月 2 日 Visual Studio 2019 将正式和大家见面&#xff0c;同时微软还将提供发布现场实时直播。除了 Visual Studio 2019 自身之外&#xff0c;VS 2019 的发布还牵动着很多 C# 开发者的心。虽然…

[蓝桥杯2020国赛]游园安排

题目&#xff1a; 题解&#xff1a; 本质就是求最长上升子序列&#xff0c;只不过这里是字符串版本的&#xff0c;我们都知道有n^2的LIS&#xff0c;但其实还有O(nlogn)版本的&#xff0c;详细看这里&#xff0c;套上就行 另外我发现这里竟然有蓝桥杯全套的编程题离谱&#xf…

重新解读DDD领域驱动设计(一)

回顾十年前&#xff0c;还未踏入某校时&#xff0c;便听闻某学长一毕业就入职北京某公司&#xff0c;月薪过万。对于一个名不见经传的小学院&#xff0c;一毕业能拿到这个薪水还是非常厉害的。听闻他学生期间参与开发了一款股票软件&#xff0c;股票那时正迎来一波疯涨。时也运…

程序员修神之路--高并发优雅的做限流(有福利)

点击上方蓝色字体&#xff0c;关注我们菜菜哥&#xff0c;有时间吗&#xff1f;YY妹&#xff0c;什么事&#xff1f;我最近的任务是做个小的秒杀活动&#xff0c;我怕把后端接口压垮&#xff0c;X总说这可关系到公司的存亡简单呀&#xff0c;你就做个限流呗这个没做过呀&#x…

免费馅饼 HDU - 1176

免费馅饼 HDU - 1176 题意&#xff1a; 都说天上不会掉馅饼&#xff0c;但有一天gameboy正走在回家的小径上&#xff0c;忽然天上掉下大把大把的馅饼。说来gameboy的人品实在是太好了&#xff0c;这馅饼别处都不掉&#xff0c;就掉落在他身旁的10米范围内。馅饼如果掉在了地上…