Skip to content

[API Compatibility] enhance paddle.enable_compat -part#79391

Open
Manfredss wants to merge 8 commits into
PaddlePaddle:developfrom
Manfredss:patch_compat
Open

[API Compatibility] enhance paddle.enable_compat -part#79391
Manfredss wants to merge 8 commits into
PaddlePaddle:developfrom
Manfredss:patch_compat

Conversation

@Manfredss

@Manfredss Manfredss commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

PR Category

User Experience

PR Types

Improvements

Description

This PR adds an optional compatibility level to paddle.enable_compat. level=1 remains the default and preserves the existing compatibility behavior. level=2 includes all level=1 behavior and additionally dispatches aligned paddle.compat.* APIs through their corresponding paddle.* namespaces. Only public compat APIs declared in __all__ participate in this dispatch. Calls from user code use the compat implementation, while Paddle-internal calls
continue to use the original native implementation. Class APIs retain their class, inheritance, and type-checking semantics. Compat APIs without a corresponding paddle.* API, currently slogdet, are exposed only through the Torch proxy in level=2. paddle.disable_compat() restores all affected Paddle namespace entries. Therefore, existing level=1 users and previously passing tests are unaffected. Targeted tests cover namespace dispatch, restoration, class APIs, and slogdet.

是否引起精度变化

@risemeup1111 risemeup1111 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

发现了需要修复后再合入的兼容性回归,具体问题已放在行级评论中:主要是 paddle.compat 的 lazy attribute 行为被破坏,以及已有的 compat public API 被删除。CI 当前仍有部分任务进行中,且已有 Windows-GPU build/test 失败,请后续一并确认。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

Comment on lines 59 to 61
def __getattr__(name):
if name == "paddle_triton":
return paddle_triton_fun()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 优先级:P1

这里删掉了 distributions 的 lazy import 和最终的 AttributeError,导致两个回归:paddle.compat.distributions 在未预先 import paddle.compat.distributions 时会通过 __getattr__ 直接返回 None,未知属性也不再抛 AttributeError,会破坏 Python 模块属性协议以及已有的 paddle.compat.distributions 访问方式。请保留 distributions 分支,并让未知属性继续抛 AttributeError

Suggested change
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',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 优先级:P1

这里把 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")(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 优先级:P1

这里删除 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/reducebeta=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 适配逻辑
    ...

PaddlePaddle-bot

This comment was marked as outdated.

@PaddlePaddle-bot

PaddlePaddle-bot commented Jun 29, 2026

Copy link
Copy Markdown

CI 分析结果

本轮达到时间上限,未完成全部失败原因分析;未分析完的 job 标记为“分析省略/待后续深挖”。

PaddlePaddle-bot

This comment was marked as outdated.

PaddlePaddle-bot

This comment was marked as outdated.

@liuhao2638 liuhao2638 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复查当前提交。此前指出的 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 目前仍有任务运行中,后续也请一并确认。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

Comment thread python/paddle/compat/proxy.py Outdated
for attr_name in getattr(compat_module, PUBLIC_ATTR_DECLARATION):
if attr_name.startswith("_"):
continue
compat_attr = getattr(compat_module, attr_name)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 优先级:P1

这里会把每个 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
)

@zhwesky2010 zhwesky2010 changed the title [API Compatibility] enhance paddle.enable_compat() -part [API Compatibility] enhance paddle.enable_compat -part Jun 29, 2026
@Manfredss

Copy link
Copy Markdown
Contributor Author

/re-run all-failed

@codecov-commenter

codecov-commenter commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.48872% with 6 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (develop@dfa69d5). Learn more about missing BASE report.

Files with missing lines Patch % Lines
python/paddle/compat/api_dispatch.py 94.93% 4 Missing ⚠️
python/paddle/compat/utils.py 90.00% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             develop   #79391   +/-   ##
==========================================
  Coverage           ?   95.48%           
==========================================
  Files              ?        6           
  Lines              ?      133           
  Branches           ?        0           
==========================================
  Hits               ?      127           
  Misses             ?        6           
  Partials           ?        0           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.



@cache
def _register_compat_override():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果 paddle.compat.* 已经patch到 paddle.* 上了,这里还需要去额外操作吗

Comment thread python/paddle/compat/proxy.py Outdated
# 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:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里需要额外操作的原因是

Comment thread python/paddle/compat/proxy.py Outdated
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这些注释清理一下吧,如果确需要注释的话,也只是简短意赅的关键1~2行,不用长篇大论的写

_restore_paddle_namespace_aliases()


def enable_compat(

@zhwesky2010 zhwesky2010 Jun 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

直接改这个可能有点不兼容,加个level参数吧

@zhwesky2010

zhwesky2010 commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

背景

这个主要是解决当前的paddle框架中无法完全对齐的问题,当前Paddle API的对齐状态分为以下三种:

  1. 可以原位对齐;
  2. 无法原位对齐,但可以新增paddle.compat.*
  3. 既无法原位对齐,也无法新增paddle.compat.*,处于完全未对齐状态,分类2的类方法API普遍为此状态,例如paddle.Tensor.max/min/split

用户在编写paddle时,很难知道哪些是对齐的1,哪些是未对齐的2/3,这使得编写paddle代码成本仍较高。
因此计划引入一个Flag开关,将2/3直接切换为pytorch形态,用户无需再关注1/2/3的名单,统一直接按pytorch思路来写代码即可

开发思路

目前考虑在enable_compat最后面加一个level参数,默认为1,对于:

  • level=1:维持之前的逻辑不变
torch.* -> paddle.*(paddle.compat.*)

paddle.*:部分API无法原位对齐torch
  • level=2:除了当前的torch重定向逻辑,还将进行paddle.compat->paddle、paddle.compat->paddle.Tensor的重定向逻辑,消除上述分类2/3的未对齐状态
torch.* -> paddle.*

paddle.*:完全对齐torch形态

针对 第三方库+存量Paddle代码 的用法:level=1,部分API无法对齐,需手动检查调整,主要为避免存量paddle代码出现不兼容

针对 第三方库+新增Paddle代码 的用法:level=2,完全对齐,统一按torch的形态即可

@SigureMo 看下这样的设计思路怎么样,有没有要调整的地方?比如 不加level直接按2来、加level但默认为2、新增一个其他API来作为这个开关不用放到enable_compat里

@zhwesky2010
zhwesky2010 requested a review from SigureMo June 29, 2026 12:45

@SigureMo SigureMo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

针对 第三方库+存量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")(

@SigureMo SigureMo Jun 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

我有个疑问,既然是 patch,那么一旦开启 compat,所有相关 API 都会变吧?为什么当前改动仅限于 paddle.compat 下?非 compat 下的 API 理论上也会受到影响吧?(只是问题并不是像递归这么明显罢了)

当然不是让你把所有 API 改一遍,而是我在想这样做的可行性

@SigureMo SigureMo Jun 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

其实这也很好做,改造一下:

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

随便搞的原型,仅供参考

Comment on lines +177 to +186
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()

@SigureMo SigureMo Jun 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这种单测不能直接用 @use_compat_guard 装饰器么?

@zhwesky2010 zhwesky2010 Jun 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Manfredss 对于整个框架内部,调用到这些compat系列API的地方(约30个),确实应该都是paddle naive版的,而这一系列API对外呈现的则是torch版的。

这个主要影响到的是 单测 + 部分调用paddle API的组合实现API。

可能得加大一下测试面,比如level=2下,paddle其他的API还能否跑过,除了paddle自身测试外,建议在paconvert里也进行测试(全局设置为level=2),测量全量API的行为是否正常。

@paddle-bot paddle-bot Bot added the contributor External developers label Jun 29, 2026
@Manfredss

Manfredss commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

paddle.enable_compat 增加 level 参数:level=2paddle.* 直接呈现 torch 形态

背景:Paddle API 对齐分三类:

  1. 可原位对齐;
  2. 无法原位、但有 paddle.compat.*
  3. 类方法等无法对齐。用户难以区分、编写成本高。目标是用一个开关把 2 和 3 统一切到 torch 形态,用户统一按 torch 思路写代码。

设计:enable_compat(level=...)

  • level=1(默认):维持现状——仅安装 import torch → paddle 代理,不改写 paddle.*,对存量代码零影响(完全向后兼容)。
  • level=2:在此基础上把 torch 对齐的 paddle.compat.* 路由到 paddle.*,用户可直接按 torch 形态写 paddle 代码。

level=2 关键实现

  • 函数用 dispatcher 包装、类直接别名;enable/disable 仅切全局标志,suspendcontextvars
  • 调用方感知:仅当调用方不是 paddle.* 模块时才走 compat —— paddle 内部约 130 处调用(F.softmax/paddle.max 等,传原生 axis=/name=)一律拿原生实现,故 TransformerEncoderLayer、原生 MultiHeadAttention 等组合层在 level=2 下正常运行

测试

  • 新增命名空间别名 + level=2 单测;本 PR 仅改动 paddle/compat/,不触碰 paddle 核心。
  • paconvert 转换后注入 enable_compat(level=2),其现有全量 API 单测即为 level=2 的全量行为测量。

PaddlePaddle-bot

This comment was marked as outdated.

PaddlePaddle-bot

This comment was marked as outdated.

PaddlePaddle-bot

This comment was marked as outdated.

@Manfredss

Copy link
Copy Markdown
Contributor Author

/re-run all-failed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) aliases paddle.* to paddle.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.

Comment on lines 840 to 842
def extra_repr(self) -> str:
return f"dim={self._dim}"
return f"dim={self.dim}"

Comment thread python/paddle/compat/proxy.py Outdated
Comment on lines +418 to +422
# (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] = {}

PaddlePaddle-bot

This comment was marked as outdated.

@Manfredss

Copy link
Copy Markdown
Contributor Author

/re-run all-failed

@Manfredss
Manfredss requested a review from risemeup1111 July 1, 2026 08:54
@Manfredss

Copy link
Copy Markdown
Contributor Author

/re-run all-failed

PaddlePaddle-bot

This comment was marked as outdated.

@Manfredss

Copy link
Copy Markdown
Contributor Author

/re-run all-failed

@risemeup1111 risemeup1111 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复查当前提交。上次的 root compat-only torch.slogdet 暴露问题已通过 level=2 专用路径补上,level=1 行为未被改动;本轮没有新增行级评论。

  • P2 优先级:P2 非行级:跨仓验证不在 changed diff line 上。此前 PaConvert 验证项仍未看到作者在本 PR 中明确回复;如果对应验证已经完成,请回复确认验证记录,或说明剩余失败与本 PR 无关。

    处理要求:请针对该评论进行回复(同意并已修改请回复 Done,不同意请说明理由)。

  • P3 优先级:P3 非行级:PR 描述不在 changed diff line 上。当前描述仍按 plain paddle.enable_compat() 即启用 alias、_native helper、以及 flash_attention.py 显式修改来表述;当前实现实际是 level=2 才启用 caller-aware alias,compat-only root 符号也通过 torch proxy 的 level=2 专用路径补齐。请把描述同步到当前语义。

    处理要求:请针对该评论进行回复(同意并已修改请回复 Done,不同意请说明理由)。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

@Manfredss

Copy link
Copy Markdown
Contributor Author

/re-run all-failed

1 similar comment
@Manfredss

Copy link
Copy Markdown
Contributor Author

/re-run all-failed

@Manfredss

Copy link
Copy Markdown
Contributor Author

Fleet 失败貌似是 CI 问题

@Manfredss

Copy link
Copy Markdown
Contributor Author

/re-run all-failed

Comment thread python/paddle/compat/api_dispatch.py Outdated
# symbol, so ``disable_compat()`` can restore the paddle namespace.
_PADDLE_NAMESPACE_SAVED: dict[tuple[types.ModuleType, str], Any] = {}

_COMPAT_ENABLED = False

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个flag也是冗余的,直接判断_PADDLE_NAMESPACE_SAVED是否为空就行

Comment thread python/paddle/compat/api_dispatch.py Outdated
_COMPAT_ENABLED = False


def is_compat_api_enabled() -> bool:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个接口就不需要了,直接判断len(_PADDLE_NAMESPACE_SAVED)

Comment thread python/paddle/compat/proxy.py Outdated
_PADDLE_NAMESPACE_SAVED,
_apply_paddle_namespace_aliases,
_restore_paddle_namespace_aliases,
is_compat_api_enabled,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个可以去掉

Comment thread python/paddle/compat/proxy.py Outdated
for k, v in GLOBAL_OVERRIDES.items()
if k.startswith(f"{fullname}.")
}
if fullname == "torch" and is_compat_api_enabled():

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里改动原因是?对level=1产生了影响吗

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#79391 (comment)

没有对 level=1 产生影响



@contextmanager
def use_compat_guard(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个接口不要改动,只针对enable_compat/disable_compat最小范围生效

Comment thread python/paddle/compat/api_dispatch.py Outdated
paddle.compat.__path__,
paddle.compat.__name__ + ".",
):
yield importlib.import_module(module_info.name)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里严格判断一下,只针对具备 __all__ 的文件才需要进行迭代dispatch,减少无意义的干扰

global _COMPAT_ENABLED

for compat_module in _iter_compat_modules():
target_name = compat_module.__name__.replace(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果没有__all__,直接continue,不要浪费时间import_module

Comment thread python/paddle/compat/api_dispatch.py Outdated

for attr_name in getattr(compat_root, "__all__", ()):
native_method = getattr(paddle.Tensor, attr_name, None)
if native_method is None or not callable(native_method):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不要判断:not callable(native_method)

后面会将 方法patch为属性、属性patch为方法,无需过度判断

if current is None or current is compat_attr:
continue
_PADDLE_NAMESPACE_SAVED[(target_module, attr_name)] = current
if isinstance(compat_attr, type):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

回复下,这个分支是什么case?

@Manfredss Manfredss Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个分支处理 paddle.compat.nn.Linear 等 class 类的 API

class 除了可调用外,还需要保留继承和 isinstance / issubclass 这样的语义,故不能使用普通函数 dispatcher;这里使用 caller-aware metaclass,在实例化时让外部调用进入 compat class、paddle 内部调用进入 native class,同时保持例如 paddle.nn.Linear 仍然是合法的类型

@risemeup1111 risemeup1111 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复查当前 head。上轮的 root torch.slogdet 暴露问题看起来已经处理完,但这次 use_compat_guard 的恢复语义又回退了,详细说明在行级评论里。

  • P2 优先级:P2 非行级:PaConvert 跨仓验证记录仍未看到明确回复;请补充确认验证结果,或说明剩余失败与本 PR 无关。

  • P3 优先级:P3 非行级:PR 描述仍按“默认 enable_compat() 即启用 alias”来写,和当前 level=1/2 语义不一致;请同步为 enable_compat(level=2) 才开启 paddle.* alias,level=1 保持原 proxy 行为。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

"""
if TORCH_PROXY_FINDER in sys.meta_path:
sys.meta_path.remove(TORCH_PROXY_FINDER)
_restore_paddle_namespace_aliases()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 优先级:P1
处理要求:请针对该评论修复并提交新的 commit。

这里把 _restore_paddle_namespace_aliases() 挂到 disable_compat() 里之后,use_compat_guard() 退出时就不再会把外层的 level=2 namespace alias 恢复回来。enable=False 分支会先 disable_compat() 清空 _PADDLE_NAMESPACE_SAVED,随后只恢复 torch proxy;enable=True 分支也会在 disable_compat() 之后丢掉外层的 paddle.sort / paddle.nn.Linear 等 alias。结果是外层 enable_compat(level=2) 进入 guard 后,退出时会被永久降回 level=1 语义。

建议保留一份“是否需要恢复 alias”的状态,并在 use_compat_guard() 两个 finally 分支里,在恢复 finder 状态后再把 namespace alias 重新装回去:

restore_namespace_aliases = bool(_PADDLE_NAMESPACE_SAVED)
...
disable_compat()
if restore_namespace_aliases:
    _apply_paddle_namespace_aliases()
...
enable_compat(scope=None, silent=True)
if restore_namespace_aliases:
    _apply_paddle_namespace_aliases()

另外,这次把原来覆盖这一行为的 test_use_compat_guard_nested / test_scoped_guard_restores_level2_alias / test_scoped_enable_survives_scoped_module_import 都删掉了,当前没有回归测试兜住这个退化。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhwesky2010 zhwesky2010 Jul 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SigureMo 这个机器人评论看看对吗,需要改吗,如果use_compat_guard没有level参数,按道理不需要管level=2的情况

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不需要给 use_compat_guard 新增 level 参数。这里的关键不是“透传一个新 level”,而是 use_compat_guard 在进入/退出时要恢复调用前的完整 compat 状态:如果外层已经通过 enable_compat(level=2) 打开了 namespace alias,那么 guard 退出后也必须把这层 alias 重新装回去,否则就会把外层状态永久降回 level=1。所以当前需要修的是 guard 的恢复逻辑,而不是把 level=2 作为新参数往下透传。

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhwesky2010 如果两者(enable_compat(level=2)use_compat_guard)没有混合的场景,那确实不需要加,如果保证没有这种使用场景的话,我觉得这里不需要改,否则确实应该加 level 参数

@risemeup1111 请等待确认,如果确认无该使用方法这条 review 就忽略吧

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@risemeup1111 不支持use_compat_guard使用,没有混用的场景,level=2计划仅支持enable_compat中使用

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 优先级:P1
处理要求:请针对该评论修复并提交新的 commit;如果最终确认不支持这种混用场景,也需要把相关测试/语义同步收紧。

这条不能按“原 PR 没改到这里所以忽略”处理。当前 use_compat_guard 本身就是公开的可嵌套接口,proxy.py 内部也在用它包住 find_spec / exec_module,而且 test_torch_proxy.py 已经覆盖了 enable=True/False 的嵌套切换。按现有实现,外层 enable_compat(level=2) 进入 use_compat_guard(enable=False) 后,退出时确实会丢掉 namespace alias。

所以结论是:如果项目要支持这种混用,还是需要补恢复逻辑;只有在明确声明“不支持 level=2use_compat_guard 混用”时,这条才能忽略。

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

收到。既然这里明确 不支持 use_compat_guardenable_compat(level=2) 混用,那这条关于 guard 退出后恢复 level=2 alias 的问题就可以按不适用处理,当前实现这里不需要再改。

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

只有在明确声明“不支持 level=2use_compat_guard 混用”时,这条才能忽略。

已经明确了

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

收到,既然已经明确 enable_compat(level=2)use_compat_guard 的混用不在支持范围内,这条关于 guard 退出后恢复 level=2 alias 的 concern 按 superseded 处理,不再作为阻塞项。

@Manfredss

Manfredss commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

已复查当前提交。上次的 root compat-only torch.slogdet 暴露问题已通过 level=2 专用路径补上,level=1 行为未被改动;本轮没有新增行级评论。

  • P2 优先级:P2 非行级:跨仓验证不在 changed diff line 上。此前 PaConvert 验证项仍未看到作者在本 PR 中明确回复;如果对应验证已经完成,请回复确认验证记录,或说明剩余失败与本 PR 无关。
    处理要求:请针对该评论进行回复(同意并已修改请回复 Done,不同意请说明理由)。
  • P3 优先级:P3 非行级:PR 描述不在 changed diff line 上。当前描述仍按 plain paddle.enable_compat() 即启用 alias、_native helper、以及 flash_attention.py 显式修改来表述;当前实现实际是 level=2 才启用 caller-aware alias,compat-only root 符号也通过 torch proxy 的 level=2 专用路径补齐。请把描述同步到当前语义。
    处理要求:请针对该评论进行回复(同意并已修改请回复 Done,不同意请说明理由)。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

  • P2 Done
  • P3 Done

@Manfredss

Copy link
Copy Markdown
Contributor Author

已复查当前 head。上轮的 root torch.slogdet 暴露问题看起来已经处理完,但这次 use_compat_guard 的恢复语义又回退了,详细说明在行级评论里。

  • P2 优先级:P2 非行级:PaConvert 跨仓验证记录仍未看到明确回复;请补充确认验证结果,或说明剩余失败与本 PR 无关。
  • P3 优先级:P3 非行级:PR 描述仍按“默认 enable_compat() 即启用 alias”来写,和当前 level=1/2 语义不一致;请同步为 enable_compat(level=2) 才开启 paddle.* alias,level=1 保持原 proxy 行为。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

  • P2 Done
  • P3 Done

@Manfredss

Copy link
Copy Markdown
Contributor Author

/re-run all-failed

@zhwesky2010

zhwesky2010 commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

@SigureMo 整体简化并人工重写了一版,辛苦再review下

Comment thread python/paddle/compat/api_dispatch.py Outdated
return native_cls(*args, **kwargs)
return super().__call__(*args, **kwargs)

def __instancecheck__(cls, instance: Any) -> bool:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个建议这么改:给paddle.compat.nn.Linear 加一个metaclass,使其即可以被判断为paddle.nn.Linear

即使没有patch时也支持这样判断,dispatch无需做处理

@zhwesky2010
zhwesky2010 requested review from SigureMo and removed request for PaddlePaddle-bot July 20, 2026 03:59
for attr_name in getattr(compat_root, "__all__", ())
if not hasattr(source_module, attr_name)
}
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里是针对什么场景?_register_compat_override 会漏掉吗?总感觉在这里加很奇怪啊

@zhwesky2010 zhwesky2010 Jul 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@risemeup1111 这里能否不修改

"""
if TORCH_PROXY_FINDER in sys.meta_path:
sys.meta_path.remove(TORCH_PROXY_FINDER)
_restore_paddle_namespace_aliases()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zhwesky2010 如果两者(enable_compat(level=2)use_compat_guard)没有混合的场景,那确实不需要加,如果保证没有这种使用场景的话,我觉得这里不需要改,否则确实应该加 level 参数

@risemeup1111 请等待确认,如果确认无该使用方法这条 review 就忽略吧

@risemeup1111 risemeup1111 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复查当前提交。前面关于 enable_compat(level=2)use_compat_guard 混用的 concern 现已明确不在支持范围内,可按 superseded 处理;其余已跟进的点也没有新的阻塞项。整体看起来可以合入。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

@Manfredss
Manfredss requested a review from risemeup1111 July 20, 2026 07:46

@risemeup1111 risemeup1111 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已复查新提交。此前 use_compat_guardlevel=2 混用的 concern 仍按不支持场景处理,不再作为阻塞项;这次新增的 Linear metaclass 调整里发现一个 class alias 类型判定回退,详细见行级评论,需要修复后再合入。

我做了 Python 语法编译和 git diff --check,都通过;完整 Paddle 单测在当前源码目录缺少已安装 wheel / libpaddle,未能本地执行。

Powered by Nyanpasu with gpt-5.5 xhigh, please check the suggestions carefully.

Comment on lines +103 to +111
def __call__(cls, *args: Any, **kwargs: Any) -> Any:
if cls is proxy:
if (
len(_PADDLE_NAMESPACE_SAVED) > 0
and not _caller_is_paddle_internal()
):
return compat_cls(*args, **kwargs)
return native_cls(*args, **kwargs)
return super().__call__(*args, **kwargs)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 优先级:P1
处理要求:请针对该评论修复并提交新的 commit。

这里删掉 proxy 自身的 __instancecheck__ / __subclasscheck__ 后,level=2 下的 class alias 会丢掉基本类型判定语义:paddle.nn.Linear 被替换成这个 proxy,但外部调用 paddle.nn.Linear(...) 实际返回的是 compat_cls(...),也就是 paddle.compat.nn.Linear 实例,而不是 proxy 实例。因此 isinstance(paddle.nn.Linear(2, 2), paddle.nn.Linear) 会变成 Falseissubclass(paddle.compat.nn.Linear, paddle.nn.Linear) 也会变成 False。这和 PR 描述里“Class APIs retain ... type-checking semantics”的目标不一致,也会影响依赖 isinstance(module, paddle.nn.Linear) 的迁移代码。

可以把类型判定保留在 proxy 这一层,但只对 cls is proxy 生效,避免影响用户从 proxy 派生出来的子类:

Suggested change
def __call__(cls, *args: Any, **kwargs: Any) -> Any:
if cls is proxy:
if (
len(_PADDLE_NAMESPACE_SAVED) > 0
and not _caller_is_paddle_internal()
):
return compat_cls(*args, **kwargs)
return native_cls(*args, **kwargs)
return super().__call__(*args, **kwargs)
def __call__(cls, *args: Any, **kwargs: Any) -> Any:
if cls is proxy:
if (
len(_PADDLE_NAMESPACE_SAVED) > 0
and not _caller_is_paddle_internal()
):
return compat_cls(*args, **kwargs)
return native_cls(*args, **kwargs)
return super().__call__(*args, **kwargs)
def __instancecheck__(cls, instance: Any) -> bool:
if cls is proxy:
return isinstance(instance, (native_cls, compat_cls))
return super().__instancecheck__(instance)
def __subclasscheck__(cls, subclass: Any) -> bool:
if cls is proxy:
return issubclass(subclass, native_cls) or issubclass(
subclass, compat_cls
)
return super().__subclasscheck__(subclass)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已在 /python/paddle/compat/utils.py 中使用 metaclass 的方式实现了

Comment thread python/paddle/compat/nn/__init__.py Outdated


class Linear(nn.Layer):
_NATIVE_LINEAR = nn.Linear

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里不要加这些多余变量

nn/_init_.py里的class都需要做处理

有没什么低成本的写法

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

那我的理解就是对所有参与 patch 且存在对应 paddle.nn.* 实现的 paddle.compat.nn 类复用一个通用 metaclass,统一处理 native/compat 的 isinstanceissubclass 语义?

@zhwesky2010 zhwesky2010 Jul 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

所有的 paddle.compat.* 类 都可以被判定为paddle.*类,无论是否dispatch,都支持这样判断

yield compat_module


def _make_caller_aware_class_proxy(native_cls: type, compat_cls: type) -> type:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个还是需要吗,直接用paddle.compat.nn.Linear patch paddle.nn.Linear会有什么问题?

@Manfredss Manfredss Jul 20, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

外部调用场景下,直接用 paddle.compat.nn.Linear patch paddle.nn.Linear 应该是没有问题的,但现在 proxy 类还有让 Paddle 内部调用仍构造 native 类的功能,删掉会影响 Paddle 内部调用,比如像 fleet/layers/mpu/mp_ops.py 第 649 行会传入 weight_attrbias_attr 等参数:

paddle.nn.Linear(
    ...,
    weight_attr=param_attr,
    bias_attr=bias_attr,
    name=name,
)

而 compat Linear 没有这些参数;install_check.py 第 109 行也有类似的调用

@zhwesky2010

@zhwesky2010 zhwesky2010 Jul 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Manfredss
内部调用应该dispatch到native_fn,外部调用才dispatch到compat_fn,是fleet/layers/mpu/mp_ops.py没有触发内部调用的判定吗

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mp_ops._parallel_linear 能触发内部调用判定。当前调用路径是 _parallel_linear -> _CompatAwareMeta.__call__ -> _caller_is_paddle_internal,会返回 native 类。直接用 compat 类覆盖 native 类时失败,是因为直接赋值会绕过 dispatcher

@Manfredss
Manfredss requested a review from risemeup1111 July 20, 2026 12:12
@Manfredss

Copy link
Copy Markdown
Contributor Author

/re-run all-failed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants