Manipulation

Devices and information

Move to CPU

void Tensor::toCPU(int dev = DEV_CPU)

Clone a tensor to the CPU.

Tensor* t1 = Tensor::zeros({2, 3}, DEV_GPU); // Tensor created in the GPU
t1->toCPU(); // Tensor transferred to CPU

Move to GPU

void Tensor::toGPU(int dev = DEV_GPU)

Clone a tensor to the GPU.

Tensor* t1 = Tensor::zeros({2, 3}, DEV_CPU); // Tensor created in the CPU
t1->toGPU(); // Tensor transferred to GPU

Check tensor device

int Tensor::isCPU()

Check if the tensor is in CPU.

Returns

int

Tensor* t1 = Tensor::zeros({2, 3}, DEV_GPU); // Tensor created in the GPU
t1->isCPU(); // returns 0
int Tensor::isGPU()

Check if the tensor is in GPU.

Returns

int

Tensor* t1 = Tensor::zeros({2, 3}, DEV_GPU); // Tensor created in the GPU
t1->isGPU(); // returns 1
int Tensor::isFPGA()

Check if the tensor is in FPGA.

Returns

int

Tensor* t1 = Tensor::zeros({2, 3}, DEV_GPU); // Tensor created in the GPU
t1->isFPGA(); // returns 0
string Tensor::getDeviceName() const

Returns the device name where the tensor is allocated (“CPU”, “GPU” or “FPGA”)

Returns

string

Tensor* t1 = Tensor::zeros({2, 3}, DEV_GPU); // Tensor created in the GPU
t1->getDeviceName(); // returns "GPU"

Get information from tensor

void Tensor::info()

Print shape, device and size information.

Returns

void

Tensor* t1 = Tensor::empty({2, 3});
t1->info();
// -------------------------------
// class:         Tensor
// ndim:          2
// shape:         (2, 3)
// strides:       (3, 1)
// itemsize:      6
// contiguous:    1
// order:         C
// data pointer:  0x7f827a6060d8
// is shared:     0
// type:          float (4 bytes)
// device:        CPU (code = 0)
// -------------------------------

Dimension check

static bool Tensor::isSquared(Tensor *A)

Check if all dimensions in the tensor are the same.

Parameters

A – Tensor

Returns

bool

Tensor* t1 = Tensor::zeros({3, 3});
Tensor::isSquared(t1);
// true

Tensor* t2 = Tensor::zeros({3, 3, 3});
Tensor::isSquared(t2);
// true

Tensor* t3 = Tensor::zeros({3, 1, 3});
Tensor::isSquared(t3);
// false

Changing array shape

reshape

Tensor *Tensor::reshape(const vector<int> &new_shape)

Set a new shape to a tensor.

Parameters

new_shape – A vector containing the new shape.

Returns

A new tensor with the result

Tensor* t1 = Tensor::zeros({3, 4});
// [
// [0.00 0.00 0.00 0.00]
// [0.00 0.00 0.00 0.00]
// [0.00 0.00 0.00 0.00]
// ]

t1->reshape_({6, 2});
// [
// [0.00 0.00]
// [0.00 0.00]
// [0.00 0.00]
// [0.00 0.00]
// [0.00 0.00]
// [0.00 0.00]
// ]

// Other ways
Tensor* t2 = Tensor::reshape(t1, {6, 2}); // returns new tensor
t1->reshape(t2, {6,2}) // static

flatten

Tensor *Tensor::flatten()

In-place conversion tensor to a 1D tensor.

Returns

A new tensor with the result

 Tensor* t1 = Tensor::zeros({3, 4});
// [
// [0.00 0.00 0.00 0.00]
// [0.00 0.00 0.00 0.00]
// [0.00 0.00 0.00 0.00]
// ]

t1->flatten_();  // In-place
// [0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00]

// Other ways

Tensor *t2 = Tensor::flatten(t1);  // returns new tensor
t1->flatten(t2) // static

Tiling arrays

repeat

static Tensor *Tensor::repeat(Tensor *A, const vector<unsigned int> &repeats, unsigned int axis = 0, Tensor *output = nullptr, bool derivative = false)

Repeats the elements of a tensor along the specified dimension.

Parameters
  • A – Input tensor.

  • repeats – The number of repetitions for the specified dimension (“int” or “vector of ints”)

  • axis – The axis along which to repeat values.

  • output – Output tensor

  • derivative – Apply derivative for: output = repeat(A)

