mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-22 19:23:30 +00:00
### Description Merge main to WindowsAI ### 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. --> --------- Signed-off-by: Nash <george.nash@intel.com> Signed-off-by: Yiming Hu <yiming.hu@amd.com> Signed-off-by: Liqun Fu <liqfu@microsoft.com> Co-authored-by: Kaz Nishimura <kazssym@linuxfront.com> Co-authored-by: Tianlei Wu <tlwu@microsoft.com> Co-authored-by: Nat Kershaw (MSFT) <nakersha@microsoft.com> Co-authored-by: Yulong Wang <7679871+fs-eire@users.noreply.github.com> Co-authored-by: Changming Sun <chasun@microsoft.com> Co-authored-by: zesongw <zesong.wang@intel.com> Co-authored-by: Yi Zhang <zhanyi@microsoft.com> Co-authored-by: Dmitri Smirnov <yuslepukhin@users.noreply.github.com> Co-authored-by: Yifan Li <109183385+yf711@users.noreply.github.com> Co-authored-by: simonjub <78098752+simonjub@users.noreply.github.com> Co-authored-by: PeixuanZuo <94887879+PeixuanZuo@users.noreply.github.com> Co-authored-by: Adrian Lizarraga <adlizarraga@microsoft.com> Co-authored-by: Edward Chen <18449977+edgchen1@users.noreply.github.com> Co-authored-by: Arthur Islamov <arthur@islamov.ai> Co-authored-by: Jambay Kinley <jambaykinley@microsoft.com> Co-authored-by: Justin Chu <justinchuby@users.noreply.github.com> Co-authored-by: Wei-Sheng Chin <wschin@outlook.com> Co-authored-by: Bowen Bao <bowbao@microsoft.com> Co-authored-by: Hariharan Seshadri <shariharan91@gmail.com> Co-authored-by: Numfor Tiapo <numsmt2@gmail.com> Co-authored-by: Vincent Wang <wangwchpku@outlook.com> Co-authored-by: Pranav Sharma <prs@microsoft.com> Co-authored-by: George Nash <george.nash@intel.com> Co-authored-by: Abhishek Jindal <abjindal@microsoft.com> Co-authored-by: pengwa <pengwa@microsoft.com> Co-authored-by: Yiming Hu <woinck@users.noreply.github.com> Co-authored-by: Jiajia Qin <jiajia.qin@intel.com> Co-authored-by: Lukas Berbuer <36054362+lukasberbuer@users.noreply.github.com> Co-authored-by: Wanming Lin <wanming.lin@intel.com> Co-authored-by: Xavier Dupré <xadupre@users.noreply.github.com> Co-authored-by: aimilefth <60664743+aimilefth@users.noreply.github.com> Co-authored-by: Baiju Meswani <bmeswani@microsoft.com> Co-authored-by: Adam Pocock <adam.pocock@oracle.com> Co-authored-by: Chi Lo <54722500+chilo-ms@users.noreply.github.com> Co-authored-by: RandySheriffH <48490400+RandySheriffH@users.noreply.github.com> Co-authored-by: Randy Shuai <rashuai@microsoft.com> Co-authored-by: Vadym Stupakov <vadim.stupakov@gmail.com> Co-authored-by: Jian Chen <cjian@microsoft.com> Co-authored-by: Brian Lambert <98757707+brian-pieces@users.noreply.github.com> Co-authored-by: Nicolò Lucchesi <nicolo.lucchesi@gmail.com> Co-authored-by: liqun Fu <liqfu@microsoft.com> Co-authored-by: trajep <trajepl@gmail.com> Co-authored-by: Scott McKay <skottmckay@gmail.com> Co-authored-by: Mustafa Ateş Uzun <mustafauzun0@gmail.com> Co-authored-by: MistEO <mistereo@hotmail.com> Co-authored-by: satyajandhyala <satya.k.jandhyala@gmail.com> Co-authored-by: shaahji <96227573+shaahji@users.noreply.github.com> Co-authored-by: Rachel Guo <35738743+YUNQIUGUO@users.noreply.github.com> Co-authored-by: rachguo <rachguo@rachguos-Mini.attlocal.net> Co-authored-by: Caroline Zhu <wolfivyaura@gmail.com> Co-authored-by: Caroline Zhu <carolinezhu@microsoft.com> Co-authored-by: Guenther Schmuelling <guschmue@microsoft.com> Co-authored-by: xhcao <xinghua.cao@intel.com> Co-authored-by: Ella Charlaix <80481427+echarlaix@users.noreply.github.com> Co-authored-by: Xu Xing <xing.xu@intel.com> Co-authored-by: Hector Li <hecli@microsoft.com> Co-authored-by: Ye Wang <52801275+wangyems@users.noreply.github.com> Co-authored-by: Your Name <you@example.com> Co-authored-by: Benedikt Hilmes <benedikt.hilmes@rwth-aachen.de> Co-authored-by: rachguo <rachguo@rachguos-Mac-mini.local> Co-authored-by: George Wu <jywu@microsoft.com> Co-authored-by: JiCheng <wejoncy@163.com> Co-authored-by: Sheil Kumar <smk2007@gmail.com> Co-authored-by: Sheil Kumar <sheilk@microsoft.com> Co-authored-by: cloudhan <guangyunhan@microsoft.com> Co-authored-by: kyoshisuki <143475866+kyoshisuki@users.noreply.github.com> Co-authored-by: aciddelgado <139922440+aciddelgado@users.noreply.github.com> Co-authored-by: tlwu@microsoft.com <tlwu@a100.crj0ad2y1kku1j4yxl4sj10o4e.gx.internal.cloudapp.net> Co-authored-by: Maximilian Müller <44298237+gedoensmax@users.noreply.github.com> Co-authored-by: Tang, Cheng <souptc@gmail.com> Co-authored-by: Cheng Tang <chenta@microsoft.com@orttrainingdev9.d32nl1ml4oruzj4qz3bqlggovf.px.internal.cloudapp.net> Co-authored-by: Cheng Tang <chenta@microsoft.com> Co-authored-by: Jeff Daily <jeff.daily@amd.com> Co-authored-by: cloudhan <cloudhan@outlook.com> Co-authored-by: Yufeng Li <liyufeng1987@gmail.com> Co-authored-by: Zhang Lei <zhang.huanning@hotmail.com> Co-authored-by: Dwayne Robinson <fdwr@hotmail.com> Co-authored-by: Zhipeng Han <zhipeng.han@outlook.com> Co-authored-by: Thiago Crepaldi <thiago.crepaldi@microsoft.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Patrice Vignola <vignola.patrice@gmail.com> Co-authored-by: kunal-vaishnavi <115581922+kunal-vaishnavi@users.noreply.github.com> Co-authored-by: snadampal <87143774+snadampal@users.noreply.github.com> Co-authored-by: Sumit Agarwal <sumitagarwal330@gmail.com> Co-authored-by: Ashwini Khade <askhade@microsoft.com> Co-authored-by: Yang Gu <yang.gu@intel.com> Co-authored-by: Cheng Tang <chenta@a100.crj0ad2y1kku1j4yxl4sj10o4e.gx.internal.cloudapp.net> Co-authored-by: mindest <30493312+mindest@users.noreply.github.com> Co-authored-by: Scott McKay <Scott.McKay@microsoft.com> Co-authored-by: Xavier Dupre <xadupre@microsoft.com@orttrainingdev9.d32nl1ml4oruzj4qz3bqlggovf.px.internal.cloudapp.net> Co-authored-by: guyang3532 <62738430+guyang3532@users.noreply.github.com> Co-authored-by: Carson M <carson@pyke.io> Co-authored-by: sophies927 <107952697+sophies927@users.noreply.github.com>
389 lines
No EOL
15 KiB
C#
389 lines
No EOL
15 KiB
C#
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
using Microsoft.ML.OnnxRuntime.Tensors;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using Xunit;
|
|
using static Microsoft.ML.OnnxRuntime.Tests.InferenceTest;
|
|
|
|
namespace Microsoft.ML.OnnxRuntime.Tests
|
|
{
|
|
[Collection("OrtBinding Tests")]
|
|
public class OrtIoBindingAllocationTests : IDisposable
|
|
{
|
|
private const string _inputName = "data_0";
|
|
private const string _outputName = "softmaxout_1";
|
|
private static readonly OrtAllocator _allocator = OrtAllocator.DefaultInstance;
|
|
|
|
private readonly RunOptions _runOptions;
|
|
private readonly InferenceSession _session;
|
|
private readonly float[] _inputData;
|
|
private readonly float[] _outputData;
|
|
|
|
private readonly long[] _inputShape;
|
|
private readonly long _inputSizeInBytes;
|
|
private readonly long[] _outputShape;
|
|
private readonly long _outputSizeInBytes;
|
|
|
|
private readonly OrtSafeMemoryHandle _inputNativeAllocation;
|
|
private readonly OrtSafeMemoryHandle _outputNativeAllocation;
|
|
|
|
private readonly DisposableListTest<IDisposable> _dispList = new DisposableListTest<IDisposable>();
|
|
|
|
private bool _disposed = false;
|
|
|
|
public OrtIoBindingAllocationTests()
|
|
{
|
|
var tuple = OpenSessionSqueezeNet();
|
|
_session = tuple.Item1;
|
|
_dispList.Add(_session);
|
|
_runOptions = new RunOptions();
|
|
_dispList.Add(_runOptions);
|
|
|
|
_inputData = tuple.Item2;
|
|
_outputData = tuple.Item4;
|
|
|
|
var inputMeta = _session.InputMetadata;
|
|
var outputMeta = _session.OutputMetadata;
|
|
|
|
_inputShape = Array.ConvertAll<int, long>(inputMeta[_inputName].Dimensions, Convert.ToInt64);
|
|
_outputShape = Array.ConvertAll<int, long>(outputMeta[_outputName].Dimensions, Convert.ToInt64);
|
|
|
|
var inputShapeSize = ShapeUtils.GetSizeForShape(_inputShape);
|
|
Assert.Equal(inputShapeSize, _inputData.Length);
|
|
|
|
var outputShapeSize = ShapeUtils.GetSizeForShape(_outputShape);
|
|
Assert.Equal(outputShapeSize, _outputData.Length);
|
|
|
|
_inputSizeInBytes = inputShapeSize * sizeof(float);
|
|
IntPtr allocPtr = Marshal.AllocHGlobal((int)_inputSizeInBytes);
|
|
_inputNativeAllocation = new OrtSafeMemoryHandle(allocPtr);
|
|
_dispList.Add(_inputNativeAllocation);
|
|
|
|
PopulateNativeBuffer<float>(allocPtr, _inputData);
|
|
|
|
_outputSizeInBytes = outputShapeSize * sizeof(float);
|
|
allocPtr = Marshal.AllocHGlobal((int)_outputSizeInBytes);
|
|
_outputNativeAllocation = new OrtSafeMemoryHandle(allocPtr);
|
|
}
|
|
|
|
// Probably redundant as we have no native resources
|
|
~OrtIoBindingAllocationTests()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (_disposed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (disposing)
|
|
{
|
|
_dispList.Dispose();
|
|
}
|
|
_disposed = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// This works only for allocations accessible from host memory
|
|
/// </summary>
|
|
/// <param name="buffer"></param>
|
|
/// <param name="elements"></param>
|
|
private static void PopulateNativeBuffer<T>(OrtMemoryAllocation buffer, T[] elements)
|
|
{
|
|
PopulateNativeBuffer(buffer.Pointer, elements);
|
|
}
|
|
|
|
private static void PopulateNativeBuffer<T>(IntPtr buffer, T[] elements)
|
|
{
|
|
Span<T> bufferSpan;
|
|
unsafe
|
|
{
|
|
bufferSpan = new Span<T>(buffer.ToPointer(), elements.Length);
|
|
}
|
|
elements.CopyTo(bufferSpan);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks that the contents of the native buffer matches the expected output.
|
|
/// </summary>
|
|
private void CheckOutput(IntPtr resultBuffer)
|
|
{
|
|
Span<byte> bufferSpan;
|
|
unsafe
|
|
{
|
|
bufferSpan = new Span<byte>(resultBuffer.ToPointer(), (int)_outputSizeInBytes);
|
|
}
|
|
var outputSpan = MemoryMarshal.Cast<byte, float>(bufferSpan);
|
|
Assert.Equal(_outputData, outputSpan.ToArray(), new FloatComparer());
|
|
}
|
|
|
|
private void ClearOutput()
|
|
{
|
|
Span<byte> bufferSpan;
|
|
unsafe
|
|
{
|
|
bufferSpan = new Span<byte>(_outputNativeAllocation.Handle.ToPointer(), (int)_outputSizeInBytes);
|
|
}
|
|
bufferSpan.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use to free globally allocated memory. Could not find
|
|
/// a framework class.
|
|
/// </summary>
|
|
class OrtSafeMemoryHandle : SafeHandle
|
|
{
|
|
public OrtSafeMemoryHandle(IntPtr allocPtr) : base(allocPtr, true) { }
|
|
|
|
public override bool IsInvalid => handle == IntPtr.Zero;
|
|
|
|
public IntPtr Handle => handle;
|
|
|
|
protected override bool ReleaseHandle()
|
|
{
|
|
Marshal.FreeHGlobal(handle);
|
|
handle = IntPtr.Zero;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestIOBindingWithOrtValues")]
|
|
public void TestIOBindingWithOrtValues()
|
|
{
|
|
ClearOutput();
|
|
|
|
using (var ioBinding = _session.CreateIoBinding())
|
|
{
|
|
// Input OrtValue on top if input buffer
|
|
using (var tensor = OrtValue.CreateTensorValueWithData(OrtMemoryInfo.DefaultInstance,
|
|
TensorElementType.Float,
|
|
_inputShape, _inputNativeAllocation.Handle, _inputSizeInBytes))
|
|
{
|
|
ioBinding.BindInput(_inputName, tensor);
|
|
}
|
|
|
|
// Output OrtValue on top if output buffer
|
|
using (var tensor = OrtValue.CreateTensorValueWithData(OrtMemoryInfo.DefaultInstance,
|
|
TensorElementType.Float,
|
|
_outputShape, _outputNativeAllocation.Handle, _outputSizeInBytes))
|
|
{
|
|
ioBinding.BindOutput(_outputName, tensor);
|
|
}
|
|
|
|
ioBinding.SynchronizeBoundInputs();
|
|
|
|
using (var results = _session.RunWithBoundResults(_runOptions, ioBinding))
|
|
{
|
|
ioBinding.SynchronizeBoundOutputs();
|
|
Assert.Single(results);
|
|
var res = results.First();
|
|
Assert.True(res.IsTensor);
|
|
|
|
var typeAndShape = res.GetTensorTypeAndShape();
|
|
Assert.Equal(_outputData.LongLength, typeAndShape.ElementCount);
|
|
|
|
var dataSpan = res.GetTensorDataAsSpan<float>();
|
|
Assert.Equal(_outputData, dataSpan.ToArray(), new FloatComparer());
|
|
|
|
// The result is good, but we want to make sure that the result actually is
|
|
// in the output memory, not some other place
|
|
CheckOutput(_outputNativeAllocation.Handle);
|
|
}
|
|
|
|
var outputNames = ioBinding.GetOutputNames();
|
|
Assert.Single(outputNames);
|
|
Assert.Equal(_outputName, outputNames[0]);
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestIOBindingWithDeviceBoundOutput")]
|
|
public void TestIOBindingWithDeviceBoundOutput()
|
|
{
|
|
ClearOutput();
|
|
|
|
using (var ioBinding = _session.CreateIoBinding())
|
|
{
|
|
// Input OrtValue on top if input buffer
|
|
using (var tensor = OrtValue.CreateTensorValueWithData(OrtMemoryInfo.DefaultInstance,
|
|
TensorElementType.Float,
|
|
_inputShape, _inputNativeAllocation.Handle, _inputSizeInBytes))
|
|
{
|
|
ioBinding.BindInput(_inputName, tensor);
|
|
}
|
|
|
|
// The output will go into the Ort allocated OrtValue
|
|
ioBinding.BindOutputToDevice(_outputName, OrtMemoryInfo.DefaultInstance);
|
|
ioBinding.SynchronizeBoundInputs();
|
|
|
|
using (var results = _session.RunWithBoundResults(_runOptions, ioBinding))
|
|
{
|
|
ioBinding.SynchronizeBoundOutputs();
|
|
Assert.Single(results);
|
|
var res = results.First();
|
|
Assert.True(res.IsTensor);
|
|
|
|
var typeAndShape = res.GetTensorTypeAndShape();
|
|
Assert.Equal(_outputData.LongLength, typeAndShape.ElementCount);
|
|
|
|
var dataSpan = res.GetTensorDataAsSpan<float>();
|
|
Assert.Equal(_outputData, dataSpan.ToArray(), new FloatComparer());
|
|
}
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "TestIOBindingToOrtAllocatedBuffer")]
|
|
public void TestIOBindingToOrtAllocatedBuffer()
|
|
{
|
|
var ortAllocationInput = _allocator.Allocate((uint)_inputSizeInBytes);
|
|
_dispList.Add(ortAllocationInput);
|
|
PopulateNativeBuffer<float>(ortAllocationInput, _inputData);
|
|
|
|
var ortAllocationOutput = _allocator.Allocate((uint)_outputSizeInBytes);
|
|
_dispList.Add(ortAllocationOutput);
|
|
|
|
using (var ioBinding = _session.CreateIoBinding())
|
|
{
|
|
// Still supporting OrtAllocations overload
|
|
ioBinding.BindInput(_inputName, Tensors.TensorElementType.Float, _inputShape, ortAllocationInput);
|
|
ioBinding.BindOutput(_outputName, Tensors.TensorElementType.Float, _outputShape, ortAllocationOutput);
|
|
ioBinding.SynchronizeBoundInputs();
|
|
using (var outputs = _session.RunWithBoundResults(_runOptions, ioBinding))
|
|
{
|
|
ioBinding.SynchronizeBoundOutputs();
|
|
Assert.Single(outputs);
|
|
var res = outputs.First();
|
|
Assert.True(res.IsTensor);
|
|
|
|
var typeAndShape = res.GetTensorTypeAndShape();
|
|
Assert.Equal(_outputData.LongLength, typeAndShape.ElementCount);
|
|
|
|
var dataSpan = res.GetTensorDataAsSpan<float>();
|
|
Assert.Equal(_outputData, dataSpan.ToArray(), new FloatComparer());
|
|
CheckOutput(ortAllocationOutput.Pointer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
[Collection("OrtBinding Tests")]
|
|
public class OrtBidingCircularTest
|
|
{
|
|
[Fact(DisplayName = "TestIOBinding Demonstrate Circular")]
|
|
public void TestIOBindingDemonstrateCircular()
|
|
{
|
|
// This model has input and output of the same shape, so we can easily feed
|
|
// output to input using binding, or not using one. The example makes use of
|
|
// the binding to demonstrate the circular feeding.
|
|
// With the OrtValue API exposed, one create OrtValues over arbitrary buffers and feed them to the model using
|
|
// OrtValues based Run APIs. Thus, the Binding is not necessary any longer
|
|
//
|
|
// However, here is the demonstration by popular request.
|
|
var model = TestDataLoader.LoadModelFromEmbeddedResource("mul_1.onnx");
|
|
|
|
const string inputName = "X";
|
|
const string outputName = "Y";
|
|
|
|
long[] inputOutputShape = { 3, 2 };
|
|
float[] input = { 1.0F, 2.0F, 3.0F, 4.0F, 5.0F, 6.0F };
|
|
var inputOutputShapeSize = ShapeUtils.GetSizeForShape(inputOutputShape);
|
|
Assert.Equal(inputOutputShapeSize, input.LongLength);
|
|
|
|
var memInput = new Memory<float>(input);
|
|
IntPtr inputPtr;
|
|
|
|
// Output data on the first iteration
|
|
float[] firstIterExpectedOutput = { 1.0F, 4.0F, 9.0F, 16.0F, 25.0F, 36.0F };
|
|
Assert.Equal(inputOutputShapeSize, firstIterExpectedOutput.LongLength);
|
|
|
|
using (var cleanUp = new DisposableListTest<IDisposable>())
|
|
{
|
|
var runOptions = new RunOptions();
|
|
cleanUp.Add(runOptions);
|
|
|
|
var session = new InferenceSession(model);
|
|
cleanUp.Add(session);
|
|
|
|
var ioBinding = session.CreateIoBinding();
|
|
cleanUp.Add(ioBinding);
|
|
|
|
|
|
|
|
var pinInput = memInput.Pin();
|
|
cleanUp.Add(pinInput);
|
|
|
|
// This can be a ptr to arbitrary buffer, not necessarily a pinned one
|
|
unsafe
|
|
{
|
|
inputPtr = (IntPtr)pinInput.Pointer;
|
|
}
|
|
|
|
// Bind the input
|
|
using (var ortInput = OrtValue.CreateTensorValueWithData(OrtMemoryInfo.DefaultInstance,
|
|
TensorElementType.Float, inputOutputShape, inputPtr, input.Length * sizeof(float)))
|
|
{
|
|
ioBinding.BindInput(inputName, ortInput);
|
|
}
|
|
|
|
// We could have bound the output as well, but we simply bind it to a device in this case.
|
|
// Just check the result the first time around.
|
|
ioBinding.BindOutputToDevice(outputName, OrtMemoryInfo.DefaultInstance);
|
|
|
|
ioBinding.SynchronizeBoundInputs();
|
|
|
|
// We dispose the output after we rebind it to the input because it will be copied during binding.
|
|
using (var results = session.RunWithBoundResults(runOptions, ioBinding))
|
|
{
|
|
ioBinding.SynchronizeBoundOutputs();
|
|
Assert.Single(results); // One output
|
|
|
|
var res = results.First();
|
|
Assert.True(res.IsTensor);
|
|
|
|
var typeShape = res.GetTensorTypeAndShape();
|
|
Assert.Equal(TensorElementType.Float, typeShape.ElementDataType);
|
|
Assert.Equal(inputOutputShape, typeShape.Shape);
|
|
Assert.Equal(inputOutputShapeSize, typeShape.ElementCount);
|
|
|
|
// First time around the output should match the expected
|
|
Assert.Equal(firstIterExpectedOutput, res.GetTensorDataAsSpan<float>().ToArray());
|
|
|
|
// Now we rebind the output to the input
|
|
// It is the same name, so the OrtValue would be replaced.
|
|
ioBinding.BindInput(inputName, res);
|
|
}
|
|
|
|
// Let's do it 2 more times.
|
|
const int iterations = 2;
|
|
for (int i = 0; i < iterations; ++i)
|
|
{
|
|
using (var results = session.RunWithBoundResults(runOptions, ioBinding))
|
|
{
|
|
ioBinding.SynchronizeBoundOutputs();
|
|
Assert.Single(results); // One output
|
|
var res = results.First();
|
|
Assert.True(res.IsTensor);
|
|
var typeShape = res.GetTensorTypeAndShape();
|
|
Assert.Equal(TensorElementType.Float, typeShape.ElementDataType);
|
|
Assert.Equal(inputOutputShapeSize, typeShape.ElementCount);
|
|
Assert.Equal(inputOutputShape, typeShape.Shape);
|
|
|
|
ioBinding.BindInput(inputName, res);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
} |