/// <summary> /// This is a factory method that creates a disposable instance of FixedBufferOnnxValue /// on top of a buffer. Internally, it will pin managed buffer and will create /// an OrtValue containing a tensor that will not own the memory. /// Such instance of FixedBufferOnnxValue can be used both as input and output in InferenceSession.Run() /// overload. As compared to CreateFromTensor(), this allows you to pass in buffers with custom data types /// that are blittable as defined in https://docs.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types /// I.e. those that have the same binary representation as the original type. This includes all existing types /// but may also allow using custom types for Float16 and BFloat16 providing they have the same layout and size. /// The resulting instance must be disposed of to release pinned memory and deallocate native OrtValue /// See example below. /// </summary> /// <typeparam name="T">Blittable data type, compatible with supported types</typeparam> /// <param name="memoryInfo">memoryInfo. For managed buffers simply use OrtMemoryInfo.DefaultInstance</param> /// <param name="memory"></param> /// <param name="elementType">TensorElementType</param> /// <param name="shape">shape of the tensor to be created</param> /// <param name="bytesSize">size of the allocation in bytes</param> /// <returns>a disposable instance of FixedBufferOnnxValue</returns> /// <example> /// Here is an example of using a 3rd party library class for processing float16/bfloat16. /// Currently, to pass tensor data and create a tensor one must copy data to Float16/BFloat16 structures /// so DenseTensor can recognize it. /// /// If you are using a library that has a class Half and it is blittable, that is its managed in memory representation /// matches native one and its size is 16-bits, you can use the following conceptual example /// to feed/fetch data for inference using Half array. This allows you to avoid copying data from your Half[] to Float16[] /// /// \code{.cs} /// unsafe { Debug.Assert(sizeof(ushort) == sizeof(Half)); } /// Half[] input = new Half[] { 5646, 12345 }; /// var input_shape = new long[] {input.Length}; /// Half[] output = new Half[40]; // Whatever the expected len/shape is must match /// var output_shape = new long[] {output.Length}; /// /// var memInfo = OrtMemoryInfo.DefaultInstance; // CPU /// /// using(var fixedBufferInput = FixedBufferOnnxvalue.CreateFromMemory<Half>(memInfo, /// input, TensorElementType.Float16, input_shape, input.Length * sizeof(ushort)) /// using(var fixedBufferOutput = FixedBufferOnnxvalue.CreateFromMemory<Half>(memInfo, /// output, TensorElementType.Float16, output_shape, output.Length * sizeof(ushort)) /// { /// FixedBufferOnnxvalue[] inputValues = new FixedBufferOnnxvalue[]{fixedBufferInput}; /// FixedBufferOnnxvalue[] outputValues = new FixedBufferOnnxvalue[]{fixedBufferOutput}; /// session.Run(inputNames, inputValues, outputNames, outputValues); /// // Output is now in output[] /// } /// \endcode /// </example> public static FixedBufferOnnxValue CreateFromMemory <T>(OrtMemoryInfo memoryInfo, Memory <T> memory, TensorElementType elementType, long[] shape, long bytesSize) { if (elementType == TensorElementType.String) { throw new ArgumentException("String data type is not supported"); } var memHandle = memory.Pin(); try { IntPtr memPtr; unsafe { memPtr = (IntPtr)memHandle.Pointer; } var ortValue = OrtValue.CreateTensorValueWithData(memoryInfo, elementType, shape, memPtr, bytesSize); return(new FixedBufferOnnxValue(memHandle, ortValue, OnnxValueType.ONNX_TYPE_TENSOR, elementType)); } catch (Exception) { memHandle.Dispose(); throw; } }
/// <summary> /// Bind model output to an OrtValue as Tensor with a given type and shape. An instance of OrtMemoryAllocaiton /// owns the memory and should be alive for the time of execution.The size of the allocation can not be less than required /// by the Tensor of the given size. /// </summary> /// <param name="name">of the output</param> /// <param name="elementType">tensor element type</param> /// <param name="shape">tensor shape</param> /// <param name="allocation">allocated memory</param> public void BindOutput(string name, Tensors.TensorElementType elementType, long[] shape, OrtMemoryAllocation allocation) { using (var ortValue = OrtValue.CreateTensorValueWithData(allocation.Info, elementType, shape, allocation.Pointer, allocation.Size)) BindInputOrOutput(name, ortValue.Handle, false); }
/// <summary> /// Bind external allocation as input or output. /// The allocation is owned by the user code. /// </summary> /// <param name="name">name </param> /// <param name="allocation">non ort allocated memory</param> /// <param name="isInput">whether this is an input or output</param> private void BindExternalAllocation(string name, OrtExternalAllocation allocation, bool isInput) { using (var ortValue = OrtValue.CreateTensorValueWithData(allocation.Info, allocation.ElementType, allocation.Shape, allocation.Pointer, allocation.Size)) BindInputOrOutput(name, ortValue.Handle, isInput); }