Basic Tensor Functionality — PyTensor dev documentation (original) (raw)

PyTensor supports symbolic tensor expressions. When you type,

import pytensor.tensor as pt x = pt.fmatrix()

the x is a TensorVariable instance.

The pt.fmatrix object itself is an instance of TensorType. PyTensor knows what type of variable x is because x.typepoints back to pt.fmatrix.

This section explains the various ways in which a tensor variable can be created, the attributes and methods of TensorVariable and TensorType, and various basic symbolic math and arithmetic that PyTensor supports for tensor variables.

In general, PyTensor’s API tries to mirror NumPy’s, so, in most cases, it’s safe to assume that the basic NumPy array functions and methods will be available.

Creation#

PyTensor 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':

x = pt.scalar('myvar', dtype='int32') x = pt.iscalar('myvar') x = pt.tensor(dtype='int32', shape=(), name='myvar') from pytensor.tensor.type import TensorType x = TensorType(dtype='int32', shape=())('myvar')

Constructors with optional dtype#

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 pytensor.config.floatX) so if you use these constructors it is easy to switch your code between different levels of floating-point precision.

pytensor.tensor.scalar(name=None, dtype=config.floatX)[source]#

Return a Variable for a 0-dimensional ndarray

pytensor.tensor.vector(name=None, dtype=config.floatX)[source]#

Return a Variable for a 1-dimensional ndarray

pytensor.tensor.row(name=None, dtype=config.floatX)[source]#

Return a Variable for a 2-dimensional ndarrayin which the number of rows is guaranteed to be 1.

pytensor.tensor.col(name=None, dtype=config.floatX)[source]#

Return a Variable for a 2-dimensional ndarrayin which the number of columns is guaranteed to be 1.

pytensor.tensor.matrix(name=None, dtype=config.floatX)[source]#

Return a Variable for a 2-dimensional ndarray

pytensor.tensor.tensor3(name=None, dtype=config.floatX)[source]#

Return a Variable for a 3-dimensional ndarray

pytensor.tensor.tensor4(name=None, dtype=config.floatX)[source]#

Return a Variable for a 4-dimensional ndarray

pytensor.tensor.tensor5(name=None, dtype=config.floatX)[source]#

Return a Variable for a 5-dimensional ndarray

pytensor.tensor.tensor6(name=None, dtype=config.floatX)[source]#

Return a Variable for a 6-dimensional ndarray

pytensor.tensor.tensor7(name=None, dtype=config.floatX)[source]#

Return a Variable for a 7-dimensional ndarray

All Fully-Typed Constructors#

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

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

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 Variables with no names

x, y, z = pt.dmatrices(3)

Creates three matrix Variables named 'x', 'y' and 'z'

x, y, z = pt.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#

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

x = pytensor.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. The argument to shared will not be copied, and subsequent changes will be reflected in x.value.

For additional information, see the shared() documentation.

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

Note

PyTensor 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 PyTensor expression in which they’re contained.

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, seepytensor.tensor.basic.autocast_float.

pytensor.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

TensorType and TensorVariable#

class pytensor.tensor.TensorType(Type)[source]#

The Type class used to mark Variables that stand for numpy.ndarrayvalues. numpy.memmap, which is a subclass of numpy.ndarray, is also allowed. Recalling to the tutorial, the purple box inthe tutorial’s graph-structure figure is an instance of this class.

shape[source]#

A tuple of ``None`` and integer values representing the static shape associated with this

`Type`. ``None`` values represent unknown/non-fixed shape values.

Note

Broadcastable tuples/values are an old Theano construct that are being phased-out in PyTensor.

broadcastable[source]#

A tuple of True/False values, one for each dimension. True in position i indicates that at evaluation-time, the ndarray will have size one in that i-th dimension. Such a dimension is called a_broadcastable dimension_ (see Broadcasting).

The broadcastable pattern indicates both the number of dimensions and whether a particular dimension must have length one.

Here is a table mapping some broadcastable patterns to what they mean:

For dimensions in which broadcasting is False, the length of this dimension can be one or more. For dimensions in which broadcasting is True, the length of this dimension must be one.

When two arguments to an element-wise operation (like addition or subtraction) have a different number of dimensions, the broadcastable pattern is expanded to the left, by padding with True. For example, a vector’s pattern, [False], could be expanded to [True, False], and would behave like a row (1xN matrix). In the same way, a matrix ([False, False]) would behave like a 1xNxP tensor ([True, False, False]).

If we wanted to create a TensorType representing a matrix that would broadcast over the middle dimension of a 3-dimensional tensor when adding them together, we would define it like this:

middle_broadcaster = TensorType('complex64', shape=(None, 1, None))

ndim[source]#

The number of dimensions that a Variable’s value will have at evaluation-time. This must be known when we are building the expression graph.

dtype[source]#

A string indicating the numerical type of the ndarray for which aVariable of this Type represents.

The dtype attribute of a TensorType instance can be any of the following strings.

__init__(self, dtype, broadcastable)[source]#

If you wish to use a Type that is not already available (for example, a 5D tensor), you can build an appropriate Type by instantiatingTensorType.

TensorVariable#

class pytensor.tensor.TensorVariable(Variable, _tensor_py_operators)[source]#

A Variable type that represents symbolic tensors.

See _tensor_py_operators for most of the attributes and methods you’ll want to call.

class pytensor.tensor.TensorConstant(Variable, _tensor_py_operators)[source]#

Python and NumPy numbers are wrapped in this type.

See _tensor_py_operators for most of the attributes and methods you’ll want to call.

class pytensor.tensor.TensorSharedVariable(Variable, _tensor_py_operators)[source]#

This type is returned by shared() when the value to share is a NumPy ndarray.

See _tensor_py_operators for most of the attributes and methods you’ll want to call.

class pytensor.tensor.variable._tensor_py_operators[source]#

This mix-in class adds convenient attributes, methods, and support to TensorVariable, TensorConstant and TensorSharedVariable for Python operators (see Operator Support).

type[source]#

A reference to the TensorType instance describing the sort of values that might be associated with this variable.

ndim[source]

The number of dimensions of this tensor. Aliased toTensorType.ndim.

dtype[source]

The numeric type of this tensor. Aliased toTensorType.dtype.

reshape(shape, ndim=None)[source]

Returns a view of this tensor that has been reshaped as innumpy.reshape. If the shape is a Variable argument, then you might need to use the optional ndim parameter to declare how many elements the shape has, and therefore how many dimensions the reshaped Variable will have.

See reshape().

dimshuffle(*pattern)[source]

Returns a view of this tensor with permuted dimensions. Typically the pattern will include the integers 0, 1, ... ndim-1, and any number of'x' characters in dimensions where this tensor should be broadcasted.

A few examples of patterns and their effect:

  • ('x',): make a 0d (scalar) into a 1d vector
  • (0, 1): identity for 2d vectors
  • (1, 0): inverts the first and second dimensions
  • ('x', 0): make a row out of a 1d vector (N to 1xN)
  • (0, 'x'): make a column out of a 1d vector (N to Nx1)
  • (2, 0, 1): AxBxC to CxAxB
  • (0, 'x', 1): AxB to Ax1xB
  • (1, 'x', 0): AxB to Bx1xA
  • (1,): This removes the dimension at index 0. It must be a broadcastable dimension.

flatten(ndim=1)[source]#

Returns a view of this tensor with ndim dimensions, whose shape for the firstndim-1 dimensions will be the same as self, and shape in the remaining dimension will be expanded to fit in all the data from self.

See flatten().

ravel()[source]#

return flatten. For NumPy compatibility.

T[source]#

Transpose of this tensor.

x = pt.zmatrix() y = 3+.2j * x.T

{any,all}(axis=None, keepdims=False)

{sum,prod,mean}(axis=None, dtype=None, keepdims=False, acc_dtype=None)

{var,std,min,max,argmin,argmax}(axis=None, keepdims=False),

diagonal(offset=0, axis1=0, axis2=1)[source]#

astype(dtype)[source]#

take(indices, axis=None, mode='raise')[source]#

copy()[source]

Return a new symbolic variable that is a copy of the variable. Does not copy the tag.

norm(L, axis=None)[source]#

nonzero(self, return_matrix=False)[source]

nonzero_values(self)[source]

sort(self, axis=-1, kind='quicksort', order=None)[source]

argsort(self, axis=-1, kind='quicksort', order=None)[source]

clip(self, a_min, a_max) with a_min <= a_max

conf()[source]#

repeat(repeats, axis=None)[source]

round(mode='half_away_from_zero')[source]

trace()[source]#

get_underlying_scalar_constant_value()[source]#

zeros_like(model, dtype=None)[source]#

All the above methods are equivalent to NumPy for PyTensor on the current tensor.

__{abs,neg,lt,le,gt,ge,invert,and,or,add,sub,mul,div,truediv,floordiv}__

Those elemwise operation are supported via Python syntax.

argmax(axis=None, keepdims=False)[source]#

See pytensor.tensor.math.argmax().

argmin(axis=None, keepdims=False)[source]#

See pytensor.tensor.math.argmin().

argsort(axis=-1, kind='quicksort', order=None)[source]#

See pytensor.tensor.sort.argsort().

property broadcastable[source]#

The broadcastable signature of this tensor.

choose(choices, mode='raise')[source]#

Construct an array from an index array and a set of arrays to choose from.

clip(a_min, a_max)[source]#

See pytensor.tensor.math.clip().

compress(a, axis=None)[source]#

Return selected slices only.

conj()[source]#

See pytensor.tensor.math.conj().

conjugate()[source]#

See pytensor.tensor.math.conj().

copy(name=None)[source]#

Return a symbolic copy and optionally assign a name.

Does not copy the tags.

dimshuffle(*pattern)[source]#

Reorder the dimensions of this variable, optionally inserting broadcasted dimensions.

Parameters:

pattern – List/tuple of int mixed with ‘x’ for broadcastable dimensions.

Examples

For example, to create a 3D view of a [2D] matrix, calldimshuffle([0,'x',1]). This will create a 3D view such that the middle dimension is an implicit broadcasted dimension. To do the same thing on the transpose of that matrix, call dimshuffle([1, 'x', 0]).

Notes

This function supports the pattern passed as a tuple, or as a variable-length argument (e.g. a.dimshuffle(pattern) is equivalent to a.dimshuffle(*pattern) where pattern is a list/tuple of ints mixed with ‘x’ characters).

property dtype[source]#

The dtype of this tensor.

fill(value)[source]#

Fill inputted tensor with the assigned value.

property imag[source]#

Return imaginary component of complex-valued tensor z.

inc(y, **kwargs)[source]#

Return a copy of the variable indexed by self with the indexed values incremented by y.

Equivalent to inc_subtensor(self, y). See docstrings for kwargs.

Raises:

TypeError: – If self is not the result of a subtensor operation

Examples

import pytensor.tensor as pt

x = pt.ones((3,)) out = x[1].inc(2) out.eval() array([1., 3., 1.])

max(axis=None, keepdims=False)[source]#

See pytensor.tensor.math.max().

mean(axis=None, dtype=None, keepdims=False, acc_dtype=None)[source]#

See pytensor.tensor.math.mean().

min(axis=None, keepdims=False)[source]#

See pytensor.tensor.math.min().

property ndim[source]#

The rank of this tensor.

nonzero(return_matrix=False)[source]#

See pytensor.tensor.basic.nonzero().

nonzero_values()[source]#

See pytensor.tensor.basic.nonzero_values().

prod(axis=None, dtype=None, keepdims=False, acc_dtype=None)[source]#

See pytensor.tensor.math.prod().

ptp(axis=None)[source]#

See pytensor.tensor.math.ptp().

property real[source]#

Return real component of complex-valued tensor z.

repeat(repeats, axis=None)[source]#

See pytensor.tensor.basic.repeat().

reshape(shape, *, ndim=None)[source]#

Return a reshaped view/copy of this variable.

Parameters:

Warning

This has a different signature than numpy’s ndarray.reshape! In numpy you do not need to wrap the shape arguments in a tuple, in pytensor you do need to.

round(mode=None)[source]#

See pytensor.tensor.math.round().

set(y, **kwargs)[source]#

Return a copy of the variable indexed by self with the indexed values set to y.

Equivalent to set_subtensor(self, y). See docstrings for kwargs.

Raises:

TypeError: – If self is not the result of a subtensor operation

Examples

import pytensor.tensor as pt

x = pt.ones((3,)) out = x[1].set(2) out.eval() array([1., 2., 1.])

sort(axis=-1, kind='quicksort', order=None)[source]#

See pytensor.tensor.sort.sort().

squeeze(axis=None)[source]#

Remove broadcastable dimensions from the shape of an array.

It returns the input array, but with the broadcastable dimensions removed. This is always x itself or a view into x.

std(axis=None, ddof=0, keepdims=False, corrected=False)[source]#

See pytensor.tensor.math.std().

sum(axis=None, dtype=None, keepdims=False, acc_dtype=None)[source]#

See pytensor.tensor.math.sum().

swapaxes(axis1, axis2)[source]#

See pytensor.tensor.basic.swapaxes().

If a matrix is provided with the right axes, its transpose will be returned.

transfer(target)[source]#

Transfer this this array’s data to another device.

If target is 'cpu' this will transfer to a TensorType (if not already one). Other types may define additional targets.

Parameters:

target (str) – The desired location of the output variable

transpose(*axes)[source]#

Transpose this array.

Returns:

var(axis=None, ddof=0, keepdims=False, corrected=False)[source]#

See pytensor.tensor.math.var().

Shaping and Shuffling#

To re-order the dimensions of a variable, to insert or remove broadcastable dimensions, see _tensor_py_operators.dimshuffle().

pytensor.tensor.shape(x)[source]#

Returns an lvector representing the shape of x.

pytensor.tensor.reshape(x, newshape, ndim=None)[source]

type x:

any TensorVariable (or compatible)

param x:

variable to be reshaped

type newshape:

lvector (or compatible)

param newshape:

the new shape for x

param ndim:

optional - the length that newshape’s value will have. If this is None, then reshape will infer it from newshape.

rtype:

variable with x’s dtype, but ndim dimensions

Note

This function can infer the length of a symbolic newshape value in some cases, but if it cannot and you do not provide the ndim, then this function will raise an Exception.

pytensor.tensor.shape_padleft(x, n_ones=1)[source]#

Reshape x by left padding the shape with n_ones 1s. All new dimensions will be broadcastable.

Parameters:

x (any TensorVariable (or compatible)) – variable to be reshaped

pytensor.tensor.shape_padright(x, n_ones=1)[source]#

Reshape x by right padding the shape with n_ones ones. All new dimensions will be broadcastable.

Parameters:

x (any TensorVariable (or compatible )) – variable to be reshaped

pytensor.tensor.shape_padaxis(t, axis)[source]#

Reshape t by inserting 1 at the dimension axis. All new dimensions will be broadcastable.

Parameters:

Example:

tensor = pytensor.tensor.type.tensor3() pytensor.tensor.shape_padaxis(tensor, axis=0) InplaceDimShuffle{x,0,1,2}.0 pytensor.tensor.shape_padaxis(tensor, axis=1) InplaceDimShuffle{0,x,1,2}.0 pytensor.tensor.shape_padaxis(tensor, axis=3) InplaceDimShuffle{0,1,2,x}.0 pytensor.tensor.shape_padaxis(tensor, axis=-1) InplaceDimShuffle{0,1,2,x}.0

pytensor.tensor.specify_shape(x, shape)[source]#

Specify a fixed shape for a Variable.

If a dimension’s shape value is None, the size of that dimension is not considered fixed/static at runtime.

pytensor.tensor.flatten(x, ndim=1)[source]#

Similar to reshape(), but the shape is inferred from the shape of x.

Parameters:

Return type:

variable with same dtype as x and ndim dimensions

Returns:

variable with the same shape as x in the leading ndim-1dimensions, but with all remaining dimensions of x collapsed into the last dimension.

For example, if we flatten a tensor of shape (2, 3, 4, 5) with flatten(x, ndim=2), then we’ll have the same (i.e. 2-1=1) leading dimensions(2,), and the remaining dimensions are collapsed, so the output in this example would have shape (2, 60).

pytensor.tensor.tile(x, reps, ndim=None)[source]#

Construct an array by repeating the input x according to repspattern.

Tiles its input according to reps. The length of reps is the number of dimension of x and contains the number of times to tile x in each dimension.

See:

numpy.tiledocumentation for examples.

See:

pytensor.tensor.extra_ops.repeat

Note:

Currently, reps must be a constant, x.ndim andlen(reps) must be equal and, if specified, ndim must be equal to both.

pytensor.tensor.roll(x, shift, axis=None)[source]#

Convenience function to roll TensorTypes along the given axis.

Syntax copies numpy.roll function.

Parameters:

Returns:

Output tensor, with the same shape as x.

Return type:

tensor

Creating Tensors#

pytensor.tensor.zeros_like(x, dtype=None)[source]#

Parameters:

Returns a tensor the shape of x filled with zeros of the type of dtype.

pytensor.tensor.ones_like(x)[source]#

Parameters:

Returns a tensor the shape of x filled with ones of the type of dtype.

pytensor.tensor.zeros(shape, dtype=None)[source]#

Parameters:

Returns a tensor filled with zeros of the provided shape.

pytensor.tensor.ones(shape, dtype=None)[source]#

Parameters:

Returns a tensor filled with ones of the provided shape.

pytensor.tensor.fill(a, b)[source]#

Parameters:

Create a matrix by filling the shape of a with b.

pytensor.tensor.alloc(value, *shape)[source]#

Parameters:

Returns:

an N-dimensional tensor initialized by value and having the specified shape.

pytensor.tensor.eye(n, m=None, k=0, dtype=pytensor.config.floatX)[source]#

Parameters:

Returns:

An array where all elements are equal to zero, except for the k-th diagonal, whose values are equal to one.

pytensor.tensor.identity_like(x, dtype=None)[source]#

Parameters:

Returns:

A tensor of same shape as x that is filled with zeros everywhere except for the main diagonal, whose values are equal to one. The output will have same dtype as x unless overridden in dtype.

pytensor.tensor.stack(tensors, axis=0)[source]#

Stack tensors in sequence on given axis (default is 0).

Take a sequence of tensors and stack them on given axis to make a single tensor. The size in dimension axis of the result will be equal to the number of tensors passed.

Parameters:

Returns:

A tensor such that rval[0] == tensors[0], rval[1] == tensors[1], etc.

Examples:

a = pytensor.tensor.type.scalar() b = pytensor.tensor.type.scalar() c = pytensor.tensor.type.scalar() x = pytensor.tensor.stack([a, b, c]) x.ndim # x is a vector of length 3. 1 a = pytensor.tensor.type.tensor4() b = pytensor.tensor.type.tensor4() c = pytensor.tensor.type.tensor4() x = pytensor.tensor.stack([a, b, c]) x.ndim # x is a 5d tensor. 5 rval = x.eval(dict((t, np.zeros((2, 2, 2, 2))) for t in [a, b, c])) rval.shape # 3 tensors are stacked on axis 0 (3, 2, 2, 2, 2)

We can also specify different axis than default value 0:

x = pytensor.tensor.stack([a, b, c], axis=3) x.ndim 5 rval = x.eval(dict((t, np.zeros((2, 2, 2, 2))) for t in [a, b, c])) rval.shape # 3 tensors are stacked on axis 3 (2, 2, 2, 3, 2) x = pytensor.tensor.stack([a, b, c], axis=-2) x.ndim 5 rval = x.eval(dict((t, np.zeros((2, 2, 2, 2))) for t in [a, b, c])) rval.shape # 3 tensors are stacked on axis -2 (2, 2, 2, 3, 2)

pytensor.tensor.stack(*tensors)[source]

Warning

The interface stack(*tensors) is deprecated! Usestack(tensors, axis=0) instead.

Stack tensors in sequence vertically (row wise).

Take a sequence of tensors and stack them vertically to make a single tensor.

param tensors:

one or more tensors of the same rank

returns:

A tensor such that rval[0] == tensors[0], rval[1] == tensors[1], etc.

x0 = pt.scalar() x1 = pt.scalar() x2 = pt.scalar() x = pt.stack(x0, x1, x2) x.ndim # x is a vector of length 3. 1

pytensor.tensor.concatenate(tensor_list, axis=0)[source]#

Parameters:

x0 = pt.fmatrix() x1 = pt.ftensor3() x2 = pt.fvector() x = pt.concatenate([x0, x1[0], pt.shape_padright(x2)], axis=1) x.ndim 2

pytensor.tensor.stacklists(tensor_list)[source]#

Parameters:

tensor_list (an iterable that contains either tensors or other iterables of the same type as tensor_list (in other words, this is a tree whose leaves are tensors).) – tensors to be stacked together.

Recursively stack lists of tensors to maintain similar structure.

This function can create a tensor from a shaped list of scalars:

from pytensor.tensor import stacklists, scalars, matrices from pytensor import function a, b, c, d = scalars('abcd') X = stacklists([[a, b], [c, d]]) f = function([a, b, c, d], X) f(1, 2, 3, 4) array([[ 1., 2.], [ 3., 4.]])

We can also stack arbitrarily shaped tensors. Here we stack matrices into a 2 by 2 grid:

from numpy import ones a, b, c, d = matrices('abcd') X = stacklists([[a, b], [c, d]]) f = function([a, b, c, d], X) x = ones((4, 4), 'float32') f(x, x, x, x).shape (2, 2, 4, 4)

pytensor.tensor.basic.choose(a, choices, mode='raise')[source]#

Construct an array from an index array and a set of arrays to choose from.

First of all, if confused or uncertain, definitely look at the Examples - in its full generality, this function is less simple than it might seem from the following code description (below ndi = numpy.lib.index_tricks):

np.choose(a,c) == np.array([c[a[I]][I] for I in ndi.ndindex(a.shape)]).

But this omits some subtleties. Here is a fully general summary:

Given an index array (a) of integers and a sequence of n arrays (choices), a and each choice array are first broadcast, as necessary, to arrays of a common shape; calling these Ba and Bchoices[i], i = 0,…,n-1 we have that, necessarily, Ba.shape == Bchoices[i].shape for each i. Then, a new array with shape Ba.shape is created as follows:

Parameters:

Returns:

The merged result.

Return type:

merged_array - array

Raises:

ValueError - shape mismatch – If a and each choice array are not all broadcastable to the same shape.

Reductions#

pytensor.tensor.max(x, axis=None, keepdims=False)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis or axes along which to compute the maximum

Parameter:

keepdims - (boolean) If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original tensor.

Returns:

maximum of x along axis

axis can be:

pytensor.tensor.argmax(x, axis=None, keepdims=False)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis along which to compute the index of the maximum

Parameter:

keepdims - (boolean) If this is set to True, the axis which is reduced is left in the result as a dimension with size one. With this option, the result will broadcast correctly against the original tensor.

Returns:

the index of the maximum value along a given axis

if axis == None, argmax over the flattened tensor (like NumPy)

pytensor.tensor.max_and_argmax(x, axis=None, keepdims=False)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis along which to compute the maximum and its index

Parameter:

keepdims - (boolean) If this is set to True, the axis which is reduced is left in the result as a dimension with size one. With this option, the result will broadcast correctly against the original tensor.

Returns:

the maximum value along a given axis and its index.

if axis == None, max_and_argmax over the flattened tensor (like NumPy)

pytensor.tensor.min(x, axis=None, keepdims=False)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis or axes along which to compute the minimum

Parameter:

keepdims - (boolean) If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original tensor.

Returns:

minimum of x along axis

axis can be:

pytensor.tensor.argmin(x, axis=None, keepdims=False)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis along which to compute the index of the minimum

Parameter:

keepdims - (boolean) If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original tensor.

Returns:

the index of the minimum value along a given axis

if axis == None, argmin over the flattened tensor (like NumPy)

pytensor.tensor.sum(x, axis=None, dtype=None, keepdims=False, acc_dtype=None)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis or axes along which to compute the sum

Parameter:

dtype - The dtype of the returned tensor. If None, then we use the default dtype which is the same as the input tensor’s dtype except when:

This default dtype does _not_ depend on the value of “acc_dtype”.

Parameter:

keepdims - (boolean) If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original tensor.

Parameter:

acc_dtype - The dtype of the internal accumulator. If None (default), we use the dtype in the list below, or the input dtype if its precision is higher:

Returns:

sum of x along axis

axis can be:

pytensor.tensor.prod(x, axis=None, dtype=None, keepdims=False, acc_dtype=None, no_zeros_in_input=False)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis or axes along which to compute the product

Parameter:

dtype - The dtype of the returned tensor. If None, then we use the default dtype which is the same as the input tensor’s dtype except when:

This default dtype does _not_ depend on the value of “acc_dtype”.

Parameter:

keepdims - (boolean) If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original tensor.

Parameter:

acc_dtype - The dtype of the internal accumulator. If None (default), we use the dtype in the list below, or the input dtype if its precision is higher:

Parameter:

no_zeros_in_input - The grad of prod is complicated as we need to handle 3 different cases: without zeros in the input reduced group, with 1 zero or with more zeros.

This could slow you down, but more importantly, we currently don’t support the second derivative of the 3 cases. So you cannot take the second derivative of the default prod().

To remove the handling of the special cases of 0 and so get some small speed up and allow second derivative setno_zeros_in_inputs to True. It defaults to False.

It is the user responsibility to make sure there are no zeros in the inputs. If there are, the grad will be wrong.

Returns:

product of every term in x along axis

axis can be:

pytensor.tensor.mean(x, axis=None, dtype=None, keepdims=False, acc_dtype=None)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis or axes along which to compute the mean

Parameter:

dtype - The dtype to cast the result of the inner summation into. For instance, by default, a sum of a float32 tensor will be done in float64 (acc_dtype would be float64 by default), but that result will be casted back in float32.

Parameter:

keepdims - (boolean) If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original tensor.

Parameter:

acc_dtype - The dtype of the internal accumulator of the inner summation. This will not necessarily be the dtype of the output (in particular if it is a discrete (int/uint) dtype, the output will be in a float type). If None, then we use the same rules as sum().

Returns:

mean value of x along axis

axis can be:

pytensor.tensor.var(x, axis=None, keepdims=False)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis or axes along which to compute the variance

Parameter:

keepdims - (boolean) If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original tensor.

Returns:

variance of x along axis

axis can be:

pytensor.tensor.std(x, axis=None, keepdims=False)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis or axes along which to compute the standard deviation

Parameter:

keepdims - (boolean) If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original tensor.

Returns:

variance of x along axis

axis can be:

pytensor.tensor.all(x, axis=None, keepdims=False)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis or axes along which to apply ‘bitwise and’

Parameter:

keepdims - (boolean) If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original tensor.

Returns:

bitwise and of x along axis

axis can be:

pytensor.tensor.any(x, axis=None, keepdims=False)[source]#

Parameter:

x - symbolic Tensor (or compatible)

Parameter:

axis - axis or axes along which to apply bitwise or

Parameter:

keepdims - (boolean) If this is set to True, the axes which are reduced are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the original tensor.

Returns:

bitwise or of x along axis

axis can be:

pytensor.tensor.ptp(x, axis=None)[source]#

Range of values (maximum - minimum) along an axis. The name of the function comes from the acronym for peak to peak.

Parameter:

x Input tensor.

Parameter:

axis Axis along which to find the peaks. By default, flatten the array.

Returns:

A new array holding the result.

Indexing#

Like NumPy, PyTensor distinguishes between basic and advanced indexing. PyTensor fully supports basic indexing (see NumPy’s indexing) and integer advanced indexing.

Index-assignment is not supported. If you want to do something like a[5] = b or a[5]+=b, see pytensor.tensor.subtensor.set_subtensor() andpytensor.tensor.subtensor.inc_subtensor() below.

pytensor.tensor.subtensor.set_subtensor(x, y, inplace=False, tolerate_inplace_aliasing=False)[source]#

Return x with the given subtensor overwritten by y.

Parameters:

Examples

To replicate the numpy expression “r[10:] = 5”, type >>> from pytensor.tensor import vector >>> r = vector(“r”) >>> new_r = set_subtensor(r[10:], 5)

pytensor.tensor.subtensor.inc_subtensor(x, y, inplace=False, set_instead_of_inc=False, tolerate_inplace_aliasing=False, ignore_duplicates=False)[source]#

Update the value of an indexed array by a given amount.

This is equivalent to x[indices] += y or np.add.at(x, indices, y), depending on the value of ignore_duplicates.

Parameters:

Examples

To replicate the expression r[10:] += 5:

..code-block:: python

r = ivector() new_r = inc_subtensor(r[10:], 5)

To replicate the expression r[[0, 1, 0]] += 5:

..code-block:: python

r = ivector() new_r = inc_subtensor(r[10:], 5, ignore_duplicates=True)

Operator Support#

Many Python operators are supported.

a, b = pt.itensor3(), pt.itensor3() # example inputs

Arithmetic#

a + 3 # pt.add(a, 3) -> itensor3 3 - a # pt.sub(3, a) a * 3.5 # pt.mul(a, 3.5) -> ftensor3 or dtensor3 (depending on casting) 2.2 / a # pt.truediv(2.2, a) 2.2 // a # pt.intdiv(2.2, a) 2.2**a # pt.pow(2.2, a) b % a # pt.mod(b, a)

Bitwise#

a & b # pt.and_(a,b) bitwise and (alias pt.bitwise_and) a ^ 1 # pt.xor(a,1) bitwise xor (alias pt.bitwise_xor) a | b # pt.or_(a,b) bitwise or (alias pt.bitwise_or) ~a # pt.invert(a) bitwise invert (alias pt.bitwise_not)

Inplace#

In-place operators are not supported. PyTensor’s graph rewrites will determine which intermediate values to use for in-place computations. If you would like to update the value of ashared variable, consider using the updates argument toPyTensor.function().

Elemwise#

Casting#

pytensor.tensor.cast(x, dtype)[source]#

Cast any tensor x to a tensor of the same shape, but with a different numerical type dtype.

This is not a reinterpret cast, but a coercion cast, similar tonumpy.asarray(x, dtype=dtype).

import pytensor.tensor as pt x = pt.matrix() x_as_int = pt.cast(x, 'int32')

Attempting to casting a complex value to a real value is ambiguous and will raise an exception. Use real, imag, abs, or angle.

pytensor.tensor.real(x)[source]#

Return the real (not imaginary) components of tensor x. For non-complex x this function returns x.

pytensor.tensor.imag(x)[source]#

Return the imaginary components of tensor x. For non-complex x this function returns zeros_like(x).

Comparisons#

The six usual equality and inequality operators share the same interface.

Parameter:

a - symbolic Tensor (or compatible)

Parameter:

b - symbolic Tensor (or compatible)

Return type:

symbolic Tensor

Returns:

a symbolic tensor representing the application of the logical Elemwise operator.

Note

PyTensor has no boolean dtype. Instead, all boolean tensors are represented in 'int8'.

Here is an example with the less-than operator.

import pytensor.tensor as pt x,y = pt.dmatrices('x','y') z = pt.le(x,y)

pytensor.tensor.lt(a, b)[source]#

Returns a symbolic 'int8' tensor representing the result of logical less-than (a<b).

Also available using syntax a < b

pytensor.tensor.gt(a, b)[source]#

Returns a symbolic 'int8' tensor representing the result of logical greater-than (a>b).

Also available using syntax a > b

pytensor.tensor.le(a, b)[source]#

Returns a variable representing the result of logical less than or equal (a<=b).

Also available using syntax a <= b

pytensor.tensor.ge(a, b)[source]#

Returns a variable representing the result of logical greater or equal than (a>=b).

Also available using syntax a >= b

pytensor.tensor.eq(a, b)[source]#

Returns a variable representing the result of logical equality (a==b).

pytensor.tensor.neq(a, b)[source]#

Returns a variable representing the result of logical inequality (a!=b).

pytensor.tensor.greater(a, b)[source]#

Alias for gt. greater is the NumPy name.

pytensor.tensor.greater_equal(a, b)[source]#

Alias for ge. greater_equal is the NumPy name.

pytensor.tensor.less(a, b)[source]#

Alias for lt. less is the NumPy name.

pytensor.tensor.less_equal(a, b)[source]#

Alias for le. less_equal is the NumPy name.

pytensor.tensor.equal(a, b)[source]#

Alias for eq. equal is the NumPy name.

pytensor.tensor.not_equal(a, b)[source]#

Alias for neq. not_equal is the NumPy name.

pytensor.tensor.isnan(a)[source]#

Returns a variable representing the comparison of a elements with nan.

This is equivalent to numpy.isnan.

pytensor.tensor.isinf(a)[source]#

Returns a variable representing the comparison of a elements with inf or -inf.

This is equivalent to numpy.isinf.

pytensor.tensor.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)[source]#

Returns a symbolic 'int8' tensor representing where two tensors are equal within a tolerance.

The tolerance values are positive, typically very small numbers. The relative difference (rtol * abs(b)) and the absolute difference atol are added together to compare against the absolute difference between a and b.

For finite values, isclose uses the following equation to test whether two floating point values are equivalent:|a - b| <= (atol + rtol * |b|)

For infinite values, isclose checks if both values are the same signed inf value.

If equal_nan is True, isclose considers NaN values in the same position to be close. Otherwise, NaN values are not considered close.

This is equivalent to numpy.isclose.

pytensor.tensor.allclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)[source]#

Returns a symbolic 'int8' value representing if all elements in two tensors are equal within a tolerance.

See notes in isclose for determining values equal within a tolerance.

This is equivalent to numpy.allclose.

Condition#

pytensor.tensor.switch(cond, ift, iff)[source]#

Returns a variable representing a switch between ift (i.e. “if true”) and iff (i.e. “if false”) based on the condition cond. This is the PyTensor equivalent of numpy.where.

Parameter:

cond - symbolic Tensor (or compatible)

Parameter:

ift - symbolic Tensor (or compatible)

Parameter:

iff - symbolic Tensor (or compatible)

Return type:

symbolic Tensor

import pytensor.tensor as pt a,b = pt.dmatrices('a','b') x,y = pt.dmatrices('x','y') z = pt.switch(pt.lt(a,b), x, y)

pytensor.tensor.where(cond, ift, iff)[source]#

Alias for switch. where is the NumPy name.

pytensor.tensor.clip(x, min, max)[source]#

Return a variable representing x, but with all elements greater thanmax clipped to max and all elements less than min clipped to min.

Normal broadcasting rules apply to each of x, min, and max.

Note that there is no warning for inputs that are the wrong way round (min > max), and that results in this case may differ from numpy.clip.

Bit-wise#

The bitwise operators possess this interface:

Parameter:

a - symbolic tensor of integer type.

Parameter:

b - symbolic tensor of integer type.

Note

The bitwise operators must have an integer type as input.

The bit-wise not (invert) takes only one parameter.

Return type:

symbolic tensor with corresponding dtype.

pytensor.tensor.and_(a, b)[source]#

Returns a variable representing the result of the bitwise and.

pytensor.tensor.or_(a, b)[source]#

Returns a variable representing the result of the bitwise or.

pytensor.tensor.xor(a, b)[source]#

Returns a variable representing the result of the bitwise xor.

pytensor.tensor.invert(a)[source]#

Returns a variable representing the result of the bitwise not.

pytensor.tensor.bitwise_and(a, b)[source]#

Alias for and_. bitwise_and is the NumPy name.

pytensor.tensor.bitwise_or(a, b)[source]#

Alias for or_. bitwise_or is the NumPy name.

pytensor.tensor.bitwise_xor(a, b)[source]#

Alias for xor_. bitwise_xor is the NumPy name.

pytensor.tensor.bitwise_not(a, b)[source]#

Alias for invert. invert is the NumPy name.

Here is an example using the bit-wise and_ via the & operator:

import pytensor.tensor as pt x,y = pt.imatrices('x','y') z = x & y

Mathematical#

pytensor.tensor.abs(a)[source]#

Returns a variable representing the absolute of a, i.e. |a|.

Note

Can also be accessed using builtins.abs: i.e. abs(a).

pytensor.tensor.angle(a)[source]#

Returns a variable representing angular component of complex-valued Tensor a.

pytensor.tensor.exp(a)[source]#

Returns a variable representing the exponential of a.

pytensor.tensor.maximum(a, b)[source]#

Returns a variable representing the maximum element by element of a and b

pytensor.tensor.minimum(a, b)[source]#

Returns a variable representing the minimum element by element of a and b

pytensor.tensor.neg(a)[source]#

Returns a variable representing the negation of a (also -a).

pytensor.tensor.reciprocal(a)[source]#

Returns a variable representing the inverse of a, ie 1.0/a. Also called reciprocal.

pytensor.tensor.log(a), log2(a), log10(a)[source]#

Returns a variable representing the base e, 2 or 10 logarithm of a.

pytensor.tensor.sign(a)[source]#

Returns a variable representing the sign of a.

pytensor.tensor.ceil(a)[source]#

Returns a variable representing the ceiling of a (for example ceil(2.1) is 3).

pytensor.tensor.floor(a)[source]#

Returns a variable representing the floor of a (for example floor(2.9) is 2).

pytensor.tensor.round(a, mode='half_away_from_zero')[source]

Returns a variable representing the rounding of a in the same dtype as a. Implemented rounding mode are half_away_from_zero and half_to_even.

pytensor.tensor.iround(a, mode='half_away_from_zero')[source]#

Short hand for cast(round(a, mode),’int64’).

pytensor.tensor.sqr(a)[source]#

Returns a variable representing the square of a, ie a^2.

pytensor.tensor.sqrt(a)[source]#

Returns a variable representing the of a, ie a^0.5.

pytensor.tensor.cos(a), sin(a), tan(a)[source]#

Returns a variable representing the trigonometric functions of a (cosine, sine and tangent).

pytensor.tensor.cosh(a), sinh(a), tanh(a)[source]#

Returns a variable representing the hyperbolic trigonometric functions of a (hyperbolic cosine, sine and tangent).

pytensor.tensor.erf(a), erfc(a)[source]#

Returns a variable representing the error function or the complementary error function. wikipedia

pytensor.tensor.erfinv(a), erfcinv(a)[source]#

Returns a variable representing the inverse error function or the inverse complementary error function. wikipedia

pytensor.tensor.gamma(a)[source]#

Returns a variable representing the gamma function.

pytensor.tensor.gammaln(a)[source]#

Returns a variable representing the logarithm of the gamma function.

pytensor.tensor.psi(a)[source]#

Returns a variable representing the derivative of the logarithm of the gamma function (also called the digamma function).

pytensor.tensor.chi2sf(a, df)[source]#

Returns a variable representing the survival function (1-cdf — sometimes more accurate).

C code is provided in the Theano_lgpl repository. This makes it faster.

Theano/Theano_lgpl.git

You can find more information about Broadcasting in the Broadcasting tutorial.

Linear Algebra#

pytensor.tensor.dot(X, Y)[source]#

For 2-D arrays it is equivalent to matrix multiplication, and for 1-D arrays to inner product of vectors (without complex conjugation). For N dimensions it is a sum product over the last axis of a and the second-to-last of b:

Parameters:

Return type:

symbolic matrix or vector

Returns:

the inner product of X and Y.

pytensor.tensor.outer(X, Y)[source]#

Parameters:

Return type:

symbolic matrix

Returns:

vector-vector outer product

pytensor.tensor.tensordot(a, b, axes=2)[source]#

Given two tensors a and b,tensordot computes a generalized dot product over the provided axes. PyTensor’s implementation reduces all expressions to matrix or vector dot products and is based on code from Tijmen Tieleman’sgnumpy (http://www.cs.toronto.edu/~tijmen/gnumpy.html).

Parameters:

Returns:

a tensor with shape equal to the concatenation of a’s shape (less any dimensions that were summed over) and b’s shape (less any dimensions that were summed over).

Return type:

symbolic tensor

It may be helpful to consider an example to see what tensordot does. PyTensor’s implementation is identical to NumPy’s. Here a has shape (2, 3, 4) and b has shape (5, 6, 4, 3). The axes to sum over are [[1, 2], [3, 2]] – note that a.shape[1] == b.shape[3] and a.shape[2] == b.shape[2]; these axes are compatible. The resulting tensor will have shape (2, 5, 6) – the dimensions that are not being summed:

import numpy as np

a = np.random.random((2,3,4)) b = np.random.random((5,6,4,3))

c = np.tensordot(a, b, [[1,2],[3,2]])

a0, a1, a2 = a.shape b0, b1, _, _ = b.shape cloop = np.zeros((a0,b0,b1))

Loop over non-summed indices--these exist in the tensor product

for i in range(a0): for j in range(b0): for k in range(b1): # Loop over summed indices--these don't exist in the tensor product for l in range(a1): for m in range(a2): cloop[i,j,k] += a[i,l,m] * b[j,k,m,l]

assert np.allclose(c, cloop)

This specific implementation avoids a loop by transposing a and b such that the summed axes of a are last and the summed axes of b are first. The resulting arrays are reshaped to 2 dimensions (or left as vectors, if appropriate) and a matrix or vector dot product is taken. The result is reshaped back to the required output dimensions.

In an extreme case, no axes may be specified. The resulting tensor will have shape equal to the concatenation of the shapes of a and b:

c = np.tensordot(a, b, 0) a.shape (2, 3, 4) b.shape (5, 6, 4, 3) print(c.shape) (2, 3, 4, 5, 6, 4, 3)

Note:

See the documentation of numpy.tensordot for more examples.

pytensor.tensor.batched_dot(X, Y)[source]#

Parameters:

This function computes the dot product between the two tensors, by iterating over the first dimension using scan. Returns a tensor of size e.g. if it is 3D: (dim1, dim3, dim4) Example:

first = pt.tensor3('first') second = pt.tensor3('second') result = batched_dot(first, second)

Note:

This is a subset of numpy.einsum, but we do not provide it for now.

Parameters:

Returns:

tensor of products

pytensor.tensor.batched_tensordot(X, Y, axes=2)[source]#

Parameters:

Returns:

a tensor with shape equal to the concatenation of a’s shape (less any dimensions that were summed over) and b’s shape (less first dimension and any dimensions that were summed over).

Return type:

tensor of tensordots

A hybrid of batch_dot and tensordot, this function computes the tensordot product between the two tensors, by iterating over the first dimension using scan to perform a sequence of tensordots.

Note:

See tensordot() and batched_dot() for supplementary documentation.

pytensor.tensor.mgrid()[source]#

Returns:

an instance which returns a dense (or fleshed out) mesh-grid when indexed, so that each returned argument has the same shape. The dimensions and number of the output arrays are equal to the number of indexing dimensions. If the step length is not a complex number, then the stop is not inclusive.

Example:

a = pt.mgrid[0:5, 0:3] a[0].eval() array([[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]) a[1].eval() array([[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]])

pytensor.tensor.ogrid()[source]#

Returns:

an instance which returns an open (i.e. not fleshed out) mesh-grid when indexed, so that only one dimension of each returned array is greater than 1. The dimension and number of the output arrays are equal to the number of indexing dimensions. If the step length is not a complex number, then the stop is not inclusive.

Example:

b = pt.ogrid[0:5, 0:3] b[0].eval() array([[0], [1], [2], [3], [4]]) b[1].eval() array([[0, 1, 2]])

Gradient / Differentiation#

Driver for gradient calculations.

pytensor.gradient.grad(cost, wrt, consider_constant=None, disconnected_inputs='raise', add_names=True, known_grads=None, return_disconnected='zero', null_gradients='raise')[source]

Return symbolic gradients of one cost with respect to one or more variables.

For more information about how automatic differentiation works in PyTensor, see gradient. For information on how to implement the gradient of a certain Op, see grad().

Parameters:

Returns:

A symbolic expression for the gradient of cost with respect to each of the wrt terms. If an element of wrt is not differentiable with respect to the output, then a zero variable is returned.

Return type:

Variable or list/tuple of Variables