MLArrayFeature

class NatML.Features.MLArrayFeature<T> : MLFeature, IMLEdgeFeature, IMLCloudFeature

This is a multidimensional array feature, a.k.a a tensor. Most models which accept tensors will accept an array feature in NatML.

The array data type T is always unmanaged.

Array features are always views of a pre-allocated array or buffer. As such, creating an array feature will never allocate tensor memory.

Creating the Feature

The array feature can be created from any numeric array or buffer representation:

From a Managed Array

/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="shape">Feature shape.</param>
MLArrayFeature (T[] data, int[] shape = null);

An array feature can be created from a managed array. In rare cases where it is useful to fully specify the feature type, there is an overload which accepts the array type:

/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="type">Feature type.</param>
MLArrayFeature (T[] data, MLArrayType type);

From a Native Array

The array feature provides variants of the managed array constructors where the data argument is a NativeArray<T>. This can be useful for working with certain performance-critical Unity API's like Burst:

/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="shape">Feature shape.</param>
MLArrayFeature (NativeArray<T> data, int[] shape = null);

Similarly, in cases where it is necessary to explicitly specify the array feature type, there is a corresponding overload:

/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="type">Feature type.</param>
MLArrayFeature (NativeArray<T> data, MLArrayType type);

From a Native Buffer

The array feature provides variants of the managed array constructors where the data argument is a typed native buffer. These can be useful for making predictions on arrays from native code or external libraries like OpenCV:

/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="shape">Feature shape.</param>
MLArrayFeature (T* data, int[] shape = null);

There is a corresponding constructor for specifying the feature type:

/// <summary>
/// Create an array feature.
/// </summary>
/// <param name="data">Feature data.</param>
/// <param name="type">Feature type.</param>
MLArrayFeature (T* data, MLArrayType type);

The data buffer MUST remain valid for the lifetime of the array feature.

From an Edge Feature

/// <summary>
/// Create an array feature from an Edge ML feature.
/// Note that this does NOT take ownership of the edge feature.
/// As such the edge feature must be explicitly disposed by the client.
/// </summary>
/// <param name="feature">Edge ML feature. This MUST be an array feature.</param>
MLArrayFeature (MLEdgeFeature feature);

An array feature can be created from an MLEdgeFeature. This is useful for making predictions with an MLEdgeModel .

The feature MUST have a numeric data type.

From a Cloud Feature

/// <summary>
/// Create an array feature from a cloud feature.
/// </summary>
/// <param name="feature">Cloud feature.</param>
MLArrayFeature (MLCloudFeature feature);

The array feature can be created from an MLCloudFeature. This is useful for making predictions with an MLCloudModel .

The feature MUST have a numeric data type.

Inspecting the Feature

The array feature provides information about its shape.

Feature Type

/// <summary>
/// Feature type.
/// </summary>
MLFeatureType type { get; }

Refer to the Inspecting the Feature section of the MLFeature class for more information.

The type is always an MLArrayType.

Feature Shape

/// <summary>
/// Feature shape.
/// </summary>
int[] shape { get; }

The feature shape is a convenience property which provides the shape from the feature type.

The shape can be null if the feature was created with no shape.

Element Count

/// <summary>
/// Feature element count.
/// </summary>
int elementCount { get; }

The element count is a convenience property which provides the element count from the feature type.

The elementCount will be zero when the feature does not have a shape.

Accessing Feature Data

The array feature provides accessors for reading and writing feature data.

Multi-Indexing

/// <summary>
/// Get or set a value at a specified multi-index.
/// </summary>
/// <param name="idx">Multi-index.</param>
T this [params int[] idx] { get; set; }

The array feature provides support for multi-indexing. This is a common pattern for working with tensors in machine learning:

// With an array feature
var feature = new MLArrayFeature<float>(...);
// You can index across multiple dimensions
var logit = feature[0,12,29,1];

Multiple indexing requires the array feature to have a valid shape, but linear indexing (i.e. indexing with a single number) does not.

The array feature does not perform bounds checking for performance, so make sure to always index correctly.

The array feature also supports linear indexing, in which case it accesses the elements of the feature assuming a flat shape:

// You can also index linearly, disregarding the shape
var logit = feature[392];

Copying

/// <summary>
/// Copy the array feature into another feature.
/// This copies `destination.elementCount * sizeof(U)` elements.
/// </summary>
/// <param name="destination">Feature to copy data into.</destination>
void CopyTo<U> (MLArrayFeature<U> destination) where U : unmanaged;

The array feature can copy it data into another array feature.

This method copies destination.elementCount * sizeof(U) bytes into the destination feature.

This method does not respect any permutations that have been applied to the array feature.

To copy data into a managed array, native buffer, or other destination, first create an MLArrayFeature to wrap the destination, then use the CopyTo method.

Converting to Array

/// <summary>
/// Convert the array feature to a flattened array.
/// </summary>
/// <returns>Result array.</returns>
 T[] ToArray ();

The array feature can copy its data into an array and return the array. The destination array type can also be specified:

/// <summary>
/// Convert the array feature to a flattened array.
/// This method always returns a copy of the array feature data.
/// </summary>
/// <returns>Result array.</returns>
U[] ToArray<U> () where U : unmanaged;

This method does not respect any permutations that have been applied to the array feature.

Pinning

/// <summary>
/// Pin the array feature.
/// </summary>
ref T GetPinnableReference ();

The array feature supports pinning, allowing direct access to the underlying feature data while bypassing all checks. This can be used in unsafe context with the fixed statement:

// Given an array feature
MLArrayFeature<float> feature = ...;
// Manually set the 12th element in the feature by pinning
fixed (float* featureData = feature)
    featureData[11] = 420.69;

Pinning is mostly used for bulk read or write operations. Use multi-indexing for individual element access.

Do not use pinning unless you know exactly what you are doing. Mistakes are almost guaranteed to result in segmentation faults and hard crashes.

Viewing Operations

The array feature supports viewing operations. Each of these operations do not allocate any memory; they simply return a shallow feature that has the proper shape.

Permute

/// <summary>
/// Permute the dimensions of this array feature.
/// This operation is a generalization of the transpose operation.
/// </summary>
/// <param name="dims">Permuted dimensions.</param>
/// <returns>Array feature with permuted dimensions.</returns>
MLArrayFeature<T> Permute (params int[] dims);

The array feature's dimensions can be permuted, allowing different dimensions to be swapped (like transposing):

// Create an array feature with shape (3,5)
var feature = new MLArrayFeature<float>(..., new [] { 3, 5 });
Debug.Log(feature.shape);              // (3,5)
// Transpose it by permuting dimensions
var transposedFeature = feature.Permute(1, 0);
Debug.Log(transposedFeature.shape);    // (5,3)

View

/// <summary>
/// Create a view of this array feature with a different shape.
/// The element count of the new shape MUST match that of the feature.
/// </summary>
/// <param name="shape">New shape.</param>
/// <returns>Array feature with new shape.</returns>
MLArrayFeature<T> View (params int[] shape);

The array feature supports creating a view of the feature data with a different shape:

// Create an array feature
var feature = new MLArrayFeature<float>(..., new [] { 5, 30 });
Debug.Log(feature.shape);          // (5,30)
// View the feature with a different shape
var viewedFeature = feature.View(5, 10, 3); 
Debug.Log(viewedFeature.shape);    // (5,10,3)

The element count of the view shape must match the element count of the feature.

Creating an Edge Feature

/// <summary>
/// Create an edge feature that is ready for prediction with edge models.
/// </summary>
/// <param name="type">Feature type used to create the edge feature.</param>
/// <returns>Edge feature.</returns>
MLEdgeFeature IMLEdgeFeature.Create (MLFeatureType type);

INCOMPLETE.

Creating a Cloud Feature

/// <summary>
/// Create a cloud feature that is ready for prediction with cloud models.
/// </summary>
/// <param name="type">Feature type used to create the cloud feature.</param>
/// <returns>Cloud feature.</returns>
MLCloudFeature IMLCloudFeature.Create (MLFeatureType type)

INCOMPLETE.

Last updated