From fb57ece7fab4161a2c5331c6199f503a546d2a10 Mon Sep 17 00:00:00 2001 From: liangzelang Date: Wed, 11 May 2022 11:28:52 +0800 Subject: [PATCH] Add tensor&functional interface for TensorScatterSub ops. --- .../api_python/mindspore.ops.functional.rst | 1 + .../api_python/mindspore/mindspore.Tensor.rst | 23 ++++++++ .../ops/mindspore.ops.TensorScatterSub.rst | 20 +------ .../mindspore.ops.func_tensor_scatter_sub.rst | 26 ++++++++++ .../mindspore.ops.functional.rst | 1 + mindspore/ccsrc/pipeline/jit/resource.cc | 1 + .../_extends/parse/standard_method.py | 9 ++++ mindspore/python/mindspore/common/tensor.py | 46 ++++++++++++++++ .../python/mindspore/ops/function/__init__.py | 6 +-- .../mindspore/ops/function/array_func.py | 52 +++++++++++++++++++ mindspore/python/mindspore/ops/functional.py | 2 +- .../mindspore/ops/operations/array_ops.py | 25 +-------- 12 files changed, 166 insertions(+), 46 deletions(-) create mode 100644 docs/api/api_python/ops/mindspore.ops.func_tensor_scatter_sub.rst diff --git a/docs/api/api_python/mindspore.ops.functional.rst b/docs/api/api_python/mindspore.ops.functional.rst index 773f4d754bf..85ca0bdb298 100644 --- a/docs/api/api_python/mindspore.ops.functional.rst +++ b/docs/api/api_python/mindspore.ops.functional.rst @@ -268,6 +268,7 @@ Array操作 mindspore.ops.shape mindspore.ops.size mindspore.ops.tensor_scatter_add + mindspore.ops.tensor_scatter_sub mindspore.ops.tensor_scatter_div mindspore.ops.space_to_batch_nd mindspore.ops.tile diff --git a/docs/api/api_python/mindspore/mindspore.Tensor.rst b/docs/api/api_python/mindspore/mindspore.Tensor.rst index ab577096371..2caca974e5f 100644 --- a/docs/api/api_python/mindspore/mindspore.Tensor.rst +++ b/docs/api/api_python/mindspore/mindspore.Tensor.rst @@ -890,6 +890,29 @@ mindspore.Tensor - **TypeError** - `indices` 的数据类型既不是int32,也不是int64。 - **ValueError** - Tensor的shape长度小于 `indices` 的shape的最后一个维度。 + .. py:method:: tensor_scatter_sub(indices, updates) + + 根据指定的更新值和输入索引,通过减法进行运算,将结果赋值到输出Tensor中。当同一索引有不同值时,更新的结果将是所有值的总和。此操作几乎等同于使用 :class:`mindspore.ops.ScatterNdSub` ,只是更新后的结果是通过算子output返回,而不是直接原地更新input。 + + `indices` 的最后一个轴是每个索引向量的深度。对于每个索引向量, `updates` 中必须有相应的值。`updates` 的shape应该等于 `input_x[indices]` 的shape。有关更多详细信息,请参见使用用例。 + + .. note:: + 如果 `indices` 的某些值超出范围,则相应的 `updates` 不会更新到 `input_x` ,而不是抛出索引错误。 + + **参数:** + + - **indices** (Tensor) - Tensor的索引,数据类型为int32或int64的。其rank必须至少为2。 + - **updates** (Tensor) - 指定与本Tensor相减操作的Tensor,其数据类型与该Tensor相同。updates.shape应等于indices.shape[:-1] + self.shape[indices.shape[-1]:]。 + + **返回:** + + Tensor,shape和数据类型与原Tensor相同。 + + **异常:** + + - **TypeError** - `indices` 的数据类型既不是int32,也不是int64。 + - **ValueError** - Tensor的shape长度小于 `indices` 的shape的最后一个维度。 + .. py:method:: tensor_scatter_div(indices, updates) 根据指定的索引, 通过除法进行计算, 将输出赋值到输出Tensor中。 diff --git a/docs/api/api_python/ops/mindspore.ops.TensorScatterSub.rst b/docs/api/api_python/ops/mindspore.ops.TensorScatterSub.rst index 3a51987d6a8..68ab0d67f67 100644 --- a/docs/api/api_python/ops/mindspore.ops.TensorScatterSub.rst +++ b/docs/api/api_python/ops/mindspore.ops.TensorScatterSub.rst @@ -5,23 +5,5 @@ 根据指定的更新值和输入索引,通过减法运算更新输入Tensor的值。当同一个索引有多个不同值时,更新的结果将分别减去这些值。此操作几乎等同于使用 :class:`mindspore.ops.ScatterNdSub` ,只是更新后的结果是通过算子output返回,而不是直接原地更新input。 - `indices` 的最后一个轴是每个索引向量的深度。对于每个索引向量, `updates` 中必须有相应的值。`updates` 的shape应该等于 `input_x[indices]` 的shape。有关更多详细信息,请参见使用用例。 - - .. note:: - 如果 `indices` 的某些值超出范围,则相应的 `updates` 不会更新为 `input_x` ,而不是抛出索引错误。 - - **输入:** - - - **input_x** (Tensor) - 输入Tensor。 `input_x` 的维度必须不小于indices.shape[-1]。 - - **indices** (Tensor) - 输入Tensor的索引,数据类型为int32或int64的,其rank必须至少为2。 - - **updates** (Tensor) - 指定与 `input_x` 相减操作的Tensor,其数据类型与输入相同。updates.shape应等于indices.shape[:-1] + input_x.shape[indices.shape[-1]:]。 - - **输出:** - - Tensor,shape和数据类型与输入 `input_x` 相同。 - - **异常:** - - - **TypeError** - `indices` 的数据类型既不是int32,也不是int64。 - - **ValueError** - `input_x` 的shape长度小于 `indices` 的shape的最后一个维度。 + 更多参考详见 :func:`mindspore.ops.tensor_scatter_sub`。 \ No newline at end of file diff --git a/docs/api/api_python/ops/mindspore.ops.func_tensor_scatter_sub.rst b/docs/api/api_python/ops/mindspore.ops.func_tensor_scatter_sub.rst new file mode 100644 index 00000000000..0578f901996 --- /dev/null +++ b/docs/api/api_python/ops/mindspore.ops.func_tensor_scatter_sub.rst @@ -0,0 +1,26 @@ +mindspore.ops.tensor_scatter_sub +================================ + +.. py:function:: mindspore.ops.tensor_scatter_sub(input_x, indices, updates) + + 根据指定的更新值和输入索引,通过减法进行运算,将结果赋值到输出Tensor中。当同一索引有不同值时,更新的结果将是所有值的总和。此操作几乎等同于使用 :class:`mindspore.ops.ScatterNdSub` ,只是更新后的结果是通过算子output返回,而不是直接原地更新input。 + + `indices` 的最后一个轴是每个索引向量的深度。对于每个索引向量, `updates` 中必须有相应的值。 `updates` 的shape应该等于 `input_x[indices]` 的shape。有关更多详细信息,请参见使用用例。 + + .. note:: + 如果 `indices` 的某些值超出范围,则相应的 `updates` 不会更新到 `input_x` ,而不是抛出索引错误。 + + **参数:** + + - **input_x** (Tensor) - 输入Tensor。 `input_x` 的维度必须不小于indices.shape[-1]。 + - **indices** (Tensor) - 输入Tensor的索引,数据类型为int32或int64的。其rank必须至少为2。 + - **updates** (Tensor) - 指定与 `input_x` 相减操作的Tensor,其数据类型与输入相同。updates.shape应等于indices.shape[:-1] + input_x.shape[indices.shape[-1]:]。 + + **返回:** + + Tensor,shape和数据类型与输入 `input_x` 相同。 + + **异常:** + + - **TypeError** - `indices` 的数据类型既不是int32,也不是int64。 + - **ValueError** - `input_x` 的shape长度小于 `indices` 的shape的最后一个维度。 \ No newline at end of file diff --git a/docs/api/api_python_en/mindspore.ops.functional.rst b/docs/api/api_python_en/mindspore.ops.functional.rst index 49a02fd5a01..c8e9ec33265 100644 --- a/docs/api/api_python_en/mindspore.ops.functional.rst +++ b/docs/api/api_python_en/mindspore.ops.functional.rst @@ -267,6 +267,7 @@ Array Operation mindspore.ops.shape mindspore.ops.size mindspore.ops.tensor_scatter_add + mindspore.ops.tensor_scatter_sub mindspore.ops.tensor_scatter_div mindspore.ops.space_to_batch_nd mindspore.ops.tile diff --git a/mindspore/ccsrc/pipeline/jit/resource.cc b/mindspore/ccsrc/pipeline/jit/resource.cc index 2e16001b96a..68dabbf260b 100644 --- a/mindspore/ccsrc/pipeline/jit/resource.cc +++ b/mindspore/ccsrc/pipeline/jit/resource.cc @@ -219,6 +219,7 @@ BuiltInTypeMap &GetMethodMap() { {"scatter_nd_add", std::string("scatter_nd_add")}, // scatter_nd_add() {"scatter_nd_sub", std::string("scatter_nd_sub")}, // scatter_nd_sub() {"tensor_scatter_add", std::string("tensor_scatter_add")}, // P.TensorScatterAdd() + {"tensor_scatter_sub", std::string("tensor_scatter_sub")}, // P.TensorScatterSub() {"tensor_scatter_div", std::string("tensor_scatter_div")}, // P.TensorScatterDiv() {"lp_norm", std::string("lp_norm")}, // lp_norm() {"trace", std::string("trace")}, // P.Eye() diff --git a/mindspore/python/mindspore/_extends/parse/standard_method.py b/mindspore/python/mindspore/_extends/parse/standard_method.py index d667653785a..3377b66feb6 100644 --- a/mindspore/python/mindspore/_extends/parse/standard_method.py +++ b/mindspore/python/mindspore/_extends/parse/standard_method.py @@ -1685,6 +1685,15 @@ def tensor_scatter_add(x, indices, updates): return F.tensor_scatter_add(x, indices, updates) +def tensor_scatter_sub(x, indices, updates): + """ + Creates a new tensor by subtracting the values from the positions in `x` indicated by + `indices`, with values from `updates`. When multiple values are given for the same + index, the updated result will be the sum of all values. + """ + return F.tensor_scatter_sub(x, indices, updates) + + def tensor_sactter_div(input_x, indices, updates): """ Create a new tensor by division the values from the positions in `input_x` indicated by diff --git a/mindspore/python/mindspore/common/tensor.py b/mindspore/python/mindspore/common/tensor.py index fbcca055cc6..fa951465a32 100644 --- a/mindspore/python/mindspore/common/tensor.py +++ b/mindspore/python/mindspore/common/tensor.py @@ -1989,6 +1989,52 @@ class Tensor(Tensor_): self._init_check() return tensor_operator_registry.get("tensor_scatter_add")()(self, indices, updates) + def tensor_scatter_sub(self, indices, updates): + """ + Creates a new tensor by subtracting the values from the positions in self tensor indicated by + `indices`, with values from `updates`. When multiple values are provided for the same + index, the result of the update will be to subtract these values respectively. This operation is almost + equivalent to using :class:`mindspore.ops.ScatterNdSub` , except that the updates are applied on output `Tensor` + instead of input `Parameter`. + + The last axis of `indices` is the depth of each index vectors. For each index vector, + there must be a corresponding value in `updates`. The shape of `updates` should be + equal to the shape of `self[indices]`. For more details, see use cases. + + Note: + If some values of the `indices` are out of bound, instead of raising an index error, + the corresponding `updates` will not be updated to `input_x`. + + Args: + indices (Tensor): The index of input tensor whose data type is int32 or int64. + The rank must be at least 2. + updates (Tensor): The tensor to update the input tensor, has the same type as input, + and updates.shape should be equal to indices.shape[:-1] + self.shape[indices.shape[-1]:]. + + Returns: + Tensor, has the same shape and type as self tensor. + + Raises: + TypeError: If dtype of `indices` is neither int32 nor int64. + ValueError: If length of shape of self tensor is less than the last dimension of shape of `indices`. + + Supported Platforms: + ``Ascend`` ``GPU`` ``CPU`` + + Examples: + >>> import numpy as np + >>> from mindspore import Tensor + >>> x = Tensor(np.array([[-0.1, 0.3, 3.6], [0.4, 0.5, -3.2]]).astype('float32')) + >>> indices = Tensor(np.array([[0, 0], [0, 0]]).astype('int32')) + >>> updates = Tensor(np.array([1.0, 2.2]).astype('float32')) + >>> output = x.tensor_scatter_sub(indices, updates) + >>> print(output) + [[-3.3000002 0.3 3.6 ] + [ 0.4 0.5 -3.2 ]] + """ + self._init_check() + return tensor_operator_registry.get('tensor_scatter_sub')()(self, indices, updates) + def fill(self, value): """ Fill the tensor with a scalar value. diff --git a/mindspore/python/mindspore/ops/function/__init__.py b/mindspore/python/mindspore/ops/function/__init__.py index f1773ed5422..ed64f3b0a27 100644 --- a/mindspore/python/mindspore/ops/function/__init__.py +++ b/mindspore/python/mindspore/ops/function/__init__.py @@ -23,9 +23,9 @@ from . import array_func, parameter_func, math_func, nn_func from .array_func import (unique, eye, matrix_band_part, fill, fill_, tile, size, ones, ones_like, shape, shape_, ger, dyn_shape, rank, reshape, reshape_, tensor_slice, slice, scalar_to_array, scalar_to_tensor, tuple_to_array, expand_dims, transpose, scatter_nd, scatter_nd_add, scatter_nd_sub, gather, - gather_d, gather_nd, scalar_cast, - masked_fill, tensor_scatter_add, tensor_scatter_div, scatter_max, scatter_min, nonzero, - space_to_batch_nd, range, select) + gather_d, gather_nd, scalar_cast, masked_fill, tensor_scatter_add, tensor_scatter_sub, + tensor_scatter_div, scatter_max, scatter_min, nonzero, space_to_batch_nd, range, select) + from .parameter_func import assign, assign_add, assign_sub, index_add from .math_func import (addn, absolute, abs, tensor_add, add, neg_tensor, neg, tensor_lt, less, tensor_le, le, lerp, lp_norm, round, tensor_gt, gt, tensor_ge, ge, tensor_sub, sub, tensor_mul, mul, tensor_div, div, diff --git a/mindspore/python/mindspore/ops/function/array_func.py b/mindspore/python/mindspore/ops/function/array_func.py index 2c7f42b1c58..da99f69acdf 100644 --- a/mindspore/python/mindspore/ops/function/array_func.py +++ b/mindspore/python/mindspore/ops/function/array_func.py @@ -1398,6 +1398,57 @@ def tensor_scatter_add(input_x, indices, updates): return tensor_scatter_add_(input_x, indices, updates) +tensor_scatter_sub_ = P.TensorScatterSub() +def tensor_scatter_sub(input_x, indices, updates): + """ + Creates a new tensor by subtracting the values from the positions in `input_x` indicated by + `indices`, with values from `updates`. When multiple values are provided for the same + index, the result of the update will be to subtract these values respectively. This operation is almost + equivalent to using :class:`mindspore.ops.ScatterNdSub` , except that the updates are applied on output `Tensor` + instead of input `Parameter`. + + The last axis of `indices` is the depth of each index vectors. For each index vector, + there must be a corresponding value in `updates`. The shape of `updates` should be + equal to the shape of `input_x[indices]`. For more details, see use cases. + + Note: + If some values of the `indices` are out of bound, instead of raising an index error, + the corresponding `updates` will not be updated to `input_x`. + + Args: + input_x (Tensor): The target tensor. The dimension of input_x must be no less than indices.shape[-1]. + indices (Tensor): The index of input tensor whose data type is int32 or int64. + The rank must be at least 2. + updates (Tensor): The tensor to update the input tensor, has the same type as input, + and updates.shape should be equal to indices.shape[:-1] + input_x.shape[indices.shape[-1]:]. + + Returns: + Tensor, has the same shape and type as `input_x`. + + Raises: + TypeError: If dtype of `indices` is neither int32 nor int64. + ValueError: If length of shape of `input_x` is less than the last dimension of shape of `indices`. + + Supported Platforms: + ``Ascend`` ``GPU`` ``CPU`` + + Examples: + >>> import mindspore + >>> import numpy as np + >>> from mindspore import Tensor + >>> from mindspore import ops + >>> input_x = Tensor(np.array([[-0.1, 0.3, 3.6], [0.4, 0.5, -3.2]]), mindspore.float32) + >>> indices = Tensor(np.array([[0, 0], [0, 0]]), mindspore.int32) + >>> updates = Tensor(np.array([1.0, 2.2]), mindspore.float32) + >>> output = ops.tensor_scatter_sub(input_x, indices, updates) + >>> print(output) + [[-3.3000002 0.3 3.6 ] + [ 0.4 0.5 -3.2 ]] + """ + + return tensor_scatter_sub_(input_x, indices, updates) + + def space_to_batch_nd(input_x, block_size, paddings): r""" Divides a tensor's spatial dimensions into blocks and combines the block sizes with the original batch. @@ -1724,6 +1775,7 @@ __all__ = [ 'scatter_nd_add', 'scatter_nd_sub', 'tensor_scatter_add', + 'tensor_scatter_sub', 'gather', 'gather_d', 'gather_nd', diff --git a/mindspore/python/mindspore/ops/functional.py b/mindspore/python/mindspore/ops/functional.py index 7faf078989f..eb792ed8d16 100644 --- a/mindspore/python/mindspore/ops/functional.py +++ b/mindspore/python/mindspore/ops/functional.py @@ -70,7 +70,6 @@ scatter_update = P.ScatterUpdate() tensor_scatter_update = P.TensorScatterUpdate() tensor_scatter_min = P.TensorScatterMin() tensor_scatter_max = P.TensorScatterMax() -tensor_scatter_sub = P.TensorScatterSub() tensor_scatter_mul = P.TensorScatterMul() scatter_nd_update = P.ScatterNdUpdate() stack = P.Stack() @@ -942,6 +941,7 @@ tensor_operator_registry.register('scatter_nd_add', scatter_nd_add) tensor_operator_registry.register('scatter_nd_sub', scatter_nd_sub) tensor_operator_registry.register('tensor_scatter_update', tensor_scatter_update) tensor_operator_registry.register('tensor_scatter_div', tensor_scatter_div) +tensor_operator_registry.register('tensor_scatter_sub', P.TensorScatterSub) tensor_operator_registry.register('tensor_scatter_add', P.TensorScatterAdd) tensor_operator_registry.register('lp_norm', lp_norm) __all__ = [name for name in dir() if name[0] != "_"] diff --git a/mindspore/python/mindspore/ops/operations/array_ops.py b/mindspore/python/mindspore/ops/operations/array_ops.py index 3d86a3911d3..2982d8b35f9 100755 --- a/mindspore/python/mindspore/ops/operations/array_ops.py +++ b/mindspore/python/mindspore/ops/operations/array_ops.py @@ -6806,31 +6806,10 @@ class TensorScatterSub(_TensorScatterOp): index, the result of the update will be to subtract these values respectively. This operation is almost equivalent to using :class:`mindspore.ops.ScatterNdSub` , except that the updates are applied on output `Tensor` instead of input `Parameter`. - - The last axis of `indices` is the depth of each index vectors. For each index vector, - there must be a corresponding value in `updates`. The shape of `updates` should be - equal to the shape of `input_x[indices]`. For more details, see use cases. - - Note: - If some values of the `indices` are out of bound, instead of raising an index error, - the corresponding `updates` will not be updated to `input_x`. - - Inputs: - - **input_x** (Tensor) - The target tensor. The dimension of input_x must be no less than indices.shape[-1]. - - **indices** (Tensor) - The index of input tensor whose data type is int32 or int64. - The rank must be at least 2. - - **updates** (Tensor) - The tensor to update the input tensor, has the same type as input, - and updates.shape should be equal to indices.shape[:-1] + input_x.shape[indices.shape[-1]:]. - - Outputs: - Tensor, has the same shape and type as `input_x`. - - Raises: - TypeError: If dtype of `indices` is neither int32 nor int64. - ValueError: If length of shape of `input_x` is less than the last dimension of shape of `indices`. + Refer to :func:`mindspore.ops.tensor_scatter_sub` for more detail. Supported Platforms: - ``GPU`` + ``Ascend`` ``GPU`` ``CPU`` Examples: >>> input_x = Tensor(np.array([[-0.1, 0.3, 3.6], [0.4, 0.5, -3.2]]), mindspore.float32)