diff --git a/csharp/sample/Microsoft.ML.OnnxRuntime.InferenceSample/Program.cs b/csharp/sample/Microsoft.ML.OnnxRuntime.InferenceSample/Program.cs index f70e06a8cd..888f0f7b14 100644 --- a/csharp/sample/Microsoft.ML.OnnxRuntime.InferenceSample/Program.cs +++ b/csharp/sample/Microsoft.ML.OnnxRuntime.InferenceSample/Program.cs @@ -39,15 +39,15 @@ namespace CSharpUsage } // Run the inference - var results = session.Run(container); // results is an IReadOnlyList container - - // dump the results - foreach (var r in results) + using (var results = session.Run(container)) // results is an IDisposableReadOnlyCollection container { - Console.WriteLine("Output for {0}", r.Name); - Console.WriteLine(r.AsTensor().GetArrayString()); + // dump the results + foreach (var r in results) + { + Console.WriteLine("Output for {0}", r.Name); + Console.WriteLine(r.AsTensor().GetArrayString()); + } } - } } diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/DisposableNamedOnnxValue.cs b/csharp/src/Microsoft.ML.OnnxRuntime/DisposableNamedOnnxValue.cs new file mode 100644 index 0000000000..f230363e6e --- /dev/null +++ b/csharp/src/Microsoft.ML.OnnxRuntime/DisposableNamedOnnxValue.cs @@ -0,0 +1,177 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Numerics.Tensors; + + +namespace Microsoft.ML.OnnxRuntime +{ + public interface IDisposableReadOnlyCollection: IReadOnlyCollection, IDisposable + { + + } + + internal class DisposableList : List, IDisposableReadOnlyCollection + where T: IDisposable + { + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // TODO: dispose managed state (managed objects). + for (int i = 0; i < this.Count; i++) + { + this[i].Dispose(); + } + this.Clear(); + } + + // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. + // TODO: set large fields to null. + + disposedValue = true; + } + } + + ~DisposableList() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(false); + } + + // This code added to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } + + + public class DisposableNamedOnnxValue: NamedOnnxValue, IDisposable + { + protected IDisposable _nativeMemoryManager; + protected DisposableNamedOnnxValue(string name, Object value, IDisposable nativeMemoryManager) + :base(name, value) + { + _nativeMemoryManager = nativeMemoryManager; + } + + + internal static DisposableNamedOnnxValue CreateFromOnnxValue(string name, IntPtr nativeOnnxValue) + { + DisposableNamedOnnxValue result = null; + + /* Get Tensor element type */ //TODO: Assumed value is Tensor, need to support non-tensor types in future + IntPtr typeAndShape = IntPtr.Zero; + TensorElementType elemType = TensorElementType.DataTypeMax; + try + { + NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorShapeAndType(nativeOnnxValue, out typeAndShape)); + elemType = NativeMethods.OrtGetTensorElementType(typeAndShape); + } + finally + { + if (typeAndShape != IntPtr.Zero) + { + NativeMethods.OrtReleaseTensorTypeAndShapeInfo(typeAndShape); + } + } + + switch (elemType) + { + case TensorElementType.Float: + result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); + break; + case TensorElementType.Double: + result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); + break; + case TensorElementType.Int16: + result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); + break; + case TensorElementType.UInt16: + result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); + break; + case TensorElementType.Int32: + result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); + break; + case TensorElementType.UInt32: + result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); + break; + case TensorElementType.Int64: + result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); + break; + case TensorElementType.UInt64: + result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); + break; + case TensorElementType.UInt8: + result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); + break; + default: + throw new NotSupportedException("Tensor of element type: " + elemType + " is not supported"); + + } + + return result; + } + + + private static DisposableNamedOnnxValue NameOnnxValueFromNativeTensor(string name, IntPtr nativeOnnxValue) + { + NativeOnnxTensorMemory nativeTensorWrapper = new NativeOnnxTensorMemory(nativeOnnxValue); + DenseTensor dt = new DenseTensor(nativeTensorWrapper.Memory, nativeTensorWrapper.Dimensions); + return new DisposableNamedOnnxValue(name, dt, nativeTensorWrapper); + } + + + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + // dispose managed state (managed objects). + if (_nativeMemoryManager != null) + { + _nativeMemoryManager.Dispose(); + _nativeMemoryManager = null; + } + } + + // free unmanaged resources (unmanaged objects) and override a finalizer below. + // set large fields to null. + disposedValue = true; + } + } + + ~DisposableNamedOnnxValue() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(false); + } + + // This code added to correctly implement the disposable pattern. + public void Dispose() + { + // Do not change this code. Put cleanup code in Dispose(bool disposing) above. + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + + } +} diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.cs b/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.cs index 5836837fda..c94c4d5db1 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/InferenceSession.cs @@ -105,7 +105,7 @@ namespace Microsoft.ML.OnnxRuntime /// /// /// Output Tensors in a Collection of NamedOnnxValue - public IReadOnlyCollection Run(IReadOnlyCollection inputs) + public IDisposableReadOnlyCollection Run(IReadOnlyCollection inputs) { string[] outputNames = new string[_outputMetadata.Count]; _outputMetadata.Keys.CopyTo(outputNames, 0); @@ -118,7 +118,7 @@ namespace Microsoft.ML.OnnxRuntime /// /// /// Output Tensors in a Collection of NamedOnnxValue - public IReadOnlyCollection Run(IReadOnlyCollection inputs, IReadOnlyCollection outputNames) + public IDisposableReadOnlyCollection Run(IReadOnlyCollection inputs, IReadOnlyCollection outputNames) { return Run(inputs, outputNames, RunOptions.Default); } @@ -129,9 +129,9 @@ namespace Microsoft.ML.OnnxRuntime /// /// /// - /// Output Tensors in a Dictionary + /// Output Tensors in a Collection of NamedOnnxValue //TODO: kept internal until RunOptions is made public - internal IReadOnlyCollection Run(IReadOnlyCollection inputs, IReadOnlyCollection outputNames, RunOptions options) + internal IDisposableReadOnlyCollection Run(IReadOnlyCollection inputs, IReadOnlyCollection outputNames, RunOptions options) { var inputNames = new string[inputs.Count]; var inputTensors = new IntPtr[inputs.Count]; @@ -166,10 +166,10 @@ namespace Microsoft.ML.OnnxRuntime try { NativeApiStatus.VerifySuccess(status); - var result = new List(); + var result = new DisposableList(); for (uint i = 0; i < outputValueArray.Length; i++) { - result.Add(NamedOnnxValue.CreateFromOnnxValue(outputNamesArray[i], outputValueArray[i])); + result.Add(DisposableNamedOnnxValue.CreateFromOnnxValue(outputNamesArray[i], outputValueArray[i])); } return result; diff --git a/csharp/src/Microsoft.ML.OnnxRuntime/NamedOnnxValue.cs b/csharp/src/Microsoft.ML.OnnxRuntime/NamedOnnxValue.cs index cf144eb256..5659d25c64 100644 --- a/csharp/src/Microsoft.ML.OnnxRuntime/NamedOnnxValue.cs +++ b/csharp/src/Microsoft.ML.OnnxRuntime/NamedOnnxValue.cs @@ -182,72 +182,6 @@ namespace Microsoft.ML.OnnxRuntime } - internal static NamedOnnxValue CreateFromOnnxValue(string name, IntPtr nativeOnnxValue) - { - NamedOnnxValue result = null; - - /* Get Tensor element type */ //TODO: Assumed value is Tensor, need to support non-tensor types in future - IntPtr typeAndShape = IntPtr.Zero; - TensorElementType elemType = TensorElementType.DataTypeMax; - try - { - NativeApiStatus.VerifySuccess(NativeMethods.OrtGetTensorShapeAndType(nativeOnnxValue, out typeAndShape)); - elemType = NativeMethods.OrtGetTensorElementType(typeAndShape); - } - finally - { - if (typeAndShape != IntPtr.Zero) - { - NativeMethods.OrtReleaseTensorTypeAndShapeInfo(typeAndShape); - } - } - - switch (elemType) - { - case TensorElementType.Float: - result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); - break; - case TensorElementType.Double: - result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); - break; - case TensorElementType.Int16: - result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); - break; - case TensorElementType.UInt16: - result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); - break; - case TensorElementType.Int32: - result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); - break; - case TensorElementType.UInt32: - result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); - break; - case TensorElementType.Int64: - result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); - break; - case TensorElementType.UInt64: - result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); - break; - case TensorElementType.UInt8: - result = NameOnnxValueFromNativeTensor(name, nativeOnnxValue); - break; - default: - throw new NotSupportedException("Tensor of element type: "+elemType+" is not supported"); - - } - - return result; - } - - - private static NamedOnnxValue NameOnnxValueFromNativeTensor(string name, IntPtr nativeOnnxValue) - { - NativeOnnxTensorMemory nativeTensorWrapper = new NativeOnnxTensorMemory(nativeOnnxValue); - DenseTensor dt = new DenseTensor(nativeTensorWrapper.Memory, nativeTensorWrapper.Dimensions); - return NamedOnnxValue.CreateFromTensor(name, dt); - } - - private bool TryPinAsTensor( out MemoryHandle pinnedMemoryHandle, out IntPtr dataBufferPointer, diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests/InferenceTest.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests/InferenceTest.cs index 9fdac5b3c6..dedfad7a57 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests/InferenceTest.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests/InferenceTest.cs @@ -70,29 +70,30 @@ namespace Microsoft.ML.OnnxRuntime.Tests } // Run the inference - var results = session.Run(container); // results is an IReadOnlyList container - - Assert.Equal(1, results.Count); - - float[] expectedOutput = LoadTensorFromFile(@"bench.expected_out"); - // validate the results - foreach (var r in results) + using (var results = session.Run(container)) // results is an IReadOnlyList container { - Assert.Equal("softmaxout_1", r.Name); + Assert.Equal(1, results.Count); - var resultTensor = r.AsTensor(); - int[] expectedDimensions = { 1, 1000, 1, 1 }; // hardcoded for now for the test data - Assert.Equal(expectedDimensions.Length, resultTensor.Rank); - - var resultDimensions = resultTensor.Dimensions; - for (int i = 0; i < expectedDimensions.Length; i++) + float[] expectedOutput = LoadTensorFromFile(@"bench.expected_out"); + // validate the results + foreach (var r in results) { - Assert.Equal(expectedDimensions[i], resultDimensions[i]); - } + Assert.Equal("softmaxout_1", r.Name); - var resultArray = r.AsTensor().ToArray(); - Assert.Equal(expectedOutput.Length, resultArray.Length); - Assert.Equal(expectedOutput, resultArray, new floatComparer()); + var resultTensor = r.AsTensor(); + int[] expectedDimensions = { 1, 1000, 1, 1 }; // hardcoded for now for the test data + Assert.Equal(expectedDimensions.Length, resultTensor.Rank); + + var resultDimensions = resultTensor.Dimensions; + for (int i = 0; i < expectedDimensions.Length; i++) + { + Assert.Equal(expectedDimensions[i], resultDimensions[i]); + } + + var resultArray = r.AsTensor().ToArray(); + Assert.Equal(expectedOutput.Length, resultArray.Length); + Assert.Equal(expectedOutput, resultArray, new floatComparer()); + } } } } @@ -247,28 +248,31 @@ namespace Microsoft.ML.OnnxRuntime.Tests } onnxModelFileName = Path.Combine(cwd, opset, modelDir.Name, onnxModelNames[0].Name); - var session = new InferenceSession(onnxModelFileName); - var inMeta = session.InputMetadata; - var innodepair = inMeta.First(); - var innodename = innodepair.Key; - var innodedims = innodepair.Value.Dimensions; - for (int i = 0; i < innodedims.Length; i++) + using (var session = new InferenceSession(onnxModelFileName)) { - if (innodedims[i] < 0) - innodedims[i] = -1 * innodedims[i]; - } + var inMeta = session.InputMetadata; + var innodepair = inMeta.First(); + var innodename = innodepair.Key; + var innodedims = innodepair.Value.Dimensions; + for (int i = 0; i < innodedims.Length; i++) + { + if (innodedims[i] < 0) + innodedims[i] = -1 * innodedims[i]; + } - var testRoot = new DirectoryInfo(Path.Combine(cwd, opset, modelDir.Name)); - var testData = testRoot.EnumerateDirectories("test_data*").First(); - var dataIn = LoadTensorFromFilePb(Path.Combine(cwd, opset, modelDir.Name, testData.ToString(), "input_0.pb")); - var dataOut = LoadTensorFromFilePb(Path.Combine(cwd, opset, modelDir.Name, testData.ToString(), "output_0.pb")); - var tensorIn = new DenseTensor(dataIn, innodedims); - var nov = new List(); - nov.Add(NamedOnnxValue.CreateFromTensor(innodename, tensorIn)); - var resnov = session.Run(nov); - var res = resnov.ToArray()[0].AsTensor().ToArray(); - Assert.Equal(res, dataOut, new floatComparer()); - session.Dispose(); + var testRoot = new DirectoryInfo(Path.Combine(cwd, opset, modelDir.Name)); + var testData = testRoot.EnumerateDirectories("test_data*").First(); + var dataIn = LoadTensorFromFilePb(Path.Combine(cwd, opset, modelDir.Name, testData.ToString(), "input_0.pb")); + var dataOut = LoadTensorFromFilePb(Path.Combine(cwd, opset, modelDir.Name, testData.ToString(), "output_0.pb")); + var tensorIn = new DenseTensor(dataIn, innodedims); + var nov = new List(); + nov.Add(NamedOnnxValue.CreateFromTensor(innodename, tensorIn)); + using (var resnov = session.Run(nov)) + { + var res = resnov.ToArray()[0].AsTensor().ToArray(); + Assert.Equal(res, dataOut, new floatComparer()); + } + } } catch (Exception ex) { @@ -284,15 +288,19 @@ namespace Microsoft.ML.OnnxRuntime.Tests { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_FLOAT.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new float[] { 1.0f, 2.0f, -3.0f, float.MinValue, float.MaxValue }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new float[] { 1.0f, 2.0f, -3.0f, float.MinValue, float.MaxValue }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } [Fact(Skip = "Boolean tensor not supported yet")] @@ -300,15 +308,18 @@ namespace Microsoft.ML.OnnxRuntime.Tests { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_BOOL.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new bool[] { true, false, true, false, true }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new bool[] { true, false, true, false, true }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } [Fact] @@ -316,15 +327,18 @@ namespace Microsoft.ML.OnnxRuntime.Tests { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_INT32.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new int[] { 1, -2, -3, int.MinValue, int.MaxValue }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new int[] { 1, -2, -3, int.MinValue, int.MaxValue }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } [Fact] @@ -332,15 +346,19 @@ namespace Microsoft.ML.OnnxRuntime.Tests { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_DOUBLE.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new double[] { 1.0, 2.0, -3.0, 5, 5 }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new double[] { 1.0, 2.0, -3.0, 5, 5 }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } + } [Fact(Skip = "String tensor not supported yet")] @@ -348,15 +366,18 @@ namespace Microsoft.ML.OnnxRuntime.Tests { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_STRING.onnx"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new string[] { "a", "c", "d", "z", "f" }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new string[] { "a", "c", "d", "z", "f" }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } [Fact(Skip = "Int8 not supported yet")] @@ -364,15 +385,18 @@ namespace Microsoft.ML.OnnxRuntime.Tests { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_INT8.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new sbyte[] { 1, 2, -3, sbyte.MinValue, sbyte.MaxValue }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new sbyte[] { 1, 2, -3, sbyte.MinValue, sbyte.MaxValue }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } [Fact] @@ -380,15 +404,18 @@ namespace Microsoft.ML.OnnxRuntime.Tests { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_UINT8.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new byte[] { 1, 2, 3, byte.MinValue, byte.MaxValue }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new byte[] { 1, 2, 3, byte.MinValue, byte.MaxValue }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } [Fact] @@ -396,15 +423,18 @@ namespace Microsoft.ML.OnnxRuntime.Tests { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_UINT16.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new UInt16[] { 1, 2, 3, UInt16.MinValue, UInt16.MaxValue }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new UInt16[] { 1, 2, 3, UInt16.MinValue, UInt16.MaxValue }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } [Fact] @@ -412,15 +442,18 @@ namespace Microsoft.ML.OnnxRuntime.Tests { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_INT16.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new Int16[] { 1, 2, 3, Int16.MinValue, Int16.MaxValue }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new Int16[] { 1, 2, 3, Int16.MinValue, Int16.MaxValue }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } [Fact] @@ -428,15 +461,18 @@ namespace Microsoft.ML.OnnxRuntime.Tests { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_INT64.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new Int64[] { 1, 2, -3, Int64.MinValue, Int64.MaxValue }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new Int64[] { 1, 2, -3, Int64.MinValue, Int64.MaxValue }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } [Fact] @@ -444,46 +480,55 @@ namespace Microsoft.ML.OnnxRuntime.Tests { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_UINT32.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new UInt32[] { 1, 2, 3, UInt32.MinValue, UInt32.MaxValue }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new UInt32[] { 1, 2, 3, UInt32.MinValue, UInt32.MaxValue }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } [Fact] private void TestModelInputUINT64() { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_UINT64.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new UInt64[] { 1, 2, 3, UInt64.MinValue, UInt64.MaxValue }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new UInt64[] { 1, 2, 3, UInt64.MinValue, UInt64.MaxValue }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } - [Fact(Skip = "Boolean FLOAT16 not available in C#")] + [Fact(Skip = "FLOAT16 not available in C#")] private void TestModelInputFLOAT16() { // model takes 1x5 input of fixed type, echoes back string modelPath = Path.Combine(Directory.GetCurrentDirectory(), "test_types_FLOAT16.pb"); - var session = new InferenceSession(modelPath); - var container = new List(); - var tensorIn = new DenseTensor(new float[] { 1.0f, 2.0f, -3.0f, float.MinValue, float.MaxValue }, new int[] { 1, 5 }); - var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); - container.Add(nov); - var res = session.Run(container); - var tensorOut = res.First().AsTensor(); - Assert.True(tensorOut.SequenceEqual(tensorIn)); - session.Dispose(); + using (var session = new InferenceSession(modelPath)) + { + var container = new List(); + var tensorIn = new DenseTensor(new float[] { 1.0f, 2.0f, -3.0f, float.MinValue, float.MaxValue }, new int[] { 1, 5 }); + var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn); + container.Add(nov); + using (var res = session.Run(container)) + { + var tensorOut = res.First().AsTensor(); + Assert.True(tensorOut.SequenceEqual(tensorIn)); + } + } } [Fact] @@ -492,15 +537,16 @@ namespace Microsoft.ML.OnnxRuntime.Tests // TODO: execute based on test pool directly (cpu or gpu) var gpu = Environment.GetEnvironmentVariable("TESTONGPU"); var tuple = (gpu != null) ? OpenSessionSqueezeNet(Int32.Parse(gpu)) : OpenSessionSqueezeNet(); - var session = tuple.Item1; - var inputData = tuple.Item2; - var tensor = tuple.Item3; - var inputMeta = session.InputMetadata; - var container = new List(); - container.Add(NamedOnnxValue.CreateFromTensor("input", tensor)); - var ex = Assert.Throws(() => session.Run(container)); - Assert.Equal("[ErrorCode:InvalidArgument] Missing required inputs: data_0", ex.Message); - session.Dispose(); + using (var session = tuple.Item1) + { + var inputData = tuple.Item2; + var tensor = tuple.Item3; + var inputMeta = session.InputMetadata; + var container = new List(); + container.Add(NamedOnnxValue.CreateFromTensor("input", tensor)); + var ex = Assert.Throws(() => session.Run(container)); + Assert.Equal("[ErrorCode:InvalidArgument] Missing required inputs: data_0", ex.Message); + } } [DllImport("kernel32", SetLastError = true)] diff --git a/csharp/test/Microsoft.ML.OnnxRuntime.Tests/OnnxMl.cs b/csharp/test/Microsoft.ML.OnnxRuntime.Tests/OnnxMl.cs index 209e62c30a..f6e2654ac0 100644 --- a/csharp/test/Microsoft.ML.OnnxRuntime.Tests/OnnxMl.cs +++ b/csharp/test/Microsoft.ML.OnnxRuntime.Tests/OnnxMl.cs @@ -53,39 +53,43 @@ namespace Onnx { "b3RvEhIKCmRvY19zdHJpbmcYCiABKAkSIwoFaW5wdXQYCyADKAsyFC5vbm54", "LlZhbHVlSW5mb1Byb3RvEiQKBm91dHB1dBgMIAMoCzIULm9ubnguVmFsdWVJ", "bmZvUHJvdG8SKAoKdmFsdWVfaW5mbxgNIAMoCzIULm9ubnguVmFsdWVJbmZv", - "UHJvdG8ioQQKC1RlbnNvclByb3RvEgwKBGRpbXMYASADKAMSEQoJZGF0YV90", + "UHJvdG8iuAUKC1RlbnNvclByb3RvEgwKBGRpbXMYASADKAMSEQoJZGF0YV90", "eXBlGAIgASgFEioKB3NlZ21lbnQYAyABKAsyGS5vbm54LlRlbnNvclByb3Rv", "LlNlZ21lbnQSFgoKZmxvYXRfZGF0YRgEIAMoAkICEAESFgoKaW50MzJfZGF0", "YRgFIAMoBUICEAESEwoLc3RyaW5nX2RhdGEYBiADKAwSFgoKaW50NjRfZGF0", "YRgHIAMoA0ICEAESDAoEbmFtZRgIIAEoCRISCgpkb2Nfc3RyaW5nGAwgASgJ", - "EhAKCHJhd19kYXRhGAkgASgMEhcKC2RvdWJsZV9kYXRhGAogAygBQgIQARIX", - "Cgt1aW50NjRfZGF0YRgLIAMoBEICEAEaJQoHU2VnbWVudBINCgViZWdpbhgB", - "IAEoAxILCgNlbmQYAiABKAMi2gEKCERhdGFUeXBlEg0KCVVOREVGSU5FRBAA", - "EgkKBUZMT0FUEAESCQoFVUlOVDgQAhIICgRJTlQ4EAMSCgoGVUlOVDE2EAQS", - "CQoFSU5UMTYQBRIJCgVJTlQzMhAGEgkKBUlOVDY0EAcSCgoGU1RSSU5HEAgS", - "CAoEQk9PTBAJEgsKB0ZMT0FUMTYQChIKCgZET1VCTEUQCxIKCgZVSU5UMzIQ", - "DBIKCgZVSU5UNjQQDRINCglDT01QTEVYNjQQDhIOCgpDT01QTEVYMTI4EA8S", - "DAoIQkZMT0FUMTYQECKVAQoQVGVuc29yU2hhcGVQcm90bxItCgNkaW0YASAD", - "KAsyIC5vbm54LlRlbnNvclNoYXBlUHJvdG8uRGltZW5zaW9uGlIKCURpbWVu", - "c2lvbhITCglkaW1fdmFsdWUYASABKANIABITCglkaW1fcGFyYW0YAiABKAlI", - "ABISCgpkZW5vdGF0aW9uGAMgASgJQgcKBXZhbHVlIsIECglUeXBlUHJvdG8S", - "LQoLdGVuc29yX3R5cGUYASABKAsyFi5vbm54LlR5cGVQcm90by5UZW5zb3JI", - "ABIxCg1zZXF1ZW5jZV90eXBlGAQgASgLMhgub25ueC5UeXBlUHJvdG8uU2Vx", - "dWVuY2VIABInCghtYXBfdHlwZRgFIAEoCzITLm9ubnguVHlwZVByb3RvLk1h", - "cEgAEi0KC29wYXF1ZV90eXBlGAcgASgLMhYub25ueC5UeXBlUHJvdG8uT3Bh", - "cXVlSAASOgoSc3BhcnNlX3RlbnNvcl90eXBlGAggASgLMhwub25ueC5UeXBl", - "UHJvdG8uU3BhcnNlVGVuc29ySAASEgoKZGVub3RhdGlvbhgGIAEoCRpCCgZU", - "ZW5zb3ISEQoJZWxlbV90eXBlGAEgASgFEiUKBXNoYXBlGAIgASgLMhYub25u", - "eC5UZW5zb3JTaGFwZVByb3RvGi4KCFNlcXVlbmNlEiIKCWVsZW1fdHlwZRgB", - "IAEoCzIPLm9ubnguVHlwZVByb3RvGjwKA01hcBIQCghrZXlfdHlwZRgBIAEo", - "BRIjCgp2YWx1ZV90eXBlGAIgASgLMg8ub25ueC5UeXBlUHJvdG8aJgoGT3Bh", - "cXVlEg4KBmRvbWFpbhgBIAEoCRIMCgRuYW1lGAIgASgJGkgKDFNwYXJzZVRl", - "bnNvchIRCgllbGVtX3R5cGUYASABKAUSJQoFc2hhcGUYAiABKAsyFi5vbm54", - "LlRlbnNvclNoYXBlUHJvdG9CBwoFdmFsdWUiNQoST3BlcmF0b3JTZXRJZFBy", - "b3RvEg4KBmRvbWFpbhgBIAEoCRIPCgd2ZXJzaW9uGAIgASgDKmMKB1ZlcnNp", - "b24SEgoOX1NUQVJUX1ZFUlNJT04QABIZChVJUl9WRVJTSU9OXzIwMTdfMTBf", - "MTAQARIZChVJUl9WRVJTSU9OXzIwMTdfMTBfMzAQAhIOCgpJUl9WRVJTSU9O", - "EANiBnByb3RvMw==")); + "EhAKCHJhd19kYXRhGAkgASgMEjMKDWV4dGVybmFsX2RhdGEYDSADKAsyHC5v", + "bm54LlN0cmluZ1N0cmluZ0VudHJ5UHJvdG8SNQoNZGF0YV9sb2NhdGlvbhgO", + "IAEoDjIeLm9ubnguVGVuc29yUHJvdG8uRGF0YUxvY2F0aW9uEhcKC2RvdWJs", + "ZV9kYXRhGAogAygBQgIQARIXCgt1aW50NjRfZGF0YRgLIAMoBEICEAEaJQoH", + "U2VnbWVudBINCgViZWdpbhgBIAEoAxILCgNlbmQYAiABKAMi2gEKCERhdGFU", + "eXBlEg0KCVVOREVGSU5FRBAAEgkKBUZMT0FUEAESCQoFVUlOVDgQAhIICgRJ", + "TlQ4EAMSCgoGVUlOVDE2EAQSCQoFSU5UMTYQBRIJCgVJTlQzMhAGEgkKBUlO", + "VDY0EAcSCgoGU1RSSU5HEAgSCAoEQk9PTBAJEgsKB0ZMT0FUMTYQChIKCgZE", + "T1VCTEUQCxIKCgZVSU5UMzIQDBIKCgZVSU5UNjQQDRINCglDT01QTEVYNjQQ", + "DhIOCgpDT01QTEVYMTI4EA8SDAoIQkZMT0FUMTYQECIpCgxEYXRhTG9jYXRp", + "b24SCwoHREVGQVVMVBAAEgwKCEVYVEVSTkFMEAEilQEKEFRlbnNvclNoYXBl", + "UHJvdG8SLQoDZGltGAEgAygLMiAub25ueC5UZW5zb3JTaGFwZVByb3RvLkRp", + "bWVuc2lvbhpSCglEaW1lbnNpb24SEwoJZGltX3ZhbHVlGAEgASgDSAASEwoJ", + "ZGltX3BhcmFtGAIgASgJSAASEgoKZGVub3RhdGlvbhgDIAEoCUIHCgV2YWx1", + "ZSLCBAoJVHlwZVByb3RvEi0KC3RlbnNvcl90eXBlGAEgASgLMhYub25ueC5U", + "eXBlUHJvdG8uVGVuc29ySAASMQoNc2VxdWVuY2VfdHlwZRgEIAEoCzIYLm9u", + "bnguVHlwZVByb3RvLlNlcXVlbmNlSAASJwoIbWFwX3R5cGUYBSABKAsyEy5v", + "bm54LlR5cGVQcm90by5NYXBIABItCgtvcGFxdWVfdHlwZRgHIAEoCzIWLm9u", + "bnguVHlwZVByb3RvLk9wYXF1ZUgAEjoKEnNwYXJzZV90ZW5zb3JfdHlwZRgI", + "IAEoCzIcLm9ubnguVHlwZVByb3RvLlNwYXJzZVRlbnNvckgAEhIKCmRlbm90", + "YXRpb24YBiABKAkaQgoGVGVuc29yEhEKCWVsZW1fdHlwZRgBIAEoBRIlCgVz", + "aGFwZRgCIAEoCzIWLm9ubnguVGVuc29yU2hhcGVQcm90bxouCghTZXF1ZW5j", + "ZRIiCgllbGVtX3R5cGUYASABKAsyDy5vbm54LlR5cGVQcm90bxo8CgNNYXAS", + "EAoIa2V5X3R5cGUYASABKAUSIwoKdmFsdWVfdHlwZRgCIAEoCzIPLm9ubngu", + "VHlwZVByb3RvGiYKBk9wYXF1ZRIOCgZkb21haW4YASABKAkSDAoEbmFtZRgC", + "IAEoCRpICgxTcGFyc2VUZW5zb3ISEQoJZWxlbV90eXBlGAEgASgFEiUKBXNo", + "YXBlGAIgASgLMhYub25ueC5UZW5zb3JTaGFwZVByb3RvQgcKBXZhbHVlIjUK", + "Ek9wZXJhdG9yU2V0SWRQcm90bxIOCgZkb21haW4YASABKAkSDwoHdmVyc2lv", + "bhgCIAEoAyp9CgdWZXJzaW9uEhIKDl9TVEFSVF9WRVJTSU9OEAASGQoVSVJf", + "VkVSU0lPTl8yMDE3XzEwXzEwEAESGQoVSVJfVkVSU0lPTl8yMDE3XzEwXzMw", + "EAISGAoUSVJfVkVSU0lPTl8yMDE3XzExXzMQAxIOCgpJUl9WRVJTSU9OEARi", + "BnByb3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Onnx.Version), }, new pbr::GeneratedClrTypeInfo[] { @@ -95,7 +99,7 @@ namespace Onnx { new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.ModelProto), global::Onnx.ModelProto.Parser, new[]{ "IrVersion", "OpsetImport", "ProducerName", "ProducerVersion", "Domain", "ModelVersion", "DocString", "Graph", "MetadataProps" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.StringStringEntryProto), global::Onnx.StringStringEntryProto.Parser, new[]{ "Key", "Value" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.GraphProto), global::Onnx.GraphProto.Parser, new[]{ "Node", "Name", "Initializer", "DocString", "Input", "Output", "ValueInfo" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TensorProto), global::Onnx.TensorProto.Parser, new[]{ "Dims", "DataType", "Segment", "FloatData", "Int32Data", "StringData", "Int64Data", "Name", "DocString", "RawData", "DoubleData", "Uint64Data" }, null, new[]{ typeof(global::Onnx.TensorProto.Types.DataType) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TensorProto.Types.Segment), global::Onnx.TensorProto.Types.Segment.Parser, new[]{ "Begin", "End" }, null, null, null)}), + new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TensorProto), global::Onnx.TensorProto.Parser, new[]{ "Dims", "DataType", "Segment", "FloatData", "Int32Data", "StringData", "Int64Data", "Name", "DocString", "RawData", "ExternalData", "DataLocation", "DoubleData", "Uint64Data" }, null, new[]{ typeof(global::Onnx.TensorProto.Types.DataType), typeof(global::Onnx.TensorProto.Types.DataLocation) }, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TensorProto.Types.Segment), global::Onnx.TensorProto.Types.Segment.Parser, new[]{ "Begin", "End" }, null, null, null)}), new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TensorShapeProto), global::Onnx.TensorShapeProto.Parser, new[]{ "Dim" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TensorShapeProto.Types.Dimension), global::Onnx.TensorShapeProto.Types.Dimension.Parser, new[]{ "DimValue", "DimParam", "Denotation" }, new[]{ "Value" }, null, null)}), new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TypeProto), global::Onnx.TypeProto.Parser, new[]{ "TensorType", "SequenceType", "MapType", "OpaqueType", "SparseTensorType", "Denotation" }, new[]{ "Value" }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TypeProto.Types.Tensor), global::Onnx.TypeProto.Types.Tensor.Parser, new[]{ "ElemType", "Shape" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Onnx.TypeProto.Types.Sequence), global::Onnx.TypeProto.Types.Sequence.Parser, new[]{ "ElemType" }, null, null, null), @@ -143,7 +147,13 @@ namespace Onnx { /// - Added opset_import in ModelProto /// - For vendor extensions, added domain in NodeProto /// - [pbr::OriginalName("IR_VERSION")] IrVersion = 3, + [pbr::OriginalName("IR_VERSION_2017_11_3")] IrVersion2017113 = 3, + /// + /// IR VERSION 4 published on Jan 22, 2019 + /// - Relax constraint that initializers should be a subset of graph inputs + /// - Add type BFLOAT16 + /// + [pbr::OriginalName("IR_VERSION")] IrVersion = 4, } #endregion @@ -1846,7 +1856,7 @@ namespace Onnx { /// /// A list of named tensor values, used to specify constant inputs of the graph. /// Each TensorProto entry must have a distinct name (within the list) that - /// also appears in the input list. + /// MAY also appear in the input list. /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute] public pbc::RepeatedField Initializer { @@ -2089,6 +2099,8 @@ namespace Onnx { name_ = other.name_; docString_ = other.docString_; rawData_ = other.rawData_; + externalData_ = other.externalData_.Clone(); + dataLocation_ = other.dataLocation_; doubleData_ = other.doubleData_.Clone(); uint64Data_ = other.uint64Data_.Clone(); _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields); @@ -2261,6 +2273,41 @@ namespace Onnx { } } + /// Field number for the "external_data" field. + public const int ExternalDataFieldNumber = 13; + private static readonly pb::FieldCodec _repeated_externalData_codec + = pb::FieldCodec.ForMessage(106, global::Onnx.StringStringEntryProto.Parser); + private readonly pbc::RepeatedField externalData_ = new pbc::RepeatedField(); + /// + /// Data can be stored inside the protobuf file using type-specific fields or raw_data. + /// Alternatively, raw bytes data can be stored in an external file, using the external_data field. + /// external_data stores key-value pairs describing data location. Recognized keys are: + /// - "location" (required) - POSIX filesystem path relative to the directory where the ONNX + /// protobuf model was stored + /// - "offset" (optional) - position of byte at which stored data begins. Integer stored as string. + /// Offset values SHOULD be multiples 4096 (page size) to enable mmap support. + /// - "length" (optional) - number of bytes containing data. Integer stored as string. + /// - "checksum" (optional) - SHA1 digest of file specified in under 'location' key. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public pbc::RepeatedField ExternalData { + get { return externalData_; } + } + + /// Field number for the "data_location" field. + public const int DataLocationFieldNumber = 14; + private global::Onnx.TensorProto.Types.DataLocation dataLocation_ = 0; + /// + /// If value not set, data is stored in raw_data (if set) otherwise in type-specified field. + /// + [global::System.Diagnostics.DebuggerNonUserCodeAttribute] + public global::Onnx.TensorProto.Types.DataLocation DataLocation { + get { return dataLocation_; } + set { + dataLocation_ = value; + } + } + /// Field number for the "double_data" field. public const int DoubleDataFieldNumber = 10; private static readonly pb::FieldCodec _repeated_doubleData_codec @@ -2318,6 +2365,8 @@ namespace Onnx { if (Name != other.Name) return false; if (DocString != other.DocString) return false; if (RawData != other.RawData) return false; + if(!externalData_.Equals(other.externalData_)) return false; + if (DataLocation != other.DataLocation) return false; if(!doubleData_.Equals(other.doubleData_)) return false; if(!uint64Data_.Equals(other.uint64Data_)) return false; return Equals(_unknownFields, other._unknownFields); @@ -2336,6 +2385,8 @@ namespace Onnx { if (Name.Length != 0) hash ^= Name.GetHashCode(); if (DocString.Length != 0) hash ^= DocString.GetHashCode(); if (RawData.Length != 0) hash ^= RawData.GetHashCode(); + hash ^= externalData_.GetHashCode(); + if (DataLocation != 0) hash ^= DataLocation.GetHashCode(); hash ^= doubleData_.GetHashCode(); hash ^= uint64Data_.GetHashCode(); if (_unknownFields != null) { @@ -2378,6 +2429,11 @@ namespace Onnx { output.WriteRawTag(98); output.WriteString(DocString); } + externalData_.WriteTo(output, _repeated_externalData_codec); + if (DataLocation != 0) { + output.WriteRawTag(112); + output.WriteEnum((int) DataLocation); + } if (_unknownFields != null) { _unknownFields.WriteTo(output); } @@ -2406,6 +2462,10 @@ namespace Onnx { if (RawData.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeBytesSize(RawData); } + size += externalData_.CalculateSize(_repeated_externalData_codec); + if (DataLocation != 0) { + size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) DataLocation); + } size += doubleData_.CalculateSize(_repeated_doubleData_codec); size += uint64Data_.CalculateSize(_repeated_uint64Data_codec); if (_unknownFields != null) { @@ -2442,6 +2502,10 @@ namespace Onnx { if (other.RawData.Length != 0) { RawData = other.RawData; } + externalData_.Add(other.externalData_); + if (other.DataLocation != 0) { + DataLocation = other.DataLocation; + } doubleData_.Add(other.doubleData_); uint64Data_.Add(other.uint64Data_); _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields); @@ -2512,6 +2576,14 @@ namespace Onnx { DocString = input.ReadString(); break; } + case 106: { + externalData_.AddEntriesFrom(input, _repeated_externalData_codec); + break; + } + case 112: { + dataLocation_ = (global::Onnx.TensorProto.Types.DataLocation) input.ReadEnum(); + break; + } } } } @@ -2582,6 +2654,16 @@ namespace Onnx { [pbr::OriginalName("BFLOAT16")] Bfloat16 = 16, } + /// + /// Location of the data for this tensor. MUST be one of: + /// - DEFAULT - data stored inside the protobuf message. Data is stored in raw_data (if set) otherwise in type-specified field. + /// - EXTERNAL - data stored in an external location as described by external_data field. + /// + public enum DataLocation { + [pbr::OriginalName("DEFAULT")] Default = 0, + [pbr::OriginalName("EXTERNAL")] External = 1, + } + /// /// For very large tensors, we may want to store them in chunks, in which /// case the following fields will specify the segment that is stored in