|
| 1 | +using System; |
| 2 | +using System.Drawing; |
| 3 | +using System.Linq; |
| 4 | +using Microsoft.ML; |
| 5 | +using Microsoft.ML.Data; |
| 6 | +using Microsoft.ML.Transforms.Image; |
| 7 | + |
| 8 | +namespace Samples.Dynamic |
| 9 | +{ |
| 10 | + public static class ApplyOnnxModelWithInMemoryImages |
| 11 | + { |
| 12 | + // Example of applying ONNX transform on in-memory images. |
| 13 | + public static void Example() |
| 14 | + { |
| 15 | + // Download the squeeznet image model from ONNX model zoo, version 1.2 |
| 16 | + // https://github.com/onnx/models/tree/master/squeezenet or use |
| 17 | + // Microsoft.ML.Onnx.TestModels nuget. |
| 18 | + // It's a multiclass classifier. It consumes an input "data_0" and produces |
| 19 | + // an output "softmaxout_1". |
| 20 | + var modelPath = @"squeezenet\00000001\model.onnx"; |
| 21 | + |
| 22 | + // Create ML pipeline to score the data using OnnxScoringEstimator |
| 23 | + var mlContext = new MLContext(); |
| 24 | + |
| 25 | + // Create in-memory data points. Its Image/Scores field is the input/output of the used ONNX model. |
| 26 | + var dataPoints = new ImageDataPoint[] |
| 27 | + { |
| 28 | + new ImageDataPoint(Color.Red), |
| 29 | + new ImageDataPoint(Color.Green) |
| 30 | + }; |
| 31 | + |
| 32 | + // Convert training data to IDataView, the general data type used in ML.NET. |
| 33 | + var dataView = mlContext.Data.LoadFromEnumerable(dataPoints); |
| 34 | + |
| 35 | + // Create a ML.NET pipeline which contains two steps. First, ExtractPixle is used to convert the 224x224 image to a 3x224x224 float tensor. |
| 36 | + // Then the float tensor is fed into a ONNX model with an input called "data_0" and an output called "softmaxout_1". Note that "data_0" and |
| 37 | + // "softmaxout_1" are model input and output names stored in the used ONNX model file. Users may need to inspect their own models to |
| 38 | + // get the right input and output column names. |
| 39 | + var pipeline = mlContext.Transforms.ExtractPixels("data_0", "Image") // Map column "Image" to column "data_0" |
| 40 | + .Append(mlContext.Transforms.ApplyOnnxModel("softmaxout_1", "data_0", modelPath)); // Map column "data_0" to column "softmaxout_1" |
| 41 | + var model = pipeline.Fit(dataView); |
| 42 | + var onnx = model.Transform(dataView); |
| 43 | + |
| 44 | + // Convert IDataView back to IEnumerable<ImageDataPoint> so that user can inspect the output, column "softmaxout_1", of the ONNX transform. |
| 45 | + // Note that Column "softmaxout_1" would be stored in ImageDataPont.Scores because the added attributed [ColumnName("softmaxout_1")] |
| 46 | + // tells that ImageDataPont.Scores is equivalent to column "softmaxout_1". |
| 47 | + var transformedDataPoints = mlContext.Data.CreateEnumerable<ImageDataPoint>(onnx, false).ToList(); |
| 48 | + |
| 49 | + // The scores are probabilities of all possible classes, so they should all be positive. |
| 50 | + foreach (var dataPoint in transformedDataPoints) |
| 51 | + { |
| 52 | + var firstClassProb = dataPoint.Scores.First(); |
| 53 | + var lastClassProb = dataPoint.Scores.Last(); |
| 54 | + Console.WriteLine($"The probability of being the first class is {firstClassProb * 100}%."); |
| 55 | + Console.WriteLine($"The probability of being the last class is {lastClassProb * 100}%."); |
| 56 | + } |
| 57 | + |
| 58 | + // Expected output: |
| 59 | + // The probability of being the first class is 0.002542659%. |
| 60 | + // The probability of being the last class is 0.0292684%. |
| 61 | + // The probability of being the first class is 0.02258059%. |
| 62 | + // The probability of being the last class is 0.394428%. |
| 63 | + } |
| 64 | + |
| 65 | + // This class is used in Example() to describe data points which will be consumed by ML.NET pipeline. |
| 66 | + private class ImageDataPoint |
| 67 | + { |
| 68 | + // Height of Image. |
| 69 | + private const int height = 224; |
| 70 | + |
| 71 | + // Width of Image. |
| 72 | + private const int width = 224; |
| 73 | + |
| 74 | + // Image will be consumed by ONNX image multiclass classification model. |
| 75 | + [ImageType(height, width)] |
| 76 | + public Bitmap Image { get; set; } |
| 77 | + |
| 78 | + // Expected output of ONNX model. It contains probabilities of all classes. |
| 79 | + // Note that the ColumnName below should match the output name in the used |
| 80 | + // ONNX model file. |
| 81 | + [ColumnName("softmaxout_1")] |
| 82 | + public float[] Scores { get; set; } |
| 83 | + |
| 84 | + public ImageDataPoint() |
| 85 | + { |
| 86 | + Image = null; |
| 87 | + } |
| 88 | + |
| 89 | + public ImageDataPoint(Color color) |
| 90 | + { |
| 91 | + Image = new Bitmap(width, height); |
| 92 | + for (int i = 0; i < width; ++i) |
| 93 | + for (int j = 0; j < height; ++j) |
| 94 | + Image.SetPixel(i, j, color); |
| 95 | + } |
| 96 | + } |
| 97 | + } |
| 98 | +} |
0 commit comments