|
- # -*- coding: utf-8 -*-
- # MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
- #
- # Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
- #
- # Unless required by applicable law or agreed to in writing,
- # software distributed under the License is distributed on an
- # "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # pylint: disable=unused-argument,invalid-name,redefined-builtin,arguments-out-of-order
- import numpy as np
-
- from ..core._imperative_rt.core2 import SymbolVar, apply
- from ..core.ops import builtin
- from ..core.ops.builtin import Elemwise
- from ..core.tensor.array_method import _elwise
- from ..core.tensor.utils import convert_inputs
- from ..tensor import Tensor
- from ..utils.deprecation import deprecated_func
-
- __all__ = [
- "abs",
- "add",
- "acos",
- "asin",
- "atan",
- "atan2",
- "asinh",
- "acosh",
- "atanh",
- "ceil",
- "clip",
- "cos",
- "cosh",
- "div",
- "equal",
- "exp",
- "expm1",
- "floor",
- "floor_div",
- "greater",
- "greater_equal",
- "left_shift",
- "less",
- "less_equal",
- "log",
- "log1p",
- "logical_and",
- "logical_not",
- "logical_or",
- "logical_xor",
- "logaddexp",
- "maximum",
- "minimum",
- "mod",
- "mul",
- "neg",
- "not_equal",
- "pow",
- "right_shift",
- "round",
- "sin",
- "sinh",
- "sqrt",
- "square",
- "sub",
- "tan",
- "tanh",
- ]
-
-
- def _elemwise_multi_type(*args, mode, **kwargs):
- op = builtin.ElemwiseMultiType(mode=mode, **kwargs)
- args = convert_inputs(*args)
- (result,) = apply(op, *args)
- return result
-
-
- # math operations
-
-
- def add(x, y):
- r"""Element-wise `addition`.
-
- Examples:
-
- .. testcode::
-
- import numpy as np
- from megengine import tensor
- import megengine.functional as F
-
- x = tensor(np.arange(0, 6, dtype=np.float32).reshape(2, 3))
- y = tensor(np.arange(0, 6, dtype=np.float32).reshape(2, 3))
- out = F.add(x, y)
- print(out.numpy())
-
- Outputs:
-
- .. testoutput::
-
- [[ 0. 2. 4.]
- [ 6. 8. 10.]]
- """
- return _elwise(x, y, mode=Elemwise.Mode.ADD)
-
-
- def sub(x, y):
- r"""Element-wise `sub`.
-
- Examples:
-
- .. testcode::
-
- import numpy as np
- from megengine import tensor
- import megengine.functional as F
-
- x = tensor(np.arange(1, 7, dtype=np.float32).reshape(2, 3))
- y = tensor(np.arange(0, 6, dtype=np.float32).reshape(2, 3))
- out = F.sub(x, y)
- print(out.numpy())
-
- Outputs:
-
- .. testoutput::
-
- [[1. 1. 1.]
- [1. 1. 1.]]
-
- """
- return _elwise(x, y, mode=Elemwise.Mode.SUB)
-
-
- def mul(x: Tensor, y: Tensor) -> Tensor:
- r"""Calculates the product for each element :math:`x_i` of the input tensor `x` with the respective element :math:`y_i` of the input tensor `y`.
-
- Note:
- * If either :math:`x_i` or :math:`y_i` is `NaN`, the result is `NaN`.
- * If :math:`x_i` is either `+infinity` or `-infinity` and :math:`y_i` is either `+0` or `-0`, the result is `NaN`.
- * If :math:`x_i` is either `+0` or `-0` and :math:`y_i` is either `+infinity` or `-infinity`, the result is `NaN`.
- * If :math:`x_i` and :math:`y_i` have different mathematical signs, the result has a negative mathematical sign, unless the result is `NaN`.
- * If :math:`x_i` is either `+infinity` or `-infinity` and :math:`y_i` is either `+infinity` or `-infinity`,
- the result is a signed infinity with the mathematical sign determined by the rule already stated above.
- * If :math:`x_i` is either `+infinity` or `-infinity` and :math:`y_i` is a nonzero finite number,
- the result is a signed infinity with the mathematical sign determined by the rule already stated above.
- * If :math:`x_i` is a nonzero finite number and :math:`y_i` is either `+infinity` or `-infinity`,
- the result is a signed infinity with the mathematical sign determined by the rule already stated above.
- * In the remaining cases, where neither `infinity` nor `NaN` is involved,
- the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode.
- If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign.
- If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign.
- * Floating-point multiplication is not always associative due to finite precision.
-
- Args:
- x: first input tensor. Should have a numeric data type.
- y: second input tensor. Must be compatible with `x` (see :ref:`broadcasting-rule` ). Should have a numeric data type.
-
- Returns:
- A tensor containing the element-wise products. The returned array must have a data type determined by :ref:`dtype-promotion`.
-
- Examples:
-
- >>> F.mul(2, 3)
- Tensor(6, dtype=int32, device=xpux:0)
-
- >>> F.mul(2.0, 3.0)
- Tensor(6.0, device=xpux:0)
-
- >>> x = F.arange(6.0).reshape(2, 3)
- >>> y = F.arange(3.0)
- >>> F.mul(x, y)
- Tensor([[ 0. 1. 4.]
- [ 0. 4. 10.]], device=xpux:0)
-
- The `*` operator can be used as a shorthand for :func:`~.functional.mul` on tensors.
-
- >>> x = F.arange(6.0).reshape(2, 3)
- >>> y = F.arange(3.0)
- >>> x * y
- Tensor([[ 0. 1. 4.]
- [ 0. 4. 10.]], device=xpux:0)
-
- """
- return _elwise(x, y, mode=Elemwise.Mode.MUL)
-
-
- def div(x, y):
- r"""Element-wise `(x / y)`."""
- return _elwise(x, y, mode=Elemwise.Mode.TRUE_DIV)
-
-
- def floor_div(x, y):
- r"""Element-wise `floor(x / y)`."""
- return _elwise(x, y, mode=Elemwise.Mode.FLOOR_DIV)
-
-
- def neg(x):
- r"""Element-wise `negation`."""
- return _elwise(x, mode=Elemwise.Mode.NEGATE)
-
-
- def pow(x, y):
- r"""Element-wise `power`."""
- return _elwise(x, y, mode=Elemwise.Mode.POW)
-
-
- def mod(x, y):
- r"""Element-wise `remainder of division`."""
- return _elwise(x, y, mode=Elemwise.Mode.MOD)
-
-
- def abs(x):
- r"""Element-wise `absolute value`."""
- return _elwise(x, mode=Elemwise.Mode.ABS)
-
-
- def exp(x):
- r"""Element-wise `exponential`."""
- return _elwise(x, mode=Elemwise.Mode.EXP)
-
-
- def expm1(x):
- r"""Element-wise `exp(x)-1`."""
- return _elwise(x, mode=Elemwise.Mode.EXPM1)
-
-
- def log(x):
- r"""Element-wise `logarithm (base e)`."""
- return _elwise(x, mode=Elemwise.Mode.LOG)
-
-
- def log1p(x):
- r"""Element-wise `log(x+1) (base e)`."""
- return _elwise(x, mode=Elemwise.Mode.LOG1P)
-
-
- def sqrt(x: Tensor) -> Tensor:
- r"""Element-wise `sqrt`.
-
- Examples:
-
- .. testcode::
-
- import numpy as np
- from megengine import tensor
- import megengine.functional as F
-
- x = tensor(np.arange(0, 6, dtype=np.float32).reshape(2, 3))
- out = F.sqrt(x)
- print(out.numpy().round(decimals=4))
-
- Outputs:
-
- .. testoutput::
-
- [[0. 1. 1.4142]
- [1.7321 2. 2.2361]]
- """
- return x ** 0.5
-
-
- def square(x: Tensor) -> Tensor:
- r"""Element-wise `square`.
-
- Examples:
-
- .. testcode::
-
- import numpy as np
- import megengine as mge
- import megengine.functional as F
-
- data = mge.tensor(np.arange(0, 6, dtype=np.float32).reshape(2, 3))
- out = F.square(data)
- print(out.numpy().round(decimals=4))
-
- Outputs:
-
- .. testoutput::
-
- [[ 0. 1. 4.]
- [ 9. 16. 25.]]
- """
- return x ** 2
-
-
- def round(x):
- r"""Element-wise `rounding to int`."""
- return _elwise(x, mode=Elemwise.Mode.ROUND)
-
-
- def ceil(x):
- r"""Element-wise `ceiling`."""
- return _elwise(x, mode=Elemwise.Mode.CEIL)
-
-
- def floor(x):
- r"""Element-wise `floor`."""
- return _elwise(x, mode=Elemwise.Mode.FLOOR)
-
-
- def maximum(x, y):
- r"""Element-wise `maximum of array elements`."""
- return _elwise(x, y, mode=Elemwise.Mode.MAX)
-
-
- def minimum(x, y):
- r"""Element-wise `minimum of array elements`."""
- return _elwise(x, y, mode=Elemwise.Mode.MIN)
-
-
- # trigonometric functions
-
-
- def cos(x):
- r"""Element-wise `cosine`.
-
- Examples:
-
- .. testcode::
-
- import numpy as np
- from megengine import tensor
- import megengine.functional as F
-
- x = tensor(np.arange(0, 6, dtype=np.float32).reshape(2, 3))
- out = F.cos(x)
- print(out.numpy().round(decimals=4))
-
- Outputs:
-
- .. testoutput::
-
- [[ 1. 0.5403 -0.4161]
- [-0.99 -0.6536 0.2837]]
- """
- return _elwise(x, mode=Elemwise.Mode.COS)
-
-
- def sin(x):
- r"""Element-wise `sine`."""
- return _elwise(x, mode=Elemwise.Mode.SIN)
-
-
- def tan(x):
- r"""Element-wise `tangent`."""
- return sin(x) / cos(x)
-
-
- def acos(x):
- r"""Element-wise `inverse cosine`."""
- return _elwise(x, mode=Elemwise.Mode.ACOS)
-
-
- def asin(x):
- r"""Element-wise `inverse sine`."""
- return _elwise(x, mode=Elemwise.Mode.ASIN)
-
-
- def atan(x):
- r"""Element-wise `inverse tangent`."""
- return _elwise(x, 1, mode=Elemwise.Mode.ATAN2)
-
-
- def atan2(y, x):
- r"""Element-wise `2-argument arctangent`."""
- return _elwise(y, x, mode=Elemwise.Mode.ATAN2)
-
-
- def cosh(x):
- r"""Element-wise `hyperbolic cosine`."""
- return 0.5 * (exp(x) + exp(-x))
-
-
- def sinh(x):
- r"""Element-wise `hyperbolic sine`."""
- u = expm1(x)
- return 0.5 * u / (u + 1) * (u + 2)
-
-
- def tanh(x):
- r"""Element-wise `hyperbolic tangent`."""
- return _elwise(x, mode=Elemwise.Mode.TANH)
-
-
- def asinh(x):
- r"""Element-wise `inverse hyperbolic sine`."""
- return log(x + (x ** 2 + 1) ** 0.5)
-
-
- def acosh(x):
- r"""Element-wise `inverse hyperbolic cosine`."""
- return log(x + (x ** 2 - 1) ** 0.5)
-
-
- def atanh(x):
- r"""Element-wise `inverse hyperbolic tangent`."""
- return log1p(2 * x / (1 - x)) / 2
-
-
- # bit-twiddling functions
-
-
- def left_shift(x, y):
- r"""Element-wise `bitwise binary: x << y`.
-
- Examples:
-
- .. testcode::
-
- import numpy as np
- from megengine import tensor
- import megengine.functional as F
-
- x = tensor(np.arange(0, 6, dtype=np.int32).reshape(2, 3))
- out = F.left_shift(x, 2)
- print(out.numpy())
-
- Outputs:
-
- .. testoutput::
-
- [[ 0 4 8]
- [12 16 20]]
-
- """
- return _elwise(x, y, mode=Elemwise.Mode.SHL)
-
-
- def right_shift(x, y):
- r"""Element-wise `bitwise binary: x >> y`."""
- return _elwise(x, y, mode=Elemwise.Mode.SHR)
-
-
- # logical functions
-
-
- def logical_and(x, y):
- r"""Element-wise `logical and: x && y`."""
- return _elwise(x, y, mode=Elemwise.Mode.AND)
-
-
- def logical_not(x):
- r"""Element-wise `logical not: ~x`."""
- return _elwise(x, mode=Elemwise.Mode.NOT)
-
-
- def logical_or(x, y):
- r"""Element-wise `logical or: x || y`."""
- return _elwise(x, y, mode=Elemwise.Mode.OR)
-
-
- def logical_xor(x, y):
- r"""Element-wise `logical xor: x ^ y`."""
- return _elwise(x, y, mode=Elemwise.Mode.XOR)
-
-
- def logaddexp(x: Tensor, y: Tensor) -> Tensor:
- r"""Element-wise `numerically stable log(exp(x) + exp(y)`
- """
- return _elwise(x, y, mode=Elemwise.Mode.LOG_SUM_EXP)
-
-
- # comparison functions
-
-
- def equal(x, y):
- r"""Element-wise `(x == y)`.
-
- Examples:
-
- .. testcode::
-
- import numpy as np
- from megengine import tensor
- import megengine.functional as F
-
- x = tensor(np.arange(0, 6, dtype=np.float32).reshape(2, 3))
- y = tensor(np.arange(0, 6, dtype=np.float32).reshape(2, 3))
- out = F.equal(x, y)
- print(out.numpy())
-
- Outputs:
-
- .. testoutput::
-
- [[1. 1. 1.]
- [1. 1. 1.]]
- """
- return _elwise(x, y, mode=Elemwise.Mode.EQ)
-
-
- def not_equal(x, y):
- r"""Element-wise `(x != y)`."""
- return x != y
-
-
- def less(x, y):
- r"""Element-wise `(x < y)`."""
- return _elwise(x, y, mode=Elemwise.Mode.LT)
-
-
- def less_equal(x, y):
- r"""Element-wise `(x <= y)`."""
- return _elwise(x, y, mode=Elemwise.Mode.LEQ)
-
-
- def greater(x, y):
- r"""Element-wise `(x > y)`."""
- return _elwise(y, x, mode=Elemwise.Mode.LT)
-
-
- def greater_equal(x, y):
- r"""Element-wise `(x >= y)`."""
- return _elwise(y, x, mode=Elemwise.Mode.LEQ)
-
-
- # other functions
-
-
- def clip(x: Tensor, lower=None, upper=None) -> Tensor:
- r"""Clamps all elements in input tensor into the range ``[ lower, upper ]`` and returns
- a resulting tensor:
-
- .. math::
-
- y_i = \begin{cases}
- \text{lower} & \text{if } x_i < \text{lower} \\
- x_i & \text{if } \text{lower} \leq x_i \leq \text{upper} \\
- \text{upper} & \text{if } x_i > \text{upper}
- \end{cases}
-
- Args:
- x: (Tensor): The input tensor.
- lower: (Numberic,optional): lower-bound of the range to be clamped to.
- upper: (Numberic,optional): upper-bound of the range to be clamped to.
-
- Note:
- * If both `lower` and `upper` are None, raises an AssertionError.
- * If `lower` is bigger than `upper`, the result is same as `clip(Tensor(), upper, upper)`.
-
- Returns:
- output clamped tensor. The result must have a data type determined by :ref:`dtype-promotion`.
-
- Examples:
-
- >>> import numpy as np
- >>> x = Tensor([0,1,2,3,4])
- >>> F.clip(x, 2, 4)
- Tensor([2 2 2 3 4], dtype=int32, device=xpux:0)
-
- >>> x = Tensor([0,1,2,3,4])
- >>> F.clip(x, 4, 3)
- Tensor([3 3 3 3 3], dtype=int32, device=xpux:0)
-
- >>> x = F.arange(5)
- >>> F.clip(x, lower=3)
- Tensor([3. 3. 3. 3. 4.], device=xpux:0)
-
- >>> x = F.arange(5, dtype=np.int32)
- >>> F.clip(x, upper=2.1)
- Tensor([0. 1. 2. 2.1 2.1], device=xpux:0)
-
- """
- assert (
- lower is not None or upper is not None
- ), "At least one of 'lower' or 'upper' must not be None"
- if lower is not None:
- if upper is not None:
- return minimum(maximum(x, lower), upper)
- else:
- return maximum(x, lower)
- else:
- return minimum(x, upper)
-
-
- sigmoid = deprecated_func("1.3", "megengine.functional.nn", "sigmoid", True)
- hsigmoid = deprecated_func("1.3", "megengine.functional.nn", "hsigmoid", True)
- relu = deprecated_func("1.3", "megengine.functional.nn", "relu", True)
- relu6 = deprecated_func("1.3", "megengine.functional.nn", "relu6", True)
- hswish = deprecated_func("1.3", "megengine.functional.nn", "hswish", True)
|