Skip to content

Commit 42d714b

Browse files
committed
fix: keep torch GPU reference independent from test_cpu
1 parent 22467f5 commit 42d714b

7 files changed

Lines changed: 129 additions & 21 deletions

File tree

engineV2.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -440,8 +440,6 @@ def validate_gpu_options(options) -> tuple:
440440
"expected -1 or a positive integer"
441441
)
442442
if getattr(options, "accuracy_stable_dual_gpu", False):
443-
if getattr(options, "test_cpu", False):
444-
raise ValueError("--accuracy_stable_dual_gpu=True does not support --test_cpu=True")
445443
if options.num_gpus < 2 or options.num_gpus % 2:
446444
raise ValueError("--accuracy_stable_dual_gpu=True requires an even --num_gpus")
447445
if options.num_workers_per_gpu != 1:
@@ -462,6 +460,29 @@ def normalize_accuracy_stable_dual_gpu_options(options):
462460
options.accuracy_stable = True
463461

464462

463+
def _mode_runs_torch_gpu_reference(options):
464+
"""只有执行 Torch reference 的模式才要求保留 GPU 运行时。"""
465+
return any(
466+
getattr(options, mode, False)
467+
for mode in (
468+
"accuracy",
469+
"accuracy_stable",
470+
"accuracy_stable_dual_gpu",
471+
"torch_gpu_performance",
472+
"paddle_torch_gpu_performance",
473+
)
474+
)
475+
476+
477+
def _requires_gpu_runtime(options):
478+
"""test_cpu 与 use_gpu_mode 正交地决定 GPU 运行时需求。"""
479+
return bool(
480+
not getattr(options, "test_cpu", False)
481+
or getattr(options, "use_gpu_mode", False)
482+
or _mode_runs_torch_gpu_reference(options)
483+
)
484+
485+
465486
def _resolve_dump_options(parser, options):
466487
try:
467488
options.use_dump, options.dump_dir = resolve_dump_options(
@@ -496,9 +517,7 @@ def _apply_single_config_gpu_defaults(options):
496517

497518
def _prepare_single_config_gpu(options):
498519
normalize_accuracy_stable_dual_gpu_options(options)
499-
if getattr(options, "accuracy_stable_dual_gpu", False) and getattr(options, "test_cpu", False):
500-
raise ValueError("--accuracy_stable_dual_gpu=True does not support --test_cpu=True")
501-
if options.test_cpu:
520+
if not _requires_gpu_runtime(options):
502521
options.gpu_workers_per_gpu_map = {}
503522
options.gpu_total_memory_map = {}
504523
options.runtime_config = TestRuntimeConfig.from_options(options)
@@ -1074,7 +1093,7 @@ def main():
10741093
)
10751094
return
10761095
normalize_accuracy_stable_dual_gpu_options(options)
1077-
if options.api_config and not options.test_cpu:
1096+
if options.api_config and _requires_gpu_runtime(options):
10781097
_apply_single_config_gpu_defaults(options)
10791098

10801099
mode = [

engineV4.py

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1135,6 +1135,29 @@ def normalize_accuracy_stable_dual_gpu_options(options):
11351135
options.accuracy_stable = True
11361136

11371137

1138+
def _mode_runs_torch_gpu_reference(options):
1139+
"""只有执行 Torch reference 的模式才要求保留 GPU 运行时。"""
1140+
return any(
1141+
getattr(options, mode, False)
1142+
for mode in (
1143+
"accuracy",
1144+
"accuracy_stable",
1145+
"accuracy_stable_dual_gpu",
1146+
"torch_gpu_performance",
1147+
"paddle_torch_gpu_performance",
1148+
)
1149+
)
1150+
1151+
1152+
def _requires_gpu_runtime(options):
1153+
"""test_cpu 与 use_gpu_mode 正交地决定 GPU 运行时需求。"""
1154+
return bool(
1155+
not getattr(options, "test_cpu", False)
1156+
or getattr(options, "use_gpu_mode", False)
1157+
or _mode_runs_torch_gpu_reference(options)
1158+
)
1159+
1160+
11381161
def validate_gpu_options(options) -> tuple:
11391162
"""Validate and normalize GPU-related options."""
11401163
normalize_accuracy_stable_dual_gpu_options(options)
@@ -1162,8 +1185,6 @@ def validate_gpu_options(options) -> tuple:
11621185
"expected -1 or a positive integer"
11631186
)
11641187
if getattr(options, "accuracy_stable_dual_gpu", False):
1165-
if getattr(options, "test_cpu", False):
1166-
raise ValueError("--accuracy_stable_dual_gpu=True does not support --test_cpu=True")
11671188
if options.num_gpus < 2 or options.num_gpus % 2:
11681189
raise ValueError("--accuracy_stable_dual_gpu=True requires an even --num_gpus")
11691190
if options.num_workers_per_gpu != 1:
@@ -1205,9 +1226,7 @@ def _apply_single_config_gpu_defaults(options):
12051226

