Shortcuts

Source code for nets.autograd.numeric

"""
This modules defines basic transformations on a ``Tensor`` like ``transpose`` or ``reshape``.
"""

import numpy as np
import nets
from .hook import Hook
from ._utils import numpy_unpad, inv_permutation


def _T(t):
    r"""Transpose a tensor object.

    .. math::

        T_{out} = (t_{i, j}^{[out]})_{i, j} \quad where \quad t_{i, j}^{[out]} = t_{j ,i}

    Args:
        t (Tensor): tensor to transpose

    Returns:
        Tensor
    """
    t = nets.to_tensor(t)
    data = t.data.T
    requires_grad = t.requires_grad
    hooks = []
    if requires_grad:
        hooks.append(Hook(t, lambda grad: grad.T))

    return nets.Tensor(data, requires_grad, hooks)


[docs]def transpose(t, indices=None): r"""Permutation a tensor object. Args: t (Tensor): indices (tuple, optional): index to transpose. Returns: Tensor """ t = nets.to_tensor(t) if indices is None: indices = tuple(range(t.ndim - 1, -1, -1)) data = t.data.transpose(indices) requires_grad = t.requires_grad hooks = [] if requires_grad: def grad_fn(grad): indices_back = tuple(inv_permutation(indices)) grad = grad.transpose(indices_back) return grad hooks.append(Hook(t, grad_fn)) return nets.Tensor(data, requires_grad, hooks)
[docs]def reshape(t, shape): r"""Reshape a ``Tensor``. Args: t (Tensor): tensor to transform shape (tuple): new shape of ``t`` Returns: Tensor """ t = nets.to_tensor(t) data = t.data.reshape(shape) requires_grad = t.requires_grad hooks = [] if requires_grad: hooks.append(Hook(t, lambda grad: grad.reshape(t.shape))) return nets.Tensor(data, requires_grad, hooks)
[docs]def pad(t, padding, constant_values=0): r"""Reshape a ``Tensor`` to a bigger size and add a ``padding`` on the side, with a ``0`` constant value. Args: t (Tensor): tensor to transform padding (tuple): padding dimensions constant_values (scalar, optional): scalar affected in the padding Returns: Tensor """ t = nets.to_tensor(t) data = np.pad(t.data, pad_width=padding, constant_values=constant_values) requires_grad = t.requires_grad hooks = [] if requires_grad: hooks.append(Hook(t, lambda grad: numpy_unpad(grad, padding))) return nets.Tensor(data, requires_grad, hooks)
[docs]def max(t, axis=None): r"""Get the maximum from a ``Tensor``. Args: t (Tensor): tensor to transform axis (int, optional): index of the axis to search. Default is ``None``. Returns: Tensor """ t = nets.to_tensor(t) data = np.max(t.data, axis=axis) requires_grad = t.requires_grad hooks = [] if requires_grad: def grad_fn(grad): bigger_grad = np.zeros_like(t.data) if axis is None: # If there is no axis, the argmax is the location of he maximum single element max_indices = np.unravel_index(np.argmax(t.data), t.shape) bigger_grad[max_indices] = grad else: # If there is an axis, we reconstruct the bigger matrix by 'rolling' on this axis max_indices = np.argmax(t.data, axis=axis) for i, roll in enumerate(np.rollaxis(bigger_grad, axis)): roll += (max_indices == i).astype(int) * grad return bigger_grad hooks.append(Hook(t, grad_fn)) return nets.Tensor(data, requires_grad, hooks)
[docs]def argmax(t, axis=None): r"""Get the indices of maximum elements from a ``Tensor``. Args: t (Tensor): tensor get maximum indices from axis (int, optional): index of the axis. Default is ``None``. Returns: Tensor """ t = nets.to_tensor(t) if axis is None: return nets.Tensor(np.unravel_index(np.argmax(t.data), t.shape)) else: return nets.Tensor(np.argmax(t.data, axis=axis))
[docs]def flatten(t): r"""Reshape in 1-dimensional a ``Tensor``. Args: t (Tensor): tensor get reshape. Returns: Tensor """ return reshape(t, (t.size,))
ITERABLE = (list, tuple)
[docs]def concatenate(iterable): r"""Concatenate multiples ``Tensor`` from an iterable. .. note:: The ``Tensor`` in ``iterable`` should and must have the same shape. Args: iterable (tuple, list): list containing ``Tensor`` to concatenate. Returns: Tensor: the concatenation of all ``Tensor``. """ assert isinstance(iterable, ITERABLE), f'iterable type {type(iterable)} unsupported for `concatenate` function.' \ f'Types currently supported are list, tuple.' requires_grad = False hooks = [] data = np.array([]) for idx, t in enumerate(iterable): t = nets.to_tensor(t) requires_grad = t.requires_grad or requires_grad if data.size == 0: data = t.data else: data = np.concatenate((data, t.data)) if t.requires_grad: def grad_fn(grad): return grad[idx:idx+t.shape[0]] hooks.append(Hook(t, grad_fn)) return nets.Tensor(data, requires_grad, hooks)
[docs]def append(t, value): r"""Append multiples ``Tensor`` from an iterable. .. note:: The ``Tensor`` in ``iterable`` should and must have the same shape. Args: t (Tensor): list containing ``Tensor`` to concatenate. Returns: Tensor: the concatenation of all ``Tensor``. """ t = nets.to_tensor(t) value = nets.to_tensor(value) requires_grad = False hooks = [] requires_grad = t.requires_grad or value.requires_grad if t.size == 0: data = [value.data] elif value.size == 0: data = [t.data] else: data = t.data.tolist() data.append(value.data) if t.requires_grad: def grad_fn(grad): return grad[:-1] hooks.append(Hook(t, grad_fn)) if value.requires_grad: def grad_fn(grad): return grad[-1] hooks.append(Hook(value, grad_fn)) return nets.Tensor(data, requires_grad, hooks)

Docs

Access comprehensive developer documentation for Nets

View Docs

Tutorials

Get beginners tutorials and create state-of-the-art models

View Tutorials

Resources

Check the GitHub page and contribute to the project

View GitHub