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,一经查实,立即删除!

相关文章

洛谷P4762: [CERC2014]Virus synthesis(PAM)

解析 自己对PAM的理解不够深刻。 最优方案必然是先选择一个偶回文串&#xff0c;递归构造出它的一半。花一步逆序&#xff0c;然后暴力解决剩下的。 这似乎已经依稀出现了某种dp的思路。 考虑如何更好的转移。设计 transxtrans_xtransx​ 表示长度不超过 xxx 一半的最长回文后…

Triangle HDU - 5914

Triangle HDU - 5914 题意&#xff1a; 有长度分别是1到n的n给木棍&#xff0c;问最少拿走几个木棍&#xff0c;使得剩下木棍无法组成三角形 题解&#xff1a; 组不成三角形的恰巧情况就是ab<c&#xff0c;也就是我们要让剩下的木棍&#xff0c;两者之和等于或小于第三个…

CodeForces - 336A Vasily the Bear and Triangle

CodeForces - 336A Vasily the Bear and Triangle 题意&#xff1a; 给你一个点x&#xff0c;现在这个点和原点组成了矩形&#xff0c;让你在x和y轴分别求一个点&#xff0c;与原点构成的三角形&#xff0c;要求矩形在三角形内&#xff0c;点x在斜边上 题解&#xff1a; 这…

数据结构之线段树合并——永无乡,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 源代码地址…

模板:广义SAM(字符串)

所谓广义SAM&#xff0c;就是更广泛意义下的SAM &#xff08;逃&#xff09; 前言 感觉字符串的理解难度的巅峰还是在SAM&#xff0c;广义SAM只是在套一些特判罢了&#xff0c;并不是太难理解。 可以解决多字符串的子串问题&#xff0c;几乎就是把SAM能做的东西从单串变成了多…

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

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

QDU-Training-01

QDU-Training-01 题号题目知识点难度CodeForces 76EPoints数论HDU 4608I-number模拟CodeForces 616DLongest k-Good Segment尺取法Gym 215177C玩游戏思维题HDU 5914Triangle构造题CodeForces 336AVasily the Bear and Triangle思维题 同时纪念我第700篇文章&#xff0c;我还是…

CF1131 G. Most Dangerous Shark (单调栈优化dp)

文章目录problemsolutioncodeproblem solution dpi:dp_i:dpi​: 前iii个多米诺骨牌全都倒下的最小花费 li,ril_i,r_ili​,ri​分别表示第iii个多米诺骨牌倒下时所能波及到的最左/右位置 往左倒&#xff0c;则[li,i)[l_i,i)[li​,i)内的牌都可以选择性地先推倒 dpimin⁡{dpjcos…

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

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

CF407 E. k-d-sequence

文章目录problemsolutioncodeproblem solution 特判d0d0d0&#xff0c;相当于寻找最长的一段数字相同的区间 如果要满足公差为ddd等差序列 区间内每个数在模ddd意义下同余每个数互不相同 算法流程 先将序列分成若干个同余mmm的子区间 从左往右扫一遍 对于同余的子区间&…

Monkey and Banana HDU - 1069

Monkey and Banana HDU - 1069 题意&#xff1a; 有n种类型的砖块&#xff0c;每种类型的砖块都有无限个。第i块砖块的长宽高分别用xi&#xff0c;yi&#xff0c;zi来表示。 同时&#xff0c;由于砖块是可以旋转的&#xff0c;每个砖块的3条边可以组成6种不同的长宽高。 在构…

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

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

洛谷P7361:拜神(SA、二分、主席树、启发式合并)

解析 很好的一道SA的题。&#xff08;觉得完全可以评黑了啊qwq&#xff09; 我一开始拿SAM和线段树硬做&#xff0c;不断修正最后发现自己无法在可接受复杂度内解决的问题&#xff0c;直接GG… 垃圾数据还骗到了50分 所以写一道题之前还是要先想仔细了&#xff0c;确定整个流程…

Doing Homework HDU - 1074

Doing Homework HDU - 1074 题意&#xff1a; 有n个任务&#xff0c;每个任务有一个截止时间&#xff0c;超过截止时间一天&#xff0c;要扣一个分。 求如何安排任务&#xff0c;使得扣的分数最少。 (1<n<15) 题解&#xff1a; n很小&#xff0c;可以往状压dp方向去想…

【学习笔记】浅谈广义矩阵乘法——动态DP

文章目录广义矩阵乘法动态DP例题&#xff1a;洛谷4719以下内容是本人做题经验&#xff0c;如有雷同&#xff0c;纯属抄袭&#xff1b;如有不对&#xff0c;纯属不懂&#xff0c;还请指正 广义矩阵乘法 众所周知&#xff0c;矩阵满足乘法交换律&#xff0c;前一个矩阵的列必须…

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

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

洛谷P5212:SubString(SAM、LCT)

解析 所谓SAM套LCT&#xff0c;真的就只是SAM套LCT。。。 考试写起来应该有亿点点恶心 每次在SAM节点修改的时候在LCT对应位置修改即可。 注意&#xff01; 克隆节点之前需要先splay一下把所有标记接收。 没了。 #include<bits/stdc.h> using namespace std; #define…

在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…

[kuangbin]专题12 基础DP

HDU 1024 Max Sum Plus Plus HDU 1029 Ignatius and the Princess IV HDU 1069 Monkey and Banana HDU 1074 Doing Homework HDU 1087 Super Jumping! Jumping! Jumping! HDU 1114 Piggy-Bank HDU 1176 免费馅饼 HDU 1260 Tickets HDU 1257 最少拦截系统 HDU 1160 FatMouse’s …