12061227
def _prepare_single_config_gpu(options):
12071228
normalize_accuracy_stable_dual_gpu_options(options)
1208-
if getattr(options, "accuracy_stable_dual_gpu", False) and getattr(options, "test_cpu", False):
1209-
raise ValueError("--accuracy_stable_dual_gpu=True does not support --test_cpu=True")
1210-
if options.test_cpu:
1229+
if not _requires_gpu_runtime(options):
12111230
options.gpu_workers_per_gpu_map = {}
12121231
options.gpu_total_memory_map = {}
12131232
options.runtime_config = TestRuntimeConfig.from_options(options)
@@ -1745,7 +1764,7 @@ def main():
17451764
)
17461765
return
17471766
normalize_accuracy_stable_dual_gpu_options(options)
1748-
if options.api_config and not options.test_cpu:
1767+
if options.api_config and _requires_gpu_runtime(options):
17491768
_apply_single_config_gpu_defaults(options)
17501769

17511770
mode = [

tester/api_config/config_analyzer.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -315,12 +315,31 @@ def get_cached_numpy(self, dtype, shape, generation_kind="input", scale=1.2):
315315
return get_cached_numpy_array(dtype, shape, generation_kind=generation_kind, scale=scale)
316316

317317
def _use_gpu(self, api_config=None, dtype=None):
318+
"""判断是否启用 GPU tensor 生成;不代表 Paddle kernel 的 place。"""
318319
if not is_gpu_mode():
319320
return False
320321
if self.place is not None and "cpu" in str(self.place).lower():
321322
return False
322323
return "gpu" in paddle.device.get_device()
323324

325+
def _paddle_kernel_uses_gpu(self, api_config):
326+
"""test_cpu 只决定 Paddle kernel,不能被 use_gpu_mode 覆盖。"""
327+
if self.place is not None and "cpu" in str(self.place).lower():
328+
return False
329+
if getattr(api_config, "test_cpu", False):
330+
return False
331+
return "gpu" in paddle.device.get_device()
332+
333+
def _torch_source_device_for_paddle(self, api_config):
334+
"""返回送入 Paddle 前的 Torch 源设备,遵守 Paddle kernel place。"""
335+
if self.place is not None and "cpu" in str(self.place).lower():
336+
return torch.device("cpu")
337+
if getattr(api_config, "test_cpu", False):
338+
return torch.device("cpu")
339+
if self._paddle_kernel_uses_gpu(api_config):
340+
return torch.device("cuda", torch.cuda.current_device())
341+
return torch.device("cpu")
342+
324343
def _supports_autograd(self, dtype=None):
325344
dtype = dtype or self.dtype
326345
return dtype in AUTOGRAD_DTYPES
@@ -3433,10 +3452,12 @@ def get_paddle_tensor(self, api_config):
34333452
and self._use_gpu(api_config)
34343453
):
34353454
self.paddle_tensor = self._make_gpu_paddle_tensor(api_config)
3455+
if getattr(api_config, "test_cpu", False):
3456+
self.paddle_tensor = self.paddle_tensor._copy_to(paddle.CPUPlace(), False)
34363457
return self.paddle_tensor
34373458
if self.cpu_tensor is not None:
34383459
torch_tensor = self.cpu_tensor.to(
3439-
device=torch.device("cuda:0") if self._use_gpu(api_config) else "cpu",
3460+
device=self._torch_source_device_for_paddle(api_config),
34403461
copy=True,
34413462
)
34423463
self.paddle_tensor = paddle.utils.dlpack.from_dlpack(
@@ -3445,7 +3466,10 @@ def get_paddle_tensor(self, api_config):
34453466
self.paddle_tensor.stop_gradient = not self._requires_autograd(api_config)
34463467
return self.paddle_tensor
34473468
if self.numpy_tensor is None and self._use_gpu(api_config):
3448-
return self.get_gpu_paddle_tensor(api_config)
3469+
tensor = self.get_gpu_paddle_tensor(api_config)
3470+
if getattr(api_config, "test_cpu", False):
3471+
self.paddle_tensor = tensor._copy_to(paddle.CPUPlace(), False)
3472+
return self.paddle_tensor
34493473
if not self.is_contiguous and self.strides is not None:
34503474
self.paddle_tensor = self._create_strided_paddle_tensor(api_config)
34513475
print(
@@ -3462,10 +3486,11 @@ def get_paddle_tensor(self, api_config):
34623486
if self.dtype == "bfloat16"
34633487
else ("float16" if self.dtype in FLOAT8_DTYPES else self.dtype)
34643488
)
3489+
operator_place = paddle.CPUPlace() if getattr(api_config, "test_cpu", False) else self.place
34653490
self.paddle_tensor = paddle.to_tensor(
34663491
self.get_numpy_tensor(api_config),
34673492
dtype=intermediate_dtype,
3468-
place=self.place,
3493+
place=operator_place,
34693494
)
34703495

34713496
if self.dtype == "bfloat16":
@@ -3497,18 +3522,19 @@ def _create_strided_paddle_tensor(self, api_config):
34973522
try:
34983523
intermediate_dtype = "float16" if self.dtype in FLOAT8_DTYPES else self.dtype
34993524
storage_size = self._strided_storage_size()
3525+
operator_place = paddle.CPUPlace() if getattr(api_config, "test_cpu", False) else self.place
35003526
flat_tensor = paddle.zeros(
35013527
[storage_size],
35023528
dtype=intermediate_dtype,
3503-
device=self.place,
3529+
device=operator_place,
35043530
)
35053531
tensor = paddle.as_strided(flat_tensor, self.shape, self.strides)
35063532
logical_tensor = self.get_numpy_tensor(api_config)
35073533
if logical_tensor.size > 0:
35083534
tensor[...] = paddle.to_tensor(
35093535
logical_tensor,
35103536
dtype=intermediate_dtype,
3511-
place=self.place,
3537+
place=operator_place,
35123538
)
35133539
if self.dtype in FLOAT8_DTYPES:
35143540
flat_tensor = paddle.cast(flat_tensor, dtype=self.dtype)

tester/base.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,8 +493,11 @@ class APITestBase:
493493
def __init__(self, api_config, use_torch=True, runtime_config=None):
494494
self.api_config = api_config
495495
self.api_config.use_torch = use_torch
496+
self.use_torch = bool(use_torch)
496497
self.runtime_config = runtime_config or TestRuntimeConfig()
497498
self.gpu_mode_config = self.runtime_config.gpu_mode
499+
# TensorConfig 需要知道 kernel place,不能从 GPU mode 反推。
500+
self.api_config.test_cpu = self.runtime_config.test_cpu
498501
self.dump_context = (
499502
DumpContext(
500503
os.environ.get("DUMP_DIR") or DEFAULT_DUMP_DIR, api_config=api_config.config
@@ -508,6 +511,14 @@ def __init__(self, api_config, use_torch=True, runtime_config=None):
508511
torch.set_num_threads(8)
509512
torch.set_printoptions(threshold=100, linewidth=120)
510513

514+
def torch_operator_device(self):
515+
"""返回当前 worker 的 Torch reference 设备。"""
516+
return torch.device(f"{self.runtime_config.torch_operator_device_type}:0")
517+
518+
def requires_gpu_runtime(self):
519+
"""算子执行或 GPU mode 任一需要 GPU 时返回 True。"""
520+
return self.use_torch or not self.runtime_config.test_cpu or self.gpu_mode_config.enabled
521+
511522
def run_with_dump(self):
512523
"""Execute the test with dump output capture and lifecycle reporting."""
513524
if self.dump_context is None:

tester/log_writer/log_report.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,16 +66,32 @@ def print_run_header(options, paddle_version):
6666
)
6767
)
6868

69+
torch_reference_gpu = any(
70+
getattr(options, name, False)
71+
for name in (
72+
"accuracy",
73+
"accuracy_stable",
74+
"accuracy_stable_dual_gpu",
75+
"torch_gpu_performance",
76+
"paddle_torch_gpu_performance",
77+
)
78+
)
79+
requires_gpu = not options.test_cpu or options.use_gpu_mode or torch_reference_gpu
80+
compute = [
81+
("paddle_kernel_device", "CPU" if options.test_cpu else "GPU"),
82+
("torch_reference_device", "GPU" if torch_reference_gpu else "N/A"),
83+
("input_compare_device", "GPU" if options.use_gpu_mode else "CPU"),
84+
]
6985
if options.test_cpu:
70-
compute = [("--test_cpu", True)]
71-
else:
86+
compute.append(("--test_cpu", True))
87+
if requires_gpu:
7288
if not options.gpu_ids:
7389
gpu_ids_display = "all visible"
7490
elif options.gpu_ids == "-1":
7591
gpu_ids_display = "-1 (all visible)"
7692
else:
7793
gpu_ids_display = options.gpu_ids
78-
compute = [("--gpu_ids", gpu_ids_display)]
94+
compute.append(("--gpu_ids", gpu_ids_display))
7995
if options.use_gpu_mode:
8096
compute.append(("--use_gpu_mode", True))
8197
if getattr(options, "accuracy_stable_dual_gpu", False):

tester/paddle_cinn_vs_dygraph.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,12 @@
99

1010
class APITestCINNVSDygraph(APITestBase):
1111
def __init__(self, api_config, **kwargs):
12-
super().__init__(api_config)
12+
# CINN 只执行 Paddle kernel,不应丢失 worker 的 test_cpu 设备协议。
13+
super().__init__(
14+
api_config,
15+
use_torch=False,
16+
runtime_config=kwargs.get("runtime_config"),
17+
)
1318
self.test_amp = kwargs.get("test_amp", False)
1419
self.test_backward = kwargs.get("test_backward", False)
1520

tester/runtime_config.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,19 @@ class TestRuntimeConfig:
2323
random_seed: int = 0
2424
bitwise_alignment: bool = False
2525
exit_on_error: bool = False
26+
# test_cpu 只控制 Paddle kernel;GPU mode 另行控制输入和比较策略。
27+
test_cpu: bool = False
2628
gpu_mode: GpuModeConfig = field(default_factory=GpuModeConfig)
2729

30+
@property
31+
def paddle_kernel_device_type(self):
32+
return "cpu" if self.test_cpu else "cuda"
33+
34+
@property
35+
def torch_operator_device_type(self):
36+
# accuracy 模式始终执行 GPU Torch reference,即使 Paddle kernel 在 CPU。
37+
return "cuda"
38+
2839
@classmethod
2940
def from_options(cls, options):
3041
dual_gpu = bool(getattr(options, "accuracy_stable_dual_gpu", False))
@@ -37,6 +48,7 @@ def from_options(cls, options):
3748
random_seed=int(options.random_seed),
3849
bitwise_alignment=bool(options.bitwise_alignment),
3950
exit_on_error=bool(options.exit_on_error),
51+
test_cpu=bool(getattr(options, "test_cpu", False)),
4052
gpu_mode=gpu_mode,
4153
)
4254

0 commit comments

Comments
 (0)