diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-79197/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/README.md new file mode 100644 index 000000000..ca662869c --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/README.md @@ -0,0 +1,44 @@ +# PaddlePaddle__Paddle-79197 + +This directory converts Paddle PR #79197 into a SWE-Paddle community task candidate. + +## Source + +| Field | Value | +| --- | --- | +| Repo | `PaddlePaddle/Paddle` | +| PR | [79197](https://github.com/PaddlePaddle/Paddle/pull/79197) | +| PR title | `[API Compatibility] Support param optimizer for lr_scheduler` | +| Base commit | `06d8af53d39ef6622689bab27e1cd03a2ffab0f3` | +| Merged at | `2026-06-08T06:44:24Z` | +| Task type | `feature_enhancement` | +| Resource | CPU | + +## Summary + +Allow commonly used learning-rate schedulers to accept an existing optimizer directly and automatically associate themselves with that optimizer, while preserving the existing `learning_rate` calling convention. + +## Why This Is A Good SWE-Paddle Candidate + +* The issue reflects a common scheduler API mismatch encountered when migrating training code, with clear trigger conditions and expected behavior. +* The change covers shared argument-handling logic used by multiple schedulers and cannot be solved through a one-off special case. +* The source PR provides real tests covering positional and keyword arguments, learning-rate updates, and the association between schedulers and optimizers. +* The tests run on CPU without external datasets, network access, or distributed devices. + +## Files + +- `proposal.md`: candidate proposal for maintainer triage. +- `instruction.md`: self-contained problem statement for the coding agent. +- `solution/code.patch`: production-only gold patch from the merged PR. +- `tests/test.patch`: exact upstream diff for `test/legacy_test/test_lr_scheduler.py`. +- `tests/test.sh`: minimal target test command. +- `environment/README.md`: environment notes for reproduction. +- `README.md`: task overview and verification entrypoint. + +## Verification + +```bash +bash tests/test.sh +``` + +Expected behavior: applying `tests/test.patch` to `base_commit` should fail when schedulers receive an optimizer; applying both `tests/test.patch` and `solution/code.patch` should pass the complete upstream test file. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-79197/environment/README.md b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/environment/README.md new file mode 100644 index 000000000..ffd5e2293 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/environment/README.md @@ -0,0 +1,27 @@ +# Environment Notes + +This candidate is part of the SWE-Paddle community task set. + +## Expected Environment + +- Repository: `PaddlePaddle/Paddle` +- Base commit: `06d8af53d39ef6622689bab27e1cd03a2ffab0f3` +- Resource: CPU +- GPU required: no +- Build path: Python-only runtime overlay; no Paddle source build is required when a compatible Paddle wheel is available. + +## Run Order + +1. Check out `PaddlePaddle/Paddle` at the base commit. +2. Apply `tests/test.patch`. +3. Run `bash tests/test.sh`; the target behavior should fail before the fix. +4. Apply `solution/code.patch`. +5. Run `bash tests/test.sh` again; the target behavior should pass after the gold patch. + +## Minimal Test Command + +```bash +bash tests/test.sh +``` + +The verifier is responsible for deriving stable F2P and P2P node IDs from repeated runs. diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-79197/instruction.md b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/instruction.md new file mode 100644 index 000000000..944bc41ff --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/instruction.md @@ -0,0 +1,22 @@ +# 让 learning-rate scheduler 可以直接接收 optimizer + +## 详细描述 + +很多训练代码会先创建 optimizer,再把这个 optimizer 传给 learning-rate scheduler。这样 scheduler 可以直接使用 optimizer 当前的学习率,并在后续训练中负责更新它。 + +目前 Paddle 的常用 scheduler 只接受一个数值形式的 `learning_rate`。开发者把 optimizer 作为位置参数或使用 `optimizer=` 传入时,会收到参数类型错误或不支持该参数的报错。即使手动取出学习率创建 scheduler,还需要额外处理 optimizer 和 scheduler 的关联,迁移代码比较麻烦。 + +需要让常用 scheduler 同时支持两种写法:继续接受原来的数值学习率,也可以直接接受已经创建好的 optimizer。使用 optimizer 创建 scheduler 后,scheduler 应从 optimizer 取得初始学习率,并由 optimizer 在训练过程中使用。 + +## 验收说明 + +- 常用 scheduler 可以通过位置参数或 `optimizer=` 接收已有 optimizer,并使用它当前的学习率。 +- 创建完成后,optimizer 应使用这个 scheduler;调用 `step()` 时,学习率仍按各 scheduler 原有规则变化。 +- 原有的 `learning_rate` 数值调用方式和计算结果保持不变。 +- 同时传入 `learning_rate` 和 `optimizer` 时,应给出清楚的参数冲突错误。 + +## 技术要求 + +- 熟悉 PaddlePaddle optimizer 和 learning-rate scheduler 的使用方式。 +- 熟悉 Python 函数的位置参数、关键字参数和参数校验。 +- 能够验证 scheduler 与 optimizer 的关联以及学习率变化结果。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-79197/proposal.md b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/proposal.md new file mode 100644 index 000000000..b6e34e655 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/proposal.md @@ -0,0 +1,56 @@ +# Task Proposal: PaddlePaddle__Paddle-79197 + +## 1. 来源信息 + +- Instance ID:`PaddlePaddle__Paddle-79197` +- PR 链接:https://github.com/PaddlePaddle/Paddle/pull/79197 +- PR 标题:`[API Compatibility] Support param optimizer for lr_scheduler` +- `base_commit`:`06d8af53d39ef6622689bab27e1cd03a2ffab0f3` +- merged 时间:`2026-06-08T06:44:24Z` +- 你的身份:熟悉该模块的 contributor +- 后续联系人:TBD + +## 2. 问题一句话 + +常用 learning-rate scheduler 只能接收数值学习率,不能直接接收已经创建好的 optimizer,导致兼容写法报错且无法自动关联二者。 + +## 3. 为什么适合作为 SWE-Paddle 样本 + +- **真实性**:训练代码迁移时,先创建 optimizer、再把 optimizer 交给 scheduler 是常见写法。 +- **代表性**:任务涉及多个 scheduler 的一致参数行为,以及 scheduler 与 optimizer 的状态关联。 +- **边界清楚**:只调整 learning-rate scheduler 的初始化兼容性,不修改优化算法、算子或训练结果计算。 +- **非平凡性**:需要同时支持位置参数和关键字参数,处理冲突输入,并确保各 scheduler 的学习率曲线不变。 +- **环境友好性**:来源 PR 单测使用小型 CPU 网络和本地随机输入,不依赖 GPU、外部数据或网络。 + +## 4. 任务类型和标签 + +- 任务类型:`feature_enhancement` +- 执行后端:`cpu` +- 设备范围:`cpu_only` +- 模块标签:`[optimizer, lr-scheduler, api-compatibility]` + +## 5. 验证思路 + +- 目标测试命令:`bash tests/test.sh` +- 目标测试文件:`test/legacy_test/test_lr_scheduler.py` +- 修复前预期:新增的 optimizer 参数测试失败;已有 `learning_rate` 调用测试通过。 +- 修复后预期:optimizer 可通过位置参数或关键字参数传入,scheduler 使用 optimizer 当前学习率并被 optimizer 持有,PR 新增的六个目标用例与已有 regression case 全部通过。 +- P2P 候选:`TestCosineAnnealingWarmRestarts::test_CosineRestartsLR` +- F2P 候选:`test_exponential_decay`、`test_cosine_annealing_decay`、`test_cosine_annealing_warm_restarts`、`test_multi_step_decay`、`test_reduce_on_plateau`、`test_step_decay` + +## 6. 环境与资源 + +- 资源需求:CPU +- Paddle 来源:`PaddlePaddle/Paddle` source checkout at `base_commit` +- 是否能提供 Docker:暂无 +- patch 类型:Python-only +- 环境建议:使用兼容的已安装 Paddle wheel 承载运行时,由 verifier 覆盖 checkout 中两个精确 Python production files。 +- 最小测试命令:`bash tests/test.sh` +- 是否有 oracle 日志:由 SWE-Paddle verifier 结果另行维护 + +## 7. 风险自查 + +- 泄露风险:instruction 只描述开发者遇到的调用问题和期望行为,不说明 Gold patch 的具体实现方式。 +- 环境风险:测试会进行小规模 CPU 前向、反向和 optimizer step,需要已安装 Paddle,但无需源码编译。 +- flaky 风险:上游测试不使用网络、并发、外部数据集或随机时序,只验证确定的学习率序列和对象关联。 +- 拆分风险:所有变更共同解决 scheduler 接收 optimizer 的兼容调用问题,没有混入其他功能。 diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-79197/solution/code.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/solution/code.patch new file mode 100644 index 000000000..3affbb806 --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/solution/code.patch @@ -0,0 +1,312 @@ +diff --git a/python/paddle/optimizer/lr.py b/python/paddle/optimizer/lr.py +index 385bf9e4dd6a49a5c8b36cf95f05c6a87537358f..09f161a2169b5333338b513793a54913a0b426a2 100644 +--- a/python/paddle/optimizer/lr.py ++++ b/python/paddle/optimizer/lr.py +@@ -20,7 +20,7 @@ from typing import TYPE_CHECKING, Any, Callable, Literal, TypedDict + + import numpy + import numpy.typing as npt +-from typing_extensions import NotRequired ++from typing_extensions import NotRequired, overload + + import paddle + from paddle import Tensor +@@ -32,6 +32,10 @@ from paddle.base.framework import ( + in_dygraph_mode, + ) + from paddle.base.layer_helper import LayerHelper ++from paddle.utils.decorator_utils import ( ++ lr_scheduler_decorator, ++ param_one_alias, ++) + + if TYPE_CHECKING: + from collections.abc import Sequence +@@ -144,6 +148,23 @@ class LRScheduler: + last_epoch: int + verbose: bool + ++ @overload ++ def __init__( ++ self, ++ learning_rate: float = 0.1, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @overload ++ def __init__( ++ self, ++ optimizer: paddle.optimizer.Optimizer, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @lr_scheduler_decorator() + def __init__( + self, + learning_rate: float = 0.1, +@@ -152,7 +173,7 @@ class LRScheduler: + ) -> None: + if not isinstance(learning_rate, (float, int)): + raise TypeError( +- f"The type of learning rate must be float, but received {type(learning_rate)}" ++ f"The type of param learning_rate or optimizer must be int, float or paddle.optimizer.Optimizer, but received {type(learning_rate)}" + ) + if learning_rate < 0: + raise ValueError(f"Invalid learning rate: {learning_rate}") +@@ -1089,6 +1110,25 @@ class ExponentialDecay(LRScheduler): + + gamma: float + ++ @overload ++ def __init__( ++ self, ++ learning_rate: float, ++ gamma: float, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @overload ++ def __init__( ++ self, ++ optimizer: paddle.optimizer.Optimizer, ++ gamma: float, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @lr_scheduler_decorator() + def __init__( + self, + learning_rate: float, +@@ -1196,6 +1236,7 @@ class MultiStepDecay(LRScheduler): + milestones: Sequence[int] + gamma: float + ++ @overload + def __init__( + self, + learning_rate: float, +@@ -1203,7 +1244,27 @@ class MultiStepDecay(LRScheduler): + gamma: float = 0.1, + last_epoch: int = -1, + verbose: bool = False, +- ): ++ ) -> None: ... ++ ++ @overload ++ def __init__( ++ self, ++ optimizer: paddle.optimizer.Optimizer, ++ milestones: Sequence[int], ++ gamma: float = 0.1, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @lr_scheduler_decorator() ++ def __init__( ++ self, ++ learning_rate: float, ++ milestones: Sequence[int], ++ gamma: float = 0.1, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: + if not isinstance(milestones, (tuple, list)): + raise TypeError( + f"The type of 'milestones' in 'MultiStepDecay' must be 'tuple, list', but received {type(milestones)}." +@@ -1317,6 +1378,27 @@ class StepDecay(LRScheduler): + step_size: int + gamma: float + ++ @overload ++ def __init__( ++ self, ++ learning_rate: float, ++ step_size: int, ++ gamma: float = 0.1, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @overload ++ def __init__( ++ self, ++ optimizer: paddle.optimizer.Optimizer, ++ step_size: int, ++ gamma: float = 0.1, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @lr_scheduler_decorator() + def __init__( + self, + learning_rate: float, +@@ -1548,6 +1630,38 @@ class ReduceOnPlateau(LRScheduler): + min_lr: float + epsilon: float + ++ @overload ++ def __init__( ++ self, ++ learning_rate: float, ++ mode: Literal["min", "max"] = 'min', ++ factor: float = 0.1, ++ patience: int = 10, ++ threshold: float = 1e-4, ++ threshold_mode: Literal["rel", "abs"] = 'rel', ++ cooldown: int = 0, ++ min_lr: float = 0, ++ epsilon: float = 1e-8, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @overload ++ def __init__( ++ self, ++ optimizer: paddle.optimizer.Optimizer, ++ mode: Literal["min", "max"] = 'min', ++ factor: float = 0.1, ++ patience: int = 10, ++ threshold: float = 1e-4, ++ threshold_mode: Literal["rel", "abs"] = 'rel', ++ cooldown: int = 0, ++ min_lr: float = 0, ++ eps: float = 1e-8, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @lr_scheduler_decorator() ++ @param_one_alias(["epsilon", "eps"]) + def __init__( + self, + learning_rate: float, +@@ -1580,7 +1694,7 @@ class ReduceOnPlateau(LRScheduler): + self.threshold_mode = threshold_mode + if not isinstance(learning_rate, (float, int)): + raise TypeError( +- f"The type of 'learning_rate' in 'ReduceOnPlateau' must be 'float', but received {type(learning_rate)}." ++ f"The type of param learning_rate or optimizer must be int, float or paddle.optimizer.Optimizer, but received {type(learning_rate)}" + ) + + self.patience = patience +@@ -1777,6 +1891,27 @@ class CosineAnnealingDecay(LRScheduler): + eta_min: float + last_epoch: int + ++ @overload ++ def __init__( ++ self, ++ learning_rate: float, ++ T_max: int, ++ eta_min: float = 0, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @overload ++ def __init__( ++ self, ++ optimizer: paddle.optimizer.Optimizer, ++ T_max: int, ++ eta_min: float = 0, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @lr_scheduler_decorator() + def __init__( + self, + learning_rate: float, +@@ -2573,6 +2708,7 @@ class CosineAnnealingWarmRestarts(LRScheduler): + eta_min: float + T_cur: int + ++ @overload + def __init__( + self, + learning_rate: float, +@@ -2581,7 +2717,29 @@ class CosineAnnealingWarmRestarts(LRScheduler): + eta_min: float = 0, + last_epoch: int = -1, + verbose: bool = False, +- ): ++ ) -> None: ... ++ ++ @overload ++ def __init__( ++ self, ++ optimizer: paddle.optimizer.Optimizer, ++ T_0: int, ++ T_mult: int = 1, ++ eta_min: float = 0, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: ... ++ ++ @lr_scheduler_decorator() ++ def __init__( ++ self, ++ learning_rate: float, ++ T_0: int, ++ T_mult: int = 1, ++ eta_min: float = 0, ++ last_epoch: int = -1, ++ verbose: bool = False, ++ ) -> None: + if T_0 <= 0 or not isinstance(T_0, int): + raise ValueError(f"Expected positive integer T_0, but got {T_0}") + if T_mult < 1 or not isinstance(T_mult, int): +diff --git a/python/paddle/utils/decorator_utils.py b/python/paddle/utils/decorator_utils.py +index 563d148645df81a87fc1e1f5332da8945dd74167..eb2d273ed2b7343cab73e18886c566c5b7d06993 100644 +--- a/python/paddle/utils/decorator_utils.py ++++ b/python/paddle/utils/decorator_utils.py +@@ -1189,6 +1189,44 @@ def batch_sampler_decorator() -> Callable[ + return decorator + + ++def lr_scheduler_decorator() -> Callable[ ++ [Callable[_InputT, _RetT]], Callable[_InputT, _RetT] ++]: ++ """ ++ Usage Example: ++ PyTorch: __init__(self, optimizer, last_epoch) -> None: ++ Paddle: __init__(self, learning_rate, last_epoch, verbose) -> None: ++ """ ++ ++ def decorator(func: Callable[_InputT, _RetT]) -> Callable[_InputT, _RetT]: ++ @functools.wraps(func) ++ def wrapper(*args: _InputT.args, **kwargs: _InputT.kwargs) -> _RetT: ++ opt = None ++ if "optimizer" in kwargs: ++ if "learning_rate" not in kwargs: ++ opt = kwargs.pop("optimizer") ++ kwargs["learning_rate"] = opt.get_lr() ++ else: ++ raise ValueError( ++ "Cannot specify both 'learning_rate' and 'optimizer'." ++ ) ++ elif len(args) > 1 and isinstance( ++ args[1], paddle.optimizer.Optimizer ++ ): ++ opt = args[1] ++ args_list = list(args) ++ args_list[1] = opt.get_lr() ++ args = tuple(args_list) ++ func(*args, **kwargs) ++ if opt is not None: ++ opt.set_lr_scheduler(args[0]) ++ ++ wrapper.__signature__ = inspect.signature(func) ++ return wrapper ++ ++ return decorator ++ ++ + def fill_diagonal_inplace_decorator() -> Callable[ + [Callable[_InputT, _RetT]], Callable[_InputT, _RetT] + ]: diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-79197/tests/test.patch b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/tests/test.patch new file mode 100644 index 000000000..dda27a53c --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/tests/test.patch @@ -0,0 +1,143 @@ +diff --git a/test/legacy_test/test_lr_scheduler.py b/test/legacy_test/test_lr_scheduler.py +index 9b1e48e97e8e33b0a78b3ecac5e44508558ace99..2721b25a63f660806bcc5f67f571be810e00e104 100644 +--- a/test/legacy_test/test_lr_scheduler.py ++++ b/test/legacy_test/test_lr_scheduler.py +@@ -1332,6 +1332,138 @@ class TestLRScheduler(unittest.TestCase): + scheduler.step() + + ++class TestLRSchedulerWithOptimizerArg(unittest.TestCase): ++ def _test_network(self, net, optimizer, scheduler): ++ paddle.disable_static() ++ lrs = [scheduler.get_lr()] ++ for epoch in range(10): ++ for batch_id in range(5): ++ x = paddle.uniform([10, 10]) ++ out = net(x) ++ loss = paddle.mean(out) ++ loss.backward() ++ optimizer.step() ++ optimizer.clear_gradients() ++ scheduler.step() ++ lrs.append(scheduler.get_lr()) ++ paddle.enable_static() ++ return lrs ++ ++ def test_exponential_decay(self): ++ paddle.disable_static() ++ linear = paddle.nn.Linear(10, 10) ++ base_lr = 0.01 ++ gamma = 0.9 ++ adam = paddle.optimizer.Adam( ++ learning_rate=base_lr, parameters=linear.parameters() ++ ) ++ scheduler = paddle.optimizer.lr.ExponentialDecay(adam, gamma=gamma) ++ self.assertEqual(scheduler.base_lr, adam.get_lr()) ++ self.assertIs(adam._learning_rate, scheduler) ++ lrs = self._test_network(linear, adam, scheduler) ++ for i in range(len(lrs)): ++ np.testing.assert_allclose(lrs[i], base_lr * gamma**i) ++ paddle.enable_static() ++ ++ def test_cosine_annealing_decay(self): ++ paddle.disable_static() ++ linear = paddle.nn.Linear(10, 10) ++ base_lr = 0.01 ++ adam = paddle.optimizer.Adam( ++ learning_rate=base_lr, parameters=linear.parameters() ++ ) ++ scheduler = paddle.optimizer.lr.CosineAnnealingDecay( ++ optimizer=adam, T_max=10 ++ ) ++ self.assertEqual(scheduler.base_lr, adam.get_lr()) ++ self.assertIs(adam._learning_rate, scheduler) ++ self._test_network(linear, adam, scheduler) ++ paddle.enable_static() ++ ++ def test_cosine_annealing_warm_restarts(self): ++ paddle.disable_static() ++ linear = paddle.nn.Linear(10, 10) ++ sgd = paddle.optimizer.SGD( ++ learning_rate=0.5, parameters=linear.parameters() ++ ) ++ scheduler = paddle.optimizer.lr.CosineAnnealingWarmRestarts( ++ optimizer=sgd, T_0=1 ++ ) ++ self.assertEqual(scheduler.base_lr, sgd.get_lr()) ++ self.assertIs(sgd._learning_rate, scheduler) ++ self._test_network(linear, sgd, scheduler) ++ paddle.enable_static() ++ ++ def test_multi_step_decay(self): ++ paddle.disable_static() ++ linear = paddle.nn.Linear(10, 10) ++ base_lr = 0.5 ++ gamma = 0.9 ++ milestones = [2, 4, 6] ++ sgd = paddle.optimizer.SGD( ++ learning_rate=base_lr, parameters=linear.parameters() ++ ) ++ scheduler = paddle.optimizer.lr.MultiStepDecay( ++ optimizer=sgd, milestones=milestones, gamma=gamma ++ ) ++ self.assertEqual(scheduler.base_lr, sgd.get_lr()) ++ self.assertIs(sgd._learning_rate, scheduler) ++ lrs = self._test_network(linear, sgd, scheduler) ++ for i in range(len(lrs)): ++ if i < milestones[0]: ++ np.testing.assert_allclose(lrs[i], base_lr) ++ elif milestones[0] <= i < milestones[1]: ++ np.testing.assert_allclose(lrs[i], base_lr * gamma) ++ elif milestones[1] <= i < milestones[2]: ++ np.testing.assert_allclose(lrs[i], base_lr * gamma**2) ++ else: ++ np.testing.assert_allclose(lrs[i], base_lr * gamma**3) ++ paddle.enable_static() ++ ++ def test_reduce_on_plateau(self): ++ paddle.disable_static() ++ linear = paddle.nn.Linear(10, 10) ++ sgd = paddle.optimizer.SGD( ++ learning_rate=0.5, parameters=linear.parameters() ++ ) ++ scheduler = paddle.optimizer.lr.ReduceOnPlateau( ++ optimizer=sgd, mode='min', eps=1e-8 ++ ) ++ self.assertEqual(scheduler.base_lr, sgd.get_lr()) ++ self.assertIs(sgd._learning_rate, scheduler) ++ for epoch in range(10): ++ for batch_id in range(5): ++ x = paddle.uniform([10, 10]) ++ out = linear(x) ++ loss = paddle.mean(out) ++ loss.backward() ++ sgd.step() ++ sgd.clear_gradients() ++ scheduler.step(loss) ++ paddle.enable_static() ++ ++ def test_step_decay(self): ++ paddle.disable_static() ++ linear = paddle.nn.Linear(10, 10) ++ base_lr = 0.5 ++ gamma = 0.9 ++ step_size = 2 ++ sgd = paddle.optimizer.SGD( ++ learning_rate=base_lr, parameters=linear.parameters() ++ ) ++ scheduler = paddle.optimizer.lr.StepDecay( ++ optimizer=sgd, step_size=step_size, gamma=gamma ++ ) ++ self.assertEqual(scheduler.base_lr, sgd.get_lr()) ++ self.assertIs(sgd._learning_rate, scheduler) ++ lrs = self._test_network(linear, sgd, scheduler) ++ for i in range(len(lrs)): ++ np.testing.assert_allclose( ++ lrs[i], base_lr * gamma ** (i // step_size) ++ ) ++ paddle.enable_static() ++ ++ + if __name__ == '__main__': + paddle.enable_static() + unittest.main() diff --git a/swe-paddle/tasks/PaddlePaddle__Paddle-79197/tests/test.sh b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/tests/test.sh new file mode 100644 index 000000000..7196ce20b --- /dev/null +++ b/swe-paddle/tasks/PaddlePaddle__Paddle-79197/tests/test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +set -euo pipefail +python -m pytest test/legacy_test/test_lr_scheduler.py::TestCosineAnnealingWarmRestarts::test_CosineRestartsLR test/legacy_test/test_lr_scheduler.py::TestLRSchedulerWithOptimizerArg -q