Example #1
0
        public void TestOnnxTransformWithCustomShapes()
        {
            // The loaded model has input shape [-1, 3] and output shape [-1].
            var modelFile = Path.Combine(Directory.GetCurrentDirectory(), "unknowndimensions", "test_unknowndimensions_float.onnx");

            var dataPoints = new InputWithCustomShape[]
            {
                // It's a flattened 3-by-3 tensor.
                // [1.1, 1.3, 1.2]
                // |1.9, 1.3, 1.2|
                // [1.1, 1.3, 1.8]
                new InputWithCustomShape()
                {
                    input = new float[] { 1.1f, 1.3f, 1.2f, 1.9f, 1.3f, 1.2f, 1.1f, 1.3f, 1.8f }
                },
                // It's a flattened 3-by-3 tensor.
                // [0, 0, 1]
                // |1, 0, 0|
                // [1, 0, 0]
                new InputWithCustomShape()
                {
                    input = new float[] { 0f, 0f, 1f, 1f, 0f, 0f, 1f, 0f, 0f }
                }
            };

            var shapeDictionary = new Dictionary <string, int[]>()
            {
                { nameof(InputWithCustomShape.input), new int[] { 3, 3 } }
            };

            var dataView = ML.Data.LoadFromEnumerable(dataPoints);

            var pipeline             = new OnnxScoringEstimator[3];
            var onnxTransformer      = new OnnxTransformer[3];
            var transformedDataViews = new IDataView[3];

            // Test three public ONNX APIs with the custom shape.

            // Test 1.
            pipeline[0] = ML.Transforms.ApplyOnnxModel(
                new[] { nameof(PredictionWithCustomShape.argmax) }, new[] { nameof(InputWithCustomShape.input) },
                modelFile, shapeDictionary);
            onnxTransformer[0]      = pipeline[0].Fit(dataView);
            transformedDataViews[0] = onnxTransformer[0].Transform(dataView);

            // Test 2.
            pipeline[1] = ML.Transforms.ApplyOnnxModel(
                nameof(PredictionWithCustomShape.argmax), nameof(InputWithCustomShape.input),
                modelFile, shapeDictionary);
            onnxTransformer[1]      = pipeline[1].Fit(dataView);
            transformedDataViews[1] = onnxTransformer[1].Transform(dataView);

            // Test 3.
            pipeline[2]             = ML.Transforms.ApplyOnnxModel(modelFile, shapeDictionary);
            onnxTransformer[2]      = pipeline[2].Fit(dataView);
            transformedDataViews[2] = onnxTransformer[2].Transform(dataView);

            // Conduct the same check for all the 3 called public APIs.
            foreach (var transformedDataView in transformedDataViews)
            {
                var transformedDataPoints = ML.Data.CreateEnumerable <PredictionWithCustomShape>(transformedDataView, false).ToList();

                // One data point generates one transformed data point.
                Assert.Equal(dataPoints.Count(), transformedDataPoints.Count);

                // Check result numbers. They are results of applying ONNX argmax along the second axis; for example
                // [1.1, 1.3, 1.2] ---> [1] because 1.3 (indexed by 1) is the largest element.
                // |1.9, 1.3, 1.2| ---> |0|         1.9             0
                // [1.1, 1.3, 1.8] ---> [2]         1.8             2
                var expectedResults = new long[][]
                {
                    new long[] { 1, 0, 2 },
                    new long[] { 2, 0, 0 }
                };

                for (int i = 0; i < transformedDataPoints.Count; ++i)
                {
                    Assert.Equal(transformedDataPoints[i].argmax, expectedResults[i]);
                }
            }
            for (int i = 0; i < 3; i++)
            {
                (onnxTransformer[i] as IDisposable)?.Dispose();
            }
        }
Example #2
0
        public void TestOnnxTransformSaveAndLoadWithCustomShapes()
        {
            // The loaded model has input shape [-1, 3] and output shape [-1].
            var modelFile = Path.Combine(Directory.GetCurrentDirectory(), "unknowndimensions", "test_unknowndimensions_float.onnx");

            var dataPoints = new InputWithCustomShape[]
            {
                // It's a flattened 3-by-3 tensor.
                // [1.1, 1.3, 1.2]
                // |1.9, 1.3, 1.2|
                // [1.1, 1.3, 1.8]
                new InputWithCustomShape()
                {
                    input = new float[] { 1.1f, 1.3f, 1.2f, 1.9f, 1.3f, 1.2f, 1.1f, 1.3f, 1.8f }
                },
                // It's a flattened 3-by-3 tensor.
                // [0, 0, 1]
                // |1, 0, 0|
                // [1, 0, 0]
                new InputWithCustomShape()
                {
                    input = new float[] { 0f, 0f, 1f, 1f, 0f, 0f, 1f, 0f, 0f }
                }
            };

            var shapeDictionary = new Dictionary <string, int[]>()
            {
                { nameof(InputWithCustomShape.input), new int[] { 3, 3 } }
            };

            var dataView = ML.Data.LoadFromEnumerable(dataPoints);

            var pipeline = ML.Transforms.ApplyOnnxModel(nameof(PredictionWithCustomShape.argmax),
                                                        nameof(InputWithCustomShape.input), modelFile, shapeDictionary);

            var model = pipeline.Fit(dataView);

            // Save the trained ONNX transformer into file and then load it back.
            ITransformer loadedModel = null;
            var          tempPath    = Path.GetTempFileName();

            using (var file = new SimpleFileHandle(Env, tempPath, true, true))
            {
                // Save.
                using (var fs = file.CreateWriteStream())
                    ML.Model.Save(model, null, fs);

                // Load.
                using (var fs = file.OpenReadStream())
                    loadedModel = ML.Model.Load(fs, out var schema);
            }

            var transformedDataView = loadedModel.Transform(dataView);

            // Conduct the same check for all the 3 called public APIs.
            var transformedDataPoints = ML.Data.CreateEnumerable <PredictionWithCustomShape>(transformedDataView, false).ToList();

            // One data point generates one transformed data point.
            Assert.Equal(dataPoints.Count(), transformedDataPoints.Count);

            // Check result numbers. They are results of applying ONNX argmax along the second axis; for example
            // [1.1, 1.3, 1.2] ---> [1] because 1.3 (indexed by 1) is the largest element.
            // |1.9, 1.3, 1.2| ---> |0|         1.9             0
            // [1.1, 1.3, 1.8] ---> [2]         1.8             2
            var expectedResults = new long[][]
            {
                new long[] { 1, 0, 2 },
                new long[] { 2, 0, 0 }
            };

            for (int i = 0; i < transformedDataPoints.Count; ++i)
            {
                Assert.Equal(transformedDataPoints[i].argmax, expectedResults[i]);
            }

            (model as IDisposable)?.Dispose();
            (loadedModel as IDisposable)?.Dispose();
        }