diff --git a/python/paddle/__init__.py b/python/paddle/__init__.py index 11a2d07d2096d..842151d83b332 100644 --- a/python/paddle/__init__.py +++ b/python/paddle/__init__.py @@ -71,7 +71,6 @@ Tensor.__qualname__ = 'Tensor' import paddle.distributed.fleet # noqa: F401 - from paddle import ( # noqa: F401 distributed, sysconfig, @@ -113,6 +112,7 @@ create_parameter, to_tensor, diag, + diag_embed, diagflat, eye, linspace, @@ -568,6 +568,7 @@ 'subtract', 'diag', 'diagflat', + 'diag_embed', 'isnan', 'scatter_nd_add', 'unstack', diff --git a/python/paddle/nn/__init__.py b/python/paddle/nn/__init__.py index 1ef27639abd13..db4c9adf3327c 100644 --- a/python/paddle/nn/__init__.py +++ b/python/paddle/nn/__init__.py @@ -164,48 +164,6 @@ from . import initializer # noqa: F401 from . import quant # noqa: F401 -# TODO: remove 'diag_embed', 'remove_weight_norm', 'weight_norm' months later. -from paddle.utils import deprecated - - -@deprecated( - since="2.0.0", - update_to="paddle.nn.functional.diag_embed", - level=1, - reason="diag_embed in paddle.nn will be removed in future", -) -def diag_embed(*args): - ''' - alias name of paddle.nn.functional.diag_embed - ''' - return functional.diag_embed(*args) - - -@deprecated( - since="2.0.0", - update_to="paddle.nn.utils.remove_weight_norm", - level=1, - reason="remove_weight_norm in paddle.nn will be removed in future", -) -def remove_weight_norm(*args): - ''' - alias name of paddle.nn.utils.remove_weight_norm - ''' - return utils.remove_weight_norm(*args) - - -@deprecated( - since="2.0.0", - update_to="paddle.nn.utils.weight_norm", - level=1, - reason="weight_norm in paddle.nn will be removed in future", -) -def weight_norm(*args): - ''' - alias name of paddle.nn.utils.weight_norm - ''' - return utils.weight_norm(*args) - __all__ = [ 'BatchNorm', diff --git a/python/paddle/nn/functional/__init__.py b/python/paddle/nn/functional/__init__.py index 608587becd952..453627b4cf049 100644 --- a/python/paddle/nn/functional/__init__.py +++ b/python/paddle/nn/functional/__init__.py @@ -183,7 +183,6 @@ 'log_softmax', 'glu', 'gumbel_softmax', - 'diag_embed', 'sequence_mask', 'dropout', 'dropout2d', diff --git a/python/paddle/nn/functional/extension.py b/python/paddle/nn/functional/extension.py index 757c9059efdd6..f52a133433120 100644 --- a/python/paddle/nn/functional/extension.py +++ b/python/paddle/nn/functional/extension.py @@ -14,141 +14,26 @@ # TODO: define the extention functions -import numpy as np -from paddle import _C_ops, _legacy_C_ops, in_dynamic_mode +from paddle import _C_ops, _legacy_C_ops, in_dynamic_mode, tensor +from paddle.utils import deprecated -from ...base.data_feeder import ( - check_dtype, - check_type, - check_variable_and_dtype, -) +from ...base.data_feeder import check_type, check_variable_and_dtype from ...base.layer_helper import LayerHelper from ...common_ops_import import Variable from ...framework import convert_np_dtype_to_dtype_, core -from ...tensor.creation import assign __all__ = [] +@deprecated( + since="2.5.2", + update_to="paddle.diag_embed", + level=1, + reason="diag_embed in paddle.nn.functional will be removed in future", +) def diag_embed(input, offset=0, dim1=-2, dim2=-1): - """ - Creates a tensor whose diagonals of certain 2D planes (specified by dim1 and dim2) - are filled by ``input``. By default, a 2D plane formed by the last two dimensions - of the returned tensor will be selected. - - The argument ``offset`` determines which diagonal is generated: - - - 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. - - Args: - input(Tensor|numpy.ndarray): The input tensor. Must be at least 1-dimensional. The input data type should be float32, float64, int32, int64. - offset(int, optional): Which diagonal to consider. Default: 0 (main diagonal). - dim1(int, optional): The first dimension with respect to which to take diagonal. Default: -2. - dim2(int, optional): The second dimension with respect to which to take diagonal. Default: -1. - - Returns: - Tensor, the output data type is the same as input data type. - - Examples: - .. code-block:: python - - >>> import paddle - >>> import paddle.nn.functional as F - - >>> diag_embed_input = paddle.arange(6) - - >>> diag_embed_output1 = F.diag_embed(diag_embed_input) - >>> print(diag_embed_output1) - Tensor(shape=[6, 6], dtype=int64, place=Place(cpu), stop_gradient=True, - [[0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0], - [0, 0, 2, 0, 0, 0], - [0, 0, 0, 3, 0, 0], - [0, 0, 0, 0, 4, 0], - [0, 0, 0, 0, 0, 5]]) - - >>> diag_embed_output2 = F.diag_embed(diag_embed_input, offset=-1, dim1=0,dim2=1 ) - >>> print(diag_embed_output2) - Tensor(shape=[7, 7], dtype=int64, place=Place(cpu), stop_gradient=True, - [[0, 0, 0, 0, 0, 0, 0], - [0, 0, 0, 0, 0, 0, 0], - [0, 1, 0, 0, 0, 0, 0], - [0, 0, 2, 0, 0, 0, 0], - [0, 0, 0, 3, 0, 0, 0], - [0, 0, 0, 0, 4, 0, 0], - [0, 0, 0, 0, 0, 5, 0]]) - - >>> diag_embed_input_2dim = paddle.reshape(diag_embed_input,[2,3]) - >>> print(diag_embed_input_2dim) - Tensor(shape=[2, 3], dtype=int64, place=Place(cpu), stop_gradient=True, - [[0, 1, 2], - [3, 4, 5]]) - >>> diag_embed_output3 = F.diag_embed(diag_embed_input_2dim,offset= 0, dim1=0, dim2=2 ) - >>> print(diag_embed_output3) - Tensor(shape=[3, 2, 3], dtype=int64, place=Place(cpu), stop_gradient=True, - [[[0, 0, 0], - [3, 0, 0]], - [[0, 1, 0], - [0, 4, 0]], - [[0, 0, 2], - [0, 0, 5]]]) - """ - if not isinstance(input, Variable): - input = assign(input) - - if in_dynamic_mode(): - return _C_ops.diag_embed(input, offset, dim1, dim2) - - inputs = {'Input': [input]} - attrs = {'offset': offset, 'dim1': dim1, 'dim2': dim2} - - def __check_input(input, offset, dim1, dim2): - check_dtype( - input.dtype, - 'Input', - ['int32', 'int64', 'float16', 'float32', 'float64'], - 'diag_embed', - ) - - input_shape = list(input.shape) - assert len(input_shape) >= 1, ( - "Input must be at least 1-dimensional, " - "But received Input's dimensional: %s.\n" % len(input_shape) - ) - - assert np.abs(dim1) <= len(input_shape), ( - "Dim1 is out of range (expected to be in range of [%d, %d], but got %d).\n" - % (-(len(input_shape) + 1), len(input_shape), dim1) - ) - - assert np.abs(dim2) <= len(input_shape), ( - "Dim2 is out of range (expected to be in range of [%d, %d], but got %d).\n" - % (-(len(input_shape) + 1), len(input_shape), dim2) - ) - - dim1_ = dim1 if dim1 >= 0 else len(input_shape) + dim1 + 1 - dim2_ = dim2 if dim2 >= 0 else len(input_shape) + dim2 + 1 - assert dim1_ != dim2_, ( - "dim1 and dim2 cannot be the same dimension." - "But received dim1 = %d, dim2 = %d\n" % (dim1, dim2) - ) - - __check_input(input, offset, dim1, dim2) - helper = LayerHelper("diag_embed", **locals()) - - out = helper.create_variable_for_type_inference(dtype=input.dtype) - - helper.append_op( - type='diag_embed', - inputs={'Input': [input]}, - attrs={'offset': offset, 'dim1': dim1, 'dim2': dim2}, - outputs={'Out': [out]}, - ) - out.stop_gradient = True - return out + return tensor.diag_embed(input, offset, dim1, dim2) def sequence_mask(x, maxlen=None, dtype='int64', name=None): diff --git a/python/paddle/tensor/__init__.py b/python/paddle/tensor/__init__.py index ce4cfc8ee883b..c8bfe99f91e6b 100644 --- a/python/paddle/tensor/__init__.py +++ b/python/paddle/tensor/__init__.py @@ -24,6 +24,7 @@ from .creation import to_tensor # noqa: F401 from .creation import diag # noqa: F401 from .creation import diagflat # noqa: F401 +from .creation import diag_embed # noqa: F401 from .creation import eye # noqa: F401 from .creation import linspace # noqa: F401 from .creation import fill_constant # noqa: F401 @@ -694,6 +695,7 @@ 'i1e', 'polygamma', 'polygamma_', + 'diag_embed', 'atan2', 'diagflat', 'multinomial', diff --git a/python/paddle/tensor/creation.py b/python/paddle/tensor/creation.py index e4f0ea824e3a4..5e99753516b0b 100644 --- a/python/paddle/tensor/creation.py +++ b/python/paddle/tensor/creation.py @@ -1674,6 +1674,125 @@ def meshgrid(*args, **kwargs): return out +def diag_embed(input, offset=0, dim1=-2, dim2=-1): + """ + Creates a tensor whose diagonals of certain 2D planes (specified by dim1 and dim2) + are filled by ``input``. By default, a 2D plane formed by the last two dimensions + of the returned tensor will be selected. + + The argument ``offset`` determines which diagonal is generated: + + - 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. + + Args: + input(Tensor|numpy.ndarray): The input tensor. Must be at least 1-dimensional. The input data type should be float32, float64, int32, int64. + offset(int, optional): Which diagonal to consider. Default: 0 (main diagonal). + dim1(int, optional): The first dimension with respect to which to take diagonal. Default: -2. + dim2(int, optional): The second dimension with respect to which to take diagonal. Default: -1. + + Returns: + Tensor, the output data type is the same as input data type. + + Examples: + .. code-block:: python + + >>> import paddle + + >>> diag_embed_input = paddle.arange(6) + + >>> diag_embed_output1 = paddle.diag_embed(diag_embed_input) + >>> print(diag_embed_output1) + Tensor(shape=[6, 6], dtype=int64, place=Place(cpu), stop_gradient=True, + [[0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0], + [0, 0, 2, 0, 0, 0], + [0, 0, 0, 3, 0, 0], + [0, 0, 0, 0, 4, 0], + [0, 0, 0, 0, 0, 5]]) + + >>> diag_embed_output2 = paddle.diag_embed(diag_embed_input, offset=-1, dim1=0,dim2=1 ) + >>> print(diag_embed_output2) + Tensor(shape=[7, 7], dtype=int64, place=Place(cpu), stop_gradient=True, + [[0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0], + [0, 1, 0, 0, 0, 0, 0], + [0, 0, 2, 0, 0, 0, 0], + [0, 0, 0, 3, 0, 0, 0], + [0, 0, 0, 0, 4, 0, 0], + [0, 0, 0, 0, 0, 5, 0]]) + + >>> diag_embed_input_2dim = paddle.reshape(diag_embed_input,[2,3]) + >>> print(diag_embed_input_2dim) + Tensor(shape=[2, 3], dtype=int64, place=Place(cpu), stop_gradient=True, + [[0, 1, 2], + [3, 4, 5]]) + >>> diag_embed_output3 = paddle.diag_embed(diag_embed_input_2dim,offset= 0, dim1=0, dim2=2 ) + >>> print(diag_embed_output3) + Tensor(shape=[3, 2, 3], dtype=int64, place=Place(cpu), stop_gradient=True, + [[[0, 0, 0], + [3, 0, 0]], + [[0, 1, 0], + [0, 4, 0]], + [[0, 0, 2], + [0, 0, 5]]]) + """ + if not isinstance(input, Variable): + input = assign(input) + + if in_dynamic_mode(): + return _C_ops.diag_embed(input, offset, dim1, dim2) + + inputs = {'Input': [input]} + attrs = {'offset': offset, 'dim1': dim1, 'dim2': dim2} + + def __check_input(input, offset, dim1, dim2): + check_dtype( + input.dtype, + 'Input', + ['int32', 'int64', 'float16', 'float32', 'float64'], + 'diag_embed', + ) + + input_shape = list(input.shape) + assert len(input_shape) >= 1, ( + "Input must be at least 1-dimensional, " + "But received Input's dimensional: %s.\n" % len(input_shape) + ) + + assert np.abs(dim1) <= len(input_shape), ( + "Dim1 is out of range (expected to be in range of [%d, %d], but got %d).\n" + % (-(len(input_shape) + 1), len(input_shape), dim1) + ) + + assert np.abs(dim2) <= len(input_shape), ( + "Dim2 is out of range (expected to be in range of [%d, %d], but got %d).\n" + % (-(len(input_shape) + 1), len(input_shape), dim2) + ) + + dim1_ = dim1 if dim1 >= 0 else len(input_shape) + dim1 + 1 + dim2_ = dim2 if dim2 >= 0 else len(input_shape) + dim2 + 1 + assert dim1_ != dim2_, ( + "dim1 and dim2 cannot be the same dimension." + "But received dim1 = %d, dim2 = %d\n" % (dim1, dim2) + ) + + __check_input(input, offset, dim1, dim2) + helper = LayerHelper("diag_embed", **locals()) + + out = helper.create_variable_for_type_inference(dtype=input.dtype) + + helper.append_op( + type='diag_embed', + inputs={'Input': [input]}, + attrs={'offset': offset, 'dim1': dim1, 'dim2': dim2}, + outputs={'Out': [out]}, + ) + out.stop_gradient = True + return out + + def diagflat(x, offset=0, name=None): """ If ``x`` is a vector (1-D tensor), a 2-D square tensor with the elements of ``x`` as the diagonal is returned. diff --git a/test/legacy_test/test_diag_embed.py b/test/legacy_test/test_diag_embed.py index 2f3869713f0e3..ab2955f9d4405 100644 --- a/test/legacy_test/test_diag_embed.py +++ b/test/legacy_test/test_diag_embed.py @@ -12,13 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +import inspect import unittest import numpy as np from op_test import OpTest, paddle_static_guard import paddle -import paddle.nn.functional as F from paddle import base from paddle.base import core @@ -26,7 +26,7 @@ class TestDiagEmbedOp(OpTest): def setUp(self): self.op_type = "diag_embed" - self.python_api = F.diag_embed + self.python_api = paddle.diag_embed self.init_config() self.outputs = {'Out': self.target} @@ -57,8 +57,8 @@ def test_case1(self): data1 = paddle.static.data( name='data1', shape=[2, 3, 4], dtype='float32' ) - out1 = F.diag_embed(data1) - out2 = F.diag_embed(data1, offset=1, dim1=-2, dim2=3) + out1 = paddle.diag_embed(data1) + out2 = paddle.diag_embed(data1, offset=1, dim1=-2, dim2=3) place = core.CPUPlace() exe = base.Executor(place) @@ -77,6 +77,11 @@ def test_case1(self): np.testing.assert_allclose(results[0], target1, rtol=1e-05) np.testing.assert_allclose(results[1], target2, rtol=1e-05) + def test_tensor_method(self): + paddle.disable_static() + x = paddle.arange(15).reshape((3, 5)).astype('float64') + self.assertTrue(inspect.ismethod(x.diag_embed)) + if __name__ == "__main__": unittest.main() diff --git a/test/legacy_test/test_pca_lowrank.py b/test/legacy_test/test_pca_lowrank.py index 107c76b442af9..68f0005b36823 100644 --- a/test/legacy_test/test_pca_lowrank.py +++ b/test/legacy_test/test_pca_lowrank.py @@ -62,9 +62,7 @@ def run_subtest( self.assertEqual(v.shape[-1], guess_rank) self.assertEqual(v.shape[-2], columns) - A1 = u.matmul(paddle.nn.functional.diag_embed(s)).matmul( - self.transpose(v) - ) + A1 = u.matmul(paddle.diag_embed(s)).matmul(self.transpose(v)) ones_m1 = paddle.ones(batches + (rows, 1), dtype=a.dtype) c = a.sum(axis=-2) / rows c = c.reshape(batches + (1, columns)) diff --git a/test/legacy_test/test_tensor_fill_diagonal_tensor.py b/test/legacy_test/test_tensor_fill_diagonal_tensor.py index 7409cdae1f007..cf3493d603976 100644 --- a/test/legacy_test/test_tensor_fill_diagonal_tensor.py +++ b/test/legacy_test/test_tensor_fill_diagonal_tensor.py @@ -17,7 +17,6 @@ import numpy as np import paddle -import paddle.nn.functional as F from paddle import base @@ -202,9 +201,9 @@ def test_largedim(self): loss.backward() expected_pred = v - 2 - expected_pred = F.diag_embed(expected_pred) + 2 + expected_pred = paddle.diag_embed(expected_pred) + 2 expected_grad = paddle.ones(v.shape, dtype=dtype) - 2 - expected_grad = F.diag_embed(expected_grad) + 1 + expected_grad = paddle.diag_embed(expected_grad) + 1 self.assertEqual((ny == expected_pred).all(), True) self.assertEqual((y.grad == expected_grad).all(), True) diff --git a/test/legacy_test/test_tensor_fill_diagonal_tensor_.py b/test/legacy_test/test_tensor_fill_diagonal_tensor_.py index 482f3e542f6fc..7966470e4e8fb 100644 --- a/test/legacy_test/test_tensor_fill_diagonal_tensor_.py +++ b/test/legacy_test/test_tensor_fill_diagonal_tensor_.py @@ -17,7 +17,6 @@ import numpy as np import paddle -import paddle.nn.functional as F from paddle import base @@ -203,9 +202,9 @@ def test_largedim(self): loss.backward() expected_pred = v - 2 - expected_pred = F.diag_embed(expected_pred) + 2 + expected_pred = paddle.diag_embed(expected_pred) + 2 expected_grad = paddle.ones(v.shape, dtype=dtype) - 2 - expected_grad = F.diag_embed(expected_grad) + 1 + expected_grad = paddle.diag_embed(expected_grad) + 1 self.assertEqual((y == expected_pred).all(), True) self.assertEqual((y.grad == expected_grad).all(), True)