Skip to content

Commit

Permalink
【不兼容升级】移除paddle.nn.functional.diag_embed,添加paddle.diag_embed并支持作为类方法 (P…
Browse files Browse the repository at this point in the history
…addlePaddle#58223)

* remove_diag_embed_to_creation

* remove_diag_embed_to_creation

* Update __init__.py

* Incompatible upgrade

* fix_bugs

* add_deprecated

* remove diag_embed from __all__
  • Loading branch information
xuxinyi389 authored and jiahy0825 committed Oct 26, 2023
1 parent 734cd84 commit f5fdb34
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 182 deletions.
3 changes: 2 additions & 1 deletion python/paddle/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@
Tensor.__qualname__ = 'Tensor'

import paddle.distributed.fleet # noqa: F401

from paddle import ( # noqa: F401
distributed,
sysconfig,
Expand Down Expand Up @@ -113,6 +112,7 @@
create_parameter,
to_tensor,
diag,
diag_embed,
diagflat,
eye,
linspace,
Expand Down Expand Up @@ -568,6 +568,7 @@
'subtract',
'diag',
'diagflat',
'diag_embed',
'isnan',
'scatter_nd_add',
'unstack',
Expand Down
42 changes: 0 additions & 42 deletions python/paddle/nn/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
1 change: 0 additions & 1 deletion python/paddle/nn/functional/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,6 @@
'log_softmax',
'glu',
'gumbel_softmax',
'diag_embed',
'sequence_mask',
'dropout',
'dropout2d',
Expand Down
135 changes: 10 additions & 125 deletions python/paddle/nn/functional/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
2 changes: 2 additions & 0 deletions python/paddle/tensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -694,6 +695,7 @@
'i1e',
'polygamma',
'polygamma_',
'diag_embed',
'atan2',
'diagflat',
'multinomial',
Expand Down
119 changes: 119 additions & 0 deletions python/paddle/tensor/creation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading

0 comments on commit f5fdb34

Please sign in to comment.