From b1ad60724d9a1203ae09809ae17ce8c12b50c1b9 Mon Sep 17 00:00:00 2001 From: Ye Wang <52801275+wangyems@users.noreply.github.com> Date: Sat, 16 May 2020 19:12:38 -0700 Subject: [PATCH 1/6] initial checkin --- .../Commands/DefaultColumnNames.cs | 1 + .../Scorers/BinaryClassifierScorer.cs | 1 + .../Scorers/MulticlassClassificationScorer.cs | 1 + test/Microsoft.ML.Tests/OnnxConversionTest.cs | 25 +++++++++++++++++++ 4 files changed, 28 insertions(+) diff --git a/src/Microsoft.ML.Data/Commands/DefaultColumnNames.cs b/src/Microsoft.ML.Data/Commands/DefaultColumnNames.cs index 994880ef13..ac9aace33d 100644 --- a/src/Microsoft.ML.Data/Commands/DefaultColumnNames.cs +++ b/src/Microsoft.ML.Data/Commands/DefaultColumnNames.cs @@ -12,6 +12,7 @@ namespace Microsoft.ML.Data [BestFriend] internal static class DefaultColumnNames { + //bugbug public const string Features = "Features"; public const string Label = "Label"; public const string GroupId = "GroupId"; diff --git a/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs b/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs index 2bfa94ffd8..1a24af716b 100644 --- a/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs +++ b/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs @@ -187,6 +187,7 @@ private protected override void SaveAsOnnxCore(OnnxContext ctx) Host.Assert(Bindable is IBindableCanSaveOnnx); Host.Assert(Bindings.InfoCount >= 2); + //bugbug if (!ctx.ContainsColumn(DefaultColumnNames.Features)) return; diff --git a/src/Microsoft.ML.Data/Scorers/MulticlassClassificationScorer.cs b/src/Microsoft.ML.Data/Scorers/MulticlassClassificationScorer.cs index a82092f430..1f1d63a39c 100644 --- a/src/Microsoft.ML.Data/Scorers/MulticlassClassificationScorer.cs +++ b/src/Microsoft.ML.Data/Scorers/MulticlassClassificationScorer.cs @@ -219,6 +219,7 @@ void IBindableCanSavePfa.SaveAsPfa(BoundPfaContext ctx, RoleMappedSchema schema, bool IBindableCanSaveOnnx.SaveAsOnnx(OnnxContext ctx, RoleMappedSchema schema, string[] outputNames) { + //bugbug Contracts.CheckValue(ctx, nameof(ctx)); Contracts.CheckValue(schema, nameof(schema)); Contracts.Check(((ICanSaveOnnx)this).CanSaveOnnx(ctx), "Cannot be saved as ONNX."); diff --git a/test/Microsoft.ML.Tests/OnnxConversionTest.cs b/test/Microsoft.ML.Tests/OnnxConversionTest.cs index 9f2482961f..fd6b09fa02 100644 --- a/test/Microsoft.ML.Tests/OnnxConversionTest.cs +++ b/test/Microsoft.ML.Tests/OnnxConversionTest.cs @@ -1959,6 +1959,31 @@ public void SelectColumnsOnnxTest() Done(); } + [Fact] + public void MyOnnxConversionTest() + { + var mlContext = new MLContext(seed: 1); + string dataPath = GetDataPath("breast-cancer.txt"); + + var data = ML.Data.LoadFromTextFile(dataPath, new[] { + new TextLoader.Column("VectorDouble2", DataKind.Single, 1), + new TextLoader.Column("VectorDouble1", DataKind.Single, 4, 8), + new TextLoader.Column("Label", DataKind.Boolean, 0) + }); + + //wrong1 + var pipeline = mlContext.Transforms.Concatenate("FeaturesVector", "VectorDouble1", "VectorDouble2").Append(mlContext.MulticlassClassification.Trainers.SdcaNonCalibrated("Label", "FeaturesVector")); + //wrong2 + //var pipeline = mlContext.Transforms.Concatenate("FeaturesVector", "VectorDouble1", "VectorDouble2").Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression("Label", "FeaturesVector")); + //right + //var pipeline = mlContext.Transforms.Concatenate("Features", "VectorDouble1", "VectorDouble2").Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression("Label", "Features")); + var model = pipeline.Fit(data); + var transformedData = model.Transform(data); + var onnxModel = mlContext.Model.ConvertToOnnxProtobuf(model, data); + + Done(); + } + private void CompareResults(string leftColumnName, string rightColumnName, IDataView left, IDataView right, int precision = 6) { var leftColumn = left.Schema[leftColumnName]; From 69a331506dcb767ce8584e5f0c2df61479f8bb51 Mon Sep 17 00:00:00 2001 From: Ye Wang <52801275+wangyems@users.noreply.github.com> Date: Tue, 19 May 2020 20:17:24 -0700 Subject: [PATCH 2/6] initial checkin --- src/Microsoft.ML.Data/Commands/DefaultColumnNames.cs | 1 - src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs | 3 +-- test/Microsoft.ML.Tests/OnnxConversionTest.cs | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.ML.Data/Commands/DefaultColumnNames.cs b/src/Microsoft.ML.Data/Commands/DefaultColumnNames.cs index ac9aace33d..994880ef13 100644 --- a/src/Microsoft.ML.Data/Commands/DefaultColumnNames.cs +++ b/src/Microsoft.ML.Data/Commands/DefaultColumnNames.cs @@ -12,7 +12,6 @@ namespace Microsoft.ML.Data [BestFriend] internal static class DefaultColumnNames { - //bugbug public const string Features = "Features"; public const string Label = "Label"; public const string GroupId = "GroupId"; diff --git a/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs b/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs index 1a24af716b..b2c85dbe49 100644 --- a/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs +++ b/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs @@ -187,9 +187,8 @@ private protected override void SaveAsOnnxCore(OnnxContext ctx) Host.Assert(Bindable is IBindableCanSaveOnnx); Host.Assert(Bindings.InfoCount >= 2); - //bugbug if (!ctx.ContainsColumn(DefaultColumnNames.Features)) - return; + throw Contracts.ExceptParam(nameof(DefaultColumnNames.Features), $"Please use default Column Names: '{DefaultColumnNames.Features}'"); base.SaveAsOnnxCore(ctx); int delta = Bindings.DerivedColumnCount; diff --git a/test/Microsoft.ML.Tests/OnnxConversionTest.cs b/test/Microsoft.ML.Tests/OnnxConversionTest.cs index fd6b09fa02..02f5670fd1 100644 --- a/test/Microsoft.ML.Tests/OnnxConversionTest.cs +++ b/test/Microsoft.ML.Tests/OnnxConversionTest.cs @@ -1959,7 +1959,7 @@ public void SelectColumnsOnnxTest() Done(); } - [Fact] + /*[Fact] public void MyOnnxConversionTest() { var mlContext = new MLContext(seed: 1); @@ -1982,7 +1982,7 @@ public void MyOnnxConversionTest() var onnxModel = mlContext.Model.ConvertToOnnxProtobuf(model, data); Done(); - } + }*/ private void CompareResults(string leftColumnName, string rightColumnName, IDataView left, IDataView right, int precision = 6) { From 53c0425093f9cfdd93510e1a5c4770f79ef3252b Mon Sep 17 00:00:00 2001 From: Ye Wang <52801275+wangyems@users.noreply.github.com> Date: Tue, 19 May 2020 21:15:11 -0700 Subject: [PATCH 3/6] clean code --- .../Scorers/MulticlassClassificationScorer.cs | 1 - test/Microsoft.ML.Tests/OnnxConversionTest.cs | 27 +------------------ 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/Microsoft.ML.Data/Scorers/MulticlassClassificationScorer.cs b/src/Microsoft.ML.Data/Scorers/MulticlassClassificationScorer.cs index 1f1d63a39c..a82092f430 100644 --- a/src/Microsoft.ML.Data/Scorers/MulticlassClassificationScorer.cs +++ b/src/Microsoft.ML.Data/Scorers/MulticlassClassificationScorer.cs @@ -219,7 +219,6 @@ void IBindableCanSavePfa.SaveAsPfa(BoundPfaContext ctx, RoleMappedSchema schema, bool IBindableCanSaveOnnx.SaveAsOnnx(OnnxContext ctx, RoleMappedSchema schema, string[] outputNames) { - //bugbug Contracts.CheckValue(ctx, nameof(ctx)); Contracts.CheckValue(schema, nameof(schema)); Contracts.Check(((ICanSaveOnnx)this).CanSaveOnnx(ctx), "Cannot be saved as ONNX."); diff --git a/test/Microsoft.ML.Tests/OnnxConversionTest.cs b/test/Microsoft.ML.Tests/OnnxConversionTest.cs index 02f5670fd1..8e807ee403 100644 --- a/test/Microsoft.ML.Tests/OnnxConversionTest.cs +++ b/test/Microsoft.ML.Tests/OnnxConversionTest.cs @@ -750,7 +750,7 @@ public void MulticlassLogisticRegressionOnnxConversionTest() separatorChar: '\t', hasHeader: true); - var pipeline = mlContext.Transforms.ReplaceMissingValues("Features"). + var pipeline = mlContext.Transforms.ReplaceMissingValues("FeaturesVector"). Append(mlContext.Transforms.NormalizeMinMax("Features")). Append(mlContext.Transforms.Conversion.MapValueToKey("Label")). Append(mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy(new LbfgsMaximumEntropyMulticlassTrainer.Options() { NumberOfThreads = 1 })); @@ -1959,31 +1959,6 @@ public void SelectColumnsOnnxTest() Done(); } - /*[Fact] - public void MyOnnxConversionTest() - { - var mlContext = new MLContext(seed: 1); - string dataPath = GetDataPath("breast-cancer.txt"); - - var data = ML.Data.LoadFromTextFile(dataPath, new[] { - new TextLoader.Column("VectorDouble2", DataKind.Single, 1), - new TextLoader.Column("VectorDouble1", DataKind.Single, 4, 8), - new TextLoader.Column("Label", DataKind.Boolean, 0) - }); - - //wrong1 - var pipeline = mlContext.Transforms.Concatenate("FeaturesVector", "VectorDouble1", "VectorDouble2").Append(mlContext.MulticlassClassification.Trainers.SdcaNonCalibrated("Label", "FeaturesVector")); - //wrong2 - //var pipeline = mlContext.Transforms.Concatenate("FeaturesVector", "VectorDouble1", "VectorDouble2").Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression("Label", "FeaturesVector")); - //right - //var pipeline = mlContext.Transforms.Concatenate("Features", "VectorDouble1", "VectorDouble2").Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression("Label", "Features")); - var model = pipeline.Fit(data); - var transformedData = model.Transform(data); - var onnxModel = mlContext.Model.ConvertToOnnxProtobuf(model, data); - - Done(); - }*/ - private void CompareResults(string leftColumnName, string rightColumnName, IDataView left, IDataView right, int precision = 6) { var leftColumn = left.Schema[leftColumnName]; From f4bede3cbcc4c396ff9871673a849ec4f541cb41 Mon Sep 17 00:00:00 2001 From: Ye Wang <52801275+wangyems@users.noreply.github.com> Date: Tue, 19 May 2020 21:40:34 -0700 Subject: [PATCH 4/6] revert --- test/Microsoft.ML.Tests/OnnxConversionTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Microsoft.ML.Tests/OnnxConversionTest.cs b/test/Microsoft.ML.Tests/OnnxConversionTest.cs index 8e807ee403..9f2482961f 100644 --- a/test/Microsoft.ML.Tests/OnnxConversionTest.cs +++ b/test/Microsoft.ML.Tests/OnnxConversionTest.cs @@ -750,7 +750,7 @@ public void MulticlassLogisticRegressionOnnxConversionTest() separatorChar: '\t', hasHeader: true); - var pipeline = mlContext.Transforms.ReplaceMissingValues("FeaturesVector"). + var pipeline = mlContext.Transforms.ReplaceMissingValues("Features"). Append(mlContext.Transforms.NormalizeMinMax("Features")). Append(mlContext.Transforms.Conversion.MapValueToKey("Label")). Append(mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy(new LbfgsMaximumEntropyMulticlassTrainer.Options() { NumberOfThreads = 1 })); From 09a7a13d944dda42a1088946a784f3220af56e4c Mon Sep 17 00:00:00 2001 From: Ye Wang <52801275+wangyems@users.noreply.github.com> Date: Wed, 20 May 2020 23:24:41 -0700 Subject: [PATCH 5/6] test --- .../Scorers/BinaryClassifierScorer.cs | 3 --- test/Microsoft.ML.Tests/OnnxConversionTest.cs | 27 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs b/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs index b2c85dbe49..4ddf832782 100644 --- a/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs +++ b/src/Microsoft.ML.Data/Scorers/BinaryClassifierScorer.cs @@ -187,9 +187,6 @@ private protected override void SaveAsOnnxCore(OnnxContext ctx) Host.Assert(Bindable is IBindableCanSaveOnnx); Host.Assert(Bindings.InfoCount >= 2); - if (!ctx.ContainsColumn(DefaultColumnNames.Features)) - throw Contracts.ExceptParam(nameof(DefaultColumnNames.Features), $"Please use default Column Names: '{DefaultColumnNames.Features}'"); - base.SaveAsOnnxCore(ctx); int delta = Bindings.DerivedColumnCount; diff --git a/test/Microsoft.ML.Tests/OnnxConversionTest.cs b/test/Microsoft.ML.Tests/OnnxConversionTest.cs index 9f2482961f..4d96e8c1c5 100644 --- a/test/Microsoft.ML.Tests/OnnxConversionTest.cs +++ b/test/Microsoft.ML.Tests/OnnxConversionTest.cs @@ -1959,6 +1959,33 @@ public void SelectColumnsOnnxTest() Done(); } + [Fact] + public void MyOnnxConversionTest() + { + var mlContext = new MLContext(seed: 1); + string dataPath = GetDataPath("breast-cancer.txt"); + + var data = ML.Data.LoadFromTextFile(dataPath, new[] { + new TextLoader.Column("VectorDouble2", DataKind.Single, 1), + new TextLoader.Column("VectorDouble1", DataKind.Single, 4, 8), + new TextLoader.Column("Label", DataKind.Boolean, 0) + }); + + + //wrong m + //var pipeline = mlContext.Transforms.Concatenate("FeaturesVector", "VectorDouble1", "VectorDouble2").Append(mlContext.MulticlassClassification.Trainers.SdcaNonCalibrated("Label", "FeaturesVector")); + //wrong b + var pipeline = mlContext.Transforms.Concatenate("FeaturesVector", "VectorDouble1", "VectorDouble2").Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression("Label", "FeaturesVector")); + //right + //var pipeline = mlContext.Transforms.Concatenate("Features", "VectorDouble1", "VectorDouble2").Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression("Label", "Features")); + + var model = pipeline.Fit(data); + var transformedData = model.Transform(data); + var onnxModel = mlContext.Model.ConvertToOnnxProtobuf(model, data); + + Done(); + } + private void CompareResults(string leftColumnName, string rightColumnName, IDataView left, IDataView right, int precision = 6) { var leftColumn = left.Schema[leftColumnName]; From 40519c1090ea76373cf95ccd28d23a7eebaebc86 Mon Sep 17 00:00:00 2001 From: Ye Wang <52801275+wangyems@users.noreply.github.com> Date: Tue, 26 May 2020 13:55:56 -0700 Subject: [PATCH 6/6] add tests --- test/Microsoft.ML.Tests/OnnxConversionTest.cs | 141 ++++++++++++++++-- 1 file changed, 126 insertions(+), 15 deletions(-) diff --git a/test/Microsoft.ML.Tests/OnnxConversionTest.cs b/test/Microsoft.ML.Tests/OnnxConversionTest.cs index 4d96e8c1c5..c14637e745 100644 --- a/test/Microsoft.ML.Tests/OnnxConversionTest.cs +++ b/test/Microsoft.ML.Tests/OnnxConversionTest.cs @@ -1959,30 +1959,141 @@ public void SelectColumnsOnnxTest() Done(); } + private class BreastCancerMulticlassExampleNonDefaultColNames + { + [LoadColumn(1)] + public string Label; + + [LoadColumn(2, 9), VectorType(8)] + public float[] MyFeatureVector; + } + + private class BreastCancerBinaryClassificationNonDefaultColNames + { + [LoadColumn(0)] + public bool Label; + + [LoadColumn(2, 9), VectorType(8)] + public float[] MyFeatureVector; + } + [Fact] - public void MyOnnxConversionTest() + public void NonDefaultColNamesBinaryClassificationOnnxConversionTest() { var mlContext = new MLContext(seed: 1); string dataPath = GetDataPath("breast-cancer.txt"); + // Now read the file (remember though, readers are lazy, so the actual reading will happen when the data is accessed). + var dataView = mlContext.Data.LoadFromTextFile(dataPath, separatorChar: '\t', hasHeader: true); + List> estimators = new List>() + { + mlContext.BinaryClassification.Trainers.AveragedPerceptron("Label", "MyFeatureVector"), + mlContext.BinaryClassification.Trainers.FastForest("Label", "MyFeatureVector"), + mlContext.BinaryClassification.Trainers.FastTree("Label", "MyFeatureVector"), + mlContext.BinaryClassification.Trainers.LbfgsLogisticRegression("Label", "MyFeatureVector"), + mlContext.BinaryClassification.Trainers.LinearSvm("Label", "MyFeatureVector"), + mlContext.BinaryClassification.Trainers.Prior(), + mlContext.BinaryClassification.Trainers.SdcaLogisticRegression("Label", "MyFeatureVector"), + mlContext.BinaryClassification.Trainers.SdcaNonCalibrated("Label", "MyFeatureVector"), + mlContext.BinaryClassification.Trainers.SgdCalibrated("Label", "MyFeatureVector"), + mlContext.BinaryClassification.Trainers.SgdNonCalibrated("Label", "MyFeatureVector"), + mlContext.BinaryClassification.Trainers.SymbolicSgdLogisticRegression("Label", "MyFeatureVector"), + }; + if (Environment.Is64BitProcess) + { + estimators.Add(mlContext.BinaryClassification.Trainers.LightGbm("Label", "MyFeatureVector")); + } - var data = ML.Data.LoadFromTextFile(dataPath, new[] { - new TextLoader.Column("VectorDouble2", DataKind.Single, 1), - new TextLoader.Column("VectorDouble1", DataKind.Single, 4, 8), - new TextLoader.Column("Label", DataKind.Boolean, 0) - }); + var initialPipeline = mlContext.Transforms.ReplaceMissingValues("MyFeatureVector"). + Append(mlContext.Transforms.NormalizeMinMax("MyFeatureVector")); + foreach (var estimator in estimators) + { + var pipeline = initialPipeline.Append(estimator); + var model = pipeline.Fit(dataView); + var transformedData = model.Transform(dataView); + var onnxModel = mlContext.Model.ConvertToOnnxProtobuf(model, dataView); + var onnxFileName = $"{estimator.ToString()}.onnx"; + var onnxModelPath = GetOutputPath(onnxFileName); + SaveOnnxModel(onnxModel, onnxModelPath, null); - //wrong m - //var pipeline = mlContext.Transforms.Concatenate("FeaturesVector", "VectorDouble1", "VectorDouble2").Append(mlContext.MulticlassClassification.Trainers.SdcaNonCalibrated("Label", "FeaturesVector")); - //wrong b - var pipeline = mlContext.Transforms.Concatenate("FeaturesVector", "VectorDouble1", "VectorDouble2").Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression("Label", "FeaturesVector")); - //right - //var pipeline = mlContext.Transforms.Concatenate("Features", "VectorDouble1", "VectorDouble2").Append(mlContext.BinaryClassification.Trainers.SdcaLogisticRegression("Label", "Features")); + // Compare model scores produced by ML.NET and ONNX's runtime. + if (IsOnnxRuntimeSupported()) + { + // Evaluate the saved ONNX model using the data used to train the ML.NET pipeline. + var onnxEstimator = mlContext.Transforms.ApplyOnnxModel(onnxModelPath); + var onnxTransformer = onnxEstimator.Fit(dataView); + var onnxResult = onnxTransformer.Transform(dataView); + CompareSelectedColumns("Score", "Score", transformedData, onnxResult, 3); //compare scores + CompareSelectedColumns("PredictedLabel", "PredictedLabel", transformedData, onnxResult); //compare predicted labels + } + } + Done(); + } - var model = pipeline.Fit(data); - var transformedData = model.Transform(data); - var onnxModel = mlContext.Model.ConvertToOnnxProtobuf(model, data); + [Fact] + public void NonDefaultColNamesMultiClassificationOnnxConversionTest() + { + var mlContext = new MLContext(seed: 1); + + string dataPath = GetDataPath("breast-cancer.txt"); + var dataView = mlContext.Data.LoadFromTextFile(dataPath, separatorChar: '\t', hasHeader: true); + + List> estimators = new List>() + { + mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy("Label", "MyFeatureVector"), + mlContext.MulticlassClassification.Trainers.NaiveBayes("Label", "MyFeatureVector"), + mlContext.MulticlassClassification.Trainers.OneVersusAll( + mlContext.BinaryClassification.Trainers.AveragedPerceptron("Label", "MyFeatureVector")), + mlContext.MulticlassClassification.Trainers.OneVersusAll( + mlContext.BinaryClassification.Trainers.AveragedPerceptron("Label", "MyFeatureVector"), useProbabilities:false), + mlContext.MulticlassClassification.Trainers.OneVersusAll( + mlContext.BinaryClassification.Trainers.LbfgsLogisticRegression("Label", "MyFeatureVector")), + mlContext.MulticlassClassification.Trainers.OneVersusAll( + mlContext.BinaryClassification.Trainers.LbfgsLogisticRegression("Label", "MyFeatureVector"), useProbabilities:false), + mlContext.MulticlassClassification.Trainers.OneVersusAll( + mlContext.BinaryClassification.Trainers.LinearSvm("Label", "MyFeatureVector")), + mlContext.MulticlassClassification.Trainers.OneVersusAll( + mlContext.BinaryClassification.Trainers.LinearSvm("Label", "MyFeatureVector"), useProbabilities:false), + mlContext.MulticlassClassification.Trainers.OneVersusAll( + mlContext.BinaryClassification.Trainers.FastForest("Label", "MyFeatureVector")), + mlContext.MulticlassClassification.Trainers.OneVersusAll( + mlContext.BinaryClassification.Trainers.FastForest("Label", "MyFeatureVector"), useProbabilities:false), + mlContext.MulticlassClassification.Trainers.SdcaMaximumEntropy("Label", "MyFeatureVector"), + mlContext.MulticlassClassification.Trainers.SdcaNonCalibrated("Label", "MyFeatureVector") + }; + + if (Environment.Is64BitProcess) + { + estimators.Add(mlContext.MulticlassClassification.Trainers.LightGbm("Label", "MyFeatureVector")); + } + + var initialPipeline = mlContext.Transforms.ReplaceMissingValues("MyFeatureVector") + .Append(mlContext.Transforms.NormalizeMinMax("MyFeatureVector")) + .Append(mlContext.Transforms.Conversion.MapValueToKey("Label")); + + foreach (var estimator in estimators) + { + var pipeline = initialPipeline.Append(estimator); + var model = pipeline.Fit(dataView); + var transformedData = model.Transform(dataView); + + var onnxModel = mlContext.Model.ConvertToOnnxProtobuf(model, dataView); + var onnxFileName = $"{estimator.ToString()}.onnx"; + var onnxModelPath = GetOutputPath(onnxFileName); + + SaveOnnxModel(onnxModel, onnxModelPath, null); + // Compare results produced by ML.NET and ONNX's runtime. + if (IsOnnxRuntimeSupported()) + { + // Evaluate the saved ONNX model using the data used to train the ML.NET pipeline. + var onnxEstimator = mlContext.Transforms.ApplyOnnxModel(onnxModelPath); + var onnxTransformer = onnxEstimator.Fit(dataView); + var onnxResult = onnxTransformer.Transform(dataView); + CompareSelectedColumns("PredictedLabel", "PredictedLabel", transformedData, onnxResult); + CompareSelectedColumns("Score", "Score", transformedData, onnxResult, 4); + } + } Done(); }