Tensor creation#

Aesara provides a list of predefined tensor types that can be used to create a tensor variables. Variables can be named to facilitate debugging, and all of these constructors accept an optional name argument. For example, the following each produce a TensorVariable instance that stands for a 0-dimensional ndarray of integers with the name 'myvar':

>>> import aesara.tensor as at
>>> x = at.scalar('myvar', dtype='int32')
>>> x = at.iscalar('myvar')
>>> x = at.tensor(dtype='int32', shape=(), name='myvar')
>>> x = at.TensorType(dtype='int32', shape=())('myvar')

Basic constructors#

These are the simplest and often-preferred methods for creating symbolic variables in your code. By default, they produce floating-point variables (with dtype determined by aesara.config.floatX) so if you use these constructors it is easy to switch your code between different levels of floating-point precision.

scalar([name, dtype])

Return a symbolic scalar variable.

vector([name, dtype])

Return a symbolic vector variable.

row([name, dtype])

Return a symbolic row variable (i.e.

col([name, dtype])

Return a symbolic column variable (i.e.

matrix([name, dtype])

Return a symbolic matrix variable.

tensor3([name, dtype])

Return a symbolic 3D variable.

tensor4([name, dtype])

Return a symbolic 4D variable.

tensor5([name, dtype])

Return a symbolic 5D variable.

tensor6([name, dtype])

Return a symbolic 6D variable.

tensor7([name, dtype])

Return a symbolic 7-D variable.

>>> x = at.scalar()
>>> x.type.shape
()
>>> y = at.vector()
>>> y.type.shape
(None,)

Typed Constructors#

The following TensorType instances are provided in the aesara.tensor module. They are all callable, and accept an optional name argument. So for example:

x = at.dmatrix()        # creates one Variable with no name
x = at.dmatrix('x')     # creates one Variable with name 'x'
xyz = at.dmatrix('xyz') # creates one Variable with name 'xyz'

Constructor

dtype

ndim

shape

broadcastable

bscalar

int8

0

()

()

bvector

int8

1

(?,)

(False,)

brow

int8

2

(1,?)

(True, False)

bcol

int8

2

(?,1)

(False, True)

bmatrix

int8

2

(?,?)

(False, False)

btensor3

int8

3

(?,?,?)

(False, False, False)

btensor4

int8

4

(?,?,?,?)

(False, False, False, False)

btensor5

int8

5

(?,?,?,?,?)

(False, False, False, False, False)

btensor6

int8

6

(?,?,?,?,?,?)

(False,) * 6

btensor7

int8

7

(?,?,?,?,?,?,?)

(False,) * 7

wscalar

int16

0

()

()

wvector

int16

1

(?,)

(False,)

wrow

int16

2

(1,?)

(True, False)

wcol

int16

2

(?,1)

(False, True)

wmatrix

int16

2

(?,?)

(False, False)

wtensor3

int16

3

(?,?,?)

(False, False, False)

wtensor4

int16

4

(?,?,?,?)

(False, False, False, False)

wtensor5

int16

5

(?,?,?,?,?)

(False, False, False, False, False)

wtensor6

int16

6

(?,?,?,?,?,?)

(False,) * 6

wtensor7

int16

7

(?,?,?,?,?,?,?)

(False,) * 7

iscalar

int32

0

()

()

ivector

int32

1

(?,)

(False,)

irow

int32

2

(1,?)

(True, False)

icol

int32

2

(?,1)

(False, True)

imatrix

int32

2

(?,?)

(False, False)

itensor3

int32

3

(?,?,?)

(False, False, False)

itensor4

int32

4

(?,?,?,?)

(False, False, False, False)

itensor5

int32

5

(?,?,?,?,?)

(False, False, False, False, False)

itensor6

int32

6

(?,?,?,?,?,?)

(False,) * 6

itensor7

int32

7

(?,?,?,?,?,?,?)

(False,) * 7

lscalar

int64

0

()

()

lvector

int64

1

(?,)

(False,)

lrow

int64

2

(1,?)

(True, False)

lcol

int64

2

(?,1)

(False, True)

lmatrix

int64

2

(?,?)

(False, False)

ltensor3

int64

3

(?,?,?)

(False, False, False)

ltensor4

int64

4

(?,?,?,?)

(False, False, False, False)

ltensor5

int64

5

(?,?,?,?,?)

(False, False, False, False, False)

ltensor6

int64

6

(?,?,?,?,?,?)

(False,) * 6

ltensor7

int64

7

(?,?,?,?,?,?,?)

(False,) * 7

dscalar

float64

0

()

()

dvector

float64

1

(?,)

(False,)

drow

float64

2

(1,?)

(True, False)

dcol

float64

2

(?,1)

(False, True)

dmatrix

float64

2

(?,?)

(False, False)

dtensor3

float64

3

(?,?,?)

(False, False, False)

dtensor4

float64

4

(?,?,?,?)

(False, False, False, False)

dtensor5

float64

5

(?,?,?,?,?)

(False, False, False, False, False)

dtensor6

float64

6

(?,?,?,?,?,?)

(False,) * 6

dtensor7

float64

7

(?,?,?,?,?,?,?)

(False,) * 7

fscalar

float32

0

()

()

fvector

float32

1

(?,)

(False,)

frow

float32

2

(1,?)

(True, False)

fcol

float32

2

(?,1)

(False, True)

fmatrix

float32

2

(?,?)

(False, False)

ftensor3

float32

3

(?,?,?)

(False, False, False)

ftensor4

float32

4

(?,?,?,?)

(False, False, False, False)

ftensor5

float32

5

(?,?,?,?,?)

(False, False, False, False, False)

ftensor6

float32

6

(?,?,?,?,?,?)

(False,) * 6

ftensor7

float32

7

(?,?,?,?,?,?,?)

(False,) * 7

cscalar

complex64

0

()

()

cvector

complex64

1

(?,)

(False,)

crow

complex64

2

(1,?)

(True, False)

ccol

complex64

2

(?,1)

(False, True)

cmatrix

complex64

2

(?,?)

(False, False)

ctensor3

complex64

3

(?,?,?)

(False, False, False)

ctensor4

complex64

4

(?,?,?,?)

(False, False, False, False)

ctensor5

complex64

5

(?,?,?,?,?)

(False, False, False, False, False)

ctensor6

complex64

6

(?,?,?,?,?,?)

(False,) * 6

ctensor7

complex64

7

(?,?,?,?,?,?,?)

(False,) * 7

zscalar

complex128

0

()

()

zvector

complex128

1

(?,)

(False,)

zrow

complex128

2

(1,?)

(True, False)

zcol

complex128

2

(?,1)

(False, True)

zmatrix

complex128

2

(?,?)

(False, False)

ztensor3

complex128

3

(?,?,?)

(False, False, False)

ztensor4

complex128

4

(?,?,?,?)

(False, False, False, False)

ztensor5

complex128

5

(?,?,?,?,?)

(False, False, False, False, False)

ztensor6

complex128

6

(?,?,?,?,?,?)

(False,) * 6

ztensor7

complex128

7

(?,?,?,?,?,?,?)

(False,) * 7

Plural Constructors#

There are several constructors that can produce multiple variables at once. These are not frequently used in practice, but often used in tutorial examples to save space!

iscalars, lscalars, fscalars, dscalars

Return one or more scalar variables.

ivectors, lvectors, fvectors, dvectors

Return one or more vector variables.

irows, lrows, frows, drows

Return one or more row variables.

icols, lcols, fcols, dcols

Return one or more col variables.

imatrices, lmatrices, fmatrices, dmatrices

Return one or more matrix variables.

Each of these plural constructors accepts an integer or several strings. If an integer is provided, the method will return that many Variables and if strings are provided, it will create one Variable for each string, using the string as the Variable’s name. For example:

# Creates three matrix `Variable`s with no names
x, y, z = at.dmatrices(3)
# Creates three matrix `Variables` named 'x', 'y' and 'z'
x, y, z = at.dmatrices('x', 'y', 'z')

Custom tensor types#

If you would like to construct a tensor variable with a non-standard broadcasting pattern, or a larger number of dimensions you’ll need to create your own TensorType instance. You create such an instance by passing the dtype and broadcasting pattern to the constructor. For example, you can create your own 8-dimensional tensor type

>>> dtensor8 = TensorType(dtype='float64', shape=(None,)*8)
>>> x = dtensor8()
>>> z = dtensor8('z')

You can also redefine some of the provided types and they will interact correctly:

>>> my_dmatrix = TensorType('float64', shape=(None,)*2)
>>> x = my_dmatrix()  # allocate a matrix variable
>>> my_dmatrix == dmatrix
True

See TensorType for more information about creating new types of tensors.

Converting from Python Objects#

One can convert python objects by calling either aesara.tensor.as_tensor_variable() or aesara.shared().

aesara.tensor.as_tensor_variable#

Note

This is the default way of converting a python object to a TensorVariable. Unless you have a need for shared variables, use this function instead.

aesara.tensor.as_tensor_variable(x, name=None, ndim=None)[source]#

Turn an argument ``x` into a TensorVariable or TensorConstant.

Many tensor Ops run their arguments through this function as pre-processing. It passes through TensorVariable instances, and tries to wrap other objects into TensorConstant.

When x is a Python number, the dtype is inferred as described above.

When x is a list or tuple it is passed through np.asarray

If the ndim argument is not None, it must be an integer and the output will be broadcasted if necessary in order to have this many dimensions.

Return type:

TensorVariable or TensorConstant

>>> import numpy as np
>>> x = np.array([[1, 2], [3, 4]])
>>> y = at.as_tensor(x)
>>> y.type.shape
(2, 2)

Finally, when you use a NumPy ndarray or a Python number together with TensorVariable instances in arithmetic expressions, the result is a TensorVariable. What happens to the ndarray or the number? Aesara requires that the inputs to all expressions be Variable instances, so Aesara automatically wraps them in a TensorConstant.

>>> x = at.vector()
>>> b = at.add(x, np.ones(3))
>>> type(b)
<class 'aesara.tensor.var.TensorVariable'>
>>> b.type.shape
(3,)
>>> b.owner.inputs[1]
>>> TensorConstant{(3,) of 1.0}

Note

Aesara makes a copy of any ndarray that is used in an expression, so subsequent changes to that ndarray will not have any effect on the Aesara expression in which they’re contained.

aesara.shared#

Another way of creating a TensorVariable (a TensorSharedVariable to be precise) is by calling aesara.shared()

x = aesara.shared(np.random.standard_normal((3, 4)))

This will return a shared variable whose .value is a NumPy ndarray. The number of dimensions and dtype of the Variable are inferred from the ndarray argument.

Danger

The argument to shared will not be copied, and subsequent changes will be reflected in x.value.

For additional information, see the documentation for shared variables.

dtype and shape#

For NumPy ndarrays the dtype is given, but the static shape/broadcastable pattern must be inferred. The TensorConstant is given a type with a matching dtype, and a static shape/broadcastable pattern with a 1/True for every shape dimension that is one and None/False for every dimension with an unknown shape.

For Python numbers, the static shape/broadcastable pattern is () but the dtype must be inferred. Python integers are stored in the smallest dtype that can hold them, so small constants like 1 are stored in a bscalar. Likewise, Python floats are stored in an fscalar if fscalar suffices to hold them perfectly, but a dscalar otherwise.

Note

When config.floatX == float32 (see config), then Python floats are stored instead as single-precision floats.

For fine control of this rounding policy, see aesara.tensor.basic.autocast_float.

Loading from file#

One can also create tensor by loading NumPy arrays from a npy file.

aesara.tensor.io.load(path, dtype, shape, mmap_mode=None)[source]#

Load an array from an .npy file.

Parameters:
  • path – A Generic symbolic variable, that will contain a string

  • dtype (data-type) – The data type of the array to be read.

  • shape – The static shape information of the loaded array.

  • mmap_mode – How the file will be loaded. None means that the data will be copied into an array in memory, ‘c’ means that the file will be mapped into virtual memory, so only the parts that are needed will be actually read from disk and put into memory. Other modes supported by numpy.load (‘r’, ‘r+’, ‘w+’) cannot be supported by Aesara.

Examples

>>> from aesara import *
>>> path = Variable(Generic(), None)
>>> x = tensor.load(path, 'int64', (None,))
>>> y = x*2
>>> fn = function([path], y)
>>> fn("stored-array.npy")  
array([0, 2, 4, 6, 8], dtype=int64)