Skip to content

Commit d0e32f4

Browse files
APITest 测试修复:🐛 修复 forward-only 用例的 autograd 冗余建图 (#659)
1 parent 3e5ba30 commit d0e32f4

1 file changed

Lines changed: 58 additions & 41 deletions

File tree

tester/api_config/config_analyzer.py

Lines changed: 58 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,28 @@
1010
import numpy
1111
import paddle
1212
import torch
13+
import yaml
1314

1415
USE_CACHED_NUMPY = os.getenv("USE_CACHED_NUMPY", "False").lower() == "true"
1516
TEST_NON_CONTIGUOUS = os.getenv("TEST_NON_CONTIGUOUS", "0").lower() in ("true", "1")
1617
USE_GPU_CACHE_MODE = os.getenv("USE_GPU_CACHE_MODE", "False").lower() == "true"
1718
SKIP_GPU_CLEANUP = os.getenv("SKIP_GPU_CLEANUP", "False").lower() == "true"
1819
cached_numpy = {}
1920
cached_gpu_inputs = {}
21+
AUTOGRAD_DTYPES = frozenset(
22+
["float32", "float64", "float16", "complex64", "complex128", "bfloat16"]
23+
)
24+
FLOAT8_DTYPES = frozenset(["float8_e5m2", "float8_e4m3fn"])
25+
CAST_THROUGH_INTERMEDIATE_DTYPES = frozenset(["bfloat16"]) | FLOAT8_DTYPES
26+
27+
28+
def _load_forward_only_apis():
29+
config_path = os.path.join(os.path.dirname(__file__), "..", "base_config.yaml")
30+
with open(config_path, encoding="utf-8") as f:
31+
return frozenset(yaml.safe_load(f).get("forward_only_apis", []))
32+
33+
34+
FORWARD_ONLY_APIS = _load_forward_only_apis()
2035

2136

2237
def _env_bool(name, default=False):
@@ -240,16 +255,35 @@ def _use_gpu_cache(self, dtype=None):
240255
return False
241256
return True
242257

258+
def _supports_autograd(self, dtype=None):
259+
dtype = dtype or self.dtype
260+
return dtype in AUTOGRAD_DTYPES
261+
262+
def _requires_autograd(self, api_config, dtype=None):
263+
if not self._supports_autograd(dtype):
264+
return False
265+
api_name = getattr(api_config, "api_name", "")
266+
api = api_name[api_name.rindex(".") + 1 :] if "." in api_name else api_name
267+
if api in FORWARD_ONLY_APIS:
268+
return False
269+
return getattr(api_config, "test_backward", True)
270+
243271
def _gpu_cache_key(self, api_config, dtype=None):
244272
dtype = dtype or self.dtype
245273
location = (
246274
getattr(self, "index", None),
247275
getattr(self, "key", None),
248276
tuple(getattr(self, "list_index", [])),
249277
)
250-
return (api_config.config, location, dtype, _shape_tuple(self.shape))
278+
return (
279+
api_config.config,
280+
location,
281+
dtype,
282+
_shape_tuple(self.shape),
283+
self._requires_autograd(api_config, dtype),
284+
)
251285

252-
def _make_gpu_cache_tensors(self, dtype=None):
286+
def _make_gpu_cache_tensors(self, api_config, dtype=None):
253287
dtype = dtype or self.dtype
254288
torch_dtype = self.convert_dtype_to_torch_type(dtype)
255289
shape = tuple(self.shape)
@@ -271,21 +305,22 @@ def _make_gpu_cache_tensors(self, dtype=None):
271305
base = (torch.rand(shape, device=device, dtype=torch.float32) - 0.5) * 1.2
272306
torch_tensor = base.to(dtype=torch_dtype)
273307

308+
requires_autograd = self._requires_autograd(api_config, dtype)
274309
torch_source = torch_tensor.detach()
275310
paddle_tensor = paddle.utils.dlpack.from_dlpack(
276311
torch.utils.dlpack.to_dlpack(torch_source.clone())
277312
)
278-
paddle_tensor.stop_gradient = False
313+
paddle_tensor.stop_gradient = not requires_autograd
279314
torch_tensor = torch_source.clone()
280-
if dtype in ["float32", "float64", "float16", "complex64", "complex128", "bfloat16"]:
281-
torch_tensor = torch_tensor.requires_grad_(True)
315+
if requires_autograd:
316+
torch_tensor = torch_tensor.detach().requires_grad_(True)
282317
return paddle_tensor, torch_tensor
283318

284319
def _get_gpu_cache_entry(self, api_config, dtype=None):
285320
dtype = dtype or self.dtype
286321
key = self._gpu_cache_key(api_config, dtype)
287322
if key not in cached_gpu_inputs:
288-
paddle_tensor, torch_tensor = self._make_gpu_cache_tensors(dtype)
323+
paddle_tensor, torch_tensor = self._make_gpu_cache_tensors(api_config, dtype)
289324
cached_gpu_inputs[key] = {
290325
"paddle": paddle_tensor,
291326
"torch": torch_tensor,
@@ -3019,24 +3054,23 @@ def get_paddle_tensor(self, api_config):
30193054
f"is_contiguous: {self.paddle_tensor.is_contiguous()}"
30203055
)
30213056
else:
3057+
requires_autograd = self._requires_autograd(api_config)
30223058
intermediate_dtype = (
30233059
"float32"
30243060
if self.dtype == "bfloat16"
3025-
else (
3026-
"float16" if self.dtype in ["float8_e5m2", "float8_e4m3fn"] else self.dtype
3027-
)
3061+
else ("float16" if self.dtype in FLOAT8_DTYPES else self.dtype)
30283062
)
30293063
self.paddle_tensor = paddle.to_tensor(
30303064
self.get_numpy_tensor(api_config),
30313065
dtype=intermediate_dtype,
30323066
place=self.place,
30333067
)
30343068

3035-
self.paddle_tensor.stop_gradient = False
30363069
if self.dtype == "bfloat16":
30373070
self.paddle_tensor = paddle.cast(self.paddle_tensor, dtype="bfloat16")
3038-
elif self.dtype in ["float8_e5m2", "float8_e4m3fn"]:
3071+
elif self.dtype in FLOAT8_DTYPES:
30393072
self.paddle_tensor = paddle.cast(self.paddle_tensor, dtype=self.dtype)
3073+
self.paddle_tensor.stop_gradient = not requires_autograd
30403074
if TEST_NON_CONTIGUOUS:
30413075
if not self.shuffle_dims:
30423076
ndim = self.paddle_tensor.dim()
@@ -3059,9 +3093,7 @@ def _create_strided_paddle_tensor(self, api_config):
30593093
original_flag = paddle.get_flags([flag_name])
30603094
paddle.set_flags({flag_name: False})
30613095
try:
3062-
intermediate_dtype = (
3063-
"float16" if self.dtype in ["float8_e5m2", "float8_e4m3fn"] else self.dtype
3064-
)
3096+
intermediate_dtype = "float16" if self.dtype in FLOAT8_DTYPES else self.dtype
30653097
storage_size = self._strided_storage_size()
30663098
flat_tensor = paddle.zeros(
30673099
[storage_size],
@@ -3076,11 +3108,11 @@ def _create_strided_paddle_tensor(self, api_config):
30763108
dtype=intermediate_dtype,
30773109
place=self.place,
30783110
)
3079-
if self.dtype in ["float8_e5m2", "float8_e4m3fn"]:
3111+
if self.dtype in FLOAT8_DTYPES:
30803112
flat_tensor = paddle.cast(flat_tensor, dtype=self.dtype)
30813113
tensor = paddle.as_strided(flat_tensor, self.shape, self.strides)
30823114

3083-
tensor.stop_gradient = False
3115+
tensor.stop_gradient = not self._requires_autograd(api_config)
30843116
return tensor
30853117
finally:
30863118
paddle.set_flags(original_flag)
@@ -3094,32 +3126,25 @@ def get_torch_tensor(self, api_config):
30943126
if not self.is_contiguous and self.strides is not None:
30953127
self.torch_tensor = self._create_strided_torch_tensor(api_config)
30963128
else:
3097-
needs_intermediate = self.dtype in ["bfloat16", "float8_e5m2", "float8_e4m3fn"]
3098-
if needs_intermediate:
3129+
needs_cast = self.dtype in CAST_THROUGH_INTERMEDIATE_DTYPES
3130+
if needs_cast:
30993131
intermediate_torch_dtype = (
31003132
torch.float32 if self.dtype == "bfloat16" else torch.float16
31013133
)
31023134
else:
31033135
intermediate_torch_dtype = self.convert_dtype_to_torch_type(self.dtype)
3136+
requires_grad = self._requires_autograd(api_config)
31043137
self.torch_tensor = torch.tensor(
31053138
self.get_numpy_tensor(api_config),
31063139
dtype=intermediate_torch_dtype,
3107-
requires_grad=self.dtype
3108-
in [
3109-
"float32",
3110-
"float64",
3111-
"float16",
3112-
"complex64",
3113-
"complex128",
3114-
"bfloat16",
3115-
],
3140+
requires_grad=requires_grad and not needs_cast,
31163141
)
3117-
if self.dtype == "bfloat16":
3118-
self.torch_tensor = self.torch_tensor.to(dtype=torch.bfloat16)
3119-
elif self.dtype in ["float8_e5m2", "float8_e4m3fn"]:
3142+
if needs_cast:
31203143
self.torch_tensor = self.torch_tensor.to(
31213144
dtype=self.convert_dtype_to_torch_type(self.dtype)
31223145
)
3146+
if requires_grad:
3147+
self.torch_tensor = self.torch_tensor.detach().requires_grad_(True)
31233148
if TEST_NON_CONTIGUOUS:
31243149
if not self.shuffle_dims:
31253150
ndim = self.torch_tensor.dim()
@@ -3132,7 +3157,7 @@ def get_torch_tensor(self, api_config):
31323157
def _create_strided_torch_tensor(self, api_config):
31333158
"""Create a non-contiguous torch tensor from the shared logical numpy input."""
31343159
device = torch.device("cuda:0") if torch.cuda.is_available() else torch.device("cpu")
3135-
needs_intermediate = self.dtype in ["float8_e5m2", "float8_e4m3fn"]
3160+
needs_intermediate = self.dtype in FLOAT8_DTYPES
31363161
if needs_intermediate:
31373162
intermediate_torch_dtype = torch.float16
31383163
else:
@@ -3153,19 +3178,11 @@ def _create_strided_torch_tensor(self, api_config):
31533178
device=device,
31543179
)
31553180
)
3156-
if self.dtype in ["float8_e5m2", "float8_e4m3fn"]:
3181+
if self.dtype in FLOAT8_DTYPES:
31573182
flat_tensor = flat_tensor.to(dtype=self.convert_dtype_to_torch_type(self.dtype))
31583183
tensor = torch.as_strided(flat_tensor, self.shape, self.strides)
31593184

3160-
requires_grad = self.dtype in [
3161-
"float32",
3162-
"float64",
3163-
"float16",
3164-
"complex64",
3165-
"complex128",
3166-
"bfloat16",
3167-
]
3168-
if requires_grad:
3185+
if self._requires_autograd(api_config):
31693186
tensor = tensor.detach().requires_grad_(True)
31703187
return tensor
31713188

0 commit comments

Comments
 (0)