From 3d6e04b2d24b62061363fc2a835749614bf98c37 Mon Sep 17 00:00:00 2001 From: yide12 Date: Wed, 21 Dec 2022 11:56:14 +0800 Subject: [PATCH] func_l1_loss_master --- docs/api/api_python/mindspore.ops.rst | 1 + .../ops/mindspore.ops.func_l1_loss.rst | 36 ++++++++++ docs/api/api_python_en/mindspore.ops.rst | 1 + .../python/mindspore/ops/function/__init__.py | 1 + .../python/mindspore/ops/function/nn_func.py | 61 ++++++++++++++++ tests/st/ops/test_func_l1_loss.py | 71 +++++++++++++++++++ 6 files changed, 171 insertions(+) create mode 100644 docs/api/api_python/ops/mindspore.ops.func_l1_loss.rst create mode 100644 tests/st/ops/test_func_l1_loss.py diff --git a/docs/api/api_python/mindspore.ops.rst b/docs/api/api_python/mindspore.ops.rst index b0b3106142d..3d89a2e1631 100644 --- a/docs/api/api_python/mindspore.ops.rst +++ b/docs/api/api_python/mindspore.ops.rst @@ -66,6 +66,7 @@ mindspore.ops mindspore.ops.cross_entropy mindspore.ops.gaussian_nll_loss mindspore.ops.hinge_embedding_loss + mindspore.ops.l1_loss mindspore.ops.mse_loss mindspore.ops.nll_loss mindspore.ops.smooth_l1_loss diff --git a/docs/api/api_python/ops/mindspore.ops.func_l1_loss.rst b/docs/api/api_python/ops/mindspore.ops.func_l1_loss.rst new file mode 100644 index 00000000000..fd12b6c941b --- /dev/null +++ b/docs/api/api_python/ops/mindspore.ops.func_l1_loss.rst @@ -0,0 +1,36 @@ +mindspore.ops.l1_loss +===================== + +.. py:function:: mindspore.ops.l1_loss(x, target, reduction='mean'): + + l1_loss用于计算预测值和目标值之间的平均绝对误差。 + + 假设 :math:`x` 和 :math:`y` 为一维Tensor,长度 :math:`N` ,`reduction` 设置为"none",则计算 :math:`x` 和 :math:`y` 的loss不进行降维操作。 + + 公式如下: + + .. math:: + \ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad \text{with } l_n = \left| x_n - y_n \right|, + + 其中, :math:`N` 为batch size。 + + 如果 `reduction` 是"mean"或者"sum",则: + + .. math:: + \ell(x, y) = + \begin{cases} + \operatorname{mean}(L), & \text{if reduction} = \text{'mean';}\\ + \operatorname{sum}(L), & \text{if reduction} = \text{'sum'.} + \end{cases} + + 参数: + - **x** (Tensor) - 预测值,任意维度的Tensor。 + - **target** (Tensor) - 目标值,与 `x` 的shape相同。 + - **reduction** (str, optional) - 应用于loss的reduction类型。取值为"mean","sum"或"none"。默认值:"mean"。 + + 返回: + Tensor,l1_loss的结果。 + + 异常: + - **ValueError** - `reduction` 不为"mean"、"sum"或"none"。 + - **ValueError** - `x` 和 `target` 有不同的shape。 diff --git a/docs/api/api_python_en/mindspore.ops.rst b/docs/api/api_python_en/mindspore.ops.rst index a550cc7d418..953850269c8 100644 --- a/docs/api/api_python_en/mindspore.ops.rst +++ b/docs/api/api_python_en/mindspore.ops.rst @@ -67,6 +67,7 @@ Loss Functions mindspore.ops.cross_entropy mindspore.ops.gaussian_nll_loss mindspore.ops.hinge_embedding_loss + mindspore.ops.l1_loss mindspore.ops.mse_loss mindspore.ops.nll_loss mindspore.ops.smooth_l1_loss diff --git a/mindspore/python/mindspore/ops/function/__init__.py b/mindspore/python/mindspore/ops/function/__init__.py index e36a3eb0997..ba4997e4b50 100644 --- a/mindspore/python/mindspore/ops/function/__init__.py +++ b/mindspore/python/mindspore/ops/function/__init__.py @@ -418,6 +418,7 @@ from .nn_func import ( mirror_pad, nll_loss, smooth_l1_loss, + l1_loss, cross_entropy, grid_sample, ctc_greedy_decoder, diff --git a/mindspore/python/mindspore/ops/function/nn_func.py b/mindspore/python/mindspore/ops/function/nn_func.py index d82aac3a8d5..152f640af01 100644 --- a/mindspore/python/mindspore/ops/function/nn_func.py +++ b/mindspore/python/mindspore/ops/function/nn_func.py @@ -2943,6 +2943,66 @@ def _nll_loss(inputs, target, target_dim=-1, weight=None, ignore_index=None, red return loss +def l1_loss(x, target, reduction='mean'): + r""" + l1_loss is used to calculate the mean absolute error between the `x` value and the target value. + + Assuming that the :math:`x` and :math:`y` are 1-D Tensor, length :math:`N`, `reduction` is set to "none" , + then calculate the loss of :math:`x` and :math:`y` without dimensionality reduction. + + The formula is as follows: + + .. math:: + \ell(x, y) = L = \{l_1,\dots,l_N\}^\top, \quad \text{with } l_n = \left| x_n - y_n \right|, + + where :math:`N` is the batch size. + + If `reduction` is "mean" or "sum", then: + + .. math:: + \ell(x, y) = + \begin{cases} + \operatorname{mean}(L), & \text{if reduction} = \text{'mean';}\\ + \operatorname{sum}(L), & \text{if reduction} = \text{'sum'.} + \end{cases} + + Args: + x (Tensor) - Predicted value, Tensor of any dimension. + target (Tensor) - Target value, same shape as the `x` . + reduction (str, optional): Type of reduction to be applied to loss. The optional value is "mean", "sum" or + "none". Default: "mean". + + Returns: + Tensor, the result of l1_loss. + + Raises: + ValueError: If `reduction` is not one of "none", "mean" or "sum". + ValueError: If `x` and `target` have different shapes. + + Supported Platforms: + ``Ascend`` ``GPU`` ``CPU`` + + Examples: + >>> x = ms.Tensor([[1, 2, 3], [4, 5, 6]], ms.float32) + >>> target = ms.Tensor([[6, 5, 4], [3, 2, 1]], ms.float32) + >>> output = ops.l1_loss(x, target, reduction="mean") + >>> print(output) + 3.0 + """ + _check_is_tensor('x', x, "l1_loss") + _check_is_tensor('target', target, "l1_loss") + if reduction not in ('mean', 'sum', 'none'): + raise ValueError(f"For l1_loss, the 'reduction' must be in ['mean', 'sum', 'none'], but got {reduction}.") + if x.shape != target.shape: + raise ValueError(f"For l1_loss, x and target must be the same shape, but got {x.shape} and {target.shape}") + loss = _get_cache_prim(P.Abs)()(x - target) + if reduction == "mean": + loss = _get_cache_prim(P.ReduceMean)()(loss, _get_axis(loss)) + if reduction == "sum": + loss = _get_cache_prim(P.ReduceSum)()(loss, _get_axis(loss)) + return loss + + def smooth_l1_loss(logits, labels, beta=1.0, reduction='none'): r""" Computes smooth L1 loss, a robust L1 loss. @@ -5101,6 +5161,7 @@ __all__ = [ 'cross_entropy', 'grid_sample', 'smooth_l1_loss', + 'l1_loss', 'nll_loss', 'ctc_loss', 'ctc_greedy_decoder', diff --git a/tests/st/ops/test_func_l1_loss.py b/tests/st/ops/test_func_l1_loss.py new file mode 100644 index 00000000000..f1599073a3b --- /dev/null +++ b/tests/st/ops/test_func_l1_loss.py @@ -0,0 +1,71 @@ +# Copyright 2022 Huawei Technologies Co., Ltd +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================ + +import numpy as np +import pytest + +import mindspore as ms +import mindspore.nn as nn +import mindspore.ops as ops + + +class Net(nn.Cell): + def construct(self, x, target): + output0 = ops.l1_loss(x, target, reduction="none") + output1 = ops.l1_loss(x, target, reduction="mean") + output2 = ops.l1_loss(x, target, reduction="sum") + return output0, output1, output2 + + +@pytest.mark.level0 +@pytest.mark.platform_x86_cpu +@pytest.mark.platform_arm_cpu +@pytest.mark.platform_x86_gpu_training +@pytest.mark.platform_arm_ascend_training +@pytest.mark.platform_x86_ascend_training +@pytest.mark.env_onecard +@pytest.mark.parametrize('mode', [ms.GRAPH_MODE, ms.PYNATIVE_MODE]) +def test_l1_loss(mode): + """ + Feature: Test l1_loss + Description: Test the functionality of l1_loss + Expectation: Success + """ + ms.set_context(mode=mode) + net = Net() + x = ms.Tensor([[[1.17273476, -0.05052809, 0.61813106, 0.16455488, -1.35581311], + [1.32487223, 0.13208311, -1.31230669, -0.50771298, 1.32278446], + [-0.04625993, 1.18794348, -1.21238798, 0.01314028, -1.20131357]], + [[-1.4510571, -1.03311918, -1.00915919, 0.6134792, 0.56710962], + [-1.39683892, -0.0932166, -1.06056463, 0.20178101, 0.47950521], + [-1.39548584, -1.70302071, -0.48198836, -0.77789908, 0.87970894]]], ms.float32) + target = ms.Tensor([[[-1.30292448, -0.35515205, 1.48585374, 0.22724189, 0.60810377], + [-1.14444725, 1.90415392, 0.45537515, -1.20027348, 1.81567979], + [0.30801377, -0.79452551, 1.80005659, 0.98829231, 2.07602126]], + [[0.05371826, 0.20575326, 1.3496286, 1.55930587, -0.50407597], + [-1.97812696, -1.38987021, -1.95899861, -1.05986999, 0.02349943], + [0.25305345, 0.42477621, 1.74664105, -0.50482991, -0.24119833]]], ms.float32) + out0, out1, out2 = net(x, target) + expect_out0 = [[[2.47565937e+00, 3.04623961e-01, 8.67722750e-01, 6.26870096e-02, 1.96391690e+00], + [2.46931934e+00, 1.77207088e+00, 1.76768184e+00, 6.92560554e-01, 4.92895365e-01], + [3.54273707e-01, 1.98246896e+00, 3.01244450e+00, 9.75152075e-01, 3.27733469e+00]], + [[1.50477529e+00, 1.23887253e+00, 2.35878778e+00, 9.45826709e-01, 1.07118559e+00], + [5.81288099e-01, 1.29665351e+00, 8.98433924e-01, 1.26165104e+00, 4.56005782e-01], + [1.64853930e+00, 2.12779689e+00, 2.22862935e+00, 2.73069203e-01, 1.12090731e+00]]] + expect_out1 = [1.3827745] + expect_out2 = [41.483234] + assert np.allclose(out0.asnumpy(), expect_out0) + assert np.allclose(out1.asnumpy(), expect_out1) + assert np.allclose(out2.asnumpy(), expect_out2)