mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-05-18 21:21:17 +00:00
### Description <!-- Describe your changes. --> Update some testing dependencies. Fix various warnings. Mainly around documentation (existing) and unit test usage (mainly resulting from xunit update). Invalid angle brackets for generics in documentation were changed to use curly braces based on https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/xmldoc/ > To refer to generic identifiers in code reference (cref) elements, you can use either the escape characters (for example, cref="List<T>") or braces (cref="List{T}"). As a special case, the compiler parses the braces as angle brackets to make the documentation comment less cumbersome to the author when referring to generic identifiers. ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. -->
2141 lines
100 KiB
C#
2141 lines
100 KiB
C#
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
using Microsoft.ML.OnnxRuntime.Tensors;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Linq.Expressions;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
using System.Runtime.InteropServices;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
// This runs in a separate package built from EndToEndTests
|
|
// and for this reason it can not refer to non-public members
|
|
// of Onnxruntime package
|
|
namespace Microsoft.ML.OnnxRuntime.Tests
|
|
{
|
|
// This is to make sure it does not run in parallel with OrtEnvTests
|
|
// or any other test class within the same collection
|
|
[Collection("Ort Inference Tests")]
|
|
public partial class InferenceTest
|
|
{
|
|
private readonly ITestOutputHelper output;
|
|
|
|
public InferenceTest(ITestOutputHelper o)
|
|
{
|
|
this.output = o;
|
|
}
|
|
|
|
[Fact(DisplayName = "TestSessionOptions")]
|
|
public void TestSessionOptions()
|
|
{
|
|
// get instance to setup logging
|
|
var ortEnvInstance = OrtEnv.Instance();
|
|
|
|
using (SessionOptions opt = new SessionOptions())
|
|
{
|
|
Assert.NotNull(opt);
|
|
|
|
// check default values of the properties
|
|
Assert.Equal(ExecutionMode.ORT_SEQUENTIAL, opt.ExecutionMode);
|
|
Assert.True(opt.EnableMemoryPattern);
|
|
Assert.False(opt.EnableProfiling);
|
|
Assert.Equal("onnxruntime_profile_", opt.ProfileOutputPathPrefix);
|
|
Assert.True(opt.EnableCpuMemArena);
|
|
Assert.Equal("", opt.LogId);
|
|
Assert.Equal(0, opt.LogVerbosityLevel);
|
|
Assert.Equal(OrtLoggingLevel.ORT_LOGGING_LEVEL_WARNING, opt.LogSeverityLevel);
|
|
Assert.Equal(0, opt.IntraOpNumThreads);
|
|
Assert.Equal(0, opt.InterOpNumThreads);
|
|
Assert.Equal(GraphOptimizationLevel.ORT_ENABLE_ALL, opt.GraphOptimizationLevel);
|
|
|
|
// No get, so no verify
|
|
opt.DisablePerSessionThreads();
|
|
|
|
// try setting options
|
|
opt.ExecutionMode = ExecutionMode.ORT_PARALLEL;
|
|
Assert.Equal(ExecutionMode.ORT_PARALLEL, opt.ExecutionMode);
|
|
|
|
opt.EnableMemoryPattern = false;
|
|
Assert.False(opt.EnableMemoryPattern);
|
|
|
|
opt.EnableProfiling = true;
|
|
Assert.True(opt.EnableProfiling);
|
|
Assert.Equal("onnxruntime_profile_", opt.ProfileOutputPathPrefix);
|
|
|
|
opt.ProfileOutputPathPrefix = "Ort_P_";
|
|
Assert.Equal("Ort_P_", opt.ProfileOutputPathPrefix);
|
|
|
|
opt.EnableCpuMemArena = false;
|
|
Assert.False(opt.EnableCpuMemArena);
|
|
|
|
opt.LogId = "MyLogId";
|
|
Assert.Equal("MyLogId", opt.LogId);
|
|
|
|
opt.LogVerbosityLevel = 1;
|
|
Assert.Equal(1, opt.LogVerbosityLevel);
|
|
|
|
opt.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_WARNING;
|
|
Assert.Equal(OrtLoggingLevel.ORT_LOGGING_LEVEL_WARNING, opt.LogSeverityLevel);
|
|
|
|
opt.IntraOpNumThreads = 4;
|
|
Assert.Equal(4, opt.IntraOpNumThreads);
|
|
|
|
opt.InterOpNumThreads = 4;
|
|
Assert.Equal(4, opt.InterOpNumThreads);
|
|
|
|
opt.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_EXTENDED;
|
|
Assert.Equal(GraphOptimizationLevel.ORT_ENABLE_EXTENDED, opt.GraphOptimizationLevel);
|
|
|
|
Assert.Throws<OnnxRuntimeException>(() => { opt.GraphOptimizationLevel = (GraphOptimizationLevel)10; });
|
|
|
|
opt.AddSessionConfigEntry("key", "value");
|
|
|
|
var ex = Assert.Throws<OnnxRuntimeException>(() => { opt.AddSessionConfigEntry("", "invalid key"); });
|
|
Assert.Contains("[ErrorCode:InvalidArgument] Config key is empty", ex.Message);
|
|
|
|
// SessionOptions.RegisterOrtExtensions can be manually tested by referencing the
|
|
// Microsoft.ML.OnnxRuntime.Extensions nuget package. After that is done, this should not throw.
|
|
ex = Assert.Throws<OnnxRuntimeException>(() => { opt.RegisterOrtExtensions(); });
|
|
Assert.Contains("Microsoft.ML.OnnxRuntime.Extensions NuGet package must be referenced", ex.Message);
|
|
|
|
#if USE_CUDA
|
|
opt.AppendExecutionProvider_CUDA(0);
|
|
#endif
|
|
|
|
#if USE_DML
|
|
// Explicitly set dll probe path so that the (potentially) stale system DirectML.dll
|
|
// doesn't get loaded by the test process when it is eventually delay loaded by onnruntime.dll
|
|
// The managed tests binary path already contains the right DirectML.dll, so use that
|
|
|
|
var directml_dll_path = AppDomain.CurrentDomain.BaseDirectory;
|
|
SetDllDirectory(directml_dll_path);
|
|
|
|
try
|
|
{
|
|
opt.AppendExecutionProvider_DML(0);
|
|
}
|
|
catch (OnnxRuntimeException ortException)
|
|
{
|
|
// if we run on a CI machine with the incorrect hardware we might get an error due to that.
|
|
// allow that as the call made it through to the DML EP so the C# layer is working correctly.
|
|
// any other exception type or error message is considered a failure.
|
|
Assert.Contains("The specified device interface or feature level is not supported on this system.",
|
|
ortException.Message);
|
|
}
|
|
|
|
// Restore the default dll search order
|
|
SetDllDirectory(null);
|
|
#endif
|
|
|
|
#if USE_DNNL
|
|
opt.AppendExecutionProvider_Dnnl(0);
|
|
#endif
|
|
|
|
#if USE_MIGRAPHX
|
|
opt.AppendExecutionProvider_MIGraphX(0);
|
|
#endif
|
|
|
|
#if USE_NNAPI
|
|
opt.AppendExecutionProvider_Nnapi(0);
|
|
#endif
|
|
|
|
#if USE_TVM
|
|
opt.AppendExecutionProvider_Tvm("Vulkan -device=amd_apu");
|
|
#endif
|
|
|
|
#if USE_OPENVINO
|
|
opt.AppendExecutionProvider_OpenVINO();
|
|
#endif
|
|
|
|
#if USE_ROCM
|
|
opt.AppendExecutionProvider_ROCm(0);
|
|
#endif
|
|
|
|
#if USE_TENSORRT
|
|
opt.AppendExecutionProvider_Tensorrt(0);
|
|
#endif
|
|
#if USE_XNNPACK
|
|
opt.AppendExecutionProvider("XNNPACK");
|
|
#else
|
|
ex = Assert.Throws<OnnxRuntimeException>(() => { opt.AppendExecutionProvider("XNNPACK"); });
|
|
Assert.Contains("XNNPACK execution provider is not supported in this build", ex.Message);
|
|
#endif
|
|
#if USE_SNPE
|
|
opt.AppendExecutionProvider("SNPE");
|
|
#else
|
|
ex = Assert.Throws<OnnxRuntimeException>(() => { opt.AppendExecutionProvider("SNPE"); });
|
|
Assert.Contains("SNPE execution provider is not supported in this build", ex.Message);
|
|
#endif
|
|
#if USE_QNN
|
|
opt.AppendExecutionProvider("QNN");
|
|
#else
|
|
ex = Assert.Throws<OnnxRuntimeException>(() => { opt.AppendExecutionProvider("QNN"); });
|
|
Assert.Contains("QNN execution provider is not supported in this build", ex.Message);
|
|
#endif
|
|
|
|
opt.AppendExecutionProvider_CPU(1);
|
|
}
|
|
}
|
|
|
|
#if! __MOBILE__
|
|
// Use to set dll probe path so that the right dll(s) is loaded by the test process
|
|
// Invoke only to specify Windows specific EPs' dll locations explicitly
|
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
|
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
static extern bool SetDllDirectory(string lpPathName);
|
|
#else
|
|
static bool SetDllDirectory(string lpPathName)
|
|
{
|
|
throw new NotSupportedException();
|
|
}
|
|
#endif
|
|
|
|
[Fact(DisplayName = "TestRunOptions")]
|
|
public void TestRunOptions()
|
|
{
|
|
using (var opt = new RunOptions())
|
|
{
|
|
Assert.NotNull(opt);
|
|
|
|
//verify default options
|
|
Assert.False(opt.Terminate);
|
|
Assert.Equal(0, opt.LogVerbosityLevel);
|
|
Assert.Equal(OrtLoggingLevel.ORT_LOGGING_LEVEL_WARNING, opt.LogSeverityLevel);
|
|
Assert.Equal("", opt.LogId);
|
|
|
|
// try setting options
|
|
opt.Terminate = true;
|
|
Assert.True(opt.Terminate);
|
|
|
|
opt.LogVerbosityLevel = 1;
|
|
Assert.Equal(1, opt.LogVerbosityLevel);
|
|
|
|
opt.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_WARNING;
|
|
Assert.Equal(OrtLoggingLevel.ORT_LOGGING_LEVEL_WARNING, opt.LogSeverityLevel);
|
|
|
|
opt.LogId = "MyLogTag";
|
|
Assert.Equal("MyLogTag", opt.LogId);
|
|
|
|
opt.AddRunConfigEntry("key", "value");
|
|
|
|
var ex = Assert.Throws<OnnxRuntimeException>(() => { opt.AddRunConfigEntry("", "missing key"); });
|
|
Assert.Contains("[ErrorCode:InvalidArgument] Config key is empty", ex.Message);
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestThreadingOptions")]
|
|
public void TestThreadingOptions()
|
|
{
|
|
using (var opt = new OrtThreadingOptions())
|
|
{
|
|
Assert.NotNull(opt);
|
|
|
|
//verify default options
|
|
opt.GlobalSpinControl = false;
|
|
opt.GlobalInterOpNumThreads = 1;
|
|
opt.GlobalIntraOpNumThreads = 1;
|
|
opt.SetGlobalDenormalAsZero();
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "CanCreateAndDisposeSessionWithModel")]
|
|
public void CanCreateAndDisposeSessionWithModel()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx");
|
|
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
Assert.NotNull(session);
|
|
Assert.NotNull(session.InputMetadata);
|
|
Assert.Single(session.InputMetadata); // 1 input node
|
|
Assert.True(session.InputMetadata.ContainsKey("data_0")); // input node name
|
|
Assert.Equal(typeof(float), session.InputMetadata["data_0"].ElementType);
|
|
Assert.True(session.InputMetadata["data_0"].IsTensor);
|
|
var expectedInputDimensions = new int[] { 1, 3, 224, 224 };
|
|
Assert.Equal(expectedInputDimensions.Length, session.InputMetadata["data_0"].Dimensions.Length);
|
|
for (int i = 0; i < expectedInputDimensions.Length; i++)
|
|
{
|
|
Assert.Equal(expectedInputDimensions[i], session.InputMetadata["data_0"].Dimensions[i]);
|
|
}
|
|
|
|
Assert.NotNull(session.OutputMetadata);
|
|
Assert.Single(session.OutputMetadata); // 1 output node
|
|
Assert.True(session.OutputMetadata.ContainsKey("softmaxout_1")); // output node name
|
|
Assert.Equal(typeof(float), session.OutputMetadata["softmaxout_1"].ElementType);
|
|
Assert.True(session.OutputMetadata["softmaxout_1"].IsTensor);
|
|
var expectedOutputDimensions = new int[] { 1, 1000, 1, 1 };
|
|
Assert.Equal(expectedOutputDimensions.Length, session.OutputMetadata["softmaxout_1"].Dimensions.Length);
|
|
for (int i = 0; i < expectedOutputDimensions.Length; i++)
|
|
{
|
|
Assert.Equal(expectedOutputDimensions[i], session.OutputMetadata["softmaxout_1"].Dimensions[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Theory(DisplayName = "CanRunInferenceOnAModel")]
|
|
[InlineData(GraphOptimizationLevel.ORT_DISABLE_ALL, true)]
|
|
[InlineData(GraphOptimizationLevel.ORT_DISABLE_ALL, false)]
|
|
[InlineData(GraphOptimizationLevel.ORT_ENABLE_EXTENDED, true)]
|
|
[InlineData(GraphOptimizationLevel.ORT_ENABLE_EXTENDED, false)]
|
|
private void CanRunInferenceOnAModel(GraphOptimizationLevel graphOptimizationLevel, bool enableParallelExecution)
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx");
|
|
|
|
using (var cleanUp = new DisposableListTest<IDisposable>())
|
|
{
|
|
// Set the graph optimization level for this session.
|
|
SessionOptions options = new SessionOptions();
|
|
cleanUp.Add(options);
|
|
options.GraphOptimizationLevel = graphOptimizationLevel;
|
|
if (enableParallelExecution) options.ExecutionMode = ExecutionMode.ORT_PARALLEL;
|
|
|
|
var session = new InferenceSession(model, options);
|
|
cleanUp.Add(session);
|
|
|
|
var inputMeta = session.InputMetadata;
|
|
var outputMeta = session.OutputMetadata;
|
|
var container = new List<NamedOnnxValue>();
|
|
|
|
float[] expectedOutput = TestDataLoader.LoadTensorFromEmbeddedResource("bench.expected_out");
|
|
int[] expectedDimensions = { 1, 1000, 1, 1 }; // hardcoded for now for the test data
|
|
ReadOnlySpan<int> expectedOutputDimensions = expectedDimensions;
|
|
string[] expectedOutputNames = new string[] { "softmaxout_1" };
|
|
|
|
float[] inputData = TestDataLoader.LoadTensorFromEmbeddedResource("bench.in"); // this is the data for only one input tensor for this model
|
|
|
|
foreach (var name in inputMeta.Keys)
|
|
{
|
|
Assert.Equal(typeof(float), inputMeta[name].ElementType);
|
|
Assert.True(inputMeta[name].IsTensor);
|
|
var tensor = new DenseTensor<float>(inputData, inputMeta[name].Dimensions);
|
|
container.Add(NamedOnnxValue.CreateFromTensor<float>(name, tensor));
|
|
}
|
|
|
|
// Run inference with named inputs and outputs created with in Run()
|
|
using (var results = session.Run(container)) // results is an IReadOnlyList<NamedOnnxValue> container
|
|
{
|
|
ValidateRunResults(results);
|
|
}
|
|
|
|
// Run inference with named inputs, outputs created with in Run() and RunOptions
|
|
using (var runOptions = new RunOptions())
|
|
{
|
|
runOptions.LogId = "CsharpTest";
|
|
runOptions.Terminate = false; // TODO: Test terminate = true, it currently crashes
|
|
runOptions.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_ERROR;
|
|
IReadOnlyCollection<string> outputNames = session.OutputMetadata.Keys.ToList();
|
|
|
|
using (var results = session.Run(container, outputNames, runOptions)) // results is an IReadOnlyList<NamedOnnxValue> container
|
|
{
|
|
ValidateRunResults(results);
|
|
}
|
|
}
|
|
|
|
// Run inference with pinned inputs and outputs created with in Run()
|
|
using (var pinnedInputs = new DisposableListTest<FixedBufferOnnxValue>())
|
|
{
|
|
var inputNames = container.Select(i => i.Name).ToArray();
|
|
pinnedInputs.AddRange(container.Select(i => FixedBufferOnnxValue.CreateFromTensor(i.AsTensor<float>())));
|
|
|
|
// output names not specified
|
|
using (var results = session.Run(inputNames, pinnedInputs)) // results is an IReadOnlyList<NamedOnnxValue> container
|
|
{
|
|
ValidateRunResults(results);
|
|
}
|
|
|
|
// output names specified explicitly
|
|
using (var results = session.Run(inputNames, pinnedInputs, expectedOutputNames)) // results is an IReadOnlyList<NamedOnnxValue> container
|
|
{
|
|
ValidateRunResults(results);
|
|
}
|
|
}
|
|
|
|
// Run inference with outputs pinned from buffers
|
|
using (var pinnedInputs = new DisposableListTest<FixedBufferOnnxValue>())
|
|
using (var pinnedOutputs = new DisposableListTest<FixedBufferOnnxValue>())
|
|
{
|
|
var memInfo = OrtMemoryInfo.DefaultInstance; // CPU
|
|
|
|
// Create inputs
|
|
Assert.Single(inputMeta.Keys);
|
|
var inputNames = inputMeta.Keys.ToArray();
|
|
var inputName = inputNames[0];
|
|
Assert.Equal(typeof(float), inputMeta[inputName].ElementType);
|
|
Assert.True(inputMeta[inputName].IsTensor);
|
|
var longShape = Array.ConvertAll<int, long>(inputMeta[inputName].Dimensions, Convert.ToInt64);
|
|
var byteSize = ShapeUtils.GetSizeForShape(longShape);
|
|
pinnedInputs.Add(FixedBufferOnnxValue.CreateFromMemory<float>(memInfo, inputData,
|
|
TensorElementType.Float, longShape, byteSize));
|
|
|
|
|
|
// Prepare output buffer
|
|
Assert.Single(outputMeta.Keys);
|
|
var outputNames = outputMeta.Keys.ToArray();
|
|
var outputName = outputNames[0];
|
|
Assert.Equal(typeof(float), outputMeta[outputName].ElementType);
|
|
Assert.True(outputMeta[outputName].IsTensor);
|
|
longShape = Array.ConvertAll<int, long>(outputMeta[outputName].Dimensions, Convert.ToInt64);
|
|
byteSize = ShapeUtils.GetSizeForShape(longShape);
|
|
float[] outputBuffer = new float[expectedOutput.Length];
|
|
pinnedOutputs.Add(FixedBufferOnnxValue.CreateFromMemory<float>(memInfo, outputBuffer,
|
|
TensorElementType.Float, longShape, byteSize));
|
|
|
|
session.Run(inputNames, pinnedInputs, outputNames, pinnedOutputs);
|
|
Assert.Equal(expectedOutput, outputBuffer, new FloatComparer());
|
|
}
|
|
|
|
// Run inference with named inputs and named outputs
|
|
{
|
|
// correct pre-allocated outputs
|
|
var expectedOutputValues = new List<NamedOnnxValue>()
|
|
{
|
|
NamedOnnxValue.CreateFromTensor("softmaxout_1", new DenseTensor<float>(expectedOutputDimensions))
|
|
};
|
|
session.Run(container, expectedOutputValues);
|
|
ValidateRunResultData(expectedOutputValues[0].AsTensor<float>(), expectedOutput, expectedDimensions);
|
|
}
|
|
|
|
// Run inference with pinned inputs and named outputs
|
|
using (var pinnedInputs = new DisposableListTest<FixedBufferOnnxValue>())
|
|
{
|
|
var inputNames = container.Select(i => i.Name).ToArray();
|
|
pinnedInputs.AddRange(container.Select(i => FixedBufferOnnxValue.CreateFromTensor(i.AsTensor<float>())));
|
|
|
|
// expected inputs and outputs
|
|
var expectedOutputValues = new List<NamedOnnxValue>()
|
|
{
|
|
NamedOnnxValue.CreateFromTensor("softmaxout_1", new DenseTensor<float>(expectedOutputDimensions))
|
|
};
|
|
session.Run(inputNames, pinnedInputs, expectedOutputValues);
|
|
ValidateRunResultData(expectedOutputValues[0].AsTensor<float>(), expectedOutput, expectedDimensions);
|
|
}
|
|
|
|
// Run inference with named inputs and pinned outputs
|
|
{
|
|
// correct pre-allocated outputs
|
|
using (var pinnedOutputs = new DisposableListTest<FixedBufferOnnxValue>())
|
|
{
|
|
var outputTensor = new DenseTensor<float>(expectedOutputDimensions);
|
|
pinnedOutputs.Add(FixedBufferOnnxValue.CreateFromTensor(outputTensor));
|
|
session.Run(container, expectedOutputNames, pinnedOutputs);
|
|
ValidateRunResultData(outputTensor, expectedOutput, expectedDimensions);
|
|
}
|
|
}
|
|
|
|
// Run inference with pinned inputs and pinned outputs
|
|
using (DisposableListTest<FixedBufferOnnxValue> pinnedInputs = new DisposableListTest<FixedBufferOnnxValue>(),
|
|
pinnedOutputs = new DisposableListTest<FixedBufferOnnxValue>())
|
|
{
|
|
var inputNames = container.Select(i => i.Name).ToArray();
|
|
pinnedInputs.AddRange(container.Select(i => FixedBufferOnnxValue.CreateFromTensor(i.AsTensor<float>())));
|
|
|
|
var outputTensor = new DenseTensor<float>(expectedOutputDimensions);
|
|
pinnedOutputs.Add(FixedBufferOnnxValue.CreateFromTensor(outputTensor));
|
|
|
|
session.Run(inputNames, pinnedInputs, expectedOutputNames, pinnedOutputs);
|
|
ValidateRunResultData(outputTensor, expectedOutput, expectedDimensions);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "RunInferenceUsingPreAllocatedOutputsAndDictionary")]
|
|
public void RunInferenceUsingPreAllocatedOutputsAndDictionary()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx");
|
|
using (var cleanUp = new DisposableListTest<IDisposable>())
|
|
{
|
|
var runOptions = new RunOptions();
|
|
cleanUp.Add(runOptions);
|
|
var session = new InferenceSession(model);
|
|
cleanUp.Add(session);
|
|
|
|
var inputMeta = session.InputMetadata;
|
|
Assert.Single(inputMeta.Keys);
|
|
var inputNames = inputMeta.Keys.ToList().AsReadOnly();
|
|
Assert.Equal(TensorElementType.Float, inputMeta[inputNames[0]].ElementDataType);
|
|
Assert.True(inputMeta[inputNames[0]].IsTensor);
|
|
var inputShape = Array.ConvertAll<int, long>(inputMeta[inputNames[0]].Dimensions, Convert.ToInt64);
|
|
|
|
|
|
var outputMeta = session.OutputMetadata;
|
|
var expectedOutputNames = new List<string> { "softmaxout_1" }.AsReadOnly();
|
|
Assert.Contains(expectedOutputNames[0], outputMeta.Keys);
|
|
long[] expectedShape = { 1, 1000, 1, 1 }; // hardcoded for the test data
|
|
|
|
// this is the data for only one input tensor for this model
|
|
float[] inputData = TestDataLoader.LoadTensorFromEmbeddedResource("bench.in");
|
|
float[] expectedOutput = TestDataLoader.LoadTensorFromEmbeddedResource("bench.expected_out");
|
|
|
|
// Allocate input OrtValue on top of the inputData
|
|
// Input should stay pinned for the entire duration of the inference
|
|
var inputOrtValue = OrtValue.CreateTensorValueFromMemory<float>(inputData, inputShape);
|
|
cleanUp.Add(inputOrtValue);
|
|
|
|
// Create OrtValue and pre-allocate output buffer using the expected output shape
|
|
using (var outputOrtValue = OrtValue.CreateAllocatedTensorValue(OrtAllocator.DefaultInstance,
|
|
TensorElementType.Float, expectedShape))
|
|
{
|
|
// Run inference
|
|
var inputValues = new List<OrtValue> { inputOrtValue }.AsReadOnly();
|
|
var outputValues = new List<OrtValue> { outputOrtValue }.AsReadOnly();
|
|
session.Run(runOptions, inputNames, inputValues,
|
|
expectedOutputNames, outputValues);
|
|
ValidateRunResult(outputOrtValue, expectedOutput, expectedShape);
|
|
}
|
|
|
|
//Let's run this again with an interface that takes a Dictionary of name/OrtValue
|
|
var inputDict = new Dictionary<string, OrtValue>();
|
|
inputDict.Add(inputNames[0], inputOrtValue);
|
|
using (var results = session.Run(runOptions, inputDict, expectedOutputNames))
|
|
{
|
|
Assert.Single(results);
|
|
var outputOrtValue = results[0];
|
|
ValidateRunResult(outputOrtValue, expectedOutput, expectedShape);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "InferenceSessionDisposed")]
|
|
public void InferenceSessionDisposed()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx");
|
|
|
|
// Set the graph optimization level for this session.
|
|
using (SessionOptions options = new SessionOptions())
|
|
{
|
|
options.ProfileOutputPathPrefix = "Ort_P_";
|
|
options.EnableProfiling = true;
|
|
using (var session = new InferenceSession(model, options))
|
|
{
|
|
var inputMeta = session.InputMetadata;
|
|
var container = new List<NamedOnnxValue>();
|
|
|
|
float[] inputData = TestDataLoader.LoadTensorFromEmbeddedResource("bench.in"); // this is the data for only one input tensor for this model
|
|
|
|
foreach (var name in inputMeta.Keys)
|
|
{
|
|
Assert.Equal(typeof(float), inputMeta[name].ElementType);
|
|
Assert.True(inputMeta[name].IsTensor);
|
|
var tensor = new DenseTensor<float>(inputData, inputMeta[name].Dimensions);
|
|
container.Add(NamedOnnxValue.CreateFromTensor<float>(name, tensor));
|
|
}
|
|
|
|
// Run inference with named inputs and outputs created with in Run()
|
|
using (var results = session.Run(container)) // results is an IReadOnlyList<NamedOnnxValue> container
|
|
{
|
|
ValidateRunResults(results);
|
|
}
|
|
|
|
string profile_file = session.EndProfiling();
|
|
|
|
// Profile file should have the output path prefix in it
|
|
Assert.Contains("Ort_P_", profile_file);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "InferenceSessionGetProfilingStartTimeNs")]
|
|
public void InferenceSessionGetProfilingStartTimeNs()
|
|
{
|
|
ulong getSingleSessionProfilingStartTime()
|
|
{
|
|
ulong startTime = 0;
|
|
using (SessionOptions options = new SessionOptions())
|
|
{
|
|
options.EnableProfiling = true;
|
|
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx");
|
|
|
|
using (var session = new InferenceSession(model, options))
|
|
{
|
|
startTime = session.ProfilingStartTimeNs;
|
|
}
|
|
}
|
|
return startTime;
|
|
}
|
|
|
|
// Get profiling's start time
|
|
ulong ProfilingStartTime = getSingleSessionProfilingStartTime();
|
|
|
|
// Check the profiling's start time has been updated
|
|
Assert.True(ProfilingStartTime != 0);
|
|
}
|
|
|
|
[Fact(DisplayName = "SessionOptionsFreeDimensionOverrides")]
|
|
public void SessionOptionsFreeDimensionOverrides()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("abs_free_dimensions.onnx");
|
|
|
|
// By Name
|
|
using (SessionOptions options = new SessionOptions())
|
|
{
|
|
options.AddFreeDimensionOverrideByName("Dim1", 4);
|
|
options.AddFreeDimensionOverrideByName("Dim2", 6);
|
|
|
|
using (var session = new InferenceSession(model, options))
|
|
{
|
|
var inputMetadata = session.InputMetadata;
|
|
var dims = inputMetadata["x"].Dimensions;
|
|
Assert.Equal(3, dims.Length);
|
|
Assert.Equal(4, dims[0]);
|
|
Assert.Equal(6, dims[1]);
|
|
Assert.Equal(5, dims[2]);
|
|
}
|
|
}
|
|
|
|
// By Denotation
|
|
using (SessionOptions options = new SessionOptions())
|
|
{
|
|
options.AddFreeDimensionOverride("DATA_BATCH", 3);
|
|
options.AddFreeDimensionOverride("DATA_CHANNEL", 5);
|
|
|
|
using (var session = new InferenceSession(model, options))
|
|
{
|
|
var inputMetadata = session.InputMetadata;
|
|
var dims = inputMetadata["x"].Dimensions;
|
|
Assert.Equal(3, dims.Length);
|
|
Assert.Equal(3, dims[0]);
|
|
Assert.Equal(5, dims[1]);
|
|
Assert.Equal(5, dims[2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ValidateRunResults(IReadOnlyCollection<NamedOnnxValue> results)
|
|
{
|
|
// validate the results
|
|
foreach (var r in results)
|
|
{
|
|
Assert.Single(results);
|
|
Assert.Equal("softmaxout_1", r.Name);
|
|
|
|
float[] expectedOutput = TestDataLoader.LoadTensorFromEmbeddedResource("bench.expected_out");
|
|
int[] expectedDimensions = { 1, 1000, 1, 1 }; // hardcoded for now for the test data
|
|
ValidateRunResultData(r.AsTensor<float>(), expectedOutput, expectedDimensions);
|
|
}
|
|
}
|
|
|
|
private void ValidateRunResultData(Tensor<float> resultTensor, float[] expectedOutput, int[] expectedDimensions)
|
|
{
|
|
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 = resultTensor.ToArray();
|
|
Assert.Equal(expectedOutput.Length, resultArray.Length);
|
|
Assert.Equal(expectedOutput, resultArray, new FloatComparer());
|
|
}
|
|
|
|
private static void ValidateRunResult(OrtValue resultTensor, ReadOnlySpan<float> expectedOutput, long[] expectedShape)
|
|
{
|
|
Assert.True(resultTensor.IsTensor);
|
|
|
|
var typeShape = resultTensor.GetTensorTypeAndShape();
|
|
Assert.Equal(TensorElementType.Float, typeShape.ElementDataType);
|
|
|
|
Assert.Equal(typeShape.Shape, expectedShape);
|
|
var resultSpan = resultTensor.GetTensorDataAsSpan<float>().ToArray();
|
|
var expectedSpan = expectedOutput.ToArray();
|
|
Assert.Equal(expectedSpan, resultSpan, new FloatComparer());
|
|
}
|
|
|
|
[Fact(DisplayName = "ThrowWrongInputName")]
|
|
private void ThrowWrongInputName()
|
|
{
|
|
var tuple = OpenSessionSqueezeNet();
|
|
var session = tuple.Item1;
|
|
var inputData = tuple.Item2;
|
|
var tensor = tuple.Item3;
|
|
var inputMeta = session.InputMetadata;
|
|
var container = new List<NamedOnnxValue>();
|
|
container.Add(NamedOnnxValue.CreateFromTensor<float>("wrong_name", tensor));
|
|
var ex = Assert.Throws<OnnxRuntimeException>(() => session.Run(container));
|
|
Assert.Contains("Input name: 'wrong_name' is not in the metadata", ex.Message);
|
|
session.Dispose();
|
|
}
|
|
|
|
[Fact(DisplayName = "ThrowWrongInputType")]
|
|
private void ThrowWrongInputType()
|
|
{
|
|
var tuple = OpenSessionSqueezeNet();
|
|
var session = tuple.Item1;
|
|
var inputData = tuple.Item2;
|
|
var inputMeta = session.InputMetadata;
|
|
var container = new List<NamedOnnxValue>();
|
|
int[] inputDataInt = inputData.Select(x => (int)x).ToArray();
|
|
var tensor = new DenseTensor<int>(inputDataInt, inputMeta["data_0"].Dimensions);
|
|
container.Add(NamedOnnxValue.CreateFromTensor<int>("data_0", tensor));
|
|
var ex = Assert.Throws<OnnxRuntimeException>(() => session.Run(container));
|
|
var msg = ex.ToString();
|
|
Assert.Contains("Tensor element data type discovered", msg);
|
|
session.Dispose();
|
|
}
|
|
|
|
[Fact(DisplayName = "ThrowExtraInputs")]
|
|
private void ThrowExtraInputs()
|
|
{
|
|
var tuple = OpenSessionSqueezeNet();
|
|
var session = tuple.Item1;
|
|
var inputData = tuple.Item2;
|
|
var tensor = tuple.Item3;
|
|
var inputMeta = session.InputMetadata;
|
|
var container = new List<NamedOnnxValue>();
|
|
var nov1 = NamedOnnxValue.CreateFromTensor<float>("data_0", tensor);
|
|
var nov2 = NamedOnnxValue.CreateFromTensor<float>("extra", tensor);
|
|
container.Add(nov1);
|
|
container.Add(nov2);
|
|
var ex = Assert.Throws<OnnxRuntimeException>(() => session.Run(container));
|
|
Assert.Contains("Input name: 'extra' is not in the metadata", ex.Message);
|
|
session.Dispose();
|
|
}
|
|
|
|
[Fact(DisplayName = "ThrowInconsistentPinnedInputs")]
|
|
private void ThrowInconsistentPinnedInputs()
|
|
{
|
|
var tuple = OpenSessionSqueezeNet();
|
|
var session = tuple.Item1;
|
|
var inputData = tuple.Item2;
|
|
var tensor = tuple.Item3;
|
|
|
|
using (var inputs = new DisposableListTest<FixedBufferOnnxValue>())
|
|
{
|
|
inputs.Add(FixedBufferOnnxValue.CreateFromTensor(tensor));
|
|
var ex = Assert.Throws<ArgumentException>(() => session.Run(new string[0], inputs));
|
|
Assert.StartsWith("Length of inputNames (0) must match that of inputValues (1).", ex.Message);
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "ThrowWrongOutputName")]
|
|
private void ThrowWrongOutputName()
|
|
{
|
|
var tuple = OpenSessionSqueezeNet();
|
|
var session = tuple.Item1;
|
|
var inputData = tuple.Item2;
|
|
var inputTensor = tuple.Item3;
|
|
var inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor<float>("data_0", inputTensor) };
|
|
var outputTensor = new DenseTensor<float>((ReadOnlySpan<int>)new[] { 1, 2 });
|
|
// var outputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor<float>("bad_output_name", outputTensor) };
|
|
var bad_names = new string[] { "bad_output_name" };
|
|
var ex = Assert.Throws<OnnxRuntimeException>(() => session.Run(inputs, bad_names));
|
|
Assert.Contains("Output name: 'bad_output_name' is not in the metadata", ex.Message);
|
|
session.Dispose();
|
|
}
|
|
|
|
[Fact(DisplayName = "ThrowWrongOutputType")]
|
|
private void ThrowWrongOutputType()
|
|
{
|
|
var tuple = OpenSessionSqueezeNet();
|
|
var session = tuple.Item1;
|
|
var inputData = tuple.Item2;
|
|
var inputTensor = tuple.Item3;
|
|
var inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor<float>("data_0", inputTensor) };
|
|
var outputTensor = new DenseTensor<int>((ReadOnlySpan<int>)new[] { 1, 1000, 1, 1 });
|
|
var outputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor("softmaxout_1", outputTensor) };
|
|
var ex = Assert.Throws<OnnxRuntimeException>(() => session.Run(inputs, outputs));
|
|
// TODO: check exception message
|
|
// InferenceSession::ValidateOutputs() does not check type so far. Currently this will finally trigger an error in Softmax.
|
|
session.Dispose();
|
|
}
|
|
|
|
[Fact(DisplayName = "ThrowWrongOutputDimension")]
|
|
private void ThrowWrongOutputDimension()
|
|
{
|
|
var tuple = OpenSessionSqueezeNet();
|
|
var session = tuple.Item1;
|
|
var inputData = tuple.Item2;
|
|
var inputTensor = tuple.Item3;
|
|
var inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor<float>("data_0", inputTensor) };
|
|
var outputTensor = new DenseTensor<float>((ReadOnlySpan<int>)new[] { 1, 1001, 1, 1 });
|
|
var outputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor("softmaxout_1", outputTensor) };
|
|
var ex = Assert.Throws<OnnxRuntimeException>(() => session.Run(inputs, outputs));
|
|
// TODO: check exception message
|
|
// InferenceSession::ValidateOutputs() does not check dims so far. Currently this will finally trigger an error in Softmax.
|
|
session.Dispose();
|
|
}
|
|
|
|
[Fact(DisplayName = "ThrowNoOutput")]
|
|
private void ThrowNoOutput()
|
|
{
|
|
var tuple = OpenSessionSqueezeNet();
|
|
var session = tuple.Item1;
|
|
var inputData = tuple.Item2;
|
|
var inputTensor = tuple.Item3;
|
|
var inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor<float>("data_0", inputTensor) };
|
|
var outputTensor = new DenseTensor<float>((ReadOnlySpan<int>)new[] { 1, 1000, 1, 1 });
|
|
var outputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor("softmaxout_1", outputTensor) };
|
|
var ex = Assert.Throws<OnnxRuntimeException>(() => session.Run(inputs, new NamedOnnxValue[0]));
|
|
Assert.Contains("[ErrorCode:InvalidArgument] At least one output should be requested.", ex.Message);
|
|
session.Dispose();
|
|
}
|
|
|
|
[Fact(DisplayName = "ThrowInconsistentPinnedOutputs")]
|
|
private void ThrowInconsistentPinnedOutputs()
|
|
{
|
|
var tuple = OpenSessionSqueezeNet();
|
|
var session = tuple.Item1;
|
|
var inputData = tuple.Item2;
|
|
var inputTensor = tuple.Item3;
|
|
var inputs = new List<NamedOnnxValue> { NamedOnnxValue.CreateFromTensor<float>("data_0", inputTensor) };
|
|
var outputTensor = new DenseTensor<float>((ReadOnlySpan<int>)new[] { 1, 1000, 1, 1 });
|
|
|
|
using (var outputs = new DisposableListTest<FixedBufferOnnxValue>())
|
|
{
|
|
var ex = Assert.Throws<ArgumentException>(() => session.Run(inputs, new string[] { "softmaxout_1" }, outputs));
|
|
Assert.StartsWith("Length of outputNames (1) must match that of outputValues (0).", ex.Message);
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestMultiThreads")]
|
|
private async Task TestMultiThreads()
|
|
{
|
|
var numThreads = 10;
|
|
var loop = 10;
|
|
var tuple = OpenSessionSqueezeNet();
|
|
var session = tuple.Item1;
|
|
var inputData = tuple.Item2;
|
|
var tensor = tuple.Item3;
|
|
var expectedOut = tuple.Item4;
|
|
var inputMeta = session.InputMetadata;
|
|
var container = new List<NamedOnnxValue>();
|
|
container.Add(NamedOnnxValue.CreateFromTensor<float>("data_0", tensor));
|
|
var tasks = new Task[numThreads];
|
|
for (int i = 0; i < numThreads; i++)
|
|
{
|
|
tasks[i] = Task.Factory.StartNew((Action)(() =>
|
|
{
|
|
for (int j = 0; j < loop; j++)
|
|
{
|
|
var resnov = session.Run(container);
|
|
var res = resnov.ToArray()[0].AsTensor<float>().ToArray();
|
|
|
|
Assert.Equal(res, expectedOut, (IEqualityComparer<float>)new FloatComparer());
|
|
}
|
|
}));
|
|
};
|
|
await Task.WhenAll(tasks);
|
|
session.Dispose();
|
|
}
|
|
|
|
[Fact(DisplayName = "TestOverridableInitializerMetadata")]
|
|
private void TestOverridableInitializerMetadata()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("overridable_initializer.onnx");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
Assert.Equal(2, session.InputMetadata.Count);
|
|
Assert.True(session.InputMetadata.ContainsKey("Label"));
|
|
Assert.True(session.InputMetadata.ContainsKey("F2"));
|
|
|
|
Assert.Single(session.OverridableInitializerMetadata);
|
|
Assert.True(session.OverridableInitializerMetadata.ContainsKey("F1"));
|
|
Assert.True(session.OverridableInitializerMetadata["F1"].IsTensor);
|
|
Assert.Equal(typeof(float), session.OverridableInitializerMetadata["F1"].ElementType);
|
|
Assert.Equal(2, session.OverridableInitializerMetadata["F1"].Dimensions.Length);
|
|
Assert.Equal(1, session.OverridableInitializerMetadata["F1"].Dimensions[0]);
|
|
Assert.Equal(1, session.OverridableInitializerMetadata["F1"].Dimensions[1]);
|
|
|
|
var container = new List<NamedOnnxValue>();
|
|
var Label_input = new DenseTensor<bool>(new bool[] { true }, new int[] { 1, 1 });
|
|
container.Add(NamedOnnxValue.CreateFromTensor("Label", Label_input));
|
|
|
|
var F2_input = new DenseTensor<string>(new string[] { "f2_string" }, new int[] { 1, 1 });
|
|
container.Add(NamedOnnxValue.CreateFromTensor("F2", F2_input));
|
|
|
|
var F1_initializer = new DenseTensor<float>(new float[] { 2.0f }, new int[] { 1, 1 });
|
|
container.Add(NamedOnnxValue.CreateFromTensor("F1", F1_initializer));
|
|
|
|
using (var result = session.Run(container))
|
|
{
|
|
var resultMap = new Dictionary<string, NamedOnnxValue>();
|
|
|
|
foreach (var output in result)
|
|
{
|
|
resultMap[output.Name] = output;
|
|
}
|
|
|
|
Assert.True(resultMap.ContainsKey("Label0"));
|
|
Assert.True(resultMap.ContainsKey("F20"));
|
|
Assert.True(resultMap.ContainsKey("F11"));
|
|
|
|
var overriddenInitializer = resultMap["F11"].AsTensor<float>();
|
|
Assert.NotNull(overriddenInitializer);
|
|
Assert.True(overriddenInitializer.SequenceEqual(F1_initializer));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestSymbolicDimsMetadata")]
|
|
private void TestSymbolicDimsMetadata()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("capi_symbolic_dims.onnx");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var inputs = session.InputMetadata;
|
|
var outputs = session.OutputMetadata;
|
|
|
|
Assert.Equal(2, inputs.Count);
|
|
Assert.Single(session.OutputMetadata);
|
|
Assert.True(inputs.ContainsKey("A"));
|
|
Assert.True(inputs.ContainsKey("B"));
|
|
Assert.True(outputs.ContainsKey("C"));
|
|
|
|
var inputA = inputs["A"];
|
|
var inputB = inputs["B"];
|
|
var outputC = outputs["C"];
|
|
|
|
// dimension values and any symbolic dimension info should have the same length
|
|
Assert.Equal(inputA.Dimensions.Length, inputA.SymbolicDimensions.Length);
|
|
Assert.Equal(inputB.Dimensions.Length, inputB.SymbolicDimensions.Length);
|
|
Assert.Equal(outputC.Dimensions.Length, outputC.SymbolicDimensions.Length);
|
|
|
|
Assert.Equal(inputA.Dimensions, new int[] { -1, 2 });
|
|
Assert.Equal(inputA.SymbolicDimensions, new string[] { "n", "" });
|
|
Assert.Equal(inputB.Dimensions, new int[] { -1 });
|
|
Assert.Equal(inputB.SymbolicDimensions, new string[] { "m" });
|
|
Assert.Equal(outputC.Dimensions, new int[] { -1 });
|
|
Assert.Equal(outputC.SymbolicDimensions, new string[] { "" }); // unnamed symbolic dim
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputFloat")]
|
|
private void TestModelInputFloat()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_FLOAT.pb");
|
|
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<float>(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<float>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputBOOL")]
|
|
private void TestModelInputBOOL()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_BOOL.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<bool>(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<bool>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestReusingRunOutputNonStringType")]
|
|
private void TestReusingRunOutputNonStringType()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_BOOL.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<bool>(new bool[] { true, false, true, false, true }, new int[] { 1, 5 });
|
|
var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn);
|
|
container.Add(nov);
|
|
var res1 = session.Run(container);
|
|
|
|
// change the name of the DisposableNamedOnnxValue
|
|
res1.First().Name = "input";
|
|
|
|
// Run inferencing 2 times using the output of the first Run()
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
using (var res2 = session.Run(res1))
|
|
{
|
|
var tensorOut = res2.First().AsTensor<bool>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestReusingRunOutputStringType")]
|
|
private void TestReusingRunOutputStringType()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_STRING.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<string>(new string[] { "a", "b", "c", "d", "e" }, new int[] { 1, 5 });
|
|
var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn);
|
|
container.Add(nov);
|
|
var res1 = session.Run(container);
|
|
|
|
// change the name of the DisposableNamedOnnxValue
|
|
res1.First().Name = "input";
|
|
|
|
// Run inferencing 2 times using the output of the first Run()
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
using (var res2 = session.Run(res1))
|
|
{
|
|
var tensorOut = res2.First().AsTensor<string>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestCreateFixedBufferOnnxValueFromStringTensor")]
|
|
public void TestCreateFixedBufferOnnxValueFromStringTensor()
|
|
{
|
|
var tensor = new DenseTensor<string>(new string[] { "a", "b" }, new int[] { 1, 2 });
|
|
using (var value = FixedBufferOnnxValue.CreateFromTensor(tensor)) { }
|
|
}
|
|
|
|
[Fact(DisplayName = "TestReusingStringFixedBufferOnnxValue")]
|
|
public void TestReusingStringFixedBufferOnnxValue()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_STRING.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var tensorA = new DenseTensor<string>(new string[] { "a", "b", "c", "d", "e" }, new int[] { 1, 5 });
|
|
var tensorB = new DenseTensor<string>(new string[] { "v", "w", "x", "y", "z" }, new int[] { 1, 5 });
|
|
var tensorC = new DenseTensor<string>(new string[] { "i", "j", "k", "l", "m" }, new int[] { 1, 5 });
|
|
var tensorD = new DenseTensor<string>(new string[] { "i", "j", "k", "l", "m" }, new int[] { 1, 5 });
|
|
using (FixedBufferOnnxValue a = FixedBufferOnnxValue.CreateFromTensor(tensorA),
|
|
b = FixedBufferOnnxValue.CreateFromTensor(tensorB),
|
|
c = FixedBufferOnnxValue.CreateFromTensor(tensorC),
|
|
d = FixedBufferOnnxValue.CreateFromTensor(tensorD))
|
|
{
|
|
// OK to use string type FixedBufferOnnxValue only in input
|
|
session.Run(new[] { "input" }, new[] { a });
|
|
|
|
// Cannot use string type FixedBufferOnnxValue in output
|
|
Assert.Throws<NotSupportedException>(() =>
|
|
{
|
|
// NamedOnnxValue inputs
|
|
session.Run(new[] { NamedOnnxValue.CreateFromTensor("input", tensorB) }, new[] { "output" }, new[] { b });
|
|
});
|
|
Assert.Throws<NotSupportedException>(() =>
|
|
{
|
|
// both FixedBufferOnnxValue for inputs and outputs
|
|
session.Run(new[] { "input" }, new[] { c }, new[] { "output" }, new[] { d });
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestReusingFixedBufferOnnxValue")]
|
|
private void TestReusingFixedBufferOnnxValue()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_BOOL.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var bufferA = new bool[] { true, false, true, false, true };
|
|
var bufferB = new bool[bufferA.Length];
|
|
var bufferC = new bool[bufferA.Length];
|
|
var tensorA = new DenseTensor<bool>(bufferA, new int[] { 1, 5 });
|
|
var tensorB = new DenseTensor<bool>(bufferB, new int[] { 1, 5 });
|
|
var tensorC = new DenseTensor<bool>(bufferC, new int[] { 1, 5 });
|
|
using (FixedBufferOnnxValue a = FixedBufferOnnxValue.CreateFromTensor(tensorA),
|
|
b = FixedBufferOnnxValue.CreateFromTensor(tensorB),
|
|
c = FixedBufferOnnxValue.CreateFromTensor(tensorC))
|
|
{
|
|
session.Run(new[] { "input" }, new[] { a }, new[] { "output" }, new[] { b });
|
|
session.Run(new[] { "input" }, new[] { b }, new[] { "output" }, new[] { c });
|
|
}
|
|
|
|
Assert.True(tensorC.SequenceEqual(tensorA));
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestReusingFixedBufferOnnxValueMultiInferences")]
|
|
private void TestReusingFixedBufferOnnxValueMultiInferences()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_INT32.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var bufferInput = new int[5];
|
|
var bufferOutput = new int[5];
|
|
var tensorInput = new DenseTensor<int>(bufferInput, new int[] { 1, 5 });
|
|
var tensorOutput = new DenseTensor<int>(bufferOutput, new int[] { 1, 5 });
|
|
|
|
using (FixedBufferOnnxValue valueInput = FixedBufferOnnxValue.CreateFromTensor(tensorInput),
|
|
valueOutput = FixedBufferOnnxValue.CreateFromTensor(tensorOutput))
|
|
{
|
|
var inputNames = new[] { "input" };
|
|
var outputNames = new[] { "output" };
|
|
var inputValues = new[] { valueInput };
|
|
var outputValues = new[] { valueOutput };
|
|
|
|
var rand = new Random();
|
|
|
|
// run the model for multiple times
|
|
for (var i = 0; i < 1000; i++)
|
|
{
|
|
// feed inputs ( 5 random integers )
|
|
var inputs = Enumerable.Range(0, 5).Select(x => rand.Next()).ToArray();
|
|
inputs.CopyTo(bufferInput, 0);
|
|
|
|
// run inference
|
|
session.Run(inputNames, inputValues, outputNames, outputValues);
|
|
|
|
// use outputs
|
|
Assert.Equal(inputs, bufferOutput);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputINT32")]
|
|
private void TestModelInputINT32()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_INT32.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<int>(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<int>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputDOUBLE")]
|
|
private void TestModelInputDOUBLE()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_DOUBLE.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<double>(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<double>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputSTRING")]
|
|
private void TestModelInputSTRING()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_STRING.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<string>(new string[] {
|
|
"hello",
|
|
"École élémentaire",
|
|
"mit freundlichen grüßen",
|
|
"Понедельник",
|
|
"最好的问候,"+
|
|
"नमस्ते," +
|
|
"こんにちは," +
|
|
"안녕하세요"
|
|
}, new int[] { 1, 5 });
|
|
var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn);
|
|
container.Add(nov);
|
|
using (var res = session.Run(container))
|
|
{
|
|
var tensorOut = res.First().AsTensor<string>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputSTRING_ShouldFailWithNullInput")]
|
|
private void TestModelInputSTRING_ShouldFailWithNullInput()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_STRING.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<string>(new string[5], // null
|
|
new int[] { 1, 5 });
|
|
var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn);
|
|
container.Add(nov);
|
|
Assert.Throws<ArgumentNullException>(() => { session.Run(container); });
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputINT8")]
|
|
private void TestModelInputINT8()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_INT8.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<sbyte>(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<sbyte>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputUINT8")]
|
|
private void TestModelInputUINT8()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_UINT8.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<byte>(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<byte>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputUINT16")]
|
|
private void TestModelInputUINT16()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_UINT16.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<UInt16>(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<UInt16>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputINT16")]
|
|
private void TestModelInputINT16()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_INT16.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<Int16>(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<Int16>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputINT64")]
|
|
private void TestModelInputINT64()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_INT64.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<Int64>(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<Int64>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputUINT32")]
|
|
private void TestModelInputUINT32()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_UINT32.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<UInt32>(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<UInt32>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputUINT64")]
|
|
private void TestModelInputUINT64()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_UINT64.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<UInt64>(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<UInt64>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputFLOAT16")]
|
|
private void TestModelInputFLOAT16()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
Float16[] modelInput = { new Float16(15360), new Float16(16384), new Float16(16896), new Float16(17408), new Float16(17664) };
|
|
int[] inputShape = { 1, 5 };
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_FLOAT16.onnx");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<Float16>(modelInput, inputShape);
|
|
var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn);
|
|
container.Add(nov);
|
|
using (var res = session.Run(container))
|
|
{
|
|
var valueOut = res.First();
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, valueOut.ValueType);
|
|
Assert.Equal(Tensors.TensorElementType.Float16, valueOut.ElementType);
|
|
var tensorOut = res.First().AsTensor<Float16>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelInputBFLOAT16")]
|
|
private void TestModelInputBFLOAT16()
|
|
{
|
|
BFloat16[] modelInput = { new BFloat16(16256), new BFloat16(16384),
|
|
new BFloat16(16448), new BFloat16(16512), new BFloat16(16544) };
|
|
int[] inputShape = { 1, 5 };
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_BFLOAT16.onnx");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<BFloat16>(modelInput, inputShape);
|
|
var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn);
|
|
container.Add(nov);
|
|
using (var res = session.Run(container))
|
|
{
|
|
var valueOut = res.First();
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, valueOut.ValueType);
|
|
Assert.Equal(Tensors.TensorElementType.BFloat16, valueOut.ElementType);
|
|
var tensorOut = res.First().AsTensor<BFloat16>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
private class IgnoreWhenMlOpsDisabledFact : FactAttribute
|
|
{
|
|
public IgnoreWhenMlOpsDisabledFact()
|
|
{
|
|
var disableMlOpsEnvVar = Environment.GetEnvironmentVariable("DisableMlOps");
|
|
var isMlOpsDisabled = (disableMlOpsEnvVar != null) ? disableMlOpsEnvVar.Equals("ON") : false;
|
|
if (isMlOpsDisabled)
|
|
{
|
|
Skip = "Skipping this test since Ml Ops are disabled.";
|
|
}
|
|
}
|
|
}
|
|
|
|
[IgnoreWhenMlOpsDisabledFact(DisplayName = "TestModelSequenceOfMapIntFloat")]
|
|
private void TestModelSequenceOfMapIntFloat()
|
|
{
|
|
// test model trained using lightgbm classifier
|
|
// produces 2 named outputs
|
|
// "label" is a tensor,
|
|
// "probabilities" is a sequence<map<int64, float>>
|
|
// https://github.com/onnx/sklearn-onnx/blob/master/docs/examples/plot_pipeline_lightgbm.py
|
|
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_sequence_map_int_float.pb");
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
|
|
var outMeta = session.OutputMetadata;
|
|
var label_meta = outMeta["label"];
|
|
Assert.True(label_meta.IsTensor);
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, label_meta.OnnxValueType);
|
|
Assert.Equal(TensorElementType.Int64, label_meta.ElementDataType);
|
|
Assert.NotEmpty(label_meta.Dimensions);
|
|
|
|
// sequence<map<int64, float>>
|
|
var probabilities_meta = outMeta["probabilities"];
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_SEQUENCE, probabilities_meta.OnnxValueType);
|
|
var seqElementMetata = probabilities_meta.AsSequenceMetadata().ElementMeta;
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_MAP, seqElementMetata.OnnxValueType);
|
|
var mapMetadata = seqElementMetata.AsMapMetadata();
|
|
// Map<int64, float tensor>
|
|
Assert.Equal(Tensors.TensorElementType.Int64, mapMetadata.KeyDataType);
|
|
var valueTensorMeta = mapMetadata.ValueMetadata;
|
|
Assert.True(valueTensorMeta.IsTensor);
|
|
Assert.Equal(Tensors.TensorElementType.Float, valueTensorMeta.ElementDataType);
|
|
|
|
// tensor<float>
|
|
var inputMeta = session.InputMetadata["input"];
|
|
Assert.True(inputMeta.IsTensor);
|
|
Assert.Equal(Tensors.TensorElementType.Float, inputMeta.ElementDataType);
|
|
Assert.Equal(2, inputMeta.Dimensions.Length);
|
|
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<float>(new float[] { 5.8f, 2.8f }, new int[] { 1, 2 });
|
|
var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn);
|
|
container.Add(nov);
|
|
|
|
using (var outputs = session.Run(container))
|
|
{
|
|
// first output is a tensor containing label
|
|
var outNode0 = outputs.ElementAtOrDefault(0);
|
|
Assert.NotNull(outNode0);
|
|
Assert.Equal("label", outNode0.Name);
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, outNode0.ValueType);
|
|
Assert.Equal(Tensors.TensorElementType.Int64, outNode0.ElementType);
|
|
|
|
// try-cast as a tensor
|
|
var outLabelTensor = outNode0.AsTensor<long>();
|
|
Assert.NotNull(outLabelTensor);
|
|
|
|
// Label 1 should have highest probability
|
|
Assert.Equal(1, outLabelTensor[0]);
|
|
|
|
// second output is a sequence<map<int64, float>>
|
|
// try-cast to an sequence of NOV
|
|
var outNode1 = outputs.ElementAtOrDefault(1);
|
|
Assert.NotNull(outNode1);
|
|
Assert.Equal("probabilities", outNode1.Name);
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_SEQUENCE, outNode1.ValueType);
|
|
|
|
// try-cast to an sequence of NOV
|
|
var seq = outNode1.AsEnumerable<NamedOnnxValue>();
|
|
Assert.NotNull(seq);
|
|
// Try-cast into DisposableNov so we can control and check the process
|
|
|
|
|
|
// try-cast first element in sequence to map/dictionary type
|
|
if (System.Environment.Is64BitProcess)
|
|
{
|
|
var map = seq.First().AsDictionary<Int64, float>();
|
|
Assert.NotNull(map);
|
|
Assert.Equal(0.25938290, map[0], 6);
|
|
Assert.Equal(0.40904793, map[1], 6);
|
|
Assert.Equal(0.33156919, map[2], 6);
|
|
}
|
|
else // 32-bit
|
|
{
|
|
var map = seq.First().AsDictionary<long, float>();
|
|
Assert.NotNull(map);
|
|
Assert.Equal(0.25938290, map[0], 6);
|
|
Assert.Equal(0.40904793, map[1], 6);
|
|
Assert.Equal(0.33156919, map[2], 6);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[IgnoreWhenMlOpsDisabledFact(DisplayName = "TestModelSequenceOfMapStringFloat")]
|
|
private void TestModelSequenceOfMapStringFloat()
|
|
{
|
|
// test model trained using lightgbm classifier
|
|
// produces 2 named outputs
|
|
// "label" is a tensor,
|
|
// "probabilities" is a sequence<map<int64, float>>
|
|
// https://github.com/onnx/sklearn-onnx/blob/master/docs/examples/plot_pipeline_lightgbm.py
|
|
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_sequence_map_string_float.pb");
|
|
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var outMeta = session.OutputMetadata;
|
|
var label_meta = outMeta["label"];
|
|
Assert.True(label_meta.IsTensor);
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, label_meta.OnnxValueType);
|
|
Assert.True(label_meta.IsString);
|
|
Assert.Equal(TensorElementType.String, label_meta.ElementDataType);
|
|
Assert.NotEmpty(label_meta.Dimensions);
|
|
|
|
// sequence<map<string, float>>
|
|
var probabilities_meta = outMeta["probabilities"];
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_SEQUENCE, probabilities_meta.OnnxValueType);
|
|
var seqElementMetata = probabilities_meta.AsSequenceMetadata().ElementMeta;
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_MAP, seqElementMetata.OnnxValueType);
|
|
var mapMetadata = seqElementMetata.AsMapMetadata();
|
|
Assert.Equal(Tensors.TensorElementType.String, mapMetadata.KeyDataType);
|
|
var valueTensorMeta = mapMetadata.ValueMetadata;
|
|
Assert.True(valueTensorMeta.IsTensor);
|
|
Assert.Equal(Tensors.TensorElementType.Float, valueTensorMeta.ElementDataType);
|
|
|
|
|
|
// tensor<float>
|
|
var inputMeta = session.InputMetadata["input"];
|
|
Assert.True(inputMeta.IsTensor);
|
|
Assert.False(inputMeta.IsString);
|
|
Assert.Equal(Tensors.TensorElementType.Float, inputMeta.ElementDataType);
|
|
Assert.Equal(2, inputMeta.Dimensions.Length);
|
|
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<float>(new float[] { 5.8f, 2.8f }, new int[] { 1, 2 });
|
|
var nov = NamedOnnxValue.CreateFromTensor("input", tensorIn);
|
|
container.Add(nov);
|
|
|
|
using (var outputs = session.Run(container))
|
|
{
|
|
// first output is a tensor containing label
|
|
var outNode0 = outputs.ElementAtOrDefault(0);
|
|
Assert.NotNull(outNode0);
|
|
Assert.Equal("label", outNode0.Name);
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_TENSOR, outNode0.ValueType);
|
|
Assert.Equal(TensorElementType.String, outNode0.ElementType);
|
|
|
|
// try-cast as a tensor
|
|
var outLabelTensor = outNode0.AsTensor<string>();
|
|
Assert.NotNull(outLabelTensor);
|
|
|
|
// Label 1 should have highest probability
|
|
Assert.Equal("1", outLabelTensor[0]);
|
|
|
|
// second output is a sequence<map<string, float>>
|
|
// try-cast to an sequence of NOV
|
|
var outNode1 = outputs.ElementAtOrDefault(1);
|
|
Assert.NotNull(outNode1);
|
|
Assert.Equal("probabilities", outNode1.Name);
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_SEQUENCE, outNode1.ValueType);
|
|
|
|
// try-cast to an sequence of NOV
|
|
var seq = outNode1.AsEnumerable<NamedOnnxValue>();
|
|
|
|
// try-cast first element in sequence to map/dictionary type
|
|
var map = seq.First().AsDictionary<string, float>();
|
|
Assert.NotNull(map);
|
|
//verify values are valid
|
|
Assert.Equal(0.25938290, map["0"], 6);
|
|
Assert.Equal(0.40904793, map["1"], 6);
|
|
Assert.Equal(0.33156919, map["2"], 6);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelSequenceOfTensors")]
|
|
private void TestModelSequenceOfTensors()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_sequence_tensors.onnx");
|
|
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var outMeta = session.OutputMetadata;
|
|
var output_seq = outMeta["output_sequence"];
|
|
Assert.False(output_seq.IsTensor);
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_SEQUENCE, output_seq.OnnxValueType);
|
|
var elemMeta = output_seq.AsSequenceMetadata().ElementMeta;
|
|
Assert.True(elemMeta.IsTensor);
|
|
Assert.Equal(Tensors.TensorElementType.Int64, elemMeta.ElementDataType);
|
|
|
|
// Inputs
|
|
var tensor1Meta = session.InputMetadata["tensor1"];
|
|
Assert.True(tensor1Meta.IsTensor);
|
|
Assert.Equal(Tensors.TensorElementType.Int64, tensor1Meta.ElementDataType);
|
|
Assert.Equal(2, tensor1Meta.Dimensions.Length);
|
|
|
|
var container = new List<NamedOnnxValue>();
|
|
var firstInputTensor = new DenseTensor<Int64>(new Int64[] { 1, 2, 3, 4, 5, 6 }, new int[] { 2, 3 });
|
|
var secondInputTensor = new DenseTensor<Int64>(new Int64[] { 7, 8, 9, 10, 11, 12 }, new int[] { 2, 3 });
|
|
|
|
var firstNov = NamedOnnxValue.CreateFromTensor("tensor1", firstInputTensor);
|
|
var secondNov = NamedOnnxValue.CreateFromTensor("tensor2", secondInputTensor);
|
|
|
|
container.Add(firstNov);
|
|
container.Add(secondNov);
|
|
|
|
using (var outputs = session.Run(container))
|
|
{
|
|
// output is a sequence<tensors>
|
|
// try-cast to an sequence of NOV
|
|
var outNode = outputs.ElementAtOrDefault(0);
|
|
Assert.NotNull(outNode);
|
|
Assert.Equal("output_sequence", outNode.Name);
|
|
Assert.Equal(OnnxValueType.ONNX_TYPE_SEQUENCE, outNode.ValueType);
|
|
|
|
// try-cast to an sequence of NOV
|
|
var seq = outNode.AsEnumerable<NamedOnnxValue>();
|
|
|
|
// make sure that the sequence holds only 2 elements (tensors)
|
|
Assert.True(seq.Count() == 2);
|
|
|
|
// try-cast the elements in sequence to tensor type
|
|
var firstTensorInOuputSequence = seq.First().AsTensor<Int64>();
|
|
var secondTensorInOuputSequence = seq.Last().AsTensor<Int64>();
|
|
Assert.NotNull(firstTensorInOuputSequence);
|
|
Assert.NotNull(secondTensorInOuputSequence);
|
|
|
|
// make sure the tensors in the output sequence hold the correct values
|
|
Assert.True(firstTensorInOuputSequence.GetValue(0) == 1);
|
|
Assert.True(firstTensorInOuputSequence.GetValue(1) == 2);
|
|
Assert.True(firstTensorInOuputSequence.GetValue(2) == 3);
|
|
Assert.True(firstTensorInOuputSequence.GetValue(3) == 4);
|
|
Assert.True(firstTensorInOuputSequence.GetValue(4) == 5);
|
|
Assert.True(firstTensorInOuputSequence.GetValue(5) == 6);
|
|
|
|
Assert.True(secondTensorInOuputSequence.GetValue(0) == 7);
|
|
Assert.True(secondTensorInOuputSequence.GetValue(1) == 8);
|
|
Assert.True(secondTensorInOuputSequence.GetValue(2) == 9);
|
|
Assert.True(secondTensorInOuputSequence.GetValue(3) == 10);
|
|
Assert.True(secondTensorInOuputSequence.GetValue(4) == 11);
|
|
Assert.True(secondTensorInOuputSequence.GetValue(5) == 12);
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelMetadata")]
|
|
private void TestModelMetadata()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("model_with_valid_ort_config_json.onnx");
|
|
|
|
using (var session = new InferenceSession(model))
|
|
{
|
|
var modelMetadata = session.ModelMetadata;
|
|
|
|
Assert.Equal(1, modelMetadata.Version);
|
|
|
|
Assert.Equal("Hari", modelMetadata.ProducerName);
|
|
|
|
Assert.Equal("matmul test", modelMetadata.GraphName);
|
|
|
|
Assert.Equal("", modelMetadata.Domain);
|
|
|
|
Assert.Equal("This is a test model with a valid ORT config Json", modelMetadata.Description);
|
|
|
|
Assert.Equal("graph description", modelMetadata.GraphDescription);
|
|
|
|
Assert.Equal(2, modelMetadata.CustomMetadataMap.Keys.Count);
|
|
Assert.Equal("dummy_value", modelMetadata.CustomMetadataMap["dummy_key"]);
|
|
Assert.Equal("{\"session_options\": {\"inter_op_num_threads\": 5, \"intra_op_num_threads\": 2, \"graph_optimization_level\": 99, \"enable_profiling\": 1}}",
|
|
modelMetadata.CustomMetadataMap["ort_config"]);
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestInferenceSessionWithByteArray")]
|
|
private void TestInferenceSessionWithByteArray()
|
|
{
|
|
// model takes 1x5 input of fixed type, echoes back
|
|
var modelData = TestDataLoader.LoadModelFromEmbeddedResource("test_types_FLOAT.pb");
|
|
|
|
using (var session = new InferenceSession(modelData))
|
|
{
|
|
var container = new List<NamedOnnxValue>();
|
|
var tensorIn = new DenseTensor<float>(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<float>();
|
|
Assert.True(tensorOut.SequenceEqual(tensorIn));
|
|
}
|
|
}
|
|
}
|
|
|
|
void TestCPUAllocatorInternal(InferenceSession session)
|
|
{
|
|
int device_id = 0;
|
|
using (var info_cpu = new OrtMemoryInfo(OrtMemoryInfo.allocatorCPU, OrtAllocatorType.ArenaAllocator, device_id, OrtMemType.Default))
|
|
{
|
|
Assert.Equal("Cpu", info_cpu.Name);
|
|
Assert.Equal(device_id, info_cpu.Id);
|
|
Assert.Equal(OrtAllocatorType.ArenaAllocator, info_cpu.GetAllocatorType());
|
|
Assert.Equal(OrtMemType.Default, info_cpu.GetMemoryType());
|
|
|
|
using (var allocator = new OrtAllocator(session, info_cpu))
|
|
{
|
|
var alloc_info = allocator.Info;
|
|
// Allocator type returned may be different on x86 so we don't compare.
|
|
Assert.Equal(info_cpu.Name, alloc_info.Name);
|
|
Assert.Equal(info_cpu.GetMemoryType(), alloc_info.GetMemoryType());
|
|
Assert.Equal(info_cpu.Id, alloc_info.Id);
|
|
|
|
uint size = 1024;
|
|
OrtMemoryAllocation chunk = allocator.Allocate(size);
|
|
Assert.Equal(chunk.Size, size);
|
|
var chunk_info = chunk.Info;
|
|
// Allocator type returned may be different on x86 so we don't compare.
|
|
Assert.Equal(chunk_info.Name, alloc_info.Name);
|
|
Assert.Equal(chunk_info.GetMemoryType(), alloc_info.GetMemoryType());
|
|
Assert.Equal(chunk_info.Id, alloc_info.Id);
|
|
chunk.Dispose();
|
|
alloc_info.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
#if USE_CUDA
|
|
void TestCUDAAllocatorInternal(InferenceSession session)
|
|
{
|
|
int device_id = 0;
|
|
using (var info_cuda = new OrtMemoryInfo(OrtMemoryInfo.allocatorCUDA, OrtAllocatorType.ArenaAllocator, device_id, OrtMemType.Default))
|
|
{
|
|
Assert.Equal("Cuda", info_cuda.Name);
|
|
Assert.Equal(device_id, info_cuda.Id);
|
|
Assert.Equal(OrtAllocatorType.ArenaAllocator, info_cuda.GetAllocatorType());
|
|
Assert.Equal(OrtMemType.Default, info_cuda.GetMemoryType());
|
|
|
|
using (var allocator = new OrtAllocator(session, info_cuda))
|
|
{
|
|
var alloc_info = allocator.Info;
|
|
Assert.True(info_cuda.Equals(alloc_info));
|
|
|
|
uint size = 1024;
|
|
OrtMemoryAllocation chunk = allocator.Allocate(size);
|
|
Assert.Equal(chunk.Size, size);
|
|
Assert.True(chunk.Info.Equals(alloc_info));
|
|
chunk.Dispose();
|
|
alloc_info.Dispose();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if USE_ROCM
|
|
void TestROCMAllocatorInternal(InferenceSession session)
|
|
{
|
|
int device_id = 0;
|
|
using (var info_rocm = new OrtMemoryInfo(OrtMemoryInfo.allocatorHIP, OrtAllocatorType.ArenaAllocator, device_id, OrtMemType.Default))
|
|
{
|
|
Assert.Equal("Hip", info_rocm.Name);
|
|
Assert.Equal(device_id, info_rocm.Id);
|
|
Assert.Equal(OrtAllocatorType.ArenaAllocator, info_rocm.GetAllocatorType());
|
|
Assert.Equal(OrtMemType.Default, info_rocm.GetMemoryType());
|
|
|
|
using (var allocator = new OrtAllocator(session, info_rocm))
|
|
{
|
|
var alloc_info = allocator.Info;
|
|
Assert.True(info_rocm.Equals(alloc_info));
|
|
|
|
uint size = 1024;
|
|
OrtMemoryAllocation chunk = allocator.Allocate(size);
|
|
Assert.Equal(chunk.Size, size);
|
|
Assert.True(chunk.Info.Equals(alloc_info));
|
|
chunk.Dispose();
|
|
alloc_info.Dispose();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
[Fact(DisplayName = "TestAllocator")]
|
|
private void TestAllocator()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx");
|
|
using (SessionOptions options = new SessionOptions())
|
|
{
|
|
options.AppendExecutionProvider_CPU(1);
|
|
#if USE_CUDA
|
|
options.AppendExecutionProvider_CUDA(0);
|
|
#endif
|
|
|
|
#if USE_ROCM
|
|
options.AppendExecutionProvider_ROCm(0);
|
|
#endif
|
|
|
|
using (var session = new InferenceSession(model, options))
|
|
{
|
|
TestCPUAllocatorInternal(session);
|
|
#if USE_CUDA
|
|
TestCUDAAllocatorInternal(session);
|
|
#endif
|
|
#if USE_ROCM
|
|
TestROCMAllocatorInternal(session);
|
|
#endif
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestSharingOfInitializerAndItsPrepackedVersion")]
|
|
private void TestSharingOfInitializerAndItsPrepackedVersion()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("matmul_1.onnx");
|
|
|
|
// create initializer to share
|
|
var ortCpuMemInfo = OrtMemoryInfo.DefaultInstance;
|
|
var dims = new long[] { 2, 1 };
|
|
var dataBuffer = new float[] { 2.0F, 1.0F };
|
|
var dataHandle = GCHandle.Alloc(dataBuffer, GCHandleType.Pinned);
|
|
|
|
try
|
|
{
|
|
unsafe
|
|
{
|
|
float* p = (float*)dataHandle.AddrOfPinnedObject();
|
|
for (int i = 0; i < dataBuffer.Length; ++i)
|
|
{
|
|
*p++ = dataBuffer[i];
|
|
}
|
|
}
|
|
var dataBufferNumBytes = (uint)dataBuffer.Length * sizeof(float);
|
|
|
|
using (var sharedInitializer = OrtValue.CreateTensorValueWithData(ortCpuMemInfo, Tensors.TensorElementType.Float,
|
|
dims, dataHandle.AddrOfPinnedObject(), dataBufferNumBytes))
|
|
{
|
|
|
|
using (var prepackedWeightsContainer = new PrePackedWeightsContainer())
|
|
{
|
|
using (var options = new SessionOptions())
|
|
{
|
|
// We want to share initializers between the two sessions
|
|
options.AddInitializer("W", sharedInitializer);
|
|
|
|
float[] expectedOutput = { 4.0F, 10.0F, 16.0F };
|
|
int[] expectedDimensions = { 3, 1 };
|
|
|
|
// We want the pre-packed weights of the shared initializer to be shared between sessions (memory savings)
|
|
// and hence we pass in the 'prepackedWeightsContainer' at session creation time
|
|
byte[] modelData = model;
|
|
|
|
// Test both InferenceSession ctors that take PrePackedWeightsContainer instances
|
|
using (var session = new InferenceSession(model, options, prepackedWeightsContainer))
|
|
using (var session2 = new InferenceSession(modelData, options, prepackedWeightsContainer))
|
|
{
|
|
var inputMeta = session.InputMetadata;
|
|
var container = new List<NamedOnnxValue>();
|
|
|
|
foreach (var name in inputMeta.Keys)
|
|
{
|
|
Assert.Equal(typeof(float), inputMeta[name].ElementType);
|
|
Assert.True(inputMeta[name].IsTensor);
|
|
var tensor = new DenseTensor<float>(new float[] { 1, 2, 3, 4, 5, 6 }, inputMeta[name].Dimensions);
|
|
container.Add(NamedOnnxValue.CreateFromTensor<float>(name, tensor));
|
|
}
|
|
|
|
ReadOnlySpan<int> expectedOutputDimensions = new int[] { 1, 1000, 1, 1 };
|
|
string[] expectedOutputNames = new string[] { "Y" };
|
|
|
|
// Run inference with named inputs and outputs created with in Run()
|
|
using (var results = session.Run(container)) // results is an IReadOnlyList<NamedOnnxValue> container
|
|
{
|
|
foreach (var r in results)
|
|
{
|
|
ValidateRunResultData(r.AsTensor<float>(), expectedOutput, expectedDimensions);
|
|
}
|
|
}
|
|
|
|
// Run inference with named inputs and outputs created with in Run()
|
|
using (var results2 = session2.Run(container)) // results is an IReadOnlyList<NamedOnnxValue> container
|
|
{
|
|
foreach (var r in results2)
|
|
{
|
|
ValidateRunResultData(r.AsTensor<float>(), expectedOutput, expectedDimensions);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
finally
|
|
{
|
|
dataHandle.Free();
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestSharedAllocatorUsingCreateAndRegisterAllocator")]
|
|
private void TestSharedAllocatorUsingCreateAndRegisterAllocator()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("mul_1.onnx");
|
|
|
|
using (var memInfo = new OrtMemoryInfo(OrtMemoryInfo.allocatorCPU,
|
|
OrtAllocatorType.ArenaAllocator, 0, OrtMemType.Default))
|
|
using (var arenaCfg = new OrtArenaCfg(0, -1, -1, -1))
|
|
{
|
|
var env = OrtEnv.Instance();
|
|
// Create and register the arena based allocator
|
|
env.CreateAndRegisterAllocator(memInfo, arenaCfg);
|
|
|
|
using (var sessionOptions = new SessionOptions())
|
|
{
|
|
// Key must match kOrtSessionOptionsConfigUseEnvAllocators in onnxruntime_session_options_config_keys.h
|
|
sessionOptions.AddSessionConfigEntry("session.use_env_allocators", "1");
|
|
|
|
// Create two sessions to share the allocator
|
|
// Create a third session that DOES NOT use the allocator in the environment
|
|
using (var session1 = new InferenceSession(model, sessionOptions))
|
|
using (var session2 = new InferenceSession(model, sessionOptions))
|
|
using (var session3 = new InferenceSession(model)) // Use the default SessionOptions instance
|
|
{
|
|
// Input data
|
|
var inputDims = new long[] { 3, 2 };
|
|
var input = new float[] { 1.0F, 2.0F, 3.0F, 4.0F, 5.0F, 6.0F };
|
|
|
|
// Output data
|
|
int[] outputDims = { 3, 2 };
|
|
float[] output = { 1.0F, 4.0F, 9.0F, 16.0F, 25.0F, 36.0F };
|
|
|
|
// Run inference on all three models
|
|
var inputMeta = session1.InputMetadata;
|
|
var container = new List<NamedOnnxValue>();
|
|
|
|
foreach (var name in inputMeta.Keys)
|
|
{
|
|
Assert.Equal(typeof(float), inputMeta[name].ElementType);
|
|
Assert.True(inputMeta[name].IsTensor);
|
|
var tensor = new DenseTensor<float>(input, inputMeta[name].Dimensions);
|
|
container.Add(NamedOnnxValue.CreateFromTensor<float>(name, tensor));
|
|
}
|
|
|
|
// Run inference with named inputs and outputs created with in Run()
|
|
using (var results = session1.Run(container)) // results is an IReadOnlyList<NamedOnnxValue> container
|
|
{
|
|
foreach (var r in results)
|
|
{
|
|
ValidateRunResultData(r.AsTensor<float>(), output, outputDims);
|
|
}
|
|
}
|
|
|
|
// Run inference with named inputs and outputs created with in Run()
|
|
using (var results = session2.Run(container)) // results is an IReadOnlyList<NamedOnnxValue> container
|
|
{
|
|
foreach (var r in results)
|
|
{
|
|
ValidateRunResultData(r.AsTensor<float>(), output, outputDims);
|
|
}
|
|
}
|
|
|
|
// Run inference with named inputs and outputs created with in Run()
|
|
using (var results = session3.Run(container)) // results is an IReadOnlyList<NamedOnnxValue> container
|
|
{
|
|
foreach (var r in results)
|
|
{
|
|
ValidateRunResultData(r.AsTensor<float>(), output, outputDims);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static Tuple<InferenceSession, float[], DenseTensor<float>, float[]> OpenSessionSqueezeNet(int? deviceId = null)
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("squeezenet.onnx");
|
|
#if USE_DML
|
|
// Explicitly set dll probe path so that the (potentially) stale system DirectML.dll
|
|
// doesn't get loaded by the test process when it is eventually delay loaded by onnruntime.dll
|
|
// The managed tests binary path already contains the right DirectML.dll, so use that
|
|
|
|
var directml_dll_path = AppDomain.CurrentDomain.BaseDirectory;
|
|
SetDllDirectory(directml_dll_path);
|
|
|
|
using (var option = new SessionOptions())
|
|
{
|
|
if (!deviceId.HasValue)
|
|
{
|
|
option.AppendExecutionProvider_CPU(1);
|
|
}
|
|
|
|
else
|
|
{
|
|
option.AppendExecutionProvider_DML(deviceId.Value);
|
|
}
|
|
|
|
// Restore the default dll search order
|
|
SetDllDirectory(null);
|
|
#elif USE_CUDA
|
|
using (var option = (deviceId.HasValue) ?
|
|
SessionOptions.MakeSessionOptionWithCudaProvider(deviceId.Value) :
|
|
new SessionOptions())
|
|
{
|
|
if(!deviceId.HasValue)
|
|
{
|
|
option.AppendExecutionProvider_CPU(1);
|
|
}
|
|
#elif USE_ROCM
|
|
using (var option = (deviceId.HasValue) ?
|
|
SessionOptions.MakeSessionOptionWithRocmProvider(deviceId.Value) :
|
|
new SessionOptions())
|
|
{
|
|
if(!deviceId.HasValue)
|
|
{
|
|
option.AppendExecutionProvider_CPU(1);
|
|
}
|
|
#else
|
|
using (var option = new SessionOptions())
|
|
{
|
|
option.AppendExecutionProvider_CPU(1);
|
|
#endif
|
|
var session = (deviceId.HasValue)
|
|
? new InferenceSession(model, option)
|
|
: new InferenceSession(model);
|
|
float[] inputData = TestDataLoader.LoadTensorFromEmbeddedResource("bench.in");
|
|
float[] expectedOutput = TestDataLoader.LoadTensorFromEmbeddedResource("bench.expected_out");
|
|
var inputMeta = session.InputMetadata;
|
|
var tensor = new DenseTensor<float>(inputData, inputMeta["data_0"].Dimensions);
|
|
return new Tuple<InferenceSession, float[], DenseTensor<float>, float[]>(session, inputData, tensor, expectedOutput);
|
|
}
|
|
}
|
|
|
|
private class GpuFact : FactAttribute
|
|
{
|
|
public GpuFact()
|
|
{
|
|
var testOnGpu = System.Environment.GetEnvironmentVariable("TESTONGPU");
|
|
if (testOnGpu == null || !testOnGpu.Equals("ON"))
|
|
{
|
|
Skip = "GPU testing not enabled";
|
|
}
|
|
}
|
|
}
|
|
|
|
private class SkipNonPackageTests : FactAttribute
|
|
{
|
|
public SkipNonPackageTests()
|
|
{
|
|
var skipNonPackageTests = System.Environment.GetEnvironmentVariable("SKIPNONPACKAGETESTS");
|
|
if (skipNonPackageTests != null && skipNonPackageTests.Equals("ON"))
|
|
{
|
|
Skip = "Test skipped while testing the package as it is not within the scope";
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelRunAsyncTask")]
|
|
private async Task TestModelRunAsyncTask()
|
|
{
|
|
Float16[] inputData = { new Float16(15360), new Float16(16384), new Float16(16896), new Float16(17408), new Float16(17664) };
|
|
long[] shape = { 1, 5 };
|
|
|
|
var inputNames = new List<string> { "input" };
|
|
var inputValues = new List<OrtValue> { OrtValue.CreateTensorValueFromMemory(inputData, shape) };
|
|
|
|
var outputNames = new List<string> { "output" };
|
|
var outputValues = new List<OrtValue> { OrtValue.CreateAllocatedTensorValue(OrtAllocator.DefaultInstance,
|
|
TensorElementType.Float16, shape) };
|
|
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_FLOAT16.onnx");
|
|
using (SessionOptions opt = new SessionOptions())
|
|
{
|
|
opt.IntraOpNumThreads = 2;
|
|
using (var session = new InferenceSession(model, opt))
|
|
{
|
|
try
|
|
{
|
|
var task = session.RunAsync(null, inputNames, inputValues, outputNames, outputValues);
|
|
var outputs = await task;
|
|
var valueOut = outputs.ElementAt<OrtValue>(0);
|
|
var float16s = valueOut.GetTensorDataAsSpan<Float16>().ToArray();
|
|
Assert.Equal(new Float16(16896), float16s[2]);
|
|
}
|
|
catch
|
|
{
|
|
Assert.True(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestModelRunAsyncTaskFail")]
|
|
private async Task TestModelRunAsyncTaskFail()
|
|
{
|
|
Float16[] inputData = { new Float16(15360), new Float16(16384), new Float16(16896), new Float16(17408), new Float16(17664) };
|
|
long[] shape = { 1, 5 };
|
|
|
|
var inputNames = new List<string> { "input" };
|
|
var inputValues = new List<OrtValue> { OrtValue.CreateTensorValueFromMemory(inputData, shape) };
|
|
|
|
var outputNames = new List<string> { "output" };
|
|
var outputValues = new List<OrtValue> { OrtValue.CreateAllocatedTensorValue(OrtAllocator.DefaultInstance,
|
|
TensorElementType.Float16, shape) };
|
|
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("test_types_FLOAT16.onnx");
|
|
using (SessionOptions opt = new SessionOptions())
|
|
{
|
|
opt.IntraOpNumThreads = 1; // this will make RunAsync fail
|
|
string err = "";
|
|
using (var session = new InferenceSession(model, opt))
|
|
{
|
|
try
|
|
{
|
|
var task = session.RunAsync(null, inputNames, inputValues, outputNames, outputValues);
|
|
var outputs = await task;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
err = ex.Message;
|
|
}
|
|
finally
|
|
{
|
|
Assert.Contains("intra op thread pool must have at least one thread for RunAsync", err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if USE_AZURE
|
|
[Fact(DisplayName = "TestLoadAzureEP")]
|
|
private void TestLoadAzureEP()
|
|
{
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("mul_1.onnx");
|
|
|
|
using (var memInfo = new OrtMemoryInfo(OrtMemoryInfo.allocatorCPU,
|
|
OrtAllocatorType.ArenaAllocator, 0, OrtMemType.Default))
|
|
using (var arenaCfg = new OrtArenaCfg(0, -1, -1, -1))
|
|
{
|
|
using (var sessionOptions = new SessionOptions())
|
|
{
|
|
sessionOptions.AppendExecutionProvider("AZURE");
|
|
try {
|
|
using (var session1 = new InferenceSession(model, sessionOptions))
|
|
{
|
|
|
|
}
|
|
}
|
|
catch (Exception) {
|
|
Assert.True(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|