# Working with data

## Tensor

In Barracuda, you can access Tensor values via the `batch`

, `height`

, `width`

, `channels`

NHWC layout also known as channels-last:

**Note:** The native ONNX data layout is NCHW, or channels-first. Barracuda automatically converts ONNX models to NHWC layout.

### Data access

You can interact with `Tensor`

data via multi-dimensional array operators:

```
var tensor = new Tensor(batchCount, height, width, channelCount);
// as N batches of 3 dimensional data: N x {X, Y, C}
tensor[n, y, x, c] = 1.0f;
// as N batches of 1 dimensional data: N x {C}
tensor[n, c] = 2.0f;
// as flat array
tensor[ i] = 3.0f;
```

### Constructor

Multiple `Tensor`

constructors cover a variety of scenarios. By default tensors initialize with `0`

upon construction, unless you provide an initialization `Array`

:

```
// batch of 3 dimensional data, 0 initialized: batchCount x {height, width, channelCount}
tensor = new Tensor(batchCount, height, width, channelCount);
// batch of 1 dimensional data, 0 initialized: batchCount x {elementCount}
tensor = new Tensor(batchCount, elementCount);
```

```
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.batch + 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.