static Tensor *Tensor::repeat(Tensor *A, unsigned int repeats, unsigned int axis = 0, Tensor *output = nullptr, bool derivative = false)
Tensor* t1 = Tensor::range(1, 6); t1->reshape_({2, 3});
// [
// [1 2 3]
// [4 5 6]
// ]

// Repeat all rows 2 times. (repeat=2, axis=0)
Tensor *t2 = Tensor::repeat(t1, 2, 0);  // returns new tensor
// [
// [1 2 3]
// [1 2 3]
// [4 5 6]
// [4 5 6]
// ]


// Repeat col 1 => 3 times; col 2 => 2 times; col 3 => 1 time. (repeat=[3,2,1], axis=1)
Tensor *t2 = Tensor::repeat(t1, {3, 2, 1}, 1);  // returns new tensor
// [
// [1 1 1 2 2 3]
// [4 4 4 5 5 6]
// ]

tile

static Tensor *Tensor::tile(Tensor *A, const vector<int> &repeats)

Construct an array by repeating A the number of times given by reps.

Parameters
  • A – Input tensor.

  • repeats – The number of repetitions of A along each axis.

  • output – Output tensor

  • derivative – Apply derivative for: output = repeat(A)

// New tensor
Tensor* t1 = new Tensor({1, 2}, {2, 1});
// [
// [1]
// [2]
// ]

// Repeat all rows and columns 2 times each
Tensor* t1_res = Tensor::tile(t1, {2, 2});
// [
// [1 1]
// [2 2]
// [1 1]
// [2 2]
// ]


// New tensor
Tensor* t2 = new Tensor({1, 2, 3}, {3, 1});
// [
// [1]
// [2]
// [3]
// ]

// Repeat columns three times but not rows
Tensor* t2_res = Tensor::tile(t2, {1, 3});
// [
// [1 1 1]
// [2 2 2]
// [3 3 3]
// ]

broadcast

static Tensor *Tensor::broadcast(Tensor *A, Tensor *B, Tensor *output = nullptr)

Returns a new tensor A to be broadcasted into B.

Parameters
  • A – Input tensor.

  • B – Input tensor.

  • output – Output tensor (optional).

Returns

A new tensor C based on A, but prepared to be broadcasted in to B

// Example: Image - constant RGB

// Define mean
auto* mean = new Tensor( {0.485, 0.456, 0.406}, {3}, DEV_CPU);
// [0.485 0.456 0.406]

// Fake image
auto* image = Tensor::ones( {3, 224, 244});
// -------------------------------
// class:         Tensor
// ndim:          3
// shape:         (3, 224, 244)
// strides:       (54656, 244, 1)
// itemsize:      163968
// contiguous:    1
// order:         C
// data pointer:  0x56305561baa8
// is shared:     0
// type:          float (4 bytes)
// device:        CPU (code = 0)
// -------------------------------

// Compute broadcast for mean
Tensor* mean_broadcasted = Tensor::broadcast(mean, image);
// -------------------------------
// class:         Tensor
// ndim:          3
// shape:         (3, 224, 244)
// strides:       (54656, 244, 1)
// itemsize:      163968
// contiguous:    1
// order:         C
// data pointer:  0x56305561f2c8
// is shared:     0
// type:          float (4 bytes)
// device:        CPU (code = 0)
// -------------------------------

// Apply: X-mean
image->sub_(mean_broadcasted);

Transpose-like operations

permute

Tensor *Tensor::permute(const vector<int> &dims)

In-place permutation of tensor dimensions.

Parameters

dims – A vector containing the new order of the dimensions.

Returns

A new tensor with the result

Tensor* t1 = Tensor::range(1, 24); t1->reshape_({2, 3, 4});
// [
// [[1.00 2.00 3.00 4.00]     [5.00 6.00 7.00 8.00]     [9.00 10.00 11.00 12.00]]
// [[13.00 14.00 15.00 16.00] [17.00 18.00 19.00 20.00] [21.00 22.00 23.00 24.00]]
// ]

t1->permute_({2, 1, 0});  // In-place
// [
// [[1.00 13.00] [5.00 17.00] [9.00 21.00]]
// [[2.00 14.00] [6.00 18.00] [10.00 22.00]]
// [[3.00 15.00] [7.00 19.00] [11.00 23.00]]
// [[4.00 16.00] [8.00 20.00] [12.00 24.00]]
// ]

