| name | compatibility-test |
| description | 负责《Paddle API 对齐 PyTorch 项目》中 Step3 兼容测试,为已修改的 Paddle API 添加兼容性单测并执行验证,确保 API 的 Paddle 用法与 PyTorch 用法均能正常工作。 |
| disable-model-invocation | false |
一、标准工作流程
Step 1:编写测试用例
在 ${ROOT_DIR}/Paddle/test/legacy_test/ 目录下找到 test_api_compatibility[1-9]\.py 中数字最大的文件,在该文件中添加测试。
严格按以下模板编写测试类:
测试模板
class Test<APIName>API(unittest.TestCase):
def setUp(self):
np.random.seed(2025)
self.np_x = np.random.rand(...).astype(...)
def test_dygraph_Compatibility(self):
paddle.disable_static()
x = paddle.to_tensor(self.np_x)
out1 = paddle.<api_name>(x, ...)
out2 = paddle.<api_name>(x=x, ...)
out3 = paddle.<api_name>(x, ...)
out4 = paddle.<api_name>(input=x, dim=...)
out5 = paddle.<api_name>(x, axis=...)
out6 = paddle.empty_like(x)
out7 = paddle.<api_name>(x, ..., out=out6)
out8 = x.<api_name>(...)
out9 = x.<api_name>(axis=...)
for out in [out1, out2, out3, out4, out5, out6, out7, out8, out9]:
np.testing.assert_allclose(out.numpy(), ...)
paddle.enable_static()
def test_static_Compatibility(self):
paddle.enable_static()
main = paddle.static.Program()
startup = paddle.static.Program()
with paddle.static.program_guard(main, startup):
x = paddle.static.data(name="x", shape=self.shape, dtype=self.dtype)
out1 = paddle.<api_name>(x, ...)
out2 = paddle.<api_name>(x=x, ...)
out3 = paddle.<api_name>(input=x, dim=...)
exe = paddle.static.Executor()
fetches = exe.run(
main,
feed={"x": self.np_x},
fetch_list=[out1, out2, out3],
)
for out in fetches:
np.testing.assert_allclose(out, ...)
测试规范
动态图模式必测项:
- ✅ Paddle 位置参数(全部位置参数)
- ✅ Paddle 关键字参数(全部关键字参数)
- ✅ PyTorch 位置参数(如果 PyTorch 与 Paddle 参数顺序不同)
- ✅ PyTorch 关键字参数(使用参数别名)
- ✅ 混合参数(如果参数量>=2,位置+关键字)
- ✅ out 参数(如果 API 支持,inplace API 无需测)
- ✅ 类方法 PyTorch 位置参数(如果有类方法)
- ✅ 类方法 PyTorch 关键字参数(如果有类方法)
静态图模式必测项(inplace API 无需测):
- ✅ Paddle 位置参数(全部位置参数)
- ✅ Paddle 关键字参数(全部关键字参数)
- ✅ PyTorch 位置参数(如果 PyTorch 与 Paddle 参数顺序不同)
- ✅ PyTorch 关键字参数(使用参数别名)
- ✅ 类方法 PyTorch 位置参数(如果有类方法)
- ✅ 类方法 PyTorch 关键字参数(如果有类方法)
测试注意事项
- 可选测试项判断:根据 API 实际支持的用法判断是否需要添加对应测试项
- 顺序要求:添加测试项需遵循上述顺序,不要打乱
- 输出编号连贯:输出结果序号需要保持连贯,每个输出结果均需检验
- 避免重复:对于内容相同的测试项,不要重复添加
- inplace API 特殊处理:inplace API 只需测试动态图,无需测试静态图
特殊参数测试
pin_memory 参数测试:
if paddle.device.is_compiled_with_cuda() or paddle.device.is_compiled_with_xpu():
x = paddle.xxx([2], device="gpu", pin_memory=True)
self.assertTrue("pinned" in str(x.place))
device 参数测试:
if paddle.device.is_compiled_with_cuda():
out_cpu = paddle.<api_name>(x, device="cpu")
out_gpu = paddle.<api_name>(x, device="gpu:0")
Step 2:编译并运行单测(每次修改代码均需执行编译)
单测编写完成后,按以下命令验证执行:
cd ${ROOT_DIR}/Paddle/build
cmake .. && make -j$(nproc) > compile.log 2>&1
python test_xxx.py
根据报错信息修改测试用例或回退,确保所有测试用例通过。每次修改后均需要重新执行本步骤。
编译注意事项:
- 无需重装,直接生效(勿执行 setup/install 等安装操作)
- 勿删除 build 目录(否则增量编译失效,编译时间极长)
二、技术背景知识
测试框架说明
- unittest:Python 标准库测试框架,本步骤采用该框架
- 动态图测试:通过
paddle.disable_static() 和 paddle.enable_static() 切换模式
- 静态图测试:通过
paddle.static.program_guard 创建程序上下文
常用断言方法
np.testing.assert_allclose(actual, expected, rtol=1e-5, atol=1e-8)
np.testing.assert_array_equal(actual, expected)
self.assertTrue(condition)
self.assertFalse(condition)
self.assertEqual(a, b)
self.assertIsInstance(obj, cls)
测试数据生成
np.random.seed(2025)
self.np_x = np.random.rand(2, 3).astype(np.float32)
self.shape = [2, 3, 4]
self.dtype = np.float32
三、注意事项
- 严格按标准工作流程执行,杜绝自行臆断和跳过步骤
${ROOT_DIR} 变量表示根目录,需自行替换为实际路径,若未通过 ROOT_DIR 指定,则均为相对于 ROOT_DIR 的路径
- 不要新建测试文件,直接在已有的
test_api_compatibility[1-9]\\.py 中添加
- 测试类命名遵循
Test<APIName>API 格式,如 TestArgmaxAPI
- 确保测试覆盖所有新增的参数别名和参数用法
- 代码测试覆盖率要求:务必要确保新增所有代码行数都能够在单测中跑到,否则无法通过 CI 检查
四、异常回退原则
当本步骤多次尝试仍无法通过时,需要根据错误信息诊断问题根源:
-
若判断为测试用例编写有误(如断言逻辑错误、测试数据错误):
-
若判断为代码实现有误(如参数处理逻辑错误、类型转换失败等):
- 回退到总步骤 Step2(代码修改)调整实现方式
- 回退后再进入本步骤(Step3),则只需执行:编译并运行,其他步骤无需执行
-
若判断为方案选择错误(如当前方案不适用、底层不支持等):
- 回退到总步骤 Step1(选择方案)重新选择
- 回退后再进入本步骤(Step3),则只需执行:编译并运行,其他步骤无需执行
五、常见问题处理
Q1:测试报错 "unexpected keyword argument"
错误现象:
TypeError: xxx() got an unexpected keyword argument 'out'
解决方法:
检查 API 签名是否正确添加了 out 参数,或参数名是否拼写正确。
Q2:pin_memory 测试报错 "Pinning memory is not supported"
错误现象:
RuntimeError: Pinning memory is not supported for Place(cpu)
解决方法:
pin_memory=True 仅在 GPU/XPU 设备上有意义。确保测试逻辑中正确添加了环境判断:
if paddle.device.is_compiled_with_cuda() or paddle.device.is_compiled_with_xpu():
x = paddle.xxx([2], device="gpu", pin_memory=True)
self.assertTrue("pinned" in str(x.place))
Q3:静态图测试失败 "object has no attribute"
错误现象:
AttributeError: 'OpResult' object has no attribute 'pin_memory'
解决方法:
某些动态图专用的方法需要在 in_dynamic_mode() 保护下执行:
if in_dynamic_mode():
tensor = tensor.pin_memory()
Q4:数值比对失败
错误现象:
AssertionError: Not equal to tolerance rtol=1e-5, atol=1e-8
解决方法:
- 检查输入数据是否正确生成
- 检查预期输出值是否正确
- 适当调整容差参数
rtol 和 atol