diff --git a/tester/api_config/11_fix_op/as_strided_unfold_overlap_grad.txt b/tester/api_config/11_fix_op/as_strided_unfold_overlap_grad.txt new file mode 100644 index 00000000..7b969f7d --- /dev/null +++ b/tester/api_config/11_fix_op/as_strided_unfold_overlap_grad.txt @@ -0,0 +1,31 @@ +paddle.as_strided(Tensor([4],"float32"), shape=tuple(2,2,), stride=tuple(1,1,), ) +paddle.as_strided(Tensor([4],"float64"), shape=tuple(2,2,), stride=tuple(1,1,), ) +paddle.as_strided(Tensor([5],"float32"), shape=tuple(3,3,), stride=tuple(1,1,), ) +paddle.as_strided(Tensor([5],"float64"), shape=tuple(3,3,), stride=tuple(1,1,), ) +paddle.as_strided(Tensor([8],"float32"), shape=tuple(3,3,), stride=tuple(1,1,), offset=4, ) +paddle.as_strided(Tensor([64],"float32"), shape=tuple(32,32,), stride=tuple(1,1,), ) +paddle.as_strided(Tensor([64],"float16"), shape=tuple(32,32,), stride=tuple(1,1,), ) +paddle.as_strided(Tensor([64],"bfloat16"), shape=tuple(32,32,), stride=tuple(1,1,), ) +paddle.as_strided(Tensor([64],"complex64"), shape=tuple(32,32,), stride=tuple(1,1,), ) +paddle.as_strided(Tensor([64],"complex128"), shape=tuple(32,32,), stride=tuple(1,1,), ) +paddle.as_strided(Tensor([1],"float32"), shape=tuple(3,4,), stride=tuple(0,0,), ) +paddle.as_strided(Tensor([1],"float32"), shape=tuple(64,64,), stride=tuple(0,0,), ) +paddle.as_strided(Tensor([3],"float32"), shape=tuple(3,4,), stride=tuple(1,0,), ) +paddle.as_strided(Tensor([32],"float32"), shape=tuple(32,16,), stride=tuple(1,0,), ) +paddle.as_strided(Tensor([8, 4],"float32"), shape=tuple(6,4,), stride=tuple(2,1,), ) +paddle.as_strided(Tensor([6],"float32"), shape=tuple(2,3,), stride=tuple(3,1,), ) +paddle.as_strided(Tensor([6],"float32"), shape=tuple(3,2,), stride=tuple(1,3,), ) +paddle.as_strided(Tensor([128, 8],"float32"), shape=tuple(64,8,), stride=tuple(8,1,), ) +paddle.Tensor.as_strided(Tensor([64],"float32"), shape=tuple(32,32,), stride=tuple(1,1,), ) +paddle.Tensor.as_strided(Tensor([6],"float32"), shape=tuple(2,3,), stride=tuple(3,1,), ) +paddle.unfold(Tensor([5],"float32"), 0, 3, 1, ) +paddle.unfold(Tensor([5],"float64"), 0, 3, 1, ) +paddle.unfold(Tensor([16],"float32"), 0, 4, 1, ) +paddle.unfold(Tensor([128],"float32"), 0, 64, 1, ) +paddle.unfold(Tensor([128],"float16"), 0, 64, 1, ) +paddle.unfold(Tensor([128],"bfloat16"), 0, 64, 1, ) +paddle.unfold(Tensor([128],"complex64"), 0, 64, 1, ) +paddle.unfold(Tensor([64, 8],"float32"), 0, 8, 1, ) +paddle.unfold(Tensor([8, 4],"float32"), 0, 4, 2, ) +paddle.unfold(Tensor([12],"float32"), -1, 2, 5, ) +paddle.unfold(Tensor([12],"float32"), 0, 4, 4, ) diff --git a/tester/paddle_to_torch/mapping.json b/tester/paddle_to_torch/mapping.json index f9aef13b..6b966413 100644 --- a/tester/paddle_to_torch/mapping.json +++ b/tester/paddle_to_torch/mapping.json @@ -229,14 +229,14 @@ } }, "paddle.as_strided": { + "Rule": "AsStridedRule", "torch_api": "torch.as_strided", - "paddle_torch_args_map": { - "x": "input", - "shape": "size", - "stride": "stride", - "offset": "storage_offset" - }, - "description": "result = torch.as_strided(input=x, size=shape, stride=stride, storage_offset=offset)" + "description": "Paddle byte offset is converted to Torch element offset" + }, + "paddle.Tensor.as_strided": { + "Rule": "AsStridedRule", + "torch_api": "torch.Tensor.as_strided", + "description": "Paddle byte offset is converted to Torch element offset" }, "paddle.asin": { "torch_api": "torch.arcsin", diff --git a/tester/paddle_to_torch/rules.py b/tester/paddle_to_torch/rules.py index 5c5f6adc..72520b8c 100644 --- a/tester/paddle_to_torch/rules.py +++ b/tester/paddle_to_torch/rules.py @@ -419,6 +419,44 @@ def apply(self, paddle_api: str) -> ConvertResult: ) +class AsStridedRule(BaseRule): + PADDLE_APIS = ("paddle.as_strided", "paddle.Tensor.as_strided") + + def apply(self, paddle_api: str) -> ConvertResult: + # Paddle 的 offset 是字节数,Torch 的 storage_offset 是元素序号,不能直接透传。 + preprocess = """ +_storage_offset = locals().get("offset", 0) +# 缺省 offset 由绑定器补成 0,独立转换调用也保持相同语义。 +if _storage_offset is None: + _storage_offset = 0 +_storage_offset = int(_storage_offset) +_item_size = int(x.element_size()) +# 非法偏移提前失败,避免 Torch 以不同单位产生静默错位。 +if _storage_offset < 0 or _storage_offset % _item_size: + raise ValueError( + f"Paddle as_strided offset must be a non-negative multiple of itemsize, " + f"got offset={_storage_offset}, itemsize={_item_size}" + ) +_storage_offset //= _item_size +""" + # 共享参数绑定器把 Tensor receiver 统一命名为 x,函数与方法只需切换调用入口。 + if paddle_api == "paddle.Tensor.as_strided": + core = ( + "result = x.as_strided(size=shape, stride=stride, storage_offset=_storage_offset)" + ) + else: + core = ( + "result = torch.as_strided(" + "input=x, size=shape, stride=stride, storage_offset=_storage_offset)" + ) + return self.build_result( + paddle_api, + kind=ConversionKind.DIRECT, + preprocess=preprocess, + core=core, + ) + + # a class AsComplexRule(BaseRule): PADDLE_APIS = ("paddle.as_complex",)