# Working with data

## Tensor

In Barracuda, Tensor values can be accessed using channels-last layout.

Four dimensional (or less) tensors should be prefered for performance reasons where possible. They can be accessed using `batch`

, `height`

, `width`

, `channels`

dimensions.

However up to 8 dimensional tensors are supported. The full set of supported dimensions is `sequence`

, `direction`

, `batch`

, `extraDimension`

, `depth`

, `height`

, `width`

, `channels`

.

Here is an exemple of Barracuda memory layout with a 4 dimensional NHWC tensor.
**Note:** The native ONNX data layout is channels-first. Barracuda automatically converts ONNX models to channel-last layout.

### Data access

You can interact with `Tensor`

data via multi-dimensional array operators:

```
var tensor4D = new Tensor(batchCount, height, width, channelCount);
// As N batches of 3 dimensional data: N x {H, W, C}
// ie accessing element at index [0,0,N,0,0,H,W,C] in this Tensor.
tensor4D[n, h, w, c] = 1.0f;
// As N batches of 1 dimensional data: N x {C}.
// ie accessing element at index [0,0,N,0,0,0,0,C] in this Tensor.
tensor4D[n, c] = 2.0f;
// As a flat array.
// accessing element at offset `index` in this Tensor.
tensor4D[ i] = 3.0f;
// Additionally for tensor with more than 4D dimension one can access data using:
var tensor8D = new Tensor(new TensorShape(sequence, direction, batchCount, time, depth, height, width, channelCount));
// As SxRxN batches of 5 dimensional data: SxRxN x {T, D, H, W, C}
// ie accessing element at index [S,R,N,T,D,H,W,C] in this Tensor.
tensor8D[s, r , n, t, d, h, w, c] = 1.0f;
// As N batches of 4 dimensional data: N x {D, H, W, C}
// ie accessing element at index [0,0,N,0,D,H,W,C] in this Tensor.
tensor8D[n, d, h, w, c] = 1.0f;
```

### Constructor

Multiple `Tensor`

constructors cover a variety of scenarios up to 8 dimensions. By default tensors initialize with `0`

upon construction, unless you provide an initialization `Array`

:

```
// batch of 1 dimensional data, 0 initialized: batchCount x {elementCount}
tensor = new Tensor(batchCount, elementCount);
// batch of 3 dimensional data, 0 initialized: batchCount x {height, width, channelCount}
tensor = new Tensor(batchCount, height, width, channelCount);
// sequence * direction * batch of 5 dimensional data, 0 initialized: sequence * direction * batchCount x {time, depth, height, width, channelCount}
tensor = new Tensor(new TensorShape(sequence, direction, batchCount, time, depth, height, width, channelCount));
```

```
var stridedArray = new float[batchCount * elementCount] { ... };
// batch of 1 dimensional data, initialized from strided array
tensor = new Tensor(batchCount, elementCount, stridedArray);
```

```
var jaggedArray = new float[batchCount][elementCount] { ... };
// batch of 1 dimensional data, initialized from jagged array
tensor = new Tensor(batchCount, elementCount, jaggedArray);
```

```
Texture2D texture = ...;
// tensor initialized with texture data: 1 x { texture.width, texture.height, 3}
tensor = new Tensor(texture);
```

You can query the shape of the `Tensor`

object, but you cannot change the shape of the `Tensor`

. If you need a different shape of `Tensor`

, you must construct a new instance of the `Tensor`

object:

```
var shape = tensor.shape;
Debug.Log(shape + " or " + shape.sequenceLength + shape.numberOfDirections + shape.batch + shape.extraDimension + shape.depth +shape.height + shape.width + shape.channels);
```

## Texture constructor

You can create a `Tensor`

from an input `Texture`

or save a `Tensor`

to a `Texture`

directly.

**Note:** When you do this, pixel values are in the range [0,1]. Convert data accordingly if your network is expecting values between [0,255], for example.

### Texture as input

You can directly pass `Texture2D`

, `Texture2DArray`

, `Texture3D`

or `RenderTexture`

to Barracuda without accessing individual pixels on the CPU:

```
// you can treat input pixels as 1 (grayscale), 3 (color) or 4 (color with alpha) channels
var channelCount = 3;
var tensor = new Tensor(texture, channelCount);
```

You can batch multiple textures into the single `Tensor`

object:

```
// these textures form a batch
var textures = new [] { texture0, texture1, texture2, texture3 };
var tensor = new Tensor(textures, channelCount);
```

**Note:** All textures in a batch must have the same width and height dimensions.

### Texture as output

If you want to use Barracuda execution results further in the graphics pipeline, you can copy data from `Tensor`

into a `RenderTexture`

without stalling the CPU or GPU:

```
var tensor = worker.PeekOutput();
var texture = BarracudaTextureUtils.TensorToRenderTexture(tensor);
```

You can reuse the same `RenderTexture`

multiple times:

```
var texture = new RenderTexture(width, height, 0);
// ...
tensor = worker.PeekOutput();
BarracudaTextureUtils.TensorToRenderTexture(tensor, texture);
```

## Cleanup

As a Barracuda user you are responsible for calling `Dispose()`

on inputs, outputs and any data that you created, received via `worker.Fetch()`

or have taken ownership of by calling `tensor.TakeOwnership()`

.

**Note:** This is necessary to free up GPU resources properly.

```
tensor.Dispose();
```

**Note:** You do not need to call `Dispose()`

on tensors that you received via the `worker.PeekOutput()`

call.