# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. # # 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 unittest import numpy as np from op_test import ( OpTest, convert_float_to_uint16, get_device_place, is_custom_device, ) from utils import static_guard import paddle from paddle import _C_ops, base from paddle.base import core from paddle.base.framework import in_dygraph_mode # hack method for test p_norm final state def p_norm_python_api( x, p=2.0, axis=-1, epsilon=1e-12, keepdim=False, as_vector=False ): if in_dygraph_mode(): return _C_ops.p_norm(x, p, axis, epsilon, keepdim, as_vector) def norm_public_python_api( x, p=2.0, axis=-1, epsilon=1e-12, keepdim=False, as_vector=False ): return paddle.linalg.norm( x, p, axis, keepdim, ) def np_linalg_vector_norm(x, axis, porder, keepdims=False): x_shape = list(x.shape) origin_axis = axis if origin_axis is None: pass elif isinstance(origin_axis, int): origin_axis = [origin_axis] else: origin_axis = list(origin_axis) if axis is None: x = x.ravel() axis = -1 if not isinstance(axis, int) and len(axis) > 1: for i in range(len(axis)): if axis[i] < 0: axis[i] += len(x.shape) tmp_axis = [] for i in range(len(axis)): tmp_axis.append(-1 - i) x = np.moveaxis(x, axis, tmp_axis) front_dim = x.shape[0 : len(x.shape) - len(axis)] back_dim = 1 for i in range(len(x.shape) - len(axis), len(x.shape)): back_dim = back_dim * x.shape[i] front_dim = list(front_dim) front_dim.append(back_dim) x = x.reshape(front_dim) axis = -1 if isinstance(axis, list): axis = tuple(axis) r = np.linalg.norm(x, ord=porder, axis=axis, keepdims=keepdims) r_shape = r.shape if keepdims: if origin_axis is None: r_shape = np.ones_like(x_shape) elif len(origin_axis) > 1: r_shape = x_shape for i in origin_axis: r_shape[i] = 1 r = r.reshape(r_shape) return r def np_linalg_matrix_norm(x, axis, porder, keepdims=False): axis = tuple(axis) r = np.linalg.norm(x, ord=porder, axis=axis, keepdims=keepdims) return r def np_linalg_norm(x, axis, porder, keepdims=False): r = [] if axis is None or isinstance(axis, (int, float)): r = np_linalg_vector_norm(x, axis, porder, keepdims) elif isinstance(axis, list) and len(axis) == 2: r = np_linalg_matrix_norm(x, axis, porder, keepdims) r = r.astype(x.dtype) return r def numpy_frobenius_norm(x, axis=None, keepdims=False): if isinstance(axis, list): axis = tuple(axis) if axis is None: axis = (-2, -1) r = np.linalg.norm(x, ord='fro', axis=axis, keepdims=keepdims).astype( x.dtype ) return r def numpy_nuclear_norm(x, axis=None, keepdims=False): if isinstance(axis, list): axis = tuple(axis) r = np.linalg.norm(x, ord='nuc', axis=axis, keepdims=keepdims).astype( x.dtype ) return r def frobenius_norm(x, dim, keep_dim): return paddle.linalg.norm(x, p='fro', axis=dim, keepdim=keep_dim) def nuclear_norm(x, dim, keep_dim): return paddle.linalg.norm(x, p='nuc', axis=dim, keepdim=keep_dim) class TestFrobeniusNormOp(OpTest): def setUp(self): self.python_api = frobenius_norm self.op_type = "frobenius_norm" self.init_test_case() self.init_dtype() x = (np.random.random(self.shape) + 1.0).astype(self.dtype) norm = numpy_frobenius_norm(x, self.axis, self.keepdim) self.reduce_all = False self.inputs = {'X': x} self.attrs = { 'dim': list(self.axis), 'keep_dim': self.keepdim, 'reduce_all': self.reduce_all, } self.outputs = {'Out': norm} def test_check_output(self): self.check_output(check_pir=True) def test_check_grad(self): self.check_grad(['X'], 'Out', check_pir=True) def init_test_case(self): self.shape = [2, 3, 4, 5] self.axis = (1, 2) self.keepdim = False def init_dtype(self): self.dtype = "float64" class TestFrobeniusNormOp2(TestFrobeniusNormOp): def init_test_case(self): self.shape = [5, 5, 5] self.axis = (0, 1) self.keepdim = True def init_dtype(self): self.dtype = "float32" def test_check_grad(self): self.check_grad(['X'], 'Out', check_pir=True) class TestFrobeniusNormOp3(TestFrobeniusNormOp): def init_test_case(self): self.shape = [5, 5, 5] self.axis = (0, 1) self.keepdim = True def init_dtype(self): self.dtype = "complex64" def test_check_grad(self): self.check_grad(['X'], 'Out', check_pir=True) class TestFrobeniusNormOp4(TestFrobeniusNormOp): def init_test_case(self): self.shape = [5, 5, 5, 2] self.axis = (0, 1) self.keepdim = True def init_dtype(self): self.dtype = "complex128" def test_check_grad(self): self.check_grad(['X'], 'Out', check_pir=True) class TestFrobeniusNormOpZeroSize(TestFrobeniusNormOp): def init_test_case(self): self.shape = [0, 20, 3] self.axis = (1, 2) self.keepdim = False def init_dtype(self): self.dtype = "float32" def test_check_output(self): places = ( [paddle.CPUPlace(), get_device_place()] if (core.is_compiled_with_cuda() or is_custom_device()) else [paddle.CPUPlace()] ) for place in places: self.check_output_with_place(place) def test_check_grad(self): pass class TestFrobeniusNormOpZeroSize2(TestFrobeniusNormOpZeroSize): def init_test_case(self): self.shape = [3, 0, 3] self.axis = (1, 2) self.keepdim = False class TestFrobeniusNormOpZeroSize3(TestFrobeniusNormOpZeroSize): def init_test_case(self): self.shape = [0, 20, 3] self.axis = (0, 2) self.keepdim = False class TestFrobeniusNormOpZeroSize4(TestFrobeniusNormOpZeroSize): def init_test_case(self): self.shape = [0, 20, 3] self.axis = (0, -1) self.keepdim = False class TestPnormOp(OpTest): def setUp(self): self.op_type = "p_norm" self.python_api = p_norm_python_api self.public_python_api = norm_public_python_api self.prim_op_type = "comp" self.init_test_case() self.init_dtype() self.fw_comp_atol = 1e-6 self.fw_comp_rtol = 1e-6 self.rev_comp_atol = 1e-6 self.rev_comp_rtol = 1e-6 x = (np.random.random(self.shape) + 0.5).astype(self.dtype) norm = np_linalg_norm(x, self.axis, self.porder, self.keepdim) self.inputs = {'X': x} self.attrs = { 'epsilon': self.epsilon, 'axis': self.axis, 'keepdim': self.keepdim, 'porder': float(self.porder), 'asvector': self.asvector, } self.outputs = {'Out': norm} self.gradient = self.calc_gradient() def test_check_output(self): self.check_output(check_prim_pir=True) def test_check_grad(self): self.check_grad(['X'], 'Out', check_prim_pir=True) def init_test_case(self): self.shape = [2, 3, 4, 5] self.axis = 1 self.epsilon = 1e-12 self.porder = 2.0 self.keepdim = False self.asvector = False def init_dtype(self): self.dtype = "float64" def calc_gradient(self): self.attrs = { 'epsilon': self.epsilon, 'axis': self.axis, 'keepdim': self.keepdim, 'porder': float(self.porder), 'asvector': self.asvector, } x = self.inputs["X"] porder = self.attrs["porder"] axis = self.attrs["axis"] asvector = self.attrs["asvector"] x_dtype = x.dtype x = x.astype(np.float32) if x.dtype == np.float16 else x if porder == 0: grad = np.zeros(x.shape).astype(x.dtype) elif porder in [float("inf"), float("-inf")]: norm = np_linalg_norm(x, axis=axis, porder=porder, keepdims=True) x_abs = np.abs(x) grad = np.sign(x) grad[x_abs != norm] = 0.0 else: norm = np_linalg_norm(x, axis=axis, porder=porder, keepdims=True) grad = ( np.power(norm, 1 - porder) * np.power(np.abs(x), porder - 1) * np.sign(x) ) numel = 1 for s in x.shape: numel *= s divisor = numel if asvector else x.shape[axis] numel /= divisor return [grad.astype(x_dtype) * 1 / numel] class TestPnormOp2(TestPnormOp): def init_test_case(self): self.shape = [3, 20, 3] self.axis = 2 self.epsilon = 1e-12 self.porder = 2.0 self.keepdim = True self.asvector = False def init_dtype(self): self.dtype = "float32" def test_check_grad(self): self.check_grad(['X'], 'Out', check_prim_pir=True) class TestPnormOp3(TestPnormOp): def init_test_case(self): self.shape = [3, 20, 3] self.axis = 2 self.epsilon = 1e-12 self.porder = np.inf self.keepdim = True self.asvector = False def init_dtype(self): self.dtype = "float32" def test_check_grad(self): self.check_grad( ['X'], 'Out', user_defined_grads=self.gradient, check_prim_pir=True ) class TestPnormOp4(TestPnormOp): def init_test_case(self): self.shape = [3, 20, 3] self.axis = 2 self.epsilon = 1e-12 self.porder = -np.inf self.keepdim = True self.asvector = False def init_dtype(self): self.dtype = "float32" def test_check_grad(self): self.check_grad( ['X'], 'Out', user_defined_grads=self.gradient, check_prim_pir=True ) class TestPnormOp5(TestPnormOp): def init_test_case(self): self.shape = [3, 20, 3] self.axis = 2 self.epsilon = 1e-12 self.porder = 0 self.keepdim = True self.asvector = False def init_dtype(self): self.dtype = "float32" def test_check_grad(self): self.check_grad(['X'], 'Out', user_defined_grads=self.gradient) class TestPnormOp6(TestPnormOp): def init_test_case(self): self.shape = [3, 20, 3] self.axis = -1 self.epsilon = 1e-12 self.porder = 2 self.keepdim = False self.asvector = False def init_dtype(self): self.dtype = "float32" def test_check_grad(self): self.check_grad( ['X'], 'Out', user_defined_grads=self.gradient, check_prim_pir=True ) class TestPnormOpZeroSize(TestPnormOp): def init_test_case(self): self.shape = [0, 20, 3] self.axis = 1 self.epsilon = 1e-12 self.porder = 2 self.keepdim = False self.asvector = False def init_dtype(self): self.dtype = "float32" def test_check_output(self): places = ( [paddle.CPUPlace(), get_device_place()] if (core.is_compiled_with_cuda() or is_custom_device()) else [paddle.CPUPlace()] ) for place in places: self.check_output_with_place(place) def test_check_grad(self): pass def calc_gradient(self): pass class TestPnormOpZeroSize2(TestPnormOpZeroSize): def init_test_case(self): self.shape = [3, 0, 3] self.axis = 1 self.epsilon = 1e-12 self.porder = 2 self.keepdim = False self.asvector = False class TestPnormOpZeroSize3(TestPnormOpZeroSize): def init_test_case(self): self.shape = [0, 20, 3] self.axis = 2 self.epsilon = 1e-12 self.porder = 2 self.keepdim = False self.asvector = False class TestPnormOpZeroSize4(TestPnormOpZeroSize): def init_test_case(self): self.shape = [0, 20, 3] self.axis = -1 self.epsilon = 1e-12 self.porder = 2 self.keepdim = False self.asvector = False def create_test_fp16_class(parent, max_relative_error=2e-3): @unittest.skipIf( not (core.is_compiled_with_cuda() or is_custom_device()), "core is not compiled with CUDA", ) class TestPnormFP16Op(parent): def init_dtype(self): self.dtype = "float16" def test_check_output(self): place = get_device_place() if core.is_float16_supported(place): self.check_output_with_place(place) def test_check_grad(self): place = get_device_place() if core.is_float16_supported(place): self.check_grad_with_place( place, ['X'], 'Out', user_defined_grads=self.gradient, max_relative_error=max_relative_error, ) cls_name = "{}_{}".format(parent.__name__, "Fp16") TestPnormFP16Op.__name__ = cls_name globals()[cls_name] = TestPnormFP16Op create_test_fp16_class(TestPnormOp) create_test_fp16_class(TestPnormOp2) create_test_fp16_class(TestPnormOp3) create_test_fp16_class(TestPnormOp4) create_test_fp16_class(TestPnormOp5) create_test_fp16_class(TestPnormOp6) @unittest.skipIf( not (core.is_compiled_with_cuda() or is_custom_device()), "core is not compiled with CUDA", ) class TestPnormBF16Op(OpTest): def setUp(self): self.op_type = "p_norm" self.prim_op_type = "comp" self.python_api = p_norm_python_api self.public_python_api = norm_public_python_api self.init_test_case() self.x = (np.random.random(self.shape) + 0.5).astype(np.float32) self.norm = np_linalg_norm(self.x, self.axis, self.porder, self.keepdim) self.gradient = self.calc_gradient() self.inputs = {'X': convert_float_to_uint16(self.x)} self.attrs = { 'epsilon': self.epsilon, 'axis': self.axis, 'keepdim': self.keepdim, 'porder': float(self.porder), 'asvector': self.asvector, } self.outputs = {'Out': convert_float_to_uint16(self.norm)} def test_check_output(self): place = get_device_place() self.check_output_with_place(place, atol=1e-3, check_prim_pir=True) def test_check_grad(self): place = get_device_place() self.check_grad_with_place( place, ['X'], 'Out', user_defined_grads=self.gradient, check_prim_pir=True, ) def init_test_case(self): self.shape = [2, 3, 4, 5] self.axis = 1 self.epsilon = 1e-12 self.porder = 2.0 self.keepdim = False self.asvector = False def init_dtype(self): self.dtype = np.uint16 def calc_gradient(self): self.attrs = { 'epsilon': self.epsilon, 'axis': self.axis, 'keepdim': self.keepdim, 'porder': float(self.porder), 'asvector': self.asvector, } x = self.x porder = self.attrs["porder"] axis = self.attrs["axis"] asvector = self.attrs["asvector"] x_dtype = x.dtype x = x.astype(np.float32) if x.dtype == np.float16 else x if porder == 0: grad = np.zeros(x.shape).astype(x.dtype) elif porder in [float("inf"), float("-inf")]: norm = np_linalg_norm(x, axis=axis, porder=porder, keepdims=True) x_abs = np.abs(x) grad = np.sign(x) grad[x_abs != norm] = 0.0 else: norm = np_linalg_norm(x, axis=axis, porder=porder, keepdims=True) grad = ( np.power(norm, 1 - porder) * np.power(np.abs(x), porder - 1) * np.sign(x) ) numel = 1 for s in x.shape: numel *= s divisor = numel if asvector else x.shape[axis] numel /= divisor return [grad.astype(x_dtype) * 1 / numel] def check_fro_static(self, p, axis, shape_x, dtype, keep_dim, check_dim=False): with base.program_guard(base.Program()): data = paddle.static.data(name="X", shape=shape_x, dtype=dtype) out = paddle.norm(x=data, p=p, axis=axis, keepdim=keep_dim) place = base.CPUPlace() exe = base.Executor(place) np_input = (np.random.rand(*shape_x) + 1.0).astype(dtype) expected_result = numpy_frobenius_norm( np_input, axis=axis, keepdims=keep_dim ) (result,) = exe.run(feed={"X": np_input}, fetch_list=[out]) np.testing.assert_allclose(result, expected_result, rtol=1e-6, atol=1e-8) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) def check_fro_dygraph(self, p, axis, shape_x, dtype, keep_dim, check_dim=False): x_numpy = (np.random.random(shape_x) + 1.0).astype(dtype) expected_result = numpy_frobenius_norm(x_numpy, axis, keep_dim) x_paddle = paddle.to_tensor(x_numpy) result = paddle.norm(x=x_paddle, p=p, axis=axis, keepdim=keep_dim) result = result.numpy() np.testing.assert_allclose(result, expected_result, rtol=1e-6, atol=1e-8) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) def check_nuc_static(self, p, axis, shape_x, dtype, keep_dim, check_dim=False): with base.program_guard(base.Program()): data = paddle.static.data(name="X", shape=shape_x, dtype=dtype) out = paddle.norm(x=data, p=p, axis=axis, keepdim=keep_dim) place = base.CPUPlace() exe = base.Executor(place) np_input = (np.random.rand(*shape_x) + 1.0).astype(dtype) expected_result = numpy_nuclear_norm( np_input, axis=axis, keepdims=keep_dim ) (result,) = exe.run(feed={"X": np_input}, fetch_list=[out]) np.testing.assert_allclose(result, expected_result, rtol=1e-6, atol=1e-8) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) def check_nuc_dygraph(self, p, axis, shape_x, dtype, keep_dim, check_dim=False): x_numpy = (np.random.random(shape_x) + 1.0).astype(dtype) expected_result = numpy_nuclear_norm(x_numpy, axis, keep_dim) x_paddle = paddle.to_tensor(x_numpy) result = paddle.norm(x=x_paddle, p=p, axis=axis, keepdim=keep_dim) result = result.numpy() np.testing.assert_allclose(result, expected_result, rtol=1e-6, atol=1e-8) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) def check_linalg_norm_static( self, p, axis, shape_x, dtype, keep_dim, check_dim=False ): with base.program_guard(base.Program()): data = paddle.static.data(name="X", shape=shape_x, dtype=dtype) out = paddle.norm(x=data, p=p, axis=axis, keepdim=keep_dim) place = base.CPUPlace() exe = base.Executor(place) np_input = (np.random.rand(*shape_x) + 1.0).astype(dtype) expected_result = np_linalg_norm( np_input, porder=p, axis=axis, keepdims=keep_dim ).astype(dtype) (result,) = exe.run(feed={"X": np_input}, fetch_list=[out]) np.testing.assert_allclose(result, expected_result, rtol=1e-6, atol=1e-8) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) def check_linalg_norm_dygraph( self, p, axis, shape_x, dtype, keep_dim, check_dim=False ): x_numpy = (np.random.random(shape_x) + 1.0).astype(dtype) expected_result = np_linalg_norm( x_numpy, porder=p, axis=axis, keepdims=keep_dim ) x_paddle = paddle.to_tensor(x_numpy) result = paddle.linalg.norm(x=x_paddle, p=p, axis=axis, keepdim=keep_dim) result = result.numpy() np.testing.assert_allclose(result, expected_result, rtol=1e-6, atol=1e-8) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) def check_linalg_matrix_static( self, p, axis, shape_x, dtype, keep_dim, check_dim=False ): with base.program_guard(base.Program()): data = paddle.static.data(name="X", shape=shape_x, dtype=dtype) out = paddle.linalg.matrix_norm( x=data, p=p, axis=axis, keepdim=keep_dim ) place = base.CPUPlace() exe = base.Executor(place) np_input = (np.random.rand(*shape_x) + 1.0).astype(dtype) expected_result = np_linalg_matrix_norm( np_input, porder=p, axis=axis, keepdims=keep_dim ).astype(dtype) (result,) = exe.run(feed={"X": np_input}, fetch_list=[out]) np.testing.assert_allclose(result, expected_result, rtol=1e-6, atol=1e-8) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) def check_linalg_matrix_dygraph( self, p, axis, shape_x, dtype, keep_dim, check_dim=False ): x_numpy = (np.random.random(shape_x) + 1.0).astype(dtype) expected_result = np_linalg_matrix_norm( x_numpy, porder=p, axis=axis, keepdims=keep_dim ) x_paddle = paddle.to_tensor(x_numpy) result = paddle.linalg.matrix_norm( x=x_paddle, p=p, axis=axis, keepdim=keep_dim ) result = result.numpy() np.testing.assert_allclose(result, expected_result, rtol=1e-6, atol=1e-8) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) def check_linalg_vector_static( self, p, axis, shape_x, dtype, keep_dim, check_dim=False ): with base.program_guard(base.Program()): data = paddle.static.data(name="X", shape=shape_x, dtype=dtype) out = paddle.linalg.vector_norm( x=data, p=p, axis=axis, keepdim=keep_dim ) place = base.CPUPlace() exe = base.Executor(place) np_input = np.array(np.random.rand(*shape_x) + 1.0).astype(dtype) expected_result = np_linalg_vector_norm( np_input, porder=p, axis=axis, keepdims=keep_dim ).astype(dtype) (result,) = exe.run(feed={"X": np_input}, fetch_list=[out]) np.testing.assert_allclose(result, expected_result, rtol=1e-6, atol=1e-8) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) def check_linalg_vector_dygraph( self, p, axis, shape_x, dtype, keep_dim, check_dim=False ): x_numpy = np.array(np.random.random(shape_x) + 1.0).astype(dtype) expected_result = np_linalg_vector_norm( x_numpy, porder=p, axis=axis, keepdims=keep_dim ) x_paddle = paddle.to_tensor(x_numpy) result = paddle.linalg.vector_norm( x=x_paddle, p=p, axis=axis, keepdim=keep_dim ) result = result.numpy() np.testing.assert_allclose(result, expected_result, rtol=1e-6, atol=1e-8) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) class NormTestForNUCAndDtype(unittest.TestCase): def test_nuc_and_dtype(self): x = np.random.randn(10, 20).astype("float32") res_numpy = np.linalg.norm(x, ord='nuc') res_paddle = paddle.tensor(x).norm(p="nuc") np.testing.assert_allclose( res_numpy, res_paddle.numpy(), rtol=1e-6, atol=1e-6 ) res_numpy = np.linalg.norm(x.astype("float64"), ord="nuc") res_paddle = paddle.tensor(x).norm(p="nuc", dtype="float64") np.testing.assert_allclose( res_numpy, res_paddle.numpy(), rtol=1e-6, atol=1e-6 ) self.assertEqual(res_paddle.dtype, paddle.float64) def test_with_out(self): # matrix x = np.random.randn(10, 20).astype("float32") res_numpy = np.linalg.norm(x, ord='nuc') res_out = paddle.zeros(res_numpy.shape, dtype="float32") res_paddle = paddle.tensor(x).norm(p='nuc', out=res_out) np.testing.assert_allclose( res_numpy, res_out.numpy(), rtol=1e-6, atol=1e-6 ) np.testing.assert_allclose( res_out.numpy(), res_paddle.numpy(), rtol=1e-6, atol=1e-6 ) res_numpy = np.linalg.norm(x, ord=2, axis=(0, 1)) res_out = paddle.zeros(res_numpy.shape, dtype="float32") res_paddle = paddle.tensor(x).norm(p=2, axis=[0, 1], out=res_out) np.testing.assert_allclose( res_out.numpy(), res_paddle.numpy(), rtol=1e-6, atol=1e-6 ) np.testing.assert_allclose( res_numpy, res_out.numpy(), rtol=1e-5, atol=1e-6 ) # vector x = np.random.randn(10).astype("float32") res_numpy = np.linalg.norm(x, ord=2, axis=0) res_out = paddle.zeros(res_numpy.shape, dtype="float32") res_paddle = paddle.tensor(x).norm(p='fro', axis=0, out=res_out) np.testing.assert_allclose( res_numpy, res_out.numpy(), rtol=1e-6, atol=1e-6 ) np.testing.assert_allclose( res_out.numpy(), res_paddle.numpy(), rtol=1e-6, atol=1e-6 ) res_numpy = np.linalg.norm(x, ord=2, axis=0) res_out = paddle.zeros(res_numpy.shape, dtype="float32") res_paddle = paddle.tensor(x).norm(p=2, axis=0, out=res_out) np.testing.assert_allclose( res_numpy, res_out.numpy(), rtol=1e-6, atol=1e-6 ) np.testing.assert_allclose( res_out.numpy(), res_paddle.numpy(), rtol=1e-6, atol=1e-6 ) class TestVectorNormDtypeAndOut(unittest.TestCase): def test_alias_dtype_and_out(self): x = np.random.randn(10).astype("float16") dtype = "float32" except_numpy = np_linalg_vector_norm(x.astype(dtype), porder=2, axis=0) out_res = paddle.zeros(except_numpy.shape, dtype="float32") res = paddle.linalg.vector_norm( paddle.tensor(x), p=2, axis=0, dtype=dtype, out=out_res ) res_alias = paddle.linalg.vector_norm( paddle.tensor(x), ord=2, dim=0, dtype=dtype, out=out_res ) np.testing.assert_allclose( except_numpy, res.numpy(), rtol=1e-6, atol=1e-6 ) np.testing.assert_allclose( except_numpy, out_res.numpy(), rtol=1e-6, atol=1e-6 ) np.testing.assert_allclose( except_numpy, res_alias.numpy(), rtol=1e-6, atol=1e-6 ) self.assertEqual(res.dtype, res_alias.dtype) self.assertEqual(res.dtype, out_res.dtype) self.assertEqual(res.dtype, paddle.float32) class API_NormTest(unittest.TestCase): def test_basic(self): with static_guard(): keep_dims = {False, True} for keep in keep_dims: check_fro_static( self, p='fro', axis=[-2, -1], shape_x=[2, 3, 4], dtype="float32", keep_dim=keep, ) check_fro_static( self, p='fro', axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_nuc_static( self, p='nuc', axis=[0, 1], shape_x=[2, 3, 4], dtype='float64', keep_dim=keep, check_dim=True, ) check_linalg_norm_static( self, p=2, axis=None, shape_x=[3, 4], dtype="float32", keep_dim=keep, ) check_linalg_norm_static( self, p=2, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_static( self, p=np.inf, axis=0, shape_x=[2, 3, 4], dtype="float32", keep_dim=keep, check_dim=True, ) check_linalg_norm_static( self, p=np.inf, axis=None, shape_x=[2, 3, 4], dtype="float32", keep_dim=keep, ) check_linalg_norm_static( self, p=-np.inf, axis=0, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_static( self, p=-np.inf, axis=None, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, ) check_linalg_norm_static( self, p=0, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_static( self, p=1, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_static( self, p=0, axis=None, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_static( self, p=2, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_static( self, p=2, axis=-1, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_static( self, p=1, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_static( self, p=np.inf, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_static( self, p=-np.inf, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=2, axis=None, shape_x=[3, 4], dtype="float32", keep_dim=keep, ) check_linalg_vector_static( self, p=4, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=np.inf, axis=0, shape_x=[2, 3, 4], dtype="float32", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=np.inf, axis=None, shape_x=[2, 3, 4], dtype="float32", keep_dim=keep, ) check_linalg_vector_static( self, p=-np.inf, axis=0, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=-np.inf, axis=None, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, ) check_linalg_vector_static( self, p=0, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=1, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=0, axis=None, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=2, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=2, axis=-1, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=1, axis=[0, 1], shape_x=[2, 3, 4, 5], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=np.inf, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=-np.inf, axis=[0, 1, 2], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=2, axis=None, shape_x=[], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=np.inf, axis=None, shape_x=[], dtype="complex64", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=-np.inf, axis=[0, 1, 2, 3], shape_x=[1, 14, 5, 14], dtype="complex128", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=np.inf, axis=2, shape_x=[1, 14, 5, 14], dtype="complex128", keep_dim=keep, check_dim=True, ) check_linalg_vector_static( self, p=0, axis=[1, 3], shape_x=[1, 14, 5, 14], dtype="complex128", keep_dim=keep, check_dim=True, ) check_linalg_matrix_static( self, p=-np.inf, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_static( self, p='fro', axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_static( self, p='nuc', axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_static( self, p=-2, axis=[1, 2], shape_x=[2, 3, 4, 5], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_static( self, p=-np.inf, axis=[-2, -1], shape_x=[0, 1, 2, 1], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_static( self, p="fro", axis=[-2, -1], shape_x=[0, 1, 2, 1], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_static( self, p="fro", axis=[-2, -1], shape_x=[3, 2, 1], dtype="complex64", keep_dim=keep, ) check_linalg_matrix_static( self, p="fro", axis=[-2, -1], shape_x=[3, 2, 1], dtype="complex128", keep_dim=keep, ) def test_dygraph(self): paddle.disable_static() keep_dims = {False, True} for keep in keep_dims: check_fro_dygraph( self, p='fro', axis=[0, 1], shape_x=[2, 3, 4], dtype='float64', keep_dim=keep, check_dim=True, ) check_fro_dygraph( self, p='fro', axis=[1, 2], shape_x=[2, 3, 4, 5], dtype='float64', keep_dim=keep, check_dim=True, ) check_nuc_dygraph( self, p='nuc', axis=[0, 1], shape_x=[2, 3, 4], dtype='float64', keep_dim=keep, check_dim=True, ) check_nuc_dygraph( self, p='nuc', axis=[1, 2], shape_x=[2, 3, 4, 5], dtype='float64', keep_dim=keep, check_dim=True, ) check_linalg_norm_dygraph( self, p=2, axis=None, shape_x=[3, 4], dtype="float32", keep_dim=keep, ) check_linalg_norm_dygraph( self, p=2, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_dygraph( self, p=np.inf, axis=0, shape_x=[2, 3, 4], dtype="float32", keep_dim=keep, check_dim=True, ) check_linalg_norm_dygraph( self, p=np.inf, axis=None, shape_x=[2, 3, 4], dtype="float32", keep_dim=keep, ) check_linalg_norm_dygraph( self, p=-np.inf, axis=0, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_dygraph( self, p=-np.inf, axis=None, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, ) check_linalg_norm_dygraph( self, p=0, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_dygraph( self, p=1, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_dygraph( self, p=0, axis=None, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_dygraph( self, p=2, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_dygraph( self, p=2, axis=-1, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_dygraph( self, p=1, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_dygraph( self, p=np.inf, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_norm_dygraph( self, p=-np.inf, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=2, axis=None, shape_x=[3, 4], dtype="float32", keep_dim=keep, ) check_linalg_vector_dygraph( self, p=2, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=np.inf, axis=0, shape_x=[2, 3, 4], dtype="float32", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=np.inf, axis=None, shape_x=[2, 3, 4], dtype="float32", keep_dim=keep, ) check_linalg_vector_dygraph( self, p=-np.inf, axis=0, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=-np.inf, axis=None, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, ) check_linalg_vector_dygraph( self, p=0, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=1, axis=1, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=0, axis=None, shape_x=[3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=2, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=2, axis=-1, shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=1, axis=[0, 1], shape_x=[2, 3, 4, 5], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=np.inf, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=-np.inf, axis=[0, 1, 2], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=2, axis=None, shape_x=(), dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=np.inf, axis=None, shape_x=[], dtype="complex64", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=-np.inf, axis=[0, 1, 2, 3], shape_x=[1, 14, 5, 14], dtype="complex128", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=np.inf, axis=2, shape_x=[1, 14, 5, 14], dtype="complex128", keep_dim=keep, check_dim=True, ) check_linalg_vector_dygraph( self, p=0, axis=[1, 3], shape_x=[1, 14, 5, 14], dtype="complex128", keep_dim=keep, check_dim=True, ) check_linalg_matrix_dygraph( self, p=-np.inf, axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_dygraph( self, p='fro', axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_dygraph( self, p='nuc', axis=[0, 1], shape_x=[2, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_dygraph( self, p=-2, axis=[1, 2], shape_x=[2, 3, 4, 5], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_dygraph( self, p=-np.inf, axis=[-2, -1], shape_x=[0, 1, 2, 1], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_dygraph( self, p="fro", axis=[-2, -1], shape_x=[0, 1, 2, 1], dtype="float64", keep_dim=keep, check_dim=True, ) check_linalg_matrix_dygraph( self, p="fro", axis=[-2, -1], shape_x=[3, 2, 1], dtype="complex64", keep_dim=keep, ) check_linalg_matrix_dygraph( self, p="fro", axis=[-2, -1], shape_x=[3, 2, 1], dtype="complex128", keep_dim=keep, ) paddle.enable_static() def test_name(self): if not paddle.framework.use_pir_api(): paddle.enable_static() with base.program_guard(base.Program()): x = paddle.static.data( name="x", shape=[10, 10], dtype="float32" ) y_1 = paddle.norm( x, p='fro', axis=[-2, -1], name='frobenius_name' ) y_2 = paddle.norm(x, p=2, name='pnorm_name') y_3 = paddle.norm(x, p='nuc', axis=[0, 1], name='nuclear_name') y_4 = paddle.norm( x, p=2, axis=[0, 1], name='p_matrix_norm_name' ) self.assertEqual(('frobenius_name' in y_1.name), True) self.assertEqual(('pnorm_name' in y_2.name), True) self.assertEqual(('nuclear_name' in y_3.name), True) self.assertEqual(('p_matrix_norm_name' in y_4.name), True) def test_errors(self): paddle.enable_static() with base.program_guard(base.Program(), base.Program()): def err_dtype(p, shape_x, xdtype, out=None): data = paddle.static.data(shape=shape_x, dtype=xdtype) paddle.norm(data, p=p, out=out) self.assertRaises(TypeError, err_dtype, "fro", [2, 2], "int64") self.assertRaises(ValueError, paddle.norm, "inf", [2], "int64") out = paddle.static.data(name="out", shape=[1], dtype="int64") self.assertRaises( TypeError, err_dtype, "fro", [2, 2], "float64", out ) self.assertRaises(TypeError, err_dtype, 2, [10], "int64") self.assertRaises(TypeError, err_dtype, 2, [10], "float64", out) data = paddle.static.data( name="data_2d", shape=[2, 2], dtype="float64" ) self.assertRaises( ValueError, paddle.norm, data, p="unsupported norm" ) self.assertRaises(ValueError, paddle.norm, data, p=[1]) self.assertRaises(ValueError, paddle.norm, data, p=[1], axis=-1) self.assertRaises(ValueError, paddle.norm, 0, [1, 0], "float64") data = paddle.static.data( name="data_3d", shape=[2, 2, 2], dtype="float64" ) self.assertRaises( ValueError, paddle.norm, data, p='unspport', axis=[-3, -2, -1] ) class API_NormTest_ZeroSize(unittest.TestCase): def check_linalg_norm_dygraph_and_grad( self, p, axis, shape_x, dtype, keep_dim, check_dim=False ): x_numpy = (np.random.random(shape_x) + 1.0).astype(dtype) expected_result = np_linalg_norm( x_numpy, porder=p, axis=axis, keepdims=keep_dim ) x_paddle = paddle.to_tensor(x_numpy) x_paddle.stop_gradient = False result1 = paddle.linalg.norm( x=x_paddle, p=p, axis=axis, keepdim=keep_dim ) result = result1.numpy() np.testing.assert_allclose( result, expected_result, rtol=1e-6, atol=1e-8 ) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) loss = paddle.sum(result1) loss.backward() np.testing.assert_equal(x_paddle.grad.shape, x_paddle.shape) def check_linalg_vector_dygraph_and_grad( self, p, axis, shape_x, dtype, keep_dim, check_dim=False ): x_numpy = np.array(np.random.random(shape_x) + 1.0).astype(dtype) expected_result = np_linalg_vector_norm( x_numpy, porder=p, axis=axis, keepdims=keep_dim ) x_paddle = paddle.to_tensor(x_numpy) x_paddle.stop_gradient = False result1 = paddle.linalg.vector_norm( x=x_paddle, p=p, axis=axis, keepdim=keep_dim ) result = result1.numpy() np.testing.assert_allclose( result, expected_result, rtol=1e-6, atol=1e-8 ) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) loss = paddle.sum(result1) loss.backward() np.testing.assert_equal(x_paddle.grad.shape, x_paddle.shape) def check_linalg_matrix_dygraph_and_grad( self, p, axis, shape_x, dtype, keep_dim, check_dim=False ): x_numpy = (np.random.random(shape_x) + 1.0).astype(dtype) expected_result = np_linalg_matrix_norm( x_numpy, porder=p, axis=axis, keepdims=keep_dim ) x_paddle = paddle.to_tensor(x_numpy) x_paddle.stop_gradient = False result1 = paddle.linalg.matrix_norm( x=x_paddle, p=p, axis=axis, keepdim=keep_dim ) result = result1.numpy() np.testing.assert_allclose( result, expected_result, rtol=1e-6, atol=1e-8 ) if keep_dim and check_dim: np.testing.assert_equal(result.shape, expected_result.shape) loss = paddle.sum(result1) loss.backward() np.testing.assert_equal(x_paddle.grad.shape, x_paddle.shape) def test_dygraph(self): paddle.disable_static() keep_dims = {False, True} for keep in keep_dims: self.check_linalg_norm_dygraph_and_grad( p=1, axis=[0, 1], shape_x=[0, 3, 4], dtype="float64", keep_dim=keep, check_dim=True, ) self.check_linalg_vector_dygraph_and_grad( p=np.inf, axis=[1], shape_x=[0, 3, 4], dtype="float32", keep_dim=keep, ) self.check_linalg_matrix_dygraph_and_grad( p=np.inf, axis=[1, 2], shape_x=[0, 3, 4], dtype="float32", keep_dim=keep, ) class API_PnormGradTest_ZeroSize(unittest.TestCase): """Cover the 0-size early-return branch in p_norm_grad CPU/GPU kernels. The PR adds `if (out_dx->numel() == 0) return;` to both paddle/phi/kernels/cpu/p_norm_grad_kernel.cc and paddle/phi/kernels/gpu/p_norm_grad_kernel.cu. Running backward on a 0-size input exercises that branch for every porder dispatch arm (porder == 0, 1, 2, <1, in (1,2), >2, +/-inf). """ def _run_pnorm_backward(self, shape, axis, porder, dtype="float32"): x_np = (np.random.random(shape) + 1.0).astype(dtype) x = paddle.to_tensor(x_np) x.stop_gradient = False out = paddle.linalg.vector_norm(x=x, p=porder, axis=axis, keepdim=False) loss = paddle.sum(out) loss.backward() # 0-size input -> 0-size grad, with shape preserved. np.testing.assert_equal(x.grad.shape, x.shape) self.assertEqual(x.grad.numel().item(), 0) def test_dygraph_zero_size_grad(self): paddle.disable_static() # Trigger every porder branch in PNormGradKernel so each new # `out_dx->numel() == 0` early-return is exercised. porders = [0.0, 0.5, 1.0, 1.5, 2.0, 3.0, float("inf"), float("-inf")] shape = [0, 3, 4] for axis in [0, 1, -1]: for p in porders: self._run_pnorm_backward(shape, axis, p) class API_NormTest_Alias(unittest.TestCase): def setUp(self): paddle.disable_static() def test_alias(self): """ Test the alias of norm function. ``norm(x=x, axis=1)`` is equivalent to ``norm(input=x, dim=1)`` """ shape_cases = [ [2, 3, 4], [3, 4, 5], ] p_cases = [2, 'fro', 'nuc', np.inf, -np.inf, 1, -1] axis_cases = [None, 1, [0, 1], [-2, -1]] for shape in shape_cases: x = paddle.rand(shape) for p in p_cases: for axis in axis_cases: # Skip invalid combinations if p == 'fro' and (axis is None or isinstance(axis, int)): continue if p == 'nuc' and (axis is None or isinstance(axis, int)): continue # Test x/input alias kwargs1 = {'x': x, 'p': p, 'axis': axis} kwargs2 = {'input': x, 'p': p, 'axis': axis} out1 = paddle.norm(**kwargs1).numpy() out2 = paddle.norm(**kwargs2).numpy() np.testing.assert_allclose(out1, out2, rtol=1e-6, atol=1e-8) # Test axis/dim alias kwargs3 = {'x': x, 'p': p, 'dim': axis} out3 = paddle.norm(**kwargs3).numpy() np.testing.assert_allclose(out1, out3, rtol=1e-6, atol=1e-8) # Test both aliases together kwargs4 = {'input': x, 'p': p, 'dim': axis} out4 = paddle.norm(**kwargs4).numpy() np.testing.assert_allclose(out1, out4, rtol=1e-6, atol=1e-8) def test_static_alias(self): """ Test alias in static mode """ paddle.enable_static() with base.program_guard(base.Program()): x = paddle.static.data(name='x', shape=[2, 3, 4], dtype='float32') # Test x/input alias out1 = paddle.norm(x=x, p=2, axis=1) out2 = paddle.norm(input=x, p=2, axis=1) # Test axis/dim alias out3 = paddle.norm(x=x, p=2, dim=1) out4 = paddle.norm(input=x, p=2, dim=1) place = base.CPUPlace() exe = base.Executor(place) x_np = np.random.random([2, 3, 4]).astype('float32') res1, res2, res3, res4 = exe.run( feed={'x': x_np}, fetch_list=[out1, out2, out3, out4] ) np.testing.assert_allclose(res1, res2, rtol=1e-6, atol=1e-8) np.testing.assert_allclose(res1, res3, rtol=1e-6, atol=1e-8) np.testing.assert_allclose(res1, res4, rtol=1e-6, atol=1e-8) paddle.disable_static() if __name__ == '__main__': paddle.enable_static() unittest.main()