NDArray API

class NDArray

Wrapper of the NDArray type in libmxnet. This is the basic building block of tensor-based computation.

Note

since C/C++ use row-major ordering for arrays while Julia follows a column-major ordering. To keep things consistent, we keep the underlying data in their original layout, but use language-native convention when we talk about shapes. For example, a mini-batch of 100 MNIST images is a tensor of C/C++/Python shape (100,1,28,28), while in Julia, the same piece of memory have shape (28,28,1,100).

context(arr :: NDArray)

Get the context that this NDArray lives on.

empty(shape :: Tuple, ctx :: Context)
empty(shape :: Tuple)
empty(dim1, dim2, ...)

Allocate memory for an uninitialized NDArray with specific shape.

Interface functions similar to Julia Arrays

zeros(shape :: Tuple, ctx :: Context)
zeros(shape :: Tuple)
zeros(dim1, dim2, ...)

Create zero-ed NDArray with specific shape.

ones(shape :: Tuple, ctx :: Context)
ones(shape :: Tuple)
ones(dim1, dim2, ...)

Create an NDArray with specific shape and initialize with 1.

size(arr :: NDArray)
size(arr :: NDArray, dim :: Int)

Get the shape of an NDArray. The shape is in Julia’s column-major convention. See also the notes on NDArray shapes.

length(arr :: NDArray)

Get the number of elements in an NDArray.

ndims(arr :: NDArray)

Get the number of dimensions of an NDArray. Is equivalent to length(size(arr)).

eltype(arr :: NDArray)

Get the element type of an NDArray. Currently the element type is always mx.MX_float.

slice(arr :: NDArray, start:stop)

Create a view into a sub-slice of an NDArray. Note only slicing at the slowest changing dimension is supported. In Julia’s column-major perspective, this is the last dimension. For example, given an NDArray of shape (2,3,4), slice(array, 2:3) will create a NDArray of shape (2,3,2), sharing the data with the original array. This operation is used in data parallelization to split mini-batch into sub-batches for different devices.

setindex!(arr :: NDArray, val, idx)

Assign values to an NDArray. Elementwise assignment is not implemented, only the following scenarios are supported

  • arr[:] = val: whole array assignment, val could be a scalar or an array (Julia Array or NDArray) of the same shape.
  • arr[start:stop] = val: assignment to a slice, val could be a scalar or an array of the same shape to the slice. See also slice().
getindex(arr :: NDArray, idx)

Shortcut for slice(). A typical use is to write

arr[:] += 5

which translates into

arr[:] = arr[:] + 5

which furthur translates into

setindex!(getindex(arr, Colon()), 5, Colon())

Note

The behavior is quite different from indexing into Julia’s Array. For example, arr[2:5] create a copy of the sub-array for Julia Array, while for NDArray, this is a slice that shares the memory.

Copying functions

copy!(dst :: Union{NDArray, Array}, src :: Union{NDArray, Array})

Copy contents of src into dst.

copy(arr :: NDArray)
copy(arr :: NDArray, ctx :: Context)
copy(arr :: Array, ctx :: Context)

Create a copy of an array. When no Context is given, create a Julia Array. Otherwise, create an NDArray on the specified context.

convert(::Type{Array{T}}, arr :: NDArray)

Convert an NDArray into a Julia Array of specific type. Data will be copied.

Basic arithmetics

@inplace()

Julia does not support re-definiton of += operator (like __iadd__ in python), When one write a += b, it gets translated to a = a+b. a+b will allocate new memory for the results, and the newly allocated NDArray object is then assigned back to a, while the original contents in a is discarded. This is very inefficient when we want to do inplace update.

This macro is a simple utility to implement this behavior. Write

@mx.inplace a += b

will translate into

mx.add_to!(a, b)

which will do inplace adding of the contents of b into a.

add_to!(dst :: NDArray, args :: Union{Real, NDArray}...)

Add a bunch of arguments into dst. Inplace updating.

+(args...)
.+(args...)

Summation. Multiple arguments of either scalar or NDArray could be added together. Note at least the first or second argument needs to be an NDArray to avoid ambiguity of built-in summation.

sub_from!(dst :: NDArray, args :: Union{Real, NDArray}...)

Subtract a bunch of arguments from dst. Inplace updating.

-(arg0, arg1)
-(arg0)
.-(arg0, arg1)