// Other ways
Tensor *t2 = Tensor::permute(t1, {2, 1, 0});  // returns new tensor
t1->permute(t2, {2, 1, 0});  // static

moveaxis

Tensor *Tensor::moveaxis(int source, int destination)

Move axes of an array to new positions.

Parameters
  • source – Original position of the axis to move. These must be unique.

  • destination – Destination position for the original axis. These must also be unique

Returns

A new tensor with the result

Tensor* t1 = Tensor::zeros({1, 2, 3, 4});
// ndim:          4
// shape:         (1, 2, 3, 4)
// strides:       (24, 12, 4, 1)

t1->moveaxis_(0, 2);  // In-place
// ndim:          4
// shape:         (2, 3, 1, 4)
// strides:       (12, 4, 4, 1)

// Other ways
Tensor *t2 = Tensor::moveaxis(t1, 0, 2);  // returns new tensor
t1->moveaxis(t2, 0, 2);  // static

swapaxis

Tensor *Tensor::swapaxis(int axis1, int axis2)

Interchange two axes of an array.

Parameters
  • axis1 – First axis.

  • axis2 – Destination position for the original axis. These must also be unique

Returns

A new tensor with the result

Tensor* t1 = Tensor::zeros({1, 2, 3, 4});
// ndim:          4
// shape:         (1, 2, 3, 4)
// strides:       (24, 12, 4, 1)

t1->swapaxis_(0, 2);  // In-place
// ndim:          4
// shape:         (3, 2, 1, 4)
// strides:       (8, 4, 4, 1)

// Other ways
Tensor *t2 = Tensor::swapaxis(t1, 0, 2);  // returns new tensor
t1->swapaxis(t2, 0, 2); // static

Changing number of dimensions

squeeze

static Tensor *Tensor::squeeze(Tensor *A, int axis = -1)

Remove all the dimensions of size 1 from the vector.

Parameters
  • A – Output tensor where the squeeze is stored.

  • axis – if given, the input will be squeezed only in this dimension. Else (-1), squeezes all dimensions of size 1

Returns

A new tensor with the result

Tensor* t1 = Tensor::zeros({1, 3, 4, 1});
// ndim:          4
// shape:         (1, 3, 4, 1)
// strides:       (12, 4, 1, 1)

Tensor* t2 = t1->squeeze();  // returns new tensor
// shape:         (3, 4)

Tensor* t3 = t1->squeeze(0);  // returns new tensor
// shape:         (3, 4, 1)

Tensor* t3 = t1->squeeze(3);  // returns new tensor
// shape:         (1, 3, 4)

// Other ways
t1->squeeze_(); // In-place
Tensor *t2 = Tensor::squeeze(t1);  // static

unsqueeze

static Tensor *Tensor::unsqueeze(Tensor *A, int axis = 0)

Returns a new tensor with a dimension of size one inserted at the specified position.

Parameters
  • A – Output tensor where the unsqueeze is stored.

  • axis – the index at which to insert the singleton dimension. Default: axis=0

Returns

A new tensor with the result

Tensor* t1 = Tensor::zeros({2, 3, 4});
// ndim:          3
// shape:         (2, 3, 4)
// strides:       (12, 4, 1)

Tensor* t2 = t1->unsqueeze(); // returns new tensor
 // shape:         (1, 2, 3, 4)

Tensor* t3 = t1->unsqueeze(2); // returns new tensor
 // shape:         (2, 3, 4, 1)

// Other ways
t1->unsqueeze_();  // In-place
Tensor *t2 = Tensor::unsqueeze(t1);  // Static

Joining arrays

concatenate

static Tensor *Tensor::concat(vector<Tensor*> A, unsigned int axis = 0, Tensor *output = nullptr)

Join a sequence of arrays along an existing axis.

Parameters
  • Vector – of Tensors The Tensors must have the same shape, except in the dimension corresponding to axis (the first, by default).

  • axis – The axis along which the arrays will be joined. If axis is None, arrays are flattened before use. Default is 0.

  • output – Output tensor

Example:

Tensor* t1 = Tensor::full({2, 2, 2}, 2);
Tensor* t2 = Tensor::full({2, 2, 2}, 5);

Tensor* t3 = Tensor::concat({t1, t2});
// ndim:          3
// shape:         (4, 2, 2)
// strides:       (4, 2, 1)

// [
// [[2.00 2.00] [2.00 2.00]]
// [[2.00 2.00] [2.00 2.00]]
// [[5.00 5.00] [5.00 5.00]]
// [[5.00 5.00] [5.00 5.00]]
// ]

Tensor *t4 = Tensor::concat({t1, t2}, 2);

// ndim:          3
// shape:         (2, 2, 4)
// strides:       (8, 4, 1)
//
// [
// [[2.00 2.00 5.00 5.00] [2.00 2.00 5.00 5.00]]
// [[2.00 2.00 5.00 5.00] [2.00 2.00 5.00 5.00]]
// ]

stack

static Tensor *Tensor::stack(vector<Tensor*> A, unsigned int axis = 0, Tensor *output = nullptr)

Join a sequence of arrays along a new axis.

Parameters
  • A – Input tensor.

  • axis – The axis in the result array along which the input arrays are stacked.

  • output – Output tensor

Example:

Tensor* t1 = Tensor::full({2, 2}, 2);
Tensor* t2 = Tensor::full({2, 2}, 5);

Tensor* t3 = Tensor::stack({t1, t2});  // axis = 0
// [
// [[2.00 2.00] [2.00 2.00]]
// [[5.00 5.00] [5.00 5.00]]
// ]

Tensor *t4 = Tensor::stack({t1, t2}, 1);  // axis = 1
// [
// [[2.00 2.00] [5.00 5.00]]
// [[2.00 2.00] [5.00 5.00]]
// ]

Value operations

Fill constant

static void Tensor::fill(Tensor *A, float v)

Fill tensor with a value.

Parameters
  • A – The output tensor.

  • v – the value to fill the tensor with

Tensor* t1 = Tensor::empty({2, 3});

t1->fill_(3.0f);  // In-place
// [
// [3.00 3.00 3.00]
// [3.00 3.00 3.00]
// ]

// Other ways
Tensor* t2 = t1->fill(3.0f); // returns new tensor
Tensor::fill(t1, 3.0f);  // static

Fill Random Uniform

void Tensor::fill_rand_uniform_(float v)

Fills a tensor in-place, with values randomly sampled from a uniform distribution.

Parameters

v – Scale factor of the values generated by the uniform distribution.

Tensor* t1 = Tensor::empty({2, 3});

t1->fill_rand_uniform_(1.0f);  // In-place
// [
// [0.10 0.53 0.88]
// [0.57 0.57 0.89]
// ]

// Other ways
Tensor* t2 = t1->fill_rand_uniform(1.0f); // returns new tensor
Tensor::fill_rand_uniform(t1, 1.0f);  // static

Fill Random Signed Uniform

void Tensor::fill_rand_signed_uniform_(float v)

Fills a tensor in-place, with values randomly sampled from a signed uniform distribution.

Parameters

v – Scale factor of the values generated by the signed uniform distribution.

Tensor* t1 = Tensor::empty({2, 3});

t1->fill_rand_signed_uniform_(1.0f);  // In-place
// [
// [0.22 -0.34 -0.78]
// [-0.03 0.10 0.90]
// ]

// Other ways
Tensor* t2 = t1->fill_rand_signed_uniform(1.0f); // returns new tensor
Tensor::fill_rand_signed_uniform(t1, 1.0f);  // static

Fill Random Normal

void Tensor::fill_rand_normal_(float m, float s, bool fast_math = true)

Fills a tensor in-place, with values randomly sampled from a normal distribution.

Parameters
  • m – Mean of the normal distribution.

  • s – Standard deviation of the normal distribution.

  • fast_math – Whether to use or not the fast math mode.

Tensor* t1 = Tensor::empty({2, 3});

t1->fill_rand_normal_(0.0f, 1.0f);  // In-place
// [
// [-0.57 0.49 -1.09]
// [0.75 0.37 -0.32]
// ]

// Other ways
Tensor* t2 = t1->fill_rand_normal(0.0f, 1.0f); // returns new tensor
Tensor::fill_rand_normal(t1, 0.0f, 1.0f);  // static

Fill Random Binary

void Tensor::fill_rand_binary_(float v)

Fills a tensor in-place, with values randomly sampled from a binary distribution.

Parameters

v – Binarization threshold. 1 if rnd() >= t, 0 otherwise

Tensor* t1 = Tensor::empty({2, 3});

t1->fill_rand_binary_(0.5f);  // In-place
// [
// [0.00 1.00 0.00]
// [1.00 1.00 0.00]
// ]

// Other ways
Tensor* t2 = t1->fill_rand_binary(0.5f); // returns new tensor
Tensor::fill_rand_binary(t1, 0.5f);  // static