[API Compatibility] enhance paddle.enable_compat -part#79391
[API Compatibility] enhance paddle.enable_compat -part#79391Manfredss wants to merge 14 commits into
Conversation
…alls resolve to the paddle.compat.* implementations at runtime. assisted by Claude
risemeup1111
left a comment
There was a problem hiding this comment.
发现了需要修复后再合入的兼容性回归,具体问题已放在行级评论中:主要是 paddle.compat 的 lazy attribute 行为被破坏,以及已有的 compat public API 被删除。CI 当前仍有部分任务进行中,且已有 Windows-GPU build/test 失败,请后续一并确认。
| def __getattr__(name): | ||
| if name == "paddle_triton": | ||
| return paddle_triton_fun() |
There was a problem hiding this comment.
这里删掉了 distributions 的 lazy import 和最终的 AttributeError,导致两个回归:paddle.compat.distributions 在未预先 import paddle.compat.distributions 时会通过 __getattr__ 直接返回 None,未知属性也不再抛 AttributeError,会破坏 Python 模块属性协议以及已有的 paddle.compat.distributions 访问方式。请保留 distributions 分支,并让未知属性继续抛 AttributeError。
| def __getattr__(name): | |
| if name == "paddle_triton": | |
| return paddle_triton_fun() | |
| def __getattr__(name): | |
| if name == "paddle_triton": | |
| return paddle_triton_fun() | |
| if name == "distributions": | |
| import importlib | |
| module = importlib.import_module("paddle.compat.distributions") | |
| globals()[name] = module | |
| return module | |
| raise AttributeError(f"module {__name__!r} has no attribute {name!r}") |
| 'BatchNorm1d', | ||
| 'BatchNorm2d', | ||
| 'BatchNorm3d', | ||
| 'MultiheadAttention', |
There was a problem hiding this comment.
这里把 paddle.compat.nn.BatchNorm1D/2D/3D、小写别名以及 SmoothL1Loss 从 public compat surface 删除了,但这些 API 已经有现有调用和测试覆盖:test/legacy_test/test_api_compatibility_part1.py 在类定义时直接绑定 paddle.compat.nn.BatchNorm*,test/legacy_test/test_compat_smooth_l1_loss.py 也直接实例化 paddle.compat.nn.SmoothL1Loss。删除后这些测试会在 import/执行阶段变成 AttributeError,也会破坏已有用户代码。请恢复这些符号及其实现;如果目标是只做命名空间 alias,仍需要保留 compat 侧的实现作为 paddle.* alias 的目标。
建议形状:
__all__ = [
# ...
'BatchNorm1D', 'BatchNorm2D', 'BatchNorm3D',
'BatchNorm1d', 'BatchNorm2d', 'BatchNorm3d',
'SmoothL1Loss',
]
class BatchNorm1D(nn.BatchNorm1D):
... # 保留 torch-style eps/momentum/track_running_stats 适配
BatchNorm1d = BatchNorm1D
# 同步恢复 2D/3D 以及 SmoothL1Loss| return x | ||
|
|
||
| return paddle.nn.functional.unfold( | ||
| return _native(paddle.nn.functional, "unfold")( |
There was a problem hiding this comment.
这里删除 paddle.compat.nn.functional.smooth_l1_loss 会直接破坏已有 compat functional API:test/legacy_test/test_compat_smooth_l1_loss.py 覆盖了 F_compat.smooth_l1_loss(..., beta=...)、target=、size_average/reduce、beta=0 和 forbidden keywords。删除后这些用例和用户迁移代码都会变成 AttributeError,并且 paddle.enable_compat() 也无法把 paddle.nn.functional.smooth_l1_loss alias 到 torch-style 语义。请恢复该函数、__all__ 条目,以及所需的 warnings 和 _ReduceMode。
建议形状:
import warnings
if TYPE_CHECKING:
_ReduceMode: TypeAlias = Literal["mean", "sum", "none"]
__all__ = [
# ...
'unfold',
'smooth_l1_loss',
]
@ForbidKeywordsDecorator(
illegal_keys={"label", "delta", "is_huber", "name"},
func_name="paddle.compat.nn.functional.smooth_l1_loss",
correct_name="paddle.nn.functional.smooth_l1_loss",
)
def smooth_l1_loss(input, target, size_average=None, reduce=None, reduction='mean', beta=1.0):
# 保留原来的 torch-style beta/size_average/reduce 适配逻辑
...
CI 分析结果本轮达到时间上限,未完成全部失败原因分析;未分析完的 job 标记为“分析省略/待后续深挖”。 |
…mpat regression test
liuhao2638
left a comment
There was a problem hiding this comment.
已复查当前提交。此前指出的 paddle.compat lazy attribute、compat.nn BatchNorm/SmoothL1Loss、compat.nn.functional.smooth_l1_loss 删除问题在当前代码中已经恢复。
不过这轮发现了一个新的全局 alias 下的 P1 回归,具体见行级评论:smooth_l1_loss wrapper 需要通过 native 实现回调,避免 enable_compat() 后自引用到 compat wrapper。CI 目前仍有任务运行中,后续也请一并确认。
| for attr_name in getattr(compat_module, PUBLIC_ATTR_DECLARATION): | ||
| if attr_name.startswith("_"): | ||
| continue | ||
| compat_attr = getattr(compat_module, attr_name) |
There was a problem hiding this comment.
这里会把每个 paddle.compat.*.__all__ 符号 alias 到真实 paddle.* namespace,因此全局 paddle.enable_compat() 后 paddle.nn.functional.smooth_l1_loss 也会变成 compat wrapper。当前 wrapper 在函数尾部仍直接调用 paddle.nn.functional.smooth_l1_loss(..., delta=beta, is_huber=False);alias 生效后这个名字已经指回 wrapper 自身,ForbidKeywordsDecorator 会拒绝 delta/is_huber(或进入自调用路径),导致迁移代码里的 paddle.nn.functional.smooth_l1_loss(x, y, beta=...) 失败。
请像 unfold/SDPA 一样通过 _native 调回 Paddle 原生实现,并补一个 enable_compat() 下的回归用例覆盖这个别名路径。建议形状:
if beta == 0:
return _native(paddle.nn.functional, "l1_loss")(
input, target, reduction=reduction
)
return _native(paddle.nn.functional, "smooth_l1_loss")(
input, target, reduction=reduction, delta=beta, is_huber=False
)|
/re-run all-failed |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #79391 +/- ##
==========================================
Coverage ? 93.92%
==========================================
Files ? 6
Lines ? 181
Branches ? 0
==========================================
Hits ? 170
Misses ? 11
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
|
||
|
|
||
| @cache | ||
| def _register_compat_override(): |
There was a problem hiding this comment.
如果 paddle.compat.* 已经patch到 paddle.* 上了,这里还需要去额外操作吗
| # disable_compat() on exit would remove the finder and destroy the | ||
| # surrounding scoped enable (the runtime entry point of the migration | ||
| # workflow). So restore the finder to exactly how it was found. | ||
| if already_has_torch_proxy: |
| public_attrs = getattr(module, PUBLIC_ATTR_DECLARATION) | ||
| torch_module_name = module_info.name.replace( | ||
| PADDLE_PREFIX, TORCH_PREFIX, 1 | ||
| # Use the root-inclusive iterator: pkgutil.walk_packages skips the |
There was a problem hiding this comment.
这些注释清理一下吧,如果确需要注释的话,也只是简短意赅的关键1~2行,不用长篇大论的写
| _restore_paddle_namespace_aliases() | ||
|
|
||
|
|
||
| def enable_compat( |
There was a problem hiding this comment.
直接改这个可能有点不兼容,加个level参数吧
背景这个主要是解决当前的paddle框架中无法完全对齐的问题,当前Paddle API的对齐状态分为以下三种:
用户在编写paddle时,很难知道哪些是对齐的1,哪些是未对齐的2/3,这使得编写paddle代码成本仍较高。 开发思路目前考虑在enable_compat最后面加一个level参数,默认为1,对于:
针对 第三方库+存量Paddle代码 的用法:level=1,部分API无法对齐,需手动检查调整,主要为避免存量paddle代码出现不兼容 针对 第三方库+新增Paddle代码 的用法:level=2,完全对齐,统一按torch的形态即可 @SigureMo 看下这样的设计思路怎么样,有没有要调整的地方?比如 不加level直接按2来、加level但默认为2、新增一个其他API来作为这个开关不用放到enable_compat里? |
SigureMo
left a comment
There was a problem hiding this comment.
针对 第三方库+存量Paddle代码 的用法:level=1,部分API无法对齐,需手动检查调整,主要为避免存量paddle代码出现不兼容
针对 第三方库+新增Paddle代码 的用法:level=2,完全对齐,统一按torch的形态即可
我比较赞同这里的 level=1/2 的方案,主要是考虑到现存代码可能有部分已经使用 Paddle 原生 API 改写过了,此时一旦自动直接将这些 API 迁移到 paddle.compat API 实现可能会出现一些因为兼容性导致的非预期的问题,直接按 2 来我倒是有些担忧的,不过倒是后面可以考虑把 2 切默认(理想情况)
不过值得注意的是,paddle.enable_compat 这个 API 真正的挑战并不在于实现这些映射功能,而在于当环境中真的安装有 PyTorch 时,如何避免发生冲突(CI 中几乎测不到,只有几个使用 fake torch 模拟的 case),这是真实业务场景中会使用的,因此在实现时候需要特别注意下
| return x | ||
|
|
||
| return paddle.nn.functional.unfold( | ||
| return _native(paddle.nn.functional, "unfold")( |
There was a problem hiding this comment.
我有个疑问,既然是 patch,那么一旦开启 compat,所有相关 API 都会变吧?为什么当前改动仅限于 paddle.compat 下?非 compat 下的 API 理论上也会受到影响吧?(只是问题并不是像递归这么明显罢了)
当然不是让你把所有 API 改一遍,而是我在想这样做的可行性
There was a problem hiding this comment.
其实这也很好做,改造一下:
from typing import Callable, TypeVar
from typing_extensions import ParamSpec
from contextlib import contextmanager
T1 = TypeVar("T1")
T2 = TypeVar("T2")
P1 = ParamSpec("P1")
P2 = ParamSpec("P2")
COMPAT_API_ENABLED = False
def is_compat_api_enabled():
return COMPAT_API_ENABLED
@contextmanager
def compat_api_guard(enable: bool = True):
global COMPAT_API_ENABLED
if enable == COMPAT_API_ENABLED:
yield
return
original_value = COMPAT_API_ENABLED
COMPAT_API_ENABLED = enable
try:
yield
finally:
COMPAT_API_ENABLED = original_value
# compat/registry.py
def dispatch_compat_api(
compat_fn: Callable[P1, T1],
) -> Callable[[Callable[P2, T2]], Callable[P2, T2]]:
def native_fn_decorator(native_fn: Callable[P2, T2]) -> Callable[P2, T2]:
def maybe_use_compat_api(*args: P2.args, **kwargs: P2.kwargs) -> T2:
if is_compat_api_enabled():
# 关键在这里,灵活关掉 compat
return compat_api_guard(enable=False)(compat_fn)(*args, **kwargs) # type: ignore
return native_fn(*args, **kwargs)
return maybe_use_compat_api
return native_fn_decorator
def unfold_compat(x, y):
return unfold(x, y) + 1
@dispatch_compat_api(unfold_compat)
def unfold(x, y):
return x * y
with compat_api_guard():
print(unfold(1, 2)) # 3
with compat_api_guard(enable=False):
print(unfold(1, 2)) # 2随便搞的原型,仅供参考
| paddle.enable_compat() | ||
| try: | ||
| self.assertEqual(paddle.min(t).item(), 1.0) | ||
| self.assertEqual(paddle.max(t).item(), 3.0) | ||
| # dim form returns a namedtuple (values, indices) | ||
| r = paddle.min(t, dim=0) | ||
| self.assertEqual(r.values.item(), 1.0) | ||
| self.assertEqual(r.indices.item(), 1) | ||
| finally: | ||
| paddle.disable_compat() |
There was a problem hiding this comment.
这种单测不能直接用 @use_compat_guard 装饰器么?
There was a problem hiding this comment.
@Manfredss 对于整个框架内部,调用到这些compat系列API的地方(约30个),确实应该都是paddle naive版的,而这一系列API对外呈现的则是torch版的。
这个主要影响到的是 单测 + 部分调用paddle API的组合实现API。
可能得加大一下测试面,比如level=2下,paddle其他的API还能否跑过,除了paddle自身测试外,建议在paconvert里也进行测试(全局设置为level=2),测量全量API的行为是否正常。
…d the compat impls) get native, only external user code sees compat -- keeps paddle's own layers working
|
paddle.enable_compat 增加 level 参数: 背景:Paddle API 对齐分三类:
设计:
level=2 关键实现
测试
|
…Co-Authored-By: Claude <noreply@anthropic.com>
…red-by: Claude <noreply@anthropic.com>
|
/re-run all-failed |
There was a problem hiding this comment.
Pull request overview
This PR extends paddle.enable_compat() with a new compatibility “level=2” mode that (when enabled globally) aliases public paddle.compat.* APIs onto the live paddle / paddle.nn / paddle.nn.functional namespaces, using caller-aware dispatch to keep Paddle internal calls on native implementations. It also adds guards to avoid recursion when compat wrappers call back into aliased paddle.* APIs, and introduces comprehensive tests for aliasing + lifecycle behavior.
Changes:
- Add a level-based compat mode where global
enable_compat(level=2)aliasespaddle.*topaddle.compat.*using caller-aware dispatchers/proxies (and restores exactly on disable). - Add
compat_api_guard(enable=False)usage in compat wrappers to ensure internal calls hit native implementations under aliasing. - Add new test coverage (including fake modules) for namespace aliasing, scoped/global lifecycle behavior, and torch root API mapping.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/compat/test_compat_namespace_aliased.py | New end-to-end tests for level=2 aliasing, restoration, lifecycle correctness, and caller-aware dispatch behavior. |
| test/compat/fake_modules/torch_proxy_root_api_module.py | Fake module used to validate scoped imports + torch root API capture behavior. |
| python/paddle/compat/proxy.py | Implements level=2 namespace aliasing, caller-aware dispatch, compat suspension guard, root-package override coverage, and improved guard restoration logic. |
| python/paddle/compat/nn/transformer.py | Applies compat_api_guard(enable=False) to internal paths that must remain native under aliasing. |
| python/paddle/compat/nn/functional/sdpa.py | Guards compat SDPA implementation so its internals consistently use native implementations. |
| python/paddle/compat/nn/functional/init.py | Guards compat unfold to ensure internal calls remain native under level=2 aliasing. |
| python/paddle/compat/nn/init.py | Guards compat AvgPool* forward; adjusts Softmax.extra_repr (but currently introduces a bug). |
| python/paddle/compat/init.py | Exposes compat dispatch/guard helpers and guards several top-level compat functions to prevent recursion under aliasing. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def extra_repr(self) -> str: | ||
| return f"dim={self._dim}" | ||
| return f"dim={self.dim}" | ||
|
|
| # (live module, attr name) -> original value (or ``_MISSING``) for every | ||
| # ``paddle.*`` symbol aliased to its ``paddle.compat.*`` counterpart, so the | ||
| # paddle namespace can be restored exactly on ``disable_compat()``. | ||
| _PADDLE_NAMESPACE_SAVED: dict[tuple[types.ModuleType, str], Any] = {} | ||
|
|
|
/re-run all-failed |
|
/re-run all-failed |
1 similar comment
|
/re-run all-failed |
也就是确保paddle.enable_compat(level=2)仅修改对外的 |
liuhao2638
left a comment
There was a problem hiding this comment.
已复查当前提交。此前由 risemeup1111 提出的 paddle.compat lazy attribute 和 compat public API 删除问题,在当前代码中看起来已恢复;本轮新增的阻塞问题已放在行级评论里,主要是公开 API 装饰器导致 API spec 签名变化并触发 Static-Check 失败。
优先级:P1
非行级:测试覆盖缺口不能准确附着到单一 diff 行。当前 Paddle 侧新增测试覆盖了几个代表性层和 Tensor 方法,但还没有把 enable_compat(level=2) 写入约 10 个会在内部调用 split/max/min 的组合 API 用例(例如 vsplit/hsplit/dsplit 及相关组合路径),也没有在本 PR 可见范围内给出 PaConvert 全量 API 在 level=2 下通过的结果。请补齐这些回归用例或在 PR 中给出对应测试记录,确保 level=2 只影响外部 paddle.* 调用,不波及 Paddle 内部组合 API。
优先级:P3
非行级:PR 描述不在 changed diff line 上。当前描述仍写 enable_compat() 后 paddle.X 即变为 compat、通过 _native helper 回调 native、以及 flash_attention.py 显式传 F.softmax(product, -1);但当前实现实际是默认 level=1、只有 enable_compat(level=2) 才启用 paddle.* namespace alias,并通过 compat_api_guard/caller-aware dispatch 处理内部调用,flash_attention.py 当前也仍是 F.softmax(product)。建议同步描述,避免后续 reviewer 和用户按旧语义理解这个开关。
| @contextmanager | ||
| def compat_api_guard(enable: bool = True) -> Generator[None, None, None]: | ||
| """Suspend/restore compat dispatch for the current thread / async task only | ||
| (task-local). Compat APIs use ``@compat_api_guard(enable=False)`` so their own | ||
| ``paddle.*`` calls hit native instead of re-dispatching into compat.""" | ||
| token = _COMPAT_SUSPENDED.set(not enable) | ||
| try: | ||
| yield | ||
| finally: | ||
| _COMPAT_SUSPENDED.reset(token) |
There was a problem hiding this comment.
compat_api_guard 现在由 contextlib.contextmanager 生成后直接当公开 API 装饰器使用,会把被装饰函数在 inspect.getfullargspec() 下暴露成 *args/**kwds。当前 Static-Check 已经因此在 paddle.compat.nn.Unfold.forward 和 paddle.compat.nn.functional.scaled_dot_product_attention 上报 api_params_diff,这会阻塞 API 兼容检查。请改成同时支持 with 和装饰器、并保留原函数签名的实现,或把这些公开 API 内的 guard 改成函数体里的 with。
一个集中修复的形状如下:
| @contextmanager | |
| def compat_api_guard(enable: bool = True) -> Generator[None, None, None]: | |
| """Suspend/restore compat dispatch for the current thread / async task only | |
| (task-local). Compat APIs use ``@compat_api_guard(enable=False)`` so their own | |
| ``paddle.*`` calls hit native instead of re-dispatching into compat.""" | |
| token = _COMPAT_SUSPENDED.set(not enable) | |
| try: | |
| yield | |
| finally: | |
| _COMPAT_SUSPENDED.reset(token) | |
| class _CompatApiGuard: | |
| def __init__(self, enable: bool = True) -> None: | |
| self.enable = enable | |
| self._token: Any | None = None | |
| def __enter__(self) -> None: | |
| self._token = _COMPAT_SUSPENDED.set(not self.enable) | |
| def __exit__(self, exc_type: Any, exc: Any, tb: Any) -> None: | |
| token = self._token | |
| self._token = None | |
| if token is not None: | |
| _COMPAT_SUSPENDED.reset(token) | |
| def __call__(self, func: Any) -> Any: | |
| @wraps(func) | |
| def wrapper(*args: Any, **kwargs: Any) -> Any: | |
| with type(self)(self.enable): | |
| return func(*args, **kwargs) | |
| wrapper.__signature__ = inspect.signature(func) | |
| return wrapper | |
| def compat_api_guard(enable: bool = True) -> _CompatApiGuard: | |
| """Suspend/restore compat dispatch for the current thread / async task only | |
| (task-local). Compat APIs use ``@compat_api_guard(enable=False)`` so their own | |
| ``paddle.*`` calls hit native instead of re-dispatching into compat.""" | |
| return _CompatApiGuard(enable) |
…omposite APIs enable_compat(level=2) only aliases the outward paddle.* surface; composite APIs (vsplit/chunk/quantile/nan_to_num/nll_loss/embedding/histogram*/GRUCell/LSTMCell/ clip_grad_norm_) that internally call split/sort/max/equal/unique must stay native via caller-aware dispatch. Verifies zhwesky2010's review request. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
/re-run all-failed |
1 similar comment
|
/re-run all-failed |
…ghtweight core The newly-added test hit the added-UT CI gate (--repeat-until-fail 3 --timeout 15/20) on Linux-CPU/XPU: heavy/exotic ops (GRUCell/LSTMCell with unseeded randn, histogramdd, in-place embedding renorm) caused nondeterministic abort+timeout, while Windows/Mac (no such gate) passed. Reduce to fixed-input, lightweight core composites (vsplit/hsplit/dsplit/chunk, quantile, nan_to_num, histogram_bin_edges, nll_loss) that still verify internal split/sort/min/max/equal stay native. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
risemeup1111
left a comment
There was a problem hiding this comment.
已复查新提交。Paddle 侧新增了 test_compat_level2_internal_composites.py,覆盖 vsplit/hsplit/dsplit/chunk、quantile、nan_to_num、histogram_bin_edges、nll_loss 等在 level=2 下仍需走 native 内部调用的轻量路径,上一轮关于 Paddle 单测覆盖的缺口已部分补齐。本轮没有新增行级评论;此前公开 API 签名变化的问题仍由已有行级评论覆盖。
优先级:P2
非行级:跨仓 PaConvert 验证不在本 PR diff 行内。关联的 PaConvert PR 已改为注入 paddle.enable_compat(level=2),但当前仍未看到全量 API/CI 通过结果,且关联 PR 的 Common API Consistency、Distributed、Modeltest 等检查仍处于失败/未完成状态。请补充通过记录或修复对应失败后再把这里作为完整验证闭环。
优先级:P3
非行级:PR 描述不在 changed diff line 上。当前描述仍按 plain paddle.enable_compat() 即启用 namespace alias、_native helper、以及 flash_attention.py 显式 F.softmax(product, -1) 来表述;当前实现实际是默认 level=1、level=2 才启用 alias,并通过 compat_api_guard/caller-aware dispatch 处理内部调用。建议同步描述到当前实现,避免 reviewer 和用户按旧语义理解。
|
/re-run all-failed |
1 similar comment
|
/re-run all-failed |
risemeup1111
left a comment
There was a problem hiding this comment.
已复查本次测试更新:test_compat_level2_internal_composites.py 补充了 tensor_split 覆盖,Paddle 侧内部组合 API 的轻量回归覆盖进一步收窄;未发现这次测试改动带来新的行级问题。此前最早提出的 paddle.compat lazy attribute 和 compat public API 删除问题在当前代码中仍为已恢复。公开 API 签名问题当前实现未变化,仍由已有行级讨论覆盖,本轮不重复评论。
优先级:P2
非行级:跨仓 PaConvert 验证不在本 PR diff 行内。关联 PaConvert PR 目前已继续调整 enable_compat(level=2) 注入/重置逻辑,但当前 CI Unittest、Common API Consistency Check、Modeltest Check 仍失败,Distributed/GPU 也尚未全部完成。请补充全量 API/CI 通过记录,或先修复关联失败后再把这里作为完整验证闭环。
优先级:P3
非行级:PR 描述不在 changed diff line 上。当前描述仍按 plain paddle.enable_compat() 即启用 namespace alias、_native helper、以及 flash_attention.py 显式 F.softmax(product, -1) 来表述;当前实现实际是默认 level=1、level=2 才启用 alias,并通过 compat_api_guard/caller-aware dispatch 处理内部调用,flash_attention.py 当前也仍是 F.softmax(product)。建议同步描述到当前实现,避免 reviewer 和用户按旧语义理解。
CI报告基于以下代码生成(30分钟更新一次): 1 Required任务 : 45/48 通过
2 失败详情🔴 Static-Check / Test — PR问题(置信度: 高)分析器: 通用分析(fallback)
关键日志:
修复建议:
关联变更: 🔴 Fleet Unit test (multi-card) — 环境问题(置信度: 高)分析器: 通用分析(fallback)
关键日志:
修复建议:
关联变更: 未发现与本 PR 修改文件的直接关联。 🔴 Fleet Unit test (single card) — 环境问题(置信度: 高)分析器: 通用分析(fallback)
关键日志:
修复建议:
关联变更: 未发现与本 PR 修改文件的直接关联。 |
|
/re-run all-failed |
|
/re-run all-failed |
1 similar comment
|
/re-run all-failed |
risemeup1111
left a comment
There was a problem hiding this comment.
已复查最新提交。compat_api_guard 已从 contextmanager 改为同时支持上下文和装饰器的 class,并在装饰器路径保留 __signature__;我用等价最小复现确认 inspect.getfullargspec 不再退化成 *args/**kwargs,此前公开 API 签名变化的 P1 问题看起来已由新 commit 修复。最早提出的 paddle.compat lazy attribute 和 compat public API 删除问题当前也仍为已恢复。本轮没有新增行级评论。
优先级:P2
非行级:跨仓 PaConvert 验证不在本 PR diff 行内。当前关联 PaConvert PR 的 checks 已显示全部通过,我倾向于认为验证证据已补齐;但该项此前作为 P2 跟进意见提出,仍需要作者在本 PR 中回复确认对应验证记录。
处理要求:请针对该评论进行回复(同意并已修改请回复 Done,不同意请说明理由)。
优先级:P3
非行级:PR 描述不在 changed diff line 上。当前描述仍按 plain paddle.enable_compat() 即启用 namespace alias、_native helper、以及 flash_attention.py 显式 F.softmax(product, -1) 来表述;当前实现实际是默认 level=1、level=2 才启用 alias,并通过 compat_api_guard/caller-aware dispatch 处理内部调用,flash_attention.py 当前也仍是 F.softmax(product)。请同步描述到当前实现。
处理要求:请针对该评论进行回复(同意并已修改请回复 Done,不同意请说明理由)。
PaddlePaddle-bot
left a comment
There was a problem hiding this comment.
🤖 Paddle-CI-Agent | pr_review |
2026-07-08 19:48:21
📋 Review 摘要
PR 概述:为 paddle.enable_compat(level=2) 增加 paddle 命名空间到 paddle.compat 的 caller-aware alias,并补充内部 composite 调用保护与测试。
变更范围:python/paddle/compat、paddle.compat.nn/functional、compat namespace 回归测试。
影响面 Tag:User Experience
问题
未发现阻塞性问题。PR 规范问题在下面章节报,不要在这里重复
历史 Findings 修复情况
| Finding | 问题 | 状态 |
|---|---|---|
| F1 | enable_compat() 默认仍是 level=1,与 plain paddle.enable_compat() 迁移入口不一致。 |
|
| F2 | dispatcher 使用 @wraps(native_fn),level=2 后公开 paddle.* 仍暴露 native 元数据/签名。 |
|
| F3 | 新测试在模块导入阶段永久追加 fake_modules 到全局 sys.path。 |
📝 PR 规范检查
标题 Tag API Compatibility 不在当前 Paddle 模板的 PR Category / PR Types 枚举中。描述包含必填四段,且“是否引起精度变化”为“否”,结构符合模板。
标题建议(可直接复制):
[User Experience] enhance paddle.enable_compat level=2 namespace aliasing
总体评价
本轮按 Python 公开 API/兼容性路径检查了 namespace alias、内部 guard、scope lifecycle、Tensor method patch 和新增测试。未新增 inline findings;历史 3 条仍未在当前 diff 中修复,建议后续一并收敛。
|
/re-run all-failed |
PR Category
User Experience
PR Types
Improvements
Description
paddle.enable_compat()currently only installs asys.meta_pathfinder so thatimport torchresolves to PaddlePaddle (a torch→paddle proxy); it does not touchthe real
paddle.*namespace, sopaddle.sort/paddle.min/... stay paddle-nativeeven while compat is enabled.
Because
paddle.Xandpaddle.compat.Xshare identical positional parameter types, acall site cannot be auto-classified as "native intent" vs "compat intent", so the clean
design is a global switch: after
enable_compat(),paddle.Xispaddle.compat.Xand its arguments are interpreted as the torch-aligned compat arguments. Users write
PyTorch-style code and no longer need to care whether an API is
paddle.*orpaddle.compat.*. (This also backs the PaConvert migration flow: prefix-onlytorch.X → paddle.X+ an injectedpaddle.enable_compat().)What this PR does
compat/proxy.py): onenable_compat()(global scope only),alias every public
paddle.compat.*symbol onto the livepaddle/paddle.nn/paddle.nn.functionalmodules viasetattr, mirroring_register_compat_override(
torch.X → paddle.compat.X).disable_compat()perfectly restores the originalnamespace (including deleting symbols that did not exist before —
paddle.slogdet,paddle.nn.AvgPool1d/2d/3d,paddle.nn.MultiheadAttention)._nativehelper): compat wrappers that internally call backinto a name they alias (
paddle.compat.min→paddle.min,Unfold/transformerF.linear/F.softmax,unfold,scaled_dot_product_attention) now route through_native(module, name)so they always reach the genuine native impl — avoidinginfinite recursion /
ForbidKeywordsrejection / a silent double-transpose, whilekeeping
paddle.X is paddle.compat.X._register_compat_override) now alsoprocess the
paddle.compatroot package thatpkgutil.walk_packagesskips, so thetop-level functions (sort/min/max/split/median/unique/...) are mapped for both global
and scoped enable.
enable_compat(scope=...)while already global no longer silently downgrades to scoped;
use_compat_guardfaithfully restores the original finder state (so importing a scoped module no longer
destroys the surrounding scoped enable); and a leaked torch
ProxyModuleis clearedwhen restoring to scoped state.
nn/functional/flash_attention.py): aliasingpaddle.nn.functional.softmaxto the torch-style compat softmax (whosedim=Nonedefault picks a different axis than native
axis=-1) silently corrupted the sdpamath backend, because
_math_attentioncalledF.softmax(product)with no axis.Pass the axis explicitly (
F.softmax(product, -1)) so attention stays correct underenable_compat(); with compat off this is identical to the previous behavior.是否引起精度变化
否