Subtraction arg0 - arg1, of scalar types or NDArray. Or create the negative of arg0.

mul_to!(dst :: NDArray, arg :: Union{Real, NDArray})

Elementwise multiplication into dst of either a scalar or an NDArray of the same shape. Inplace updating.

.*(arg0, arg1)

Elementwise multiplication of arg0 and arg, could be either scalar or NDArray.

*(arg0, arg1)

Currently only multiplication a scalar with an NDArray is implemented. Matrix multiplication is to be added soon.

div_from!(dst :: NDArray, arg :: Union{Real, NDArray})

Elementwise divide a scalar or an NDArray of the same shape from dst. Inplace updating.

./(arg0 :: NDArray, arg :: Union{Real, NDArray})

Elementwise dividing an NDArray by a scalar or another NDArray of the same shape.

/(arg0 :: NDArray, arg :: Real)

Divide an NDArray by a scalar. Matrix division (solving linear systems) is not implemented yet.

Manipulating as Julia Arrays

@nd_as_jl(captures..., statement)

A convenient macro that allows to operate NDArray as Julia Arrays. For example,

x = mx.zeros(3,4)
y = mx.ones(3,4)
z = mx.zeros((3,4), mx.gpu())

@mx.nd_as_jl ro=(x,y) rw=z begin
  # now x, y, z are just ordinary Julia Arrays
  z[:,1] = y[:,2]
  z[:,2] = 5
end

Under the hood, the macro convert all the declared captures from NDArray into Julia Arrays, by using try_get_shared(). And automatically commit the modifications back into the NDArray that is declared as rw. This is useful for fast prototyping and when implement non-critical computations, such as AbstractEvalMetric.

Note

  • Multiple rw and / or ro capture declaration could be made.
  • The macro does not check to make sure that ro captures are not modified. If the original NDArray lives in CPU memory, then it is very likely the corresponding Julia Array shares data with the NDArray, so modifying the Julia Array will also modify the underlying NDArray.
  • More importantly, since the NDArray is asynchronized, we will wait for writing for rw variables but wait only for reading in ro variables. If we write into those ro variables, and if the memory is shared, racing condition might happen, and the behavior is undefined.
  • When an NDArray is declared to be captured as rw, its contents is always sync back in the end.
  • The execution results of the expanded macro is always nothing.
  • The statements are wrapped in a let, thus locally introduced new variables will not be available after the statements. So you will need to declare the variables before calling the macro if needed.
try_get_shared(arr)

Try to create a Julia array by sharing the data with the underlying NDArray.

Parameters:arr (NDArray) – the array to be shared.

Warning

The returned array does not guarantee to share data with the underlying NDArray. In particular, data sharing is possible only when the NDArray lives on CPU.

is_shared(j_arr, arr)

Test whether j_arr is sharing data with arr.

Parameters:
  • j_arr (Array) – the Julia Array.
  • arr (NDArray) – the NDArray.

IO

load(filename, ::Type{NDArray})

Load NDArrays from binary file.

Parameters:filename (AbstractString) – the path of the file to load. It could be S3 or HDFS address.
Returns:Either Dict{Base.Symbol, NDArray} or Vector{NDArray}.

If the libmxnet is built with the corresponding component enabled. Examples

  • s3://my-bucket/path/my-s3-ndarray
  • hdfs://my-bucket/path/my-hdfs-ndarray
  • /path-to/my-local-ndarray
save(filename :: AbstractString, data)

Save NDarrays to binary file. Filename could be S3 or HDFS address, if libmxnet is built with corresponding support.

Parameters:
  • filename (AbstractString) – path to the binary file to write to.
  • data (NDArray, or a Vector{NDArray} or a Dict{Base.Symbol, NDArray}.) – data to save to file.

libmxnet APIs

The libxmnet APIs are automatically imported from libmxnet.so. The functions listed here operate on NDArray objects. The arguments to the functions are typically ordered as

func_name(arg_in1, arg_in2, ..., scalar1, scalar2, ..., arg_out1, arg_out2, ...)

unless NDARRAY_ARG_BEFORE_SCALAR is not set. In this case, the scalars are put before the input arguments:

func_name(scalar1, scalar2, ..., arg_in1, arg_in2, ..., arg_out1, arg_out2, ...)

If ACCEPT_EMPTY_MUTATE_TARGET is set. An overloaded function without the output arguments will also be defined:

func_name(arg_in1, arg_in2, ..., scalar1, scalar2, ...)

Upon calling, the output arguments will be automatically initialized with empty NDArrays.

Those functions always return the output arguments. If there is only one output (the typical situation), that object (NDArray) is returned. Otherwise, a tuple containing all the outputs will be returned.

Public APIs

abs(...)

Take absolute value of the src

Parameters:src (NDArray) – Source input to the function
argmax_channel(...)

Take argmax indices of each channel of the src.The result will be ndarray of shape (num_channel,) on the same device.

Parameters:src (NDArray) – Source input to the function
ceil(...)

Take ceil value of the src

Parameters:src (NDArray) – Source input to the function
choose_element_0index(...)

Choose one element from each line(row for python, column for R/Julia) in lhs according to index indicated by rhs. This function assume rhs uses 0-based index.

Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (NDArray) – Right operand to the function.
clip(...)

Clip ndarray elements to range (a_min, a_max)

Parameters:
  • src (NDArray) – Source input
  • a_min (real_t) – Minimum value
  • a_max (real_t) – Maximum value
cos(...)

Take cos of the src

Parameters:src (NDArray) – Source input to the function
dot(...)

Calculate 2D matrix multiplication

Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (NDArray) – Right operand to the function.
exp(...)

Take exp of the src

Parameters:src (NDArray) – Source input to the function
fill_element_0index(...)

Fill one element of each line(row for python, column for R/Julia) in lhs according to index indicated by rhs and values indicated by mhs. This function assume rhs uses 0-based index.

Parameters:
  • lhs (NDArray) – Left operand to the function.
  • mhs (NDArray) – Middle operand to the function.
  • rhs (NDArray) – Right operand to the function.
floor(...)

Take floor value of the src

Parameters:src (NDArray) – Source input to the function
log(...)

Take log of the src

Parameters:src (NDArray) – Source input to the function
max(...)

Take max of the src.The result will be ndarray of shape (1,) on the same device.

Parameters:src (NDArray) – Source input to the function
min(...)

Take min of the src.The result will be ndarray of shape (1,) on the same device.

Parameters:src (NDArray) – Source input to the function
norm(...)

Take L2 norm of the src.The result will be ndarray of shape (1,) on the same device.

Parameters:src (NDArray) – Source input to the function
round(...)

Take round value of the src

Parameters:src (NDArray) – Source input to the function
rsqrt(...)

Take rsqrt of the src

Parameters:src (NDArray) – Source input to the function
sign(...)

Take sign value of the src

Parameters:src (NDArray) – Source input to the function
sin(...)

Take sin of the src

Parameters:src (NDArray) – Source input to the function
sqrt(...)

Take sqrt of the src

Parameters:src (NDArray) – Source input to the function
square(...)

Take square of the src

Parameters:src (NDArray) – Source input to the function
sum(...)

Take sum of the src.The result will be ndarray of shape (1,) on the same device.

Parameters:src (NDArray) – Source input to the function

Internal APIs

Note

Document and signatures for internal API functions might be incomplete.

_copyto(...)
Parameters:src (NDArray) – Source input to the function.
_div(...)
Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (NDArray) – Right operand to the function.
_div_scalar(...)
Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (real_t) – Right operand to the function.
_imdecode(...)

Decode an image, clip to (x0, y0, x1, y1), substract mean, and write to buffer

Parameters:
  • mean (NDArray) – image mean
  • index (int) – buffer position for output
  • x0 (int) – x0
  • y0 (int) – y0
  • x1 (int) – x1
  • y1 (int) – y1
  • c (int) – channel
  • size (int) – length of str_img
_minus(...)
Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (NDArray) – Right operand to the function.
_minus_scalar(...)
Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (real_t) – Right operand to the function.
_mul(...)
Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (NDArray) – Right operand to the function.
_mul_scalar(...)
Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (real_t) – Right operand to the function.
_onehot_encode(...)
Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (NDArray) – Right operand to the function.
_plus(...)
Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (NDArray) – Right operand to the function.
_plus_scalar(...)
Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (real_t) – Right operand to the function.
_random_gaussian(...)
_random_uniform(...)
_rdiv_scalar(...)
Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (real_t) – Right operand to the function.
_rminus_scalar(...)
Parameters:
  • lhs (NDArray) – Left operand to the function.
  • rhs (real_t) – Right operand to the function.
_set_value(...)
Parameters:src (real_t) – Source input to the function.