shrinath-suresh/blogs-docs-splitted huggingface dataset:
torch.linalg.lu
torch.linalg.lu(A, *, pivot=True, out=None)
Computes the LU decomposition with partial pivoting of a matrix.
Letting \mathbb{K} be \mathbb{R} or \mathbb{C}, the LU
   decomposition with partial pivoting of a matrix A \in
   \mathbb{K}^{m \times n} is defined as
  A = PLU\mathrlap{\qquad P \in \mathbb{K}^{m \times m}, L \in
  \mathbb{K}^{m \times k}, U \in \mathbb{K}^{k \times n}}

where k = min(m,n), P is a permutation matrix, L is lower
   triangular with ones on the diagonal and U is upper triangular.
If "pivot"= False and "A" is on GPU, then the LU decomposition
   without pivoting is computed
  A = LU\mathrlap{\qquad L \in \mathbb{K}^{m \times k}, U \in
  \mathbb{K}^{k \times n}}

When "pivot"= False, the returned matrix "P" will be empty. The
   LU decomposition without pivoting may not exist if any of the
   principal minors of "A" is singular. In this case, the output
   matrix may contain inf or NaN.
matrix may contain inf or NaN.
Supports input of float, double, cfloat and cdouble dtypes. Also
   supports batches of matrices, and if "A" is a batch of matrices
   then the output has the same batch dimensions.
See also:
 "torch.linalg.solve()" solves a system of linear equations using
 the LU decomposition with partial pivoting.

Warning:
 The LU decomposition is almost never unique, as often there are
 different permutation matrices that can yield different LU
 decompositions. As such, different platforms, like SciPy, or
 inputs on different devices, may produce different valid
 decompositions.

Warning:
 Gradient computations are only supported if the input matrix is
 full-rank. If this condition is not met, no error will be thrown,
 but the gradient may not be finite. This is because the LU
 decomposition with pivoting is not differentiable at these
 points.

Parameters:
points.
Parameters:
      * A (Tensor) -- tensor of shape (, m, n)* where *** is
        zero or more batch dimensions.
  * **pivot** (*bool**, **optional*) -- Controls whether to
    compute the LU decomposition with partial pivoting or no
    pivoting. Default: *True*.

Keyword Arguments:
      out (tuple, optional) -- output tuple of three
      tensors. Ignored if None. Default: None.
Returns:
      A named tuple (P, L, U).
Examples:
  >>> A = torch.randn(3, 2)
  >>> P, L, U = torch.linalg.lu(A)
  >>> P
  tensor([[0., 1., 0.],
          [0., 0., 1.],
          [1., 0., 0.]])
  >>> L
  tensor([[1.0000, 0.0000],
          [0.5007, 1.0000],
          [0.0633, 0.9755]])
  >>> U
  tensor([[0.3771, 0.0489],
          [0.0000, 0.9644]])
  >>> torch.dist(A, P @ L @ U)
  tensor(5.9605e-08)

  >>> A = torch.randn(2, 5, 7, device="cuda")
  >>> P, L, U = torch.linalg.lu(A, pivot=False)
quantize
class torch.quantization.quantize(model, run_fn, run_args, mapping=None, inplace=False)
Quantize the input float model with post training static
   quantization.
First it will prepare the model for calibration, then it calls
   run_fn which will run the calibration step, after that we will
   convert the model to a quantized model.
Parameters:
      * model -- input float model
  * **run_fn** -- a calibration function for calibrating the
    prepared model

  * **run_args** -- positional arguments for *run_fn*

  * **inplace** -- carry out model transformations in-place, the
    original module is mutated

  * **mapping** -- correspondence between original module types
    and quantized counterparts

Returns:
      Quantized model.
torch.log1p
torch.log1p(input, *, out=None) -> Tensor
Returns a new tensor with the natural logarithm of (1 + "input").
  y_i = \log_{e} (x_i + 1)

Note:
 This function is more accurate than "torch.log()" for small
 values of "input"

Parameters:
      input (Tensor) -- the input tensor.
Keyword Arguments:
      out (Tensor, optional) -- the output tensor.
Example:
  >>> a = torch.randn(5)
  >>> a
  tensor([-1.0090, -0.9923,  1.0249, -0.5372,  0.2492])
  >>> torch.log1p(a)
  tensor([    nan, -4.8653,  0.7055, -0.7705,  0.2225])
torch.diagflat
torch.diagflat(input, offset=0) -> Tensor


If "input" is a vector (1-D tensor), then returns a 2-D square
     tensor with the elements of "input" as the diagonal.


If "input" is a tensor with more than one dimension, then returns
     a 2-D tensor with diagonal elements equal to a flattened "input".


The argument "offset" controls which diagonal to consider:


If "offset" = 0, it is the main diagonal.


If "offset" > 0, it is above the main diagonal.


If "offset" < 0, it is below the main diagonal.


Parameters:
      * input (Tensor) -- the input tensor.
  * **offset** (*int**, **optional*) -- the diagonal to consider.
    Default: 0 (main diagonal).

Examples:
  >>> a = torch.randn(3)
  >>> a
  tensor([-0.2956, -0.9068,  0.1695])
  >>> torch.diagflat(a)
  tensor([[-0.2956,  0.0000,  0.0000],
          [ 0.0000, -0.9068,  0.0000],
          [ 0.0000,  0.0000,  0.1695]])
  >>> torch.diagflat(a, 1)
torch.diagflat(a, 1)
      tensor([[ 0.0000, -0.2956,  0.0000,  0.0000],
              [ 0.0000,  0.0000, -0.9068,  0.0000],
              [ 0.0000,  0.0000,  0.0000,  0.1695],
              [ 0.0000,  0.0000,  0.0000,  0.0000]])



  >>> a = torch.randn(2, 2)
  >>> a
  tensor([[ 0.2094, -0.3018],
          [-0.1516,  1.9342]])
  >>> torch.diagflat(a)
  tensor([[ 0.2094,  0.0000,  0.0000,  0.0000],
          [ 0.0000, -0.3018,  0.0000,  0.0000],
          [ 0.0000,  0.0000, -0.1516,  0.0000],
          [ 0.0000,  0.0000,  0.0000,  1.9342]])
torch.Tensor.masked_scatter_
Tensor.masked_scatter_(mask, source)
Copies elements from "source" into "self" tensor at positions where
   the "mask" is True. The shape of "mask" must be broadcastable with
   the shape of the underlying tensor. The "source" should have at
   least as many elements as the number of ones in "mask"
Parameters:
      * mask (BoolTensor) -- the boolean mask
  * **source** (*Tensor*) -- the tensor to copy from

Note:
 The "mask" operates on the "self" tensor, not on the given
 "source" tensor.
dual_level
class torch.autograd.forward_ad.dual_level
Context-manager that enables forward AD. All forward AD computation
   must be performed in a "dual_level" context.
Note:
 The "dual_level" context appropriately enters and exit the dual
 level to controls the current forward AD level, which is used by
 default by the other functions in this API.We currently don't
 plan to support nested "dual_level" contexts, however, so only a
 single forward AD level is supported. To compute higher-order
 forward grads, one can use "torch.func.jvp()".

Example:
  >>> x = torch.tensor([1])
  >>> x_t = torch.tensor([1])
  >>> with dual_level():
  ...     inp = make_dual(x, x_t)
  ...     # Do computations with inp
  ...     out = your_fn(inp)
  ...     _, grad = unpack_dual(out)
  >>> grad is None
  False
  >>> # After exiting the level, the grad is deleted
  >>> _, grad_after = unpack_dual(out)
  >>> grad is None
  True
LBFGS
class torch.optim.LBFGS(params, lr=1, max_iter=20, max_eval=None, tolerance_grad=1e-07, tolerance_change=1e-09, history_size=100, line_search_fn=None)
Implements L-BFGS algorithm, heavily inspired by minFunc.
Warning:
 This optimizer doesn't support per-parameter options and
 parameter groups (there can be only one).

Warning:
 Right now all parameters have to be on a single device. This will
 be improved in the future.

Note:
 This is a very memory intensive optimizer (it requires additional
 "param_bytes * (history_size + 1)" bytes). If it doesn't fit in
 memory try reducing the history size, or use a different
 algorithm.

Parameters:
      * lr (float) -- learning rate (default: 1)
  * **max_iter** (*int*) -- maximal number of iterations per
    optimization step (default: 20)

  * **max_eval** (*int*) -- maximal number of function evaluations
    per optimization step (default: max_iter * 1.25).
tolerance_grad (float) -- termination tolerance on first
        order optimality (default: 1e-5).


tolerance_change (float) -- termination tolerance on
    function value/parameter changes (default: 1e-9).


history_size (int) -- update history size (default:
    100).


line_search_fn (str) -- either 'strong_wolfe' or None
    (default: None).




add_param_group(param_group)
  Add a param group to the "Optimizer" s *param_groups*.

  This can be useful when fine tuning a pre-trained network as
  frozen layers can be made trainable and added to the "Optimizer"
  as training progresses.

  Parameters:
     **param_group** (*dict*) -- Specifies what Tensors should be
     optimized along with group specific optimization options.

load_state_dict(state_dict)
  Loads the optimizer state.

  Parameters:
     **state_dict** (*dict*) -- optimizer state. Should be an
object returned from a call to "state_dict()".
register_step_post_hook(hook)
  Register an optimizer step post hook which will be called after
  optimizer step. It should have the following signature:

     hook(optimizer, args, kwargs) -> None

  The "optimizer" argument is the optimizer instance being used.

  Parameters:
     **hook** (*Callable*) -- The user defined hook to be
     registered.

  Returns:
     a handle that can be used to remove the added hook by calling
     "handle.remove()"

  Return type:
     "torch.utils.hooks.RemoveableHandle"

register_step_pre_hook(hook)
  Register an optimizer step pre hook which will be called before
  optimizer step. It should have the following signature:

     hook(optimizer, args, kwargs) -> None or modified args and kwargs

  The "optimizer" argument is the optimizer instance being used.
  If args and kwargs are modified by the pre-hook, then the
transformed values are returned as a tuple containing the
      new_args and new_kwargs.
  Parameters:
     **hook** (*Callable*) -- The user defined hook to be
     registered.

  Returns:
     a handle that can be used to remove the added hook by calling
     "handle.remove()"

  Return type:
     "torch.utils.hooks.RemoveableHandle"

state_dict()
  Returns the state of the optimizer as a "dict".

  It contains two entries:

  * state - a dict holding current optimization state. Its content
       differs between optimizer classes.

  * param_groups - a list containing all parameter groups where
    each
       parameter group is a dict

step(closure)
  Performs a single optimization step.

  Parameters:
     **closure** (*Callable*) -- A closure that reevaluates the
     model and returns the loss.

zero_grad(set_to_none=False)
  Sets the gradients of all optimized "torch.Tensor" s to zero.

  Parameters:
Parameters:
         set_to_none (bool) -- instead of setting to zero, set
         the grads to None. This will in general have lower memory
         footprint, and can modestly improve performance. However, it
         changes certain behaviors. For example: 1. When the user
         tries to access a gradient and perform manual ops on it, a
         None attribute or a Tensor full of 0s will behave
         differently. 2. If the user requests
         "zero_grad(set_to_none=True)" followed by a backward pass,
         ".grad"s are guaranteed to be None for params that did not
         receive a gradient. 3. "torch.optim" optimizers have a
         different behavior if the gradient is 0 or None (in one case
         it does the step with a gradient of 0 and in the other it
         skips the step altogether).
torch.Tensor.type
Tensor.type(dtype=None, non_blocking=False, **kwargs) -> str or Tensor
Returns the type if dtype is not provided, else casts this object
   to the specified type.
If this is already of the correct type, no copy is performed and
   the original object is returned.
Parameters:
      * dtype (dtype or string) -- The desired type
  * **non_blocking** (*bool*) -- If "True", and the source is in
    pinned memory and destination is on the GPU or vice versa, the
    copy is performed asynchronously with respect to the host.
    Otherwise, the argument has no effect.

  * ****kwargs** -- For compatibility, may contain the key "async"
    in place of the "non_blocking" argument. The "async" arg is
    deprecated.
LazyInstanceNorm3d
class torch.nn.LazyInstanceNorm3d(eps=1e-05, momentum=0.1, affine=True, track_running_stats=True, device=None, dtype=None)
A "torch.nn.InstanceNorm3d" module with lazy initialization of the
   "num_features" argument of the "InstanceNorm3d" that is inferred
   from the "input.size(1)". The attributes that will be lazily
   initialized are weight, bias, running_mean and running_var.
Check the "torch.nn.modules.lazy.LazyModuleMixin" for further
   documentation on lazy modules and their limitations.
Parameters:
      * num_features -- C from an expected input of size (N, C, D,
        H, W) or (C, D, H, W)
  * **eps** (*float*) -- a value added to the denominator for
    numerical stability. Default: 1e-5

  * **momentum** (*float*) -- the value used for the running_mean
    and running_var computation. Default: 0.1

  * **affine** (*bool*) -- a boolean value that when set to
"True", this module has learnable affine parameters,
        initialized the same way as done for batch normalization.
        Default: "False".
  * **track_running_stats** (*bool*) -- a boolean value that when
    set to "True", this module tracks the running mean and
    variance, and when set to "False", this module does not track
    such statistics and always uses batch statistics in both
    training and eval modes. Default: "False"

Shape:
      * Input: (N, C, D, H, W) or (C, D, H, W)
  * Output: (N, C, D, H, W) or (C, D, H, W) (same shape as input)

cls_to_become
  alias of "InstanceNorm3d"
ConstantPad2d
class torch.nn.ConstantPad2d(padding, value)
Pads the input tensor boundaries with a constant value.
For N-dimensional padding, use "torch.nn.functional.pad()".
Parameters:
      padding (int, tuple) -- the size of the padding. If is
      int, uses the same padding in all boundaries. If a 4-tuple,
      uses (\text{padding_left}, \text{padding_right},
      \text{padding_top}, \text{padding_bottom})
Shape:
      * Input: (N, C, H_{in}, W_{in}) or (C, H_{in}, W_{in}).
  * Output: (N, C, H_{out}, W_{out}) or (C, H_{out}, W_{out}),
    where

    H_{out} = H_{in} + \text{padding\_top} +
    \text{padding\_bottom}

    W_{out} = W_{in} + \text{padding\_left} +
    \text{padding\_right}

Examples:
  >>> m = nn.ConstantPad2d(2, 3.5)
  >>> input = torch.randn(1, 2, 2)
  >>> input
  tensor([[[ 1.6585,  0.4320],
           [-0.8701, -0.4649]]])
  >>> m(input)
m(input)
      tensor([[[ 3.5000,  3.5000,  3.5000,  3.5000,  3.5000,  3.5000],
               [ 3.5000,  3.5000,  3.5000,  3.5000,  3.5000,  3.5000],
               [ 3.5000,  3.5000,  1.6585,  0.4320,  3.5000,  3.5000],
               [ 3.5000,  3.5000, -0.8701, -0.4649,  3.5000,  3.5000],
               [ 3.5000,  3.5000,  3.5000,  3.5000,  3.5000,  3.5000],
               [ 3.5000,  3.5000,  3.5000,  3.5000,  3.5000,  3.5000]]])
      >>> # using different paddings for different sides
      >>> m = nn.ConstantPad2d((3, 0, 2, 1), 3.5)
      >>> m(input)
      tensor([[[ 3.5000,  3.5000,  3.5000,  3.5000,  3.5000],
               [ 3.5000,  3.5000,  3.5000,  3.5000,  3.5000],
               [ 3.5000,  3.5000,  3.5000,  1.6585,  0.4320],
               [ 3.5000,  3.5000,  3.5000, -0.8701, -0.4649],
               [ 3.5000,  3.5000,  3.5000,  3.5000,  3.5000]]])
GRUCell
class torch.nn.GRUCell(input_size, hidden_size, bias=True, device=None, dtype=None)
A gated recurrent unit (GRU) cell
  \begin{array}{ll} r = \sigma(W_{ir} x + b_{ir} + W_{hr} h +
  b_{hr}) \\ z = \sigma(W_{iz} x + b_{iz} + W_{hz} h + b_{hz}) \\
  n = \tanh(W_{in} x + b_{in} + r * (W_{hn} h + b_{hn})) \\ h' =
  (1 - z) * n + z * h \end{array}

where \sigma is the sigmoid function, and * is the Hadamard
   product.
Parameters:
      * input_size (int) -- The number of expected features in
        the input x
  * **hidden_size** (*int*) -- The number of features in the
    hidden state *h*

  * **bias** (*bool*) -- If "False", then the layer does not use
    bias weights *b_ih* and *b_hh*. Default: "True"

Inputs: input, hidden
      * input : tensor containing input features
  * **hidden** : tensor containing the initial hidden state for
    each element in the batch. Defaults to zero if not provided.

Outputs: h'
Outputs: h'
      * h' : tensor containing the next hidden state for each
        element in the batch
Shape:
      * input: (N, H_{in}) or (H_{in}) tensor containing input
        features where H_{in} = input_size.
  * hidden: (N, H_{out}) or (H_{out}) tensor containing the
    initial hidden state where H_{out} = *hidden_size*. Defaults
    to zero if not provided.

  * output: (N, H_{out}) or (H_{out}) tensor containing the next
    hidden state.

Variables:
      * weight_ih (torch.Tensor) -- the learnable input-hidden
        weights, of shape (3hidden_size, input_size)*
  * **weight_hh** (*torch.Tensor*) -- the learnable hidden-hidden
    weights, of shape *(3*hidden_size, hidden_size)*

  * **bias_ih** -- the learnable input-hidden bias, of shape
    *(3*hidden_size)*

  * **bias_hh** -- the learnable hidden-hidden bias, of shape
    *(3*hidden_size)*

Note:
 All the weights and biases are initialized from
\mathcal{U}(-\sqrt{k}, \sqrt{k}) where k =
     \frac{1}{\text{hidden_size}}
On certain ROCm devices, when using float16 inputs this module will
   use different precision for backward.
Examples:
  >>> rnn = nn.GRUCell(10, 20)
  >>> input = torch.randn(6, 3, 10)
  >>> hx = torch.randn(3, 20)
  >>> output = []
  >>> for i in range(6):
  ...     hx = rnn(input[i], hx)
  ...     output.append(hx)
torch.fft.ifftshift
torch.fft.ifftshift(input, dim=None) -> Tensor
Inverse of "fftshift()".
Parameters:
      * input (Tensor) -- the tensor in FFT order
  * **dim** (*int**, **Tuple**[**int**]**, **optional*) -- The
    dimensions to rearrange. Only dimensions specified here will
    be rearranged, any other dimensions will be left in their
    original order. Default: All dimensions of "input".

-[ Example ]-



f = torch.fft.fftfreq(5)
f
   tensor([ 0.0000,  0.2000,  0.4000, -0.4000, -0.2000])



A round-trip through "fftshift()" and "ifftshift()" gives the same
   result:



shifted = torch.fft.fftshift(f)
torch.fft.ifftshift(shifted)
   tensor([ 0.0000,  0.2000,  0.4000, -0.4000, -0.2000])
torch.Tensor.repeat
Tensor.repeat(*sizes) -> Tensor
Repeats this tensor along the specified dimensions.
Unlike "expand()", this function copies the tensor's data.
Warning:
 "repeat()" behaves differently from numpy.repeat, but is more
 similar to numpy.tile. For the operator similar to
 *numpy.repeat*, see "torch.repeat_interleave()".

Parameters:
      sizes (torch.Size or int...) -- The number of times
      to repeat this tensor along each dimension
Example:
  >>> x = torch.tensor([1, 2, 3])
  >>> x.repeat(4, 2)
  tensor([[ 1,  2,  3,  1,  2,  3],
          [ 1,  2,  3,  1,  2,  3],
          [ 1,  2,  3,  1,  2,  3],
          [ 1,  2,  3,  1,  2,  3]])
  >>> x.repeat(4, 2, 1).size()
  torch.Size([4, 2, 3])
torch.func.jacrev
torch.func.jacrev(func, argnums=0, *, has_aux=False, chunk_size=None, _preallocate_and_copy=False)
Computes the Jacobian of "func" with respect to the arg(s) at index
   "argnum" using reverse mode autodiff
Note:
 Using "chunk_size=1" is equivalent to computing the jacobian row-
 by-row with a for-loop i.e. the constraints of "vmap()" are not
 applicable.

Parameters:
      * func (function) -- A Python function that takes one or
        more arguments, one of which must be a Tensor, and returns one
        or more Tensors
  * **argnums** (*int** or **Tuple**[**int**]*) -- Optional,
    integer or tuple of integers, saying which arguments to get
    the Jacobian with respect to. Default: 0.

  * **has_aux** (*bool*) -- Flag indicating that "func" returns a
    "(output, aux)" tuple where the first element is the output of
    the function to be differentiated and the second element is
auxiliary objects that will not be differentiated. Default:
        False.
  * **chunk_size** (*None** or **int*) -- If None (default), use
    the maximum chunk size (equivalent to doing a single vmap over
    vjp to compute the jacobian). If 1, then compute the jacobian
    row-by-row with a for-loop. If not None, then compute the
    jacobian "chunk_size" rows at a time (equivalent to doing
    multiple vmap over vjp). If you run into memory issues
    computing the jacobian, please try to specify a non-None
    chunk_size.

Returns:
      Returns a function that takes in the same inputs as "func" and
      returns the Jacobian of "func" with respect to the arg(s) at
      "argnums". If "has_aux is True", then the returned function
      instead returns a "(jacobian, aux)" tuple where "jacobian" is
      the Jacobian and "aux" is auxiliary objects returned by "func".
A basic usage with a pointwise, unary operation will give a
   diagonal array as the Jacobian
diagonal array as the Jacobian



from torch.func import jacrev
x = torch.randn(5)
jacobian = jacrev(torch.sin)(x)
expected = torch.diag(torch.cos(x))
assert torch.allclose(jacobian, expected)



If you would like to compute the output of the function as well as
   the jacobian of the function, use the "has_aux" flag to return the
   output as an auxiliary object:



from torch.func import jacrev
x = torch.randn(5)
def f(x):
  return x.sin()
def g(x):
  result = f(x)
  return result, result
jacobian_f, f_x = jacrev(g, has_aux=True)(x)
assert torch.allclose(f_x, f(x))



"jacrev()" can be composed with vmap to produce batched Jacobians:



from torch.func import jacrev, vmap
x = torch.randn(64, 5)
jacobian = vmap(jacrev(torch.sin))(x)
assert jacobian.shape == (64, 5, 5)



Additionally, "jacrev()" can be composed with itself to produce
   Hessians
Hessians



from torch.func import jacrev
def f(x):
  return x.sin().sum()
x = torch.randn(5)
hessian = jacrev(jacrev(f))(x)
assert torch.allclose(hessian, torch.diag(-x.sin()))



By default, "jacrev()" computes the Jacobian with respect to the
   first input. However, it can compute the Jacboian with respect to a
   different argument by using "argnums":



from torch.func import jacrev
def f(x, y):
  return x + y ** 2
x, y = torch.randn(5), torch.randn(5)
jacobian = jacrev(f, argnums=1)(x, y)
expected = torch.diag(2 * y)
assert torch.allclose(jacobian, expected)



Additionally, passing a tuple to "argnums" will compute the
   Jacobian with respect to multiple arguments



from torch.func import jacrev
def f(x, y):
  return x + y ** 2
x, y = torch.randn(5), torch.randn(5)
jacobian = jacrev(f, argnums=(0, 1))(x, y)
expectedX = torch.diag(torch.ones_like(x))
expectedX = torch.diag(torch.ones_like(x))
expectedY = torch.diag(2 * y)
assert torch.allclose(jacobian[0], expectedX)
assert torch.allclose(jacobian[1], expectedY)



Note:
 Using PyTorch "torch.no_grad" together with "jacrev". Case 1:
 Using "torch.no_grad" inside a function:

 >>> def f(x):
 >>>     with torch.no_grad():
 >>>         c = x ** 2
 >>>     return x - c

 In this case, "jacrev(f)(x)" will respect the inner
 "torch.no_grad".Case 2: Using "jacrev" inside "torch.no_grad"
 context manager:

 >>> with torch.no_grad():
 >>>     jacrev(f)(x)

 In this case, "jacrev" will respect the inner "torch.no_grad",
 but not the outer one. This is because "jacrev" is a "function
 transform": its result should not depend on the result of a
 context manager outside of "f".
Conv2d
class torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros', device=None, dtype=None)
Applies a 2D convolution over an input signal composed of several
   input planes.
In the simplest case, the output value of the layer with input size
   (N, C_{\text{in}}, H, W) and output (N, C_{\text{out}},
   H_{\text{out}}, W_{\text{out}}) can be precisely described as:
  \text{out}(N_i, C_{\text{out}_j}) =
  \text{bias}(C_{\text{out}_j}) + \sum_{k = 0}^{C_{\text{in}} - 1}
  \text{weight}(C_{\text{out}_j}, k) \star \text{input}(N_i, k)

where \star is the valid 2D cross-correlation operator, N is a
   batch size, C denotes a number of channels, H is a height of input
   planes in pixels, and W is width in pixels.
This module supports TensorFloat32.
On certain ROCm devices, when using float16 inputs this module will
   use different precision for backward.