From f03071bdef10bc38452ea7eb82e6b5d288df726c Mon Sep 17 00:00:00 2001 From: Jignesh Parmar Date: Wed, 21 Nov 2018 03:20:42 +0000 Subject: [PATCH 1/4] upgrade to Sonoma v 1.2.0, with bug fixes and gpu support --- build/Dependencies.props | 2 +- .../OnnxTransform.cs | 23 +++++++++++-------- src/Microsoft.ML.OnnxTransform/OnnxUtils.cs | 8 +++---- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/build/Dependencies.props b/build/Dependencies.props index 884584d28e..d8d71f9953 100644 --- a/build/Dependencies.props +++ b/build/Dependencies.props @@ -16,7 +16,7 @@ 3.5.1 2.2.1.1 - 1.1.0 + 1.2.0 0.0.0.7 2.1.3 4.5.0 diff --git a/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs b/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs index be35d87e52..ae7d7e5c80 100644 --- a/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs +++ b/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs @@ -47,6 +47,9 @@ public sealed class Arguments : TransformInputBase [Argument(ArgumentType.Multiple | ArgumentType.Required, HelpText = "Name of the output column.", SortOrder = 2)] public string[] OutputColumns; + + [Argument(ArgumentType.AtMostOnce | ArgumentType.Required, HelpText = "GPU device id to run on. Typically 0,1 etc. Default of -1 runs on CPU. Requires CUDA 9.2.", SortOrder = 3)] + public int GpuDeviceId; } private readonly Arguments _args; @@ -74,9 +77,9 @@ private static VersionInfo GetVersionInfo() loaderAssemblyName: typeof(OnnxTransform).Assembly.FullName); } - public static IDataTransform Create(IHostEnvironment env, IDataView input, string modelFile, string[] inputColumns, string[] outputColumns) + public static IDataTransform Create(IHostEnvironment env, IDataView input, string modelFile, string[] inputColumns, string[] outputColumns, int gpuDeviceId = -1) { - var args = new Arguments { ModelFile = modelFile, InputColumns = inputColumns, OutputColumns = outputColumns }; + var args = new Arguments { ModelFile = modelFile, InputColumns = inputColumns, OutputColumns = outputColumns, GpuDeviceId = gpuDeviceId }; return Create(env, args, input); } @@ -140,10 +143,10 @@ private OnnxTransform(IHostEnvironment env, Arguments args, byte[] modelBytes = { Host.CheckNonWhiteSpace(args.ModelFile, nameof(args.ModelFile)); Host.CheckUserArg(File.Exists(args.ModelFile), nameof(args.ModelFile)); - Model = new OnnxModel(args.ModelFile); + Model = new OnnxModel(args.ModelFile, args.GpuDeviceId); } else - Model = OnnxModel.CreateFromBytes(modelBytes); + Model = OnnxModel.CreateFromBytes(modelBytes, args.GpuDeviceId); var modelInfo = Model.ModelInfo; Inputs = args.InputColumns; @@ -164,13 +167,13 @@ private OnnxTransform(IHostEnvironment env, Arguments args, byte[] modelBytes = _args = args; } - public OnnxTransform(IHostEnvironment env, string modelFile, string inputColumn, string outputColumn) - : this(env, new Arguments() { ModelFile = modelFile, InputColumns = new[] { inputColumn }, OutputColumns = new[] { outputColumn } }) + public OnnxTransform(IHostEnvironment env, string modelFile, string inputColumn, string outputColumn, int gpuDeviceId = -1) + : this(env, new Arguments() { ModelFile = modelFile, InputColumns = new[] { inputColumn }, OutputColumns = new[] { outputColumn }, GpuDeviceId = gpuDeviceId }) { } - public OnnxTransform(IHostEnvironment env, string modelFile, string[] inputColumns, string[] outputColumns) - : this(env, new Arguments() { ModelFile = modelFile, InputColumns = inputColumns, OutputColumns = outputColumns }) + public OnnxTransform(IHostEnvironment env, string modelFile, string[] inputColumns, string[] outputColumns, int gpuDeviceId = -1) + : this(env, new Arguments() { ModelFile = modelFile, InputColumns = inputColumns, OutputColumns = outputColumns, GpuDeviceId = gpuDeviceId }) { } @@ -419,8 +422,8 @@ public Tensor GetTensor() } public sealed class OnnxScoringEstimator : TrivialEstimator { - public OnnxScoringEstimator(IHostEnvironment env, string modelFile, string[] inputs, string[] outputs) - : this(env, new OnnxTransform(env, modelFile, inputs, outputs)) + public OnnxScoringEstimator(IHostEnvironment env, string modelFile, string[] inputs, string[] outputs, int gpuDeviceId = -1) + : this(env, new OnnxTransform(env, modelFile, inputs, outputs, gpuDeviceId)) { } diff --git a/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs b/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs index 687133296f..c21db9bd56 100644 --- a/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs +++ b/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs @@ -67,7 +67,7 @@ public OnnxNodeInfo(string name, OnnxShape shape, DataType type) public readonly List InputNames; public readonly List OutputNames; - public OnnxModel(string modelFile) + public OnnxModel(string modelFile, int gpuDeviceId) { _modelFile = modelFile; @@ -75,21 +75,21 @@ public OnnxModel(string modelFile) var modelFileInfo = new FileInfo(modelFile); _modelName = Path.GetFileNameWithoutExtension(modelFileInfo.Name); _modelManager = new ModelManager(modelFileInfo.Directory.FullName, true); - _modelManager.InitOnnxModel(_modelName, _ignoredVersion); + _modelManager.InitOnnxModel(_modelName, _ignoredVersion, gpuDeviceId); ModelInfo = new OnnxModelInfo(GetInputsInfo(), GetOutputsInfo()); InputNames = ModelInfo.InputsInfo.Select(i => i.Name).ToList(); OutputNames = ModelInfo.OutputsInfo.Select(i => i.Name).ToList(); } - public static OnnxModel CreateFromBytes(byte[] modelBytes) + public static OnnxModel CreateFromBytes(byte[] modelBytes, int gpuDeviceId) { var tempModelDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(tempModelDir); var tempModelFile = Path.Combine(tempModelDir, "model.onnx"); File.WriteAllBytes(tempModelFile, modelBytes); - return new OnnxModel(tempModelFile); + return new OnnxModel(tempModelFile, gpuDeviceId); // TODO: // tempModelFile is needed in case the model needs to be saved From c806a54ff56ae61170aca68fbc7c68a8bb886ce7 Mon Sep 17 00:00:00 2001 From: Jignesh Parmar Date: Thu, 22 Nov 2018 02:42:09 +0000 Subject: [PATCH 2/4] update unit test --- src/Microsoft.ML.OnnxTransform/OnnxTransform.cs | 2 +- .../OnnxTransformTests.cs | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs b/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs index ae7d7e5c80..c92c2c9738 100644 --- a/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs +++ b/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs @@ -49,7 +49,7 @@ public sealed class Arguments : TransformInputBase public string[] OutputColumns; [Argument(ArgumentType.AtMostOnce | ArgumentType.Required, HelpText = "GPU device id to run on. Typically 0,1 etc. Default of -1 runs on CPU. Requires CUDA 9.2.", SortOrder = 3)] - public int GpuDeviceId; + public int GpuDeviceId = -1; } private readonly Arguments _args; diff --git a/test/Microsoft.ML.OnnxTransformTest/OnnxTransformTests.cs b/test/Microsoft.ML.OnnxTransformTest/OnnxTransformTests.cs index af6a26d440..43ee3ff209 100644 --- a/test/Microsoft.ML.OnnxTransformTest/OnnxTransformTests.cs +++ b/test/Microsoft.ML.OnnxTransformTest/OnnxTransformTests.cs @@ -220,7 +220,7 @@ void TestCommandLine() return; var env = new MLContext(); - var x = Maml.Main(new[] { @"showschema loader=Text{col=data_0:R4:0-150527} xf=Onnx{InputColumns={data_0} OutputColumns={softmaxout_1} model={squeezenet/00000001/model.onnx}}" }); + var x = Maml.Main(new[] { @"showschema loader=Text{col=data_0:R4:0-150527} xf=Onnx{InputColumns={data_0} OutputColumns={softmaxout_1} model={squeezenet/00000001/model.onnx} GpuDeviceId=-1}" }); Assert.Equal(0, x); } @@ -298,8 +298,16 @@ public void OnnxModelMultiInput() { getScoresa(ref buffera); getScoresb(ref bufferb); - Console.WriteLine(buffera.GetValues().ToArray()); + var suma = 0f; + var sumb = 0f; + foreach (var x in buffera.DenseValues()) + suma += x; + foreach (var x in bufferb.DenseValues()) + sumb += x; Assert.Equal(5, buffera.Length); + Assert.Equal(5, bufferb.Length); + Assert.Equal(0, suma); + Assert.Equal(30, sumb); } } } From 068fe9ee85e0bceeaddc61fcc7e1f65ec9c59358 Mon Sep 17 00:00:00 2001 From: Jignesh Parmar Date: Sun, 25 Nov 2018 12:03:16 +0000 Subject: [PATCH 3/4] Added XML documentation and end-to-end example --- .../Dynamic/OnnxTransform.cs | 123 ++++++++++++++++++ .../OnnxTransform.cs | 35 ++++- src/Microsoft.ML.OnnxTransform/OnnxUtils.cs | 52 +++++++- 3 files changed, 202 insertions(+), 8 deletions(-) create mode 100644 docs/samples/Microsoft.ML.Samples/Dynamic/OnnxTransform.cs diff --git a/docs/samples/Microsoft.ML.Samples/Dynamic/OnnxTransform.cs b/docs/samples/Microsoft.ML.Samples/Dynamic/OnnxTransform.cs new file mode 100644 index 0000000000..ef58d54434 --- /dev/null +++ b/docs/samples/Microsoft.ML.Samples/Dynamic/OnnxTransform.cs @@ -0,0 +1,123 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.ML.Transforms; +using Microsoft.ML.Runtime.Data; +using Microsoft.ML.Runtime.ImageAnalytics; +using Microsoft.ML; +using System; +using System.IO; + +namespace Microsoft.ML.Samples.Dynamic +{ + class Program + { + static void Main(string[] args) + { + // Download the squeeznet image model from ONNX model zoo, version 1.2 + // https://github.com/onnx/models/tree/master/squeezenet + var model_location = @"squeezenet\model.onnx"; + + var env = new MLContext(); + + // Use the utility functions to inspect models inputs, outputs, shape and type + // Load the model using the OnnxModel class + var onnxModel = new OnnxModel(model_location); + + // This model has only 1 input, so inspect 0th index for input node metadata + var inputSchema = onnxModel.ModelInfo.InputsInfo[0]; + var inputName = inputSchema.Name; + var inputShape = inputSchema.Shape; + var inputType = inputSchema.Type; + + // Deduce image dimensions from inputShape + var numChannels = inputShape[1]; + var imageHeight = inputShape[2]; + var imageWidth = inputShape[3]; + + // Similarly, get output node metadata + var outputSchema = onnxModel.ModelInfo.OutputsInfo[0]; + var outputName = outputSchema.Name; + var outputShape = outputSchema.Shape; + var outputType = outputSchema.Type; + + var dataFile = @"test\data\images\images.tsv"; + var imageFolder = Path.GetDirectoryName(dataFile); + + // Use Textloader to load the text file which references the images to load + // Preview ... + // banana.jpg banana + // hotdog.jpg hotdog + // tomato.jpg tomato + var data = TextLoader.Create(env, new TextLoader.Arguments() + { + Column = new[] + { + new TextLoader.Column("ImagePath", DataKind.TX, 0), + new TextLoader.Column("Name", DataKind.TX, 1), + } + }, new MultiFileSource(dataFile)); + + // Load the images referenced in the text file + var images = ImageLoaderTransform.Create(env, new ImageLoaderTransform.Arguments() + { + Column = new ImageLoaderTransform.Column[1] + { + new ImageLoaderTransform.Column() { Source= "ImagePath", Name="ImageReal" } + }, + ImageFolder = imageFolder + }, data); + + // Resize the images to match model dimensions + var cropped = ImageResizerTransform.Create(env, new ImageResizerTransform.Arguments() + { + Column = new ImageResizerTransform.Column[1]{ + new ImageResizerTransform.Column(){ Source = "ImageReal", Name= "ImageCropped", ImageHeight =imageHeight, ImageWidth = imageWidth, Resizing = ImageResizerTransform.ResizingKind.IsoCrop}} + }, images); + + // Extract out the RBG pixel values. + // InterleaveArgb = true makes the values RGBRGBRGB. Otherwise it's RRR...GGG...BBB. + var pixels = ImagePixelExtractorTransform.Create(env, new ImagePixelExtractorTransform.Arguments() + { + Column = new ImagePixelExtractorTransform.Column[1]{ + new ImagePixelExtractorTransform.Column() { Source= "ImageCropped", Name = inputName, InterleaveArgb=true} + } + }, cropped); + + // Create OnnxTransform, passing in the input and output names the model expects. + IDataView trans = OnnxTransform.Create(env, pixels, model_location, new[] { inputName }, new[] { outputName }); + + trans.Schema.TryGetColumnIndex(outputName, out int output); + using (var cursor = trans.GetRowCursor(col => col == output)) + { + var numRows = 0; + var buffer = default(VBuffer); + var getter = cursor.GetGetter>(output); + // For each image, retrieve the model scores + while (cursor.MoveNext()) + { + int i = 0; + getter(ref buffer); + // print scores for first 3 classes + foreach(var score in buffer.GetValues()) + { + Console.WriteLine(String.Format("Example # {0} :Score for class {1} = {2} ",numRows, i, score)); + if (++i > 2) break; + } + numRows += 1; + } + } + // Results look like below... + // Example # 0 :Score for class 0 = 1.133263E-06 + // Example # 0 :Score for class 1 = 1.80478E-07 + // Example # 0 :Score for class 2 = 1.595297E-07 + // Example # 1 :Score for class 0 = 1.805106E-05 + // Example # 1 :Score for class 1 = 1.257452E-05 + // Example # 1 :Score for class 2 = 2.412128E-06 + // Example # 2 :Score for class 0 = 1.346096E-06 + // Example # 2 :Score for class 1 = 1.918751E-07 + // Example # 2 :Score for class 2 = 7.203341E-08 + } + } +} \ No newline at end of file diff --git a/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs b/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs index c92c2c9738..c6933eb7c0 100644 --- a/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs +++ b/src/Microsoft.ML.OnnxTransform/OnnxTransform.cs @@ -35,6 +35,29 @@ namespace Microsoft.ML.Transforms { + /// + ///

A transform for scoring ONNX models in the ML.NET framework.

+ /// + /// + /// + ///
+ /// + ///

Supports inferencing of models in 1.2 and 1.3 format, using the + /// Microsoft.ML.Scoring library + ///

+ ///

The inputs and outputs of the onnx models must of of Tensors. Sequence and Maps are not yet supported.

+ ///

Supports optional GPU execution via the CUDA 9.2 libraries. The + /// CUDA 9.2 Toolkit + /// and + /// cuDNN + /// libraries need to be installed separately. By default models are run on CPU. To run on GPU if available, + /// set the parameter 'gpuDeviceID' to a valid non-negative number. + ///

+ ///

Visit https://github.com/onnx/models to see a list of readily available models to get started with.

+ ///

Refer to http://onnx.ai' for more information about ONNX.

+ ///
public sealed class OnnxTransform : RowToRowTransformerBase { public sealed class Arguments : TransformInputBase @@ -77,6 +100,12 @@ private static VersionInfo GetVersionInfo() loaderAssemblyName: typeof(OnnxTransform).Assembly.FullName); } + public static IDataTransform Create(IHostEnvironment env, IDataView input, string modelFile, string[] inputColumns, string[] outputColumns) + { + var args = new Arguments { ModelFile = modelFile, InputColumns = inputColumns, OutputColumns = outputColumns, GpuDeviceId = -1 }; + return Create(env, args, input); + } + public static IDataTransform Create(IHostEnvironment env, IDataView input, string modelFile, string[] inputColumns, string[] outputColumns, int gpuDeviceId = -1) { var args = new Arguments { ModelFile = modelFile, InputColumns = inputColumns, OutputColumns = outputColumns, GpuDeviceId = gpuDeviceId }; @@ -420,6 +449,10 @@ public Tensor GetTensor() } } } + + /// + /// A class implementing the estimator interface of the OnnxTransform. + /// public sealed class OnnxScoringEstimator : TrivialEstimator { public OnnxScoringEstimator(IHostEnvironment env, string modelFile, string[] inputs, string[] outputs, int gpuDeviceId = -1) @@ -461,7 +494,7 @@ public override SchemaShape GetOutputSchema(SchemaShape inputSchema) { resultDic[Transformer.Outputs[i]] = new SchemaShape.Column(Transformer.Outputs[i], Transformer.OutputTypes[i].IsKnownSizeVector ? SchemaShape.Column.VectorKind.Vector - : SchemaShape.Column.VectorKind.VariableVector, NumberType.R4, false); + : SchemaShape.Column.VectorKind.VariableVector, Transformer.OutputTypes[i].ItemType, false); } return new SchemaShape(resultDic.Values); } diff --git a/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs b/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs index c21db9bd56..7720db9859 100644 --- a/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs +++ b/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs @@ -17,12 +17,12 @@ namespace Microsoft.ML.Transforms { /// - /// OnnxModel is a facad for ModelManager. ModelManager is provided by Sonoma API, - /// and it has a lot of functionality (multiple models, multiple versions) that are not - /// needed by Onnx transform, which only needs a single model. This facad simplifies the - /// usage of onnx model. + /// OnnxModel is a utility class to load ONNX models, and retrieve metadata + /// for inputs and outputs. The metadata includes the names, shapes and types + /// It provides API to open a session, score tensors and return + /// the results. /// - internal sealed class OnnxModel + public sealed class OnnxModel { /// /// OnnxModelInfo contains the data that we should get from @@ -46,8 +46,17 @@ public OnnxModelInfo(OnnxNodeInfo[] inputsInfo, OnnxNodeInfo[] outputsInfo) /// public class OnnxNodeInfo { + /// + /// The Name of the input node + /// public readonly string Name; + /// + /// The shape of the input node + /// public readonly OnnxShape Shape; + /// + /// The type of the input node + /// public readonly DataType Type; public OnnxNodeInfo(string name, OnnxShape shape, DataType type) @@ -82,7 +91,23 @@ public OnnxModel(string modelFile, int gpuDeviceId) OutputNames = ModelInfo.OutputsInfo.Select(i => i.Name).ToList(); } - public static OnnxModel CreateFromBytes(byte[] modelBytes, int gpuDeviceId) + /// + /// Create an OnnxModel from a byte[] + /// + /// A byte array containing the serialized model + /// + public static OnnxModel CreateFromBytes(byte[] modelBytes) + { + return CreateFromBytes(modelBytes, -1); + } + + /// + /// Create an OnnxModel from a byte[] + /// + /// A byte array containing the serialized model + /// Default =-1 for CPU execution. Specify non-negative device ID for GPU execution + /// OnnxModel + public static OnnxModel CreateFromBytes(byte[] modelBytes, int gpuDeviceId=-1) { var tempModelDir = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); Directory.CreateDirectory(tempModelDir); @@ -97,6 +122,11 @@ public static OnnxModel CreateFromBytes(byte[] modelBytes, int gpuDeviceId) // or keep the dir/file and write proper cleanup when application closes } + /// + /// Uses an already open session to score a list of Tensors/NamedOnnxValues. + /// + /// The NamedOnnxValues/Tensors to score + /// A list of NamedOnnxValues/Tensors public List Run(List inputTensors) { var outputTensors = _modelManager.RunModel( @@ -105,12 +135,20 @@ public List Run(List inputTensors) return outputTensors; } + /// + /// Convert the model to a byte array. + /// + /// byte[] public byte[] ToByteArray() { return File.ReadAllBytes(_modelFile); } - private OnnxNodeInfo[] GetInputsInfo() + /// + /// Returns input metadata of the ONNX model. + /// + /// OnnxNodeInfo[] + public OnnxNodeInfo[] GetInputsInfo() { return DictToNodesInfo( _modelManager.GetInputTypeDict(_modelName, _ignoredVersion), From 24c36eede385c9f8ce8fd1f1cf27f82ea799c24e Mon Sep 17 00:00:00 2001 From: Jignesh Parmar Date: Sun, 25 Nov 2018 12:41:34 +0000 Subject: [PATCH 4/4] updated example --- .../Microsoft.ML.Samples/Dynamic/OnnxTransform.cs | 12 +++++------- .../Microsoft.ML.Samples.csproj | 2 ++ src/Microsoft.ML.OnnxTransform/OnnxUtils.cs | 13 +++++++++++++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/docs/samples/Microsoft.ML.Samples/Dynamic/OnnxTransform.cs b/docs/samples/Microsoft.ML.Samples/Dynamic/OnnxTransform.cs index ef58d54434..a0fd62ca45 100644 --- a/docs/samples/Microsoft.ML.Samples/Dynamic/OnnxTransform.cs +++ b/docs/samples/Microsoft.ML.Samples/Dynamic/OnnxTransform.cs @@ -11,9 +11,9 @@ namespace Microsoft.ML.Samples.Dynamic { - class Program + class OnnxTransformExample { - static void Main(string[] args) + public static void OnnxTransformSample(string[] args) { // Download the squeeznet image model from ONNX model zoo, version 1.2 // https://github.com/onnx/models/tree/master/squeezenet @@ -29,18 +29,16 @@ static void Main(string[] args) var inputSchema = onnxModel.ModelInfo.InputsInfo[0]; var inputName = inputSchema.Name; var inputShape = inputSchema.Shape; - var inputType = inputSchema.Type; // Deduce image dimensions from inputShape - var numChannels = inputShape[1]; - var imageHeight = inputShape[2]; - var imageWidth = inputShape[3]; + var numChannels = (int) inputShape[1]; + var imageHeight = (int) inputShape[2]; + var imageWidth = (int) inputShape[3]; // Similarly, get output node metadata var outputSchema = onnxModel.ModelInfo.OutputsInfo[0]; var outputName = outputSchema.Name; var outputShape = outputSchema.Shape; - var outputType = outputSchema.Type; var dataFile = @"test\data\images\images.tsv"; var imageFolder = Path.GetDirectoryName(dataFile); diff --git a/docs/samples/Microsoft.ML.Samples/Microsoft.ML.Samples.csproj b/docs/samples/Microsoft.ML.Samples/Microsoft.ML.Samples.csproj index 6b3d9f957b..8029135d61 100644 --- a/docs/samples/Microsoft.ML.Samples/Microsoft.ML.Samples.csproj +++ b/docs/samples/Microsoft.ML.Samples/Microsoft.ML.Samples.csproj @@ -13,6 +13,8 @@ + + diff --git a/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs b/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs index af32e6358a..19f9359d70 100644 --- a/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs +++ b/src/Microsoft.ML.OnnxTransform/OnnxUtils.cs @@ -77,6 +77,19 @@ public OnnxNodeInfo(string name, OnnxShape shape, DataType type) public readonly List InputNames; public readonly List OutputNames; + /// + /// Constructs OnnxModel object from file. + /// + /// File path to onnx model + public OnnxModel(string modelFile) : this(modelFile, -1) + { + } + + /// + /// Constructs OnnxModel object from file. + /// + /// File path to onnx model + /// -1 for CPU execution. A non-negative value runs execution on the specified GPU public OnnxModel(string modelFile, int gpuDeviceId) { _modelFile = modelFile;