Skip to main content
Tensors are multi-dimensional arrays used for input and output data in ONNX Runtime.

Namespace

Microsoft.ML.OnnxRuntime.Tensors

Tensor Element Types

TensorElementType Enum

Supported tensor data types:
public enum TensorElementType
{
    Float = 1,      // float32
    UInt8 = 2,      // uint8
    Int8 = 3,       // int8
    UInt16 = 4,     // uint16
    Int16 = 5,      // int16
    Int32 = 6,      // int32
    Int64 = 7,      // int64
    String = 8,     // string
    Bool = 9,       // bool
    Float16 = 10,   // float16
    Double = 11,    // float64/double
    UInt32 = 12,    // uint32
    UInt64 = 13,    // uint64
    Complex64 = 14, // complex64
    Complex128 = 15,// complex128
    BFloat16 = 16   // bfloat16
}

DenseTensor<T>

The main tensor class for dense multi-dimensional arrays.

Constructors

DenseTensor(T[], int[])

Creates a tensor from an array and shape.
public DenseTensor(T[] data, int[] dimensions)
Example:
using Microsoft.ML.OnnxRuntime.Tensors;

// Create a 2x3 tensor
var data = new float[] { 1, 2, 3, 4, 5, 6 };
var shape = new int[] { 2, 3 };
var tensor = new DenseTensor<float>(data, shape);

// Access elements
Console.WriteLine(tensor[0, 0]); // 1
Console.WriteLine(tensor[1, 2]); // 6

DenseTensor(int[])

Creates an empty tensor with specified dimensions.
public DenseTensor(int[] dimensions)
Example:
// Create empty 3x4x5 tensor
var tensor = new DenseTensor<float>(new[] { 3, 4, 5 });

// Fill with values
for (int i = 0; i < 3; i++)
    for (int j = 0; j < 4; j++)
        for (int k = 0; k < 5; k++)
            tensor[i, j, k] = i * j * k;

DenseTensor(Memory<T>, int[])

Creates a tensor backed by Memory<T>.
public DenseTensor(Memory<T> memory, int[] dimensions)
Example:
var memory = new Memory<float>(new float[12]);
var tensor = new DenseTensor<float>(memory, new[] { 3, 4 });

Properties

Dimensions

Gets the tensor dimensions.
public ReadOnlySpan<int> Dimensions { get; }
Example:
var tensor = new DenseTensor<float>(new[] { 2, 3, 4 });
Console.WriteLine($"Shape: [{string.Join(", ", tensor.Dimensions.ToArray())}]");
// Output: Shape: [2, 3, 4]

Length

Gets total number of elements.
public int Length { get; }
Example:
var tensor = new DenseTensor<float>(new[] { 2, 3, 4 });
Console.WriteLine($"Total elements: {tensor.Length}"); // 24

Rank

Gets the number of dimensions.
public int Rank { get; }

Methods

Clone

Creates a deep copy of the tensor.
public DenseTensor<T> Clone()
Example:
var original = new DenseTensor<float>(new float[] { 1, 2, 3 }, new[] { 3 });
var copy = original.Clone();
copy[0] = 10; // Doesn't affect original

Reshape

Reshapes the tensor to new dimensions.
public DenseTensor<T> Reshape(int[] dimensions)
Example:
var tensor = new DenseTensor<float>(new[] { 2, 6 });
var reshaped = tensor.Reshape(new[] { 3, 4 });

ToArray

Converts tensor to flat array.
public T[] ToArray()
Example:
var tensor = new DenseTensor<float>(new float[] { 1, 2, 3, 4 }, new[] { 2, 2 });
var array = tensor.ToArray();
// array = [1, 2, 3, 4]

NamedOnnxValue

Wrapper for named tensor inputs/outputs.

Creating Named Values

CreateFromTensor

Creates a named value from a tensor.
public static NamedOnnxValue CreateFromTensor<T>(string name, Tensor<T> value)
Example:
var tensor = new DenseTensor<float>(new float[] { 1, 2, 3 }, new[] { 1, 3 });
var namedValue = NamedOnnxValue.CreateFromTensor("input", tensor);

var inputs = new List<NamedOnnxValue> { namedValue };

Accessing Tensor Data

AsTensor<T>

Extracts tensor from named value.
public Tensor<T> AsTensor<T>()
Example:
using (var results = session.Run(inputs))
{
    foreach (var result in results)
    {
        var tensor = result.AsTensor<float>();
        var data = tensor.ToArray();
        Console.WriteLine($"{result.Name}: {string.Join(", ", data)}");
    }
}

Common Tensor Operations

Creating Image Tensors

using System.Drawing;
using System.Drawing.Imaging;

public static DenseTensor<float> ImageToTensor(Bitmap image)
{
    // Resize to model input size
    var resized = new Bitmap(image, new Size(224, 224));
    
    // Create tensor in CHW format (channels, height, width)
    var tensor = new DenseTensor<float>(new[] { 1, 3, 224, 224 });
    
    // Mean and std for normalization (ImageNet)
    var mean = new[] { 0.485f, 0.456f, 0.406f };
    var std = new[] { 0.229f, 0.224f, 0.225f };
    
    for (int y = 0; y < 224; y++)
    {
        for (int x = 0; x < 224; x++)
        {
            var pixel = resized.GetPixel(x, y);
            
            // Normalize and set RGB channels
            tensor[0, 0, y, x] = (pixel.R / 255f - mean[0]) / std[0];
            tensor[0, 1, y, x] = (pixel.G / 255f - mean[1]) / std[1];
            tensor[0, 2, y, x] = (pixel.B / 255f - mean[2]) / std[2];
        }
    }
    
    return tensor;
}

// Usage
var image = new Bitmap("image.jpg");
var tensor = ImageToTensor(image);
var input = NamedOnnxValue.CreateFromTensor("input", tensor);

Batch Processing

public static DenseTensor<float> CreateBatch(List<float[]> samples, int featureSize)
{
    int batchSize = samples.Count;
    var tensor = new DenseTensor<float>(new[] { batchSize, featureSize });
    
    for (int i = 0; i < batchSize; i++)
    {
        for (int j = 0; j < featureSize; j++)
        {
            tensor[i, j] = samples[i][j];
        }
    }
    
    return tensor;
}

// Usage
var samples = new List<float[]>
{
    new float[] { 1.0f, 2.0f, 3.0f },
    new float[] { 4.0f, 5.0f, 6.0f },
    new float[] { 7.0f, 8.0f, 9.0f }
};

var batchTensor = CreateBatch(samples, 3);
// Shape: [3, 3]

Working with Sequences

public static DenseTensor<long> CreateSequenceTensor(List<long> sequence, int maxLength)
{
    var tensor = new DenseTensor<long>(new[] { 1, maxLength });
    
    // Copy sequence and pad with zeros
    for (int i = 0; i < maxLength; i++)
    {
        tensor[0, i] = i < sequence.Count ? sequence[i] : 0;
    }
    
    return tensor;
}

// Usage for text tokenization
var tokenIds = new List<long> { 101, 2023, 2003, 1037, 3231, 102 };
var inputIds = CreateSequenceTensor(tokenIds, 512);

String Tensors

var strings = new[] { "hello", "world", "onnx" };
var stringTensor = new DenseTensor<string>(strings, new[] { 3 });

var input = NamedOnnxValue.CreateFromTensor("text_input", stringTensor);

Advanced Tensor Usage

Memory-Efficient Tensors

// Use Memory<T> for zero-copy scenarios
public static DenseTensor<float> CreateFromExistingBuffer(float[] buffer, int[] shape)
{
    var memory = new Memory<float>(buffer);
    return new DenseTensor<float>(memory, shape);
}

// Buffer is not copied, tensor uses it directly
var buffer = new float[1000];
var tensor = CreateFromExistingBuffer(buffer, new[] { 10, 10, 10 });

Slicing Tensors

public static DenseTensor<T> GetBatchItem<T>(DenseTensor<T> batch, int index)
{
    var shape = batch.Dimensions.ToArray();
    var itemShape = shape.Skip(1).ToArray();
    var itemSize = itemShape.Aggregate(1, (a, b) => a * b);
    
    var itemData = new T[itemSize];
    var offset = index * itemSize;
    
    Array.Copy(batch.ToArray(), offset, itemData, 0, itemSize);
    
    return new DenseTensor<T>(itemData, itemShape);
}

Type Conversions

public static DenseTensor<TOut> ConvertTensor<TIn, TOut>(
    DenseTensor<TIn> input,
    Func<TIn, TOut> converter)
{
    var output = new DenseTensor<TOut>(input.Dimensions.ToArray());
    var inputArray = input.ToArray();
    var outputArray = inputArray.Select(converter).ToArray();
    
    Array.Copy(outputArray, 0, output.Buffer.ToArray(), 0, outputArray.Length);
    return output;
}

// Usage: Convert int to float
var intTensor = new DenseTensor<int>(new[] { 1, 2, 3 }, new[] { 3 });
var floatTensor = ConvertTensor(intTensor, x => (float)x);

Performance Tips

  1. Reuse tensors: Avoid creating new tensors in hot paths
  2. Use Memory<T>: For zero-copy scenarios
  3. Batch operations: Process multiple items together
  4. Pre-allocate: Create tensors with known sizes upfront
  5. Avoid ToArray(): Access elements directly when possible

Complete Example: NLP Model

using Microsoft.ML.OnnxRuntime;
using Microsoft.ML.OnnxRuntime.Tensors;
using System;
using System.Collections.Generic;
using System.Linq;

public class BertTokenClassifier
{
    private InferenceSession _session;
    private const int MaxSequenceLength = 128;
    
    public BertTokenClassifier(string modelPath)
    {
        _session = new InferenceSession(modelPath);
    }
    
    public float[][] Classify(List<long> inputIds, List<long> attentionMask)
    {
        // Create input tensors
        var inputIdsTensor = CreateTensor(inputIds);
        var attentionMaskTensor = CreateTensor(attentionMask);
        
        var inputs = new List<NamedOnnxValue>
        {
            NamedOnnxValue.CreateFromTensor("input_ids", inputIdsTensor),
            NamedOnnxValue.CreateFromTensor("attention_mask", attentionMaskTensor)
        };
        
        // Run inference
        using (var results = _session.Run(inputs))
        {
            var logits = results.First().AsTensor<float>();
            return ConvertToJaggedArray(logits);
        }
    }
    
    private DenseTensor<long> CreateTensor(List<long> data)
    {
        var tensor = new DenseTensor<long>(new[] { 1, MaxSequenceLength });
        
        for (int i = 0; i < MaxSequenceLength; i++)
        {
            tensor[0, i] = i < data.Count ? data[i] : 0;
        }
        
        return tensor;
    }
    
    private float[][] ConvertToJaggedArray(Tensor<float> tensor)
    {
        var dims = tensor.Dimensions.ToArray();
        var result = new float[dims[0]][];
        
        for (int i = 0; i < dims[0]; i++)
        {
            result[i] = new float[dims[1]];
            for (int j = 0; j < dims[1]; j++)
            {
                result[i][j] = tensor[i, j];
            }
        }
        
        return result;
    }
}

See Also