-
Notifications
You must be signed in to change notification settings - Fork 6k
[API Compatibility] Align paddle.Tensor.is_sparse, paddle.Tensor.type, paddle.Tensor.size api, paddle.nn.PReLU and paddle.distributions.categorical.Categorical -part #79550
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 26 commits
91b9144
3451263
d5154f3
4865ecc
8aa81ef
7f2684a
7eda286
ec4686b
cf76ec4
f668adb
111a665
b3bb47c
2f3cc36
ec1295c
f514e71
a721161
c64978f
826269a
a119dbe
5a5b7b3
219307c
fde90cf
b0217d4
82f8ebf
ce136ec
3eeb401
43c95f1
8c035b1
d72bb61
83282be
d993584
1198ed6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,6 +40,7 @@ | |
| from collections.abc import Sequence | ||
|
|
||
| from paddle import Tensor | ||
| from paddle._typing import DTypeLike | ||
|
|
||
| __all__ = [ | ||
| 'allclose', | ||
|
|
@@ -56,6 +57,39 @@ | |
| ] | ||
|
|
||
|
|
||
| # root compat APIs that torch also exposes as Tensor methods | ||
| _TENSOR_API_NAMES = ( | ||
| 'allclose', | ||
| 'equal', | ||
| 'slogdet', | ||
| 'sort', | ||
| 'split', | ||
| 'min', | ||
| 'max', | ||
| 'unique', | ||
| 'median', | ||
| 'nanmedian', | ||
| ) | ||
|
|
||
|
|
||
| _TENSOR_TYPE_DTYPES = { | ||
| 'HalfTensor': 'float16', | ||
| 'FloatTensor': 'float32', | ||
| 'DoubleTensor': 'float64', | ||
| 'Float8_e4m3fnTensor': 'float8_e4m3fn', | ||
| 'Float8_e5m2Tensor': 'float8_e5m2', | ||
| 'BFloat16Tensor': 'bfloat16', | ||
| 'ByteTensor': 'uint8', | ||
| 'CharTensor': 'int8', | ||
| 'ShortTensor': 'int16', | ||
| 'IntTensor': 'int32', | ||
| 'LongTensor': 'int64', | ||
| 'BoolTensor': 'bool', | ||
| 'ComplexFloatTensor': 'complex64', | ||
| 'ComplexDoubleTensor': 'complex128', | ||
| } | ||
|
|
||
|
|
||
| def __getattr__(name): | ||
| if name == "paddle_triton": | ||
| return paddle_triton_fun() | ||
|
|
@@ -66,6 +100,113 @@ def __getattr__(name): | |
| raise AttributeError(f"module {__name__!r} has no attribute {name!r}") | ||
|
|
||
|
|
||
| def _tensor_numel(input: Tensor) -> int: | ||
| """ | ||
| Returns the total number of elements in the tensor. | ||
|
|
||
| Args: | ||
| input (Tensor): The input tensor. | ||
|
|
||
| Returns: | ||
| int: The number of elements in ``input``. | ||
| """ | ||
| return int(input.size) | ||
|
|
||
|
|
||
| def _tensor_type( | ||
| input: Tensor, | ||
| dtype: DTypeLike | str | type | None = None, | ||
| non_blocking: bool = False, | ||
| **kwargs: Any, | ||
| ) -> str | Tensor: | ||
| """ | ||
| Returns the tensor dtype when ``dtype`` is not specified, otherwise casts | ||
| the tensor to the requested type. | ||
|
|
||
| Args: | ||
| input (Tensor): The input tensor. | ||
| dtype (DTypeLike|str|type|None, optional): The target tensor type or | ||
| data type. Qualified ``torch.*`` and ``paddle.*`` dtype or tensor | ||
| type strings are supported. When it is ``None``, returns a Paddle | ||
| dtype string. Default: ``None``. | ||
| non_blocking (bool, optional): Whether the conversion may occur | ||
| asynchronously. Default: ``False``. | ||
|
|
||
| Returns: | ||
| str|Tensor: A Paddle dtype string when ``dtype`` is ``None``; | ||
| otherwise, a tensor with the requested type. | ||
| """ | ||
| if "async" in kwargs: | ||
| non_blocking = kwargs.pop("async") | ||
| if kwargs: | ||
| key = next(iter(kwargs)) | ||
| raise TypeError(f"type() got an unexpected keyword argument {key!r}") | ||
|
|
||
| if dtype is None: | ||
| return str(input.dtype) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 你这个地方需要映射为torch一致的
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个是 >>> import torch
>>> a = torch.tensor([2.], dtype=float32)
>>> a.type()
'torch.FloatTensor'然后像
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 我的想法是另开一个 PR 修这个问题,要涉及到修改 creation.py,并且还有是 torch 还是 paddle 前缀的问题
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
我认为 #79641 这样的修改是对的
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 当前这项仍需在本 PR 修复。compat 模式下
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 当前提交已修复 CPU、CUDA 和 sparse COO 的查询,但这项仍是部分修复:
Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 已确认当前提交为 XPU 和已注册 custom device 保留了设备段,字符串解析与 no-op 判断也使用相同的 place 映射;新增测试覆盖了 CPU/GPU/XPU/custom 输出、有效转换和非法多设备段。此前的设备 round-trip 问题已解决。
Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.
|
||
|
|
||
| device = None | ||
| if isinstance(dtype, type) and dtype.__name__ in _TENSOR_TYPE_DTYPES: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里是否考虑了全部情况且能正确执行: |
||
| tensor_type = dtype.__name__ | ||
| dtype = _TENSOR_TYPE_DTYPES[tensor_type] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. np.float32触发这个分支吗?看起来有点问题 直接判断np.dtype、paddle.dtype吧,鲁棒些。 这个isinstance(dtype, type) 比较奇怪 |
||
| device = "cpu" | ||
| elif isinstance(dtype, str): | ||
| dtype_string = dtype | ||
| tensor_type = dtype_string.rsplit(".", 1)[-1] | ||
| if not dtype_string.startswith(("torch.", "paddle.")): | ||
| raise ValueError(f"invalid type: {dtype_string!r}") | ||
| if tensor_type in _TENSOR_TYPE_DTYPES: | ||
| dtype = _TENSOR_TYPE_DTYPES[tensor_type] | ||
| device = ( | ||
| "gpu" | ||
| if dtype_string.startswith(("torch.cuda.", "paddle.cuda.")) | ||
| else "cpu" | ||
| ) | ||
| elif tensor_type in _TENSOR_TYPE_DTYPES.values(): | ||
| dtype = tensor_type | ||
| if dtype_string.startswith(("torch.cuda.", "paddle.cuda.")): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这个是什么case?有
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 确实没有 我删一下 |
||
| device = "gpu" | ||
| else: | ||
| raise ValueError(f"invalid type: {dtype_string!r}") | ||
|
|
||
| dtype_name = str(input.dtype).removeprefix("paddle.") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 直接判断: dtype本身就是字符串
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| target_dtype_name = str(dtype).removeprefix("paddle.") | ||
| same_device = ( | ||
| device is None | ||
| or (device == "cpu" and input.place.is_cpu_place()) | ||
| or (device == "gpu" and input.place.is_gpu_place()) | ||
| ) | ||
| if dtype_name == target_dtype_name and same_device: | ||
| return input | ||
|
|
||
| return input.to( | ||
| device=device, | ||
| dtype=dtype, | ||
| blocking=not non_blocking, | ||
| ) | ||
|
|
||
|
|
||
| @property | ||
| def _tensor_is_sparse(input: Tensor) -> bool: | ||
|
Manfredss marked this conversation as resolved.
Manfredss marked this conversation as resolved.
|
||
| """ | ||
| Whether the tensor uses the sparse COO layout. | ||
|
|
||
| Args: | ||
| input (Tensor): The input tensor. | ||
|
|
||
| Returns: | ||
| bool: ``True`` for a sparse COO tensor, otherwise ``False``. | ||
| """ | ||
| return input.is_sparse_coo() | ||
|
|
||
|
|
||
| _TENSOR_API_OVERRIDES = { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 我建议这个是不是和上面的字典合并起来,统一成一个字典: |
||
| 'numel': _tensor_numel, | ||
| 'type': _tensor_type, | ||
| 'is_sparse': _tensor_is_sparse, | ||
| } | ||
|
|
||
|
|
||
| def allclose( | ||
| input: Tensor, | ||
| other: Tensor, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -51,29 +51,19 @@ def _caller_is_paddle_internal() -> bool: | |
| return name == "paddle" or name.startswith("paddle.") | ||
|
|
||
|
|
||
| def dispatch_function(compat_fn: Any) -> Any: | ||
| """Wrap a native ``paddle`` callable to route external callers to | ||
| ``compat_fn`` while compat is enabled; paddle-internal callers and the | ||
| disabled state get the native callable. Installed only under | ||
| ``enable_compat(level=2)``; ``disable_compat`` restores the originals, | ||
| so the default hot path is untouched.""" | ||
|
|
||
| def decorator(native_fn: Any) -> Any: | ||
| @wraps(native_fn) | ||
| def dispatcher(*args: Any, **kwargs: Any) -> Any: | ||
| if ( | ||
| len(_PADDLE_NAMESPACE_SAVED) > 0 | ||
| and not _caller_is_paddle_internal() | ||
| ): | ||
| return compat_fn(*args, **kwargs) | ||
| return native_fn(*args, **kwargs) | ||
| def dispatch_function(native_fn: Any, compat_fn: Any) -> Any: | ||
| """Wrap a native ``paddle`` callable for caller-aware dispatch.""" | ||
|
|
||
| dispatcher.__compat_fn__ = compat_fn | ||
| dispatcher.__native_fn__ = native_fn | ||
| dispatcher.__signature__ = inspect.signature(compat_fn) | ||
| return dispatcher | ||
| @wraps(native_fn) | ||
| def dispatcher(*args: Any, **kwargs: Any) -> Any: | ||
| if _caller_is_paddle_internal(): | ||
| return native_fn(*args, **kwargs) | ||
| return compat_fn(*args, **kwargs) | ||
|
|
||
| return decorator | ||
| dispatcher.__compat_fn__ = compat_fn | ||
| dispatcher.__native_fn__ = native_fn | ||
| dispatcher.__signature__ = inspect.signature(compat_fn) | ||
| return dispatcher | ||
|
|
||
|
|
||
| def _iter_compat_modules() -> Generator[types.ModuleType, None, None]: | ||
|
|
@@ -123,28 +113,54 @@ def __call__(cls, *args: Any, **kwargs: Any) -> Any: | |
| return proxy | ||
|
|
||
|
|
||
| def dispatch_property( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里有点奇怪,property->func、func->property、property->property 三个分支可以共享这一个dispatch吗? 如果能共享,那后面三个分支也可以合并了 |
||
| native_attr: Any, | ||
| compat_attr: Any, | ||
| ) -> Any: | ||
| """Route a Tensor API when either side uses the property protocol.""" | ||
| compat_fn = ( | ||
| compat_attr.fget if isinstance(compat_attr, property) else compat_attr | ||
| ) | ||
|
|
||
| class _PropertyDispatcher: | ||
| def __get__(self, instance: Any, owner: type | None = None) -> Any: | ||
| if _caller_is_paddle_internal(): | ||
| attr = native_attr | ||
| else: | ||
| attr = compat_attr | ||
| return attr.__get__(instance, owner) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里能保证
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 不用一定是
现在只有两个 API 会走到这里:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 是 descriptor 还是 function 不重要,关键是能不能 bind object( 算了,反正大概率也没人会在这两处注册 int 之类的 normal object,大概率也没啥问题,有问题再说吧 另外,其实 |
||
|
|
||
| dispatcher = _PropertyDispatcher() | ||
| dispatcher.__native_fn__ = native_attr | ||
| dispatcher.__compat_fn__ = compat_fn | ||
| dispatcher.__doc__ = compat_fn.__doc__ | ||
| dispatcher.__name__ = compat_fn.__name__ | ||
| dispatcher.__signature__ = inspect.signature(compat_fn) | ||
| return dispatcher | ||
|
|
||
|
|
||
| def _patch_tensor_methods() -> None: | ||
| """Route ``paddle.Tensor.<m>`` to the compat function for the root compat APIs | ||
| that torch also exposes as Tensor methods (max/min/sort/split/unique/...), so | ||
| ``x.max(dim=1)`` works torch-style for external callers (native for internal). | ||
| The dispatcher is patched directly like any paddle Tensor method: the | ||
| descriptor protocol forwards the tensor as the first positional argument, | ||
| which is exactly the compat function's ``input`` parameter. | ||
| """ | ||
| """Route ``paddle.Tensor`` APIs to their root compat implementations.""" | ||
| import paddle | ||
| import paddle.compat as compat_root | ||
|
|
||
| for attr_name in getattr(compat_root, "__all__", ()): | ||
| native_method = getattr(paddle.Tensor, attr_name, None) | ||
| if native_method is None: | ||
| tensor_apis = { | ||
| name: getattr(compat_root, name) | ||
| for name in compat_root._TENSOR_API_NAMES | ||
| } | ||
| tensor_apis.update(compat_root._TENSOR_API_OVERRIDES) | ||
| for attr_name, compat_attr in tensor_apis.items(): | ||
| native_attr = inspect.getattr_static(paddle.Tensor, attr_name, None) | ||
| if native_attr is None: | ||
| continue | ||
| compat_fn = getattr(compat_root, attr_name) | ||
| _PADDLE_NAMESPACE_SAVED[(paddle.Tensor, attr_name)] = native_method | ||
| setattr( | ||
| paddle.Tensor, | ||
| attr_name, | ||
| dispatch_function(compat_fn)(native_method), | ||
| ) | ||
| _PADDLE_NAMESPACE_SAVED[(paddle.Tensor, attr_name)] = native_attr | ||
| if inspect.isdatadescriptor(native_attr) or isinstance( | ||
| compat_attr, property | ||
| ): | ||
| dispatcher = dispatch_property(native_attr, compat_attr) | ||
| else: | ||
| dispatcher = dispatch_function(native_attr, compat_attr) | ||
| setattr(paddle.Tensor, attr_name, dispatcher) | ||
|
|
||
|
|
||
| def _apply_paddle_namespace_aliases() -> None: | ||
|
|
@@ -177,7 +193,7 @@ def _apply_paddle_namespace_aliases() -> None: | |
| setattr( | ||
| target_module, | ||
| attr_name, | ||
| dispatch_function(compat_attr)(current), | ||
| dispatch_function(current, compat_attr), | ||
| ) | ||
| _patch_tensor_methods() | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.