Skip to content

Commit da5005e

Browse files
authored
[API Compatiblity] sink expand_as (#74882)
* expand_as support alias * fix * add check for static * rm python api
1 parent d0a3d14 commit da5005e

File tree

10 files changed

+274
-104
lines changed

10 files changed

+274
-104
lines changed

paddle/fluid/eager/auto_code_generator/generator/python_c_gen.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,11 @@ def FindParsingFunctionFromAttributeType(atype):
9191
' auto& {} = {}("{}", "{}", args, {}, {});\n'
9292
)
9393
PARSE_PYTHON_C_TENSORS_FROM_ARGS_OR_KWARGS_TEMPLATE = ' auto {} = GetTensorFromArgsOrKWArgs("{}", "{}", args, {}, kwargs,{},nargs,&remaining_kwargs,{});\n'
94-
94+
PARSE_PYTHON_C_OPTIONAL_TENSORS_FROM_ARGS_OR_KWARGS_TEMPLATE = ' auto {} = GetOptionalTensorFromArgsOrKWArgs("{}", "{}", args, {}, kwargs,{},nargs,&remaining_kwargs,{});\n'
9595
CONVERT_TO_DISTTENSOR_AND_PARSE_PYTHON_C_TENSORS_TEMPLATE = (
9696
' {} = {}("{}", "{}", args, {}, {}, mesh);\n'
9797
)
98+
CONVERT_TO_DISTTENSOR_AND_PARSE_PYTHON_C_TENSORS_FROM_ARGS_OR_KWARGS_TEMPLATE = ' {} = {}("{}", "{}", args, {}, kwargs,{},nargs,&remaining_kwargs,{},mesh);\n'
9899

99100
CONVERT_INPUT_TENSORS_TO_DIST_TENSOR_WITH_SINGLE_TENSOR_TEMPLATE = """
100101
const phi::distributed::ProcessMesh* mesh = nullptr;
@@ -458,16 +459,27 @@ def _get_keywords(name, alias_map):
458459
)
459460
else:
460461
if is_optional:
461-
get_eager_tensor_str += (
462-
PARSE_PYTHON_C_TENSORS_TEMPLATE.format(
462+
if need_parse_python_api_args:
463+
keywords = _get_keywords(name, args_alias_map)
464+
get_eager_tensor_str += PARSE_PYTHON_C_OPTIONAL_TENSORS_FROM_ARGS_OR_KWARGS_TEMPLATE.format(
463465
name,
464-
"GetOptionalTensorFromArgs",
465466
forward_api_name,
466467
name,
467468
pos,
469+
keywords,
468470
"true",
469471
)
470-
)
472+
else:
473+
get_eager_tensor_str += (
474+
PARSE_PYTHON_C_TENSORS_TEMPLATE.format(
475+
name,
476+
"GetOptionalTensorFromArgs",
477+
forward_api_name,
478+
name,
479+
pos,
480+
"true",
481+
)
482+
)
471483
else:
472484
input_single_tensor_names = (
473485
input_single_tensor_names + ", " + name
@@ -621,14 +633,26 @@ def pre_process_add_ampersand(s):
621633
)
622634
else:
623635
if is_optional:
624-
optional_and_vector_convert_code += CONVERT_TO_DISTTENSOR_AND_PARSE_PYTHON_C_TENSORS_TEMPLATE.format(
625-
name,
626-
"GetOptionalTensorFromArgs",
627-
forward_api_name,
628-
name,
629-
pos,
630-
"true",
631-
)
636+
if need_parse_python_api_args:
637+
keywords = _get_keywords(name, args_alias_map)
638+
optional_and_vector_convert_code += CONVERT_TO_DISTTENSOR_AND_PARSE_PYTHON_C_TENSORS_FROM_ARGS_OR_KWARGS_TEMPLATE.format(
639+
name,
640+
"GetOptionalTensorFromArgsOrKWArgs",
641+
forward_api_name,
642+
name,
643+
pos,
644+
keywords,
645+
"true",
646+
)
647+
else:
648+
optional_and_vector_convert_code += CONVERT_TO_DISTTENSOR_AND_PARSE_PYTHON_C_TENSORS_TEMPLATE.format(
649+
name,
650+
"GetOptionalTensorFromArgs",
651+
forward_api_name,
652+
name,
653+
pos,
654+
"true",
655+
)
632656
if len(input_single_tensor_names) > 0:
633657
convert_to_dist_str += CONVERT_INPUT_TENSORS_TO_DIST_TENSOR_WITH_SINGLE_TENSOR_TEMPLATE.format(
634658
input_names=input_names,

paddle/fluid/pybind/arg_pre_process.cc

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,60 @@
1818
// paddle/fluid/pybind/eager_op_function.cc. Mainly used to customize the
1919
// processing of parameters originally done in the Python API
2020
#include "paddle/fluid/pybind/arg_pre_process.h"
21+
#include "paddle/common/ddim.h"
2122
#include "paddle/fluid/eager/utils.h"
2223
#include "paddle/fluid/pir/dialect/operator/utils/utils.h"
2324
#include "paddle/fluid/pir/utils/general_functions.h"
2425
#include "paddle/fluid/pybind/eager_utils.h"
2526
#include "paddle/fluid/pybind/op_function_common.h"
2627
#include "paddle/phi/common/data_type.h"
2728
#include "paddle/phi/core/enforce.h"
29+
2830
namespace paddle {
2931
namespace pybind {
32+
constexpr char kStopGradientAttrName[] = "stop_gradient"; // NOLINT
33+
void ExpandAsPreProcess(paddle::Tensor* x,
34+
paddle::optional<paddle::Tensor>* y,
35+
std::vector<int64_t>* target_shape) {
36+
if (target_shape->empty() && y->get_ptr() == nullptr) {
37+
PADDLE_THROW(common::errors::InvalidArgument(
38+
"The y of expand_as api must be specified."));
39+
}
40+
if (y->get_ptr() == nullptr) return;
41+
*target_shape = common::vectorize<int64_t>(y->get_ptr()->dims());
42+
}
43+
void ExpandAsPreProcess(pir::Value* x,
44+
paddle::optional<pir::Value>* y,
45+
std::vector<int64_t>* target_shape) {
46+
if (target_shape->empty() && y->get_ptr() == nullptr) {
47+
PADDLE_THROW(common::errors::InvalidArgument(
48+
"The y of expand_as api must be specified."));
49+
}
50+
if (y->get_ptr() == nullptr) return;
51+
*target_shape = pir::GetShapeFromValue(*(y->get_ptr()));
52+
53+
/**
54+
* if convert_dtype(x.dtype) == 'bool' and not x.stop_gradient:
55+
* raise ValueError(
56+
* "When the data type of input 'x' for expand_as is bool, "
57+
* "you must set its stop_gradient to be False by "
58+
* "some_var.stop_gradient = True, supporting "
59+
* "some_var as the input 'x'."
60+
* )
61+
*
62+
*/
63+
auto dtype = pir::GetValueDtype(*x);
64+
auto stop_gradient_attr =
65+
x->attribute<pir::BoolAttribute>(kStopGradientAttrName);
66+
auto stop_gradient = !stop_gradient_attr || stop_gradient_attr.data();
67+
if (dtype == phi::DataType::BOOL && !stop_gradient) {
68+
PADDLE_THROW(common::errors::InvalidArgument(
69+
"When the data type of input 'x' for expand_as is bool, "
70+
"you must set its stop_gradient to be False by "
71+
"some_var.stop_gradient = True, supporting "
72+
"some_var as the input 'x'."));
73+
}
74+
}
3075
void RollPreProcess(Tensor* x, IntArray* shifts, IntVector* axis) {
3176
int64_t len_origin_shape = x->dims().size();
3277
if (axis != NULL) {

paddle/fluid/pybind/arg_pre_process.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include "paddle/phi/common/data_type.h"
2222
#include "paddle/phi/common/scalar.h"
2323
#include "paddle/pir/include/core/value.h"
24-
24+
#include "paddle/utils/optional.h"
2525
namespace paddle {
2626

2727
namespace pybind {
@@ -30,6 +30,12 @@ using Value = pir::Value;
3030
using IntArray = paddle::experimental::IntArray;
3131
using IntVector = std::vector<int64_t>;
3232

33+
void ExpandAsPreProcess(paddle::Tensor* x,
34+
paddle::optional<paddle::Tensor>* y,
35+
std::vector<int64_t>* target_shape);
36+
void ExpandAsPreProcess(Value* x,
37+
paddle::optional<pir::Value>* y,
38+
std::vector<int64_t>* target_shape);
3339
void RollPreProcess(Tensor* x, IntArray* shifts, IntVector* axis);
3440
void RollPreProcess(Value* x, Value* shifts, IntVector* axis);
3541

paddle/fluid/pybind/eager_utils.cc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,48 @@ paddle::optional<paddle::Tensor> GetOptionalTensorFromArgs(
14321432
}
14331433
}
14341434

1435+
paddle::optional<paddle::Tensor> GetOptionalTensorFromArgsOrKWArgs(
1436+
const std::string& op_type,
1437+
const std::string& arg_name,
1438+
PyObject* args,
1439+
ssize_t arg_idx,
1440+
PyObject* kwargs,
1441+
const std::vector<std::string>& keywords,
1442+
const int nargs,
1443+
int* remaining_kwargs,
1444+
bool dispensable,
1445+
const phi::distributed::ProcessMesh* mesh) {
1446+
PyObject* obj = GetItemFromArgsOrKWArgs(
1447+
args, arg_idx, kwargs, keywords, nargs, remaining_kwargs);
1448+
1449+
if (obj == nullptr || obj == Py_None) {
1450+
if (!dispensable) {
1451+
PADDLE_THROW(common::errors::InvalidArgument(
1452+
"%s(): argument '%s' (position %d) must be Tensor, but got None",
1453+
op_type,
1454+
arg_name,
1455+
arg_idx));
1456+
}
1457+
return paddle::none;
1458+
}
1459+
1460+
if (PyObject_TypeCheck(obj, p_tensor_type)) {
1461+
if (mesh) {
1462+
ConvertToDistTensor(&(reinterpret_cast<TensorObject*>(obj)->tensor),
1463+
mesh);
1464+
}
1465+
return paddle::make_optional<paddle::Tensor>(
1466+
reinterpret_cast<TensorObject*>(obj)->tensor);
1467+
} else {
1468+
PADDLE_THROW(common::errors::InvalidArgument(
1469+
"%s(): argument '%s' (position %d) must be Tensor, but got %s",
1470+
op_type,
1471+
arg_name,
1472+
arg_idx,
1473+
reinterpret_cast<PyTypeObject*>(obj->ob_type)->tp_name));
1474+
}
1475+
}
1476+
14351477
PyObject* ToPyObject(std::shared_ptr<egr::GradNodeBase> grad_node) {
14361478
py::object py_obj = py::cast(grad_node, py::return_value_policy::reference);
14371479
PyObject* py_grad_node = py_obj.release().ptr();

paddle/fluid/pybind/eager_utils.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,18 @@ paddle::optional<paddle::Tensor> GetOptionalTensorFromArgs(
409409
bool dispensable = false,
410410
const phi::distributed::ProcessMesh* mesh = nullptr);
411411

412+
paddle::optional<paddle::Tensor> GetOptionalTensorFromArgsOrKWArgs(
413+
const std::string& op_type,
414+
const std::string& arg_name,
415+
PyObject* args,
416+
ssize_t arg_idx,
417+
PyObject* kwargs,
418+
const std::vector<std::string>& keywords,
419+
const int nargs,
420+
int* remaining_kwargs,
421+
bool dispensable = false,
422+
const phi::distributed::ProcessMesh* mesh = nullptr);
423+
412424
paddle::Tensor& GetTensorFromArgs(const std::string& op_type,
413425
const std::string& arg_name,
414426
PyObject* args,

paddle/phi/ops/yaml/python_api_info.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
args_alias :
99
use_default_mapping : True
1010

11+
- op : expand_as
12+
name : [paddle.expand_as,paddle.Tensor.expand_as]
13+
args_alias :
14+
use_default_mapping : True
15+
pre_process :
16+
func : ExpandAsPreProcess(x,y,target_shape)
1117
- op : logical_and
1218
name : [paddle.logical_and, paddle.Tensor.logical_and]
1319
args_alias:

python/paddle/_paddle_docs.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,46 @@ def any(
825825
) -> Tensor
826826
""",
827827
)
828+
add_doc_and_signature(
829+
"expand_as",
830+
"""
831+
832+
Expand the input tensor ``x`` to the same shape as the input tensor ``y``.
833+
834+
Both the number of dimensions of ``x`` and ``y`` must be less than or equal to 6, and the number of dimensions of ``y`` must be greater than or equal to that of ``x``. The dimension to expand must have a value of 0.
835+
836+
The following diagram illustrates how a one-dimensional tensor is transformed into a tensor with a shape of [2,3] through the expand_as operation. The target tensor has a shape of [2,3], and through expand_as, the one-dimensional tensor is expanded into a tensor with a shape of [2,3].
837+
838+
.. image:: https://githubraw.cdn.bcebos.com/PaddlePaddle/docs/develop/docs/images/api_legend/expand_as.png
839+
:width: 800
840+
:alt: expand_as API
841+
:align: center
842+
843+
Args:
844+
x (Tensor): The input tensor, its data type is bool, float32, float64, int32 or int64.
845+
y (Tensor): The input tensor that gives the shape to expand to.
846+
name (str|None, optional): The default value is None. Normally there is no need for user to set this property. For more information, please refer to :ref:`api_guide_Name`.
847+
848+
Returns:
849+
N-D Tensor, A Tensor with the same shape as ``y``. The data type is the same as ``x``.
850+
851+
Examples:
852+
.. code-block:: python
853+
854+
>>> import paddle
855+
856+
>>> data_x = paddle.to_tensor([1, 2, 3], 'int32')
857+
>>> data_y = paddle.to_tensor([[1, 2, 3], [4, 5, 6]], 'int32')
858+
>>> out = paddle.expand_as(data_x, data_y)
859+
>>> print(out)
860+
Tensor(shape=[2, 3], dtype=int32, place=Place(cpu), stop_gradient=True,
861+
[[1, 2, 3],
862+
[1, 2, 3]])
863+
""",
864+
"""
865+
def expand_as(x: Tensor, y: Tensor, name: str | None = None) -> Tensor
866+
""",
867+
)
828868

829869
# shenwei
830870

python/paddle/tensor/manipulation.py

Lines changed: 1 addition & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
ShapeLike,
6666
TensorOrTensors,
6767
)
68-
68+
from paddle._C_ops import expand_as # noqa: F401
6969
from paddle.utils.decorator_utils import ForbidKeywordsDecorator
7070

7171
__all__ = []
@@ -4832,90 +4832,6 @@ def repeat(
48324832
return tile(input, repeat_times=repeats)
48334833

48344834

4835-
def expand_as(x: Tensor, y: Tensor, name: str | None = None) -> Tensor:
4836-
"""
4837-
4838-
Expand the input tensor ``x`` to the same shape as the input tensor ``y``.
4839-
4840-
Both the number of dimensions of ``x`` and ``y`` must be less than or equal to 6, and the number of dimensions of ``y`` must be greater than or equal to that of ``x``. The dimension to expand must have a value of 0.
4841-
4842-
The following diagram illustrates how a one-dimensional tensor is transformed into a tensor with a shape of [2,3] through the expand_as operation. The target tensor has a shape of [2,3], and through expand_as, the one-dimensional tensor is expanded into a tensor with a shape of [2,3].
4843-
4844-
.. image:: https://githubraw.cdn.bcebos.com/PaddlePaddle/docs/develop/docs/images/api_legend/expand_as.png
4845-
:width: 800
4846-
:alt: expand_as API
4847-
:align: center
4848-
4849-
Args:
4850-
x (Tensor): The input tensor, its data type is bool, float32, float64, int32 or int64.
4851-
y (Tensor): The input tensor that gives the shape to expand to.
4852-
name (str|None, optional): The default value is None. Normally there is no need for user to set this property. For more information, please refer to :ref:`api_guide_Name`.
4853-
4854-
Returns:
4855-
N-D Tensor, A Tensor with the same shape as ``y``. The data type is the same as ``x``.
4856-
4857-
Examples:
4858-
.. code-block:: python
4859-
4860-
>>> import paddle
4861-
4862-
>>> data_x = paddle.to_tensor([1, 2, 3], 'int32')
4863-
>>> data_y = paddle.to_tensor([[1, 2, 3], [4, 5, 6]], 'int32')
4864-
>>> out = paddle.expand_as(data_x, data_y)
4865-
>>> print(out)
4866-
Tensor(shape=[2, 3], dtype=int32, place=Place(cpu), stop_gradient=True,
4867-
[[1, 2, 3],
4868-
[1, 2, 3]])
4869-
"""
4870-
if in_dynamic_mode():
4871-
return _C_ops.expand_as(x, None, y.shape)
4872-
elif in_pir_mode():
4873-
if convert_dtype(x.dtype) == 'bool' and not x.stop_gradient:
4874-
raise ValueError(
4875-
"When the data type of input 'x' for expand_as is bool, "
4876-
"you must set its stop_gradient to be False by "
4877-
"some_var.stop_gradient = True, supporting "
4878-
"some_var as the input 'x'."
4879-
)
4880-
return _C_ops.expand_as(x, y, y.shape)
4881-
else:
4882-
check_variable_and_dtype(
4883-
x,
4884-
'x',
4885-
[
4886-
'bool',
4887-
'float32',
4888-
'float64',
4889-
'int32',
4890-
'int64',
4891-
'float16',
4892-
'uint16',
4893-
],
4894-
'expand_as',
4895-
)
4896-
check_type(y, 'y', Variable, 'expand_as')
4897-
4898-
if convert_dtype(x.dtype) == 'bool' and not x.stop_gradient:
4899-
raise ValueError(
4900-
"When the data type of input 'x' for expand_as is bool, "
4901-
"you must set its stop_gradient to be False by "
4902-
"some_var.stop_gradient = True, supporting "
4903-
"some_var as the input 'x'."
4904-
)
4905-
inputs = {"X": [x], "Y": [y]}
4906-
4907-
helper = LayerHelper('expand_as', **locals())
4908-
dtype = helper.input_dtype(input_param_name='x')
4909-
out = helper.create_variable_for_type_inference(dtype)
4910-
helper.append_op(
4911-
type='expand_as_v2',
4912-
inputs=inputs,
4913-
attrs={'target_shape': y.shape},
4914-
outputs={'Out': out},
4915-
)
4916-
return out
4917-
4918-
49194835
@ParamAliasDecorator({"x": ["input"], "shape": ["size"]})
49204836
def broadcast_to(
49214837
x: Tensor,

0 commit comments

Comments
 (0)