diff --git a/engineV2.py b/engineV2.py index 805d4604..af0a5616 100644 --- a/engineV2.py +++ b/engineV2.py @@ -282,6 +282,85 @@ def _print_argument(prefix, message): print(f"{prefix} {message}", flush=True) +def _mode_uses_torch(options): + return any( + getattr(options, opt, False) + for opt in ( + "accuracy", + "paddle_cinn", + "paddle_gpu_performance", + "torch_gpu_performance", + "paddle_torch_gpu_performance", + "accuracy_stable", + "paddle_custom_device", + "custom_device_vs_gpu", + ) + ) + + +def _load_test_classes(options): + from tester import APIConfig, APITestPaddleOnly + + test_classes = { + "APIConfig": APIConfig, + "APITestPaddleOnly": APITestPaddleOnly, + } + if _mode_uses_torch(options): + from tester import ( + APITestAccuracy, + APITestAccuracyStable, + APITestCINNVSDygraph, + APITestCustomDeviceVSCPU, + APITestPaddleDeviceVSGPU, + APITestPaddleGPUPerformance, + APITestPaddleTorchGPUPerformance, + APITestTorchGPUPerformance, + ) + + test_classes.update( + { + "APITestAccuracy": APITestAccuracy, + "APITestCINNVSDygraph": APITestCINNVSDygraph, + "APITestPaddleGPUPerformance": APITestPaddleGPUPerformance, + "APITestTorchGPUPerformance": APITestTorchGPUPerformance, + "APITestPaddleTorchGPUPerformance": APITestPaddleTorchGPUPerformance, + "APITestAccuracyStable": APITestAccuracyStable, + "APITestCustomDeviceVSCPU": APITestCustomDeviceVSCPU, + "APITestPaddleDeviceVSGPU": APITestPaddleDeviceVSGPU, + } + ) + return test_classes + + +def _select_test_class(options): + test_classes = _load_test_classes(options) + option_to_class_name = { + "paddle_only": "APITestPaddleOnly", + "paddle_cinn": "APITestCINNVSDygraph", + "accuracy": "APITestAccuracy", + "paddle_gpu_performance": "APITestPaddleGPUPerformance", + "torch_gpu_performance": "APITestTorchGPUPerformance", + "paddle_torch_gpu_performance": "APITestPaddleTorchGPUPerformance", + "accuracy_stable": "APITestAccuracyStable", + "paddle_custom_device": "APITestCustomDeviceVSCPU", + "custom_device_vs_gpu": "APITestPaddleDeviceVSGPU", + } + for opt, class_name in option_to_class_name.items(): + if getattr(options, opt, False): + return test_classes[class_name] + return test_classes["APITestAccuracy"] + + +def _clear_device_cache(options): + import paddle + + if _mode_uses_torch(options): + import torch + + torch.cuda.empty_cache() + paddle.device.cuda.empty_cache() + + def _parse_gpu_ids(gpu_ids_arg, device_count): gpu_ids = [] for raw_part in gpu_ids_arg.split(","): @@ -441,7 +520,6 @@ def pid_exists(pid): os.environ["CUDA_VISIBLE_DEVICES"] = str(assigned_gpu) import paddle - import torch # Load custom ops from paddlefleet to register _run_custom_op operators try: @@ -453,39 +531,11 @@ def pid_exists(pid): except ImportError: pass - globals()["torch"] = torch globals()["paddle"] = paddle - - from tester import ( - APIConfig, - APITestAccuracy, - APITestAccuracyStable, - APITestCINNVSDygraph, - APITestCustomDeviceVSCPU, - APITestPaddleDeviceVSGPU, - APITestPaddleGPUPerformance, - APITestPaddleOnly, - APITestPaddleTorchGPUPerformance, - APITestTorchGPUPerformance, - ) - - test_classes = { - "APIConfig": APIConfig, - "APITestAccuracy": APITestAccuracy, - "APITestCINNVSDygraph": APITestCINNVSDygraph, - "APITestPaddleOnly": APITestPaddleOnly, - "APITestPaddleGPUPerformance": APITestPaddleGPUPerformance, - "APITestTorchGPUPerformance": APITestTorchGPUPerformance, - "APITestPaddleTorchGPUPerformance": APITestPaddleTorchGPUPerformance, - "APITestAccuracyStable": APITestAccuracyStable, - "APITestCustomDeviceVSCPU": APITestCustomDeviceVSCPU, - "APITestPaddleDeviceVSGPU": APITestPaddleDeviceVSGPU, - } - globals().update(test_classes) + globals().update(_load_test_classes(options)) def signal_handler(*args): - torch.cuda.empty_cache() - paddle.device.cuda.empty_cache() + _clear_device_cache(options) restore_stdio() close_process_files() sys.exit(0) @@ -540,22 +590,7 @@ def run_test_case(api_config_str, options): print(f"[config parse error] {api_config_str} {err!s}", flush=True) return - option_to_class = { - "paddle_only": APITestPaddleOnly, - "paddle_cinn": APITestCINNVSDygraph, - "accuracy": APITestAccuracy, - "paddle_gpu_performance": APITestPaddleGPUPerformance, - "torch_gpu_performance": APITestTorchGPUPerformance, - "paddle_torch_gpu_performance": APITestPaddleTorchGPUPerformance, - "accuracy_stable": APITestAccuracyStable, - "paddle_custom_device": APITestCustomDeviceVSCPU, - "custom_device_vs_gpu": APITestPaddleDeviceVSGPU, - } - - test_class = next( - (cls for opt, cls in option_to_class.items() if getattr(options, opt, False)), - APITestAccuracy, # default fallback - ) + test_class = _select_test_class(options) kwargs = {k: v for k, v in vars(options).items() if k in VALID_TEST_ARGS} case = test_class(api_config, **kwargs) try: @@ -582,8 +617,7 @@ def run_test_case(api_config_str, options): "paddle_torch_gpu_performance", ) ) and not getattr(options, "use_gpu_cache_mode", False): - torch.cuda.empty_cache() - paddle.device.cuda.empty_cache() + _clear_device_cache(options) def main(): @@ -903,18 +937,7 @@ def main(): except ImportError: pass - from tester import ( - APIConfig, - APITestAccuracy, - APITestAccuracyStable, - APITestCINNVSDygraph, - APITestCustomDeviceVSCPU, - APITestPaddleDeviceVSGPU, - APITestPaddleGPUPerformance, - APITestPaddleOnly, - APITestPaddleTorchGPUPerformance, - APITestTorchGPUPerformance, - ) + globals().update(_load_test_classes(options)) # set log_writer set_engineV2() @@ -930,22 +953,7 @@ def main(): print(f"[config parse error] {options.api_config} {err!s}", flush=True) return - option_to_class = { - "paddle_only": APITestPaddleOnly, - "paddle_cinn": APITestCINNVSDygraph, - "accuracy": APITestAccuracy, - "paddle_gpu_performance": APITestPaddleGPUPerformance, - "torch_gpu_performance": APITestTorchGPUPerformance, - "paddle_torch_gpu_performance": APITestPaddleTorchGPUPerformance, - "accuracy_stable": APITestAccuracyStable, - "paddle_custom_device": APITestCustomDeviceVSCPU, - "custom_device_vs_gpu": APITestPaddleDeviceVSGPU, - } - - test_class = next( - (cls for opt, cls in option_to_class.items() if getattr(options, opt, False)), - APITestAccuracy, # default fallback - ) + test_class = _select_test_class(options) if options.test_cpu: import paddle diff --git a/engineV4.py b/engineV4.py index 0922cc90..4170700e 100644 --- a/engineV4.py +++ b/engineV4.py @@ -138,7 +138,6 @@ def _init_worker_runtime(slot_index, gpu_id, options, *, redirect_output): os.environ["CUDA_VISIBLE_DEVICES"] = str(gpu_id) import paddle - import torch try: import paddlefleet_ops # noqa: F401 @@ -149,35 +148,8 @@ def _init_worker_runtime(slot_index, gpu_id, options, *, redirect_output): except ImportError: pass - globals()["torch"] = torch globals()["paddle"] = paddle - - from tester import ( - APIConfig, - APITestAccuracy, - APITestAccuracyStable, - APITestCINNVSDygraph, - APITestCustomDeviceVSCPU, - APITestPaddleDeviceVSGPU, - APITestPaddleGPUPerformance, - APITestPaddleOnly, - APITestPaddleTorchGPUPerformance, - APITestTorchGPUPerformance, - ) - - test_classes = { - "APIConfig": APIConfig, - "APITestAccuracy": APITestAccuracy, - "APITestCINNVSDygraph": APITestCINNVSDygraph, - "APITestPaddleOnly": APITestPaddleOnly, - "APITestPaddleGPUPerformance": APITestPaddleGPUPerformance, - "APITestTorchGPUPerformance": APITestTorchGPUPerformance, - "APITestPaddleTorchGPUPerformance": APITestPaddleTorchGPUPerformance, - "APITestAccuracyStable": APITestAccuracyStable, - "APITestCustomDeviceVSCPU": APITestCustomDeviceVSCPU, - "APITestPaddleDeviceVSGPU": APITestPaddleDeviceVSGPU, - } - globals().update(test_classes) + globals().update(_load_test_classes(options)) if options.test_cpu: paddle.device.set_device("cpu") @@ -865,6 +837,85 @@ def _print_argument(prefix, message): print(f"{prefix} {message}", flush=True) +def _mode_uses_torch(options): + return any( + getattr(options, opt, False) + for opt in ( + "accuracy", + "paddle_cinn", + "paddle_gpu_performance", + "torch_gpu_performance", + "paddle_torch_gpu_performance", + "accuracy_stable", + "paddle_custom_device", + "custom_device_vs_gpu", + ) + ) + + +def _load_test_classes(options): + from tester import APIConfig, APITestPaddleOnly + + test_classes = { + "APIConfig": APIConfig, + "APITestPaddleOnly": APITestPaddleOnly, + } + if _mode_uses_torch(options): + from tester import ( + APITestAccuracy, + APITestAccuracyStable, + APITestCINNVSDygraph, + APITestCustomDeviceVSCPU, + APITestPaddleDeviceVSGPU, + APITestPaddleGPUPerformance, + APITestPaddleTorchGPUPerformance, + APITestTorchGPUPerformance, + ) + + test_classes.update( + { + "APITestAccuracy": APITestAccuracy, + "APITestCINNVSDygraph": APITestCINNVSDygraph, + "APITestPaddleGPUPerformance": APITestPaddleGPUPerformance, + "APITestTorchGPUPerformance": APITestTorchGPUPerformance, + "APITestPaddleTorchGPUPerformance": APITestPaddleTorchGPUPerformance, + "APITestAccuracyStable": APITestAccuracyStable, + "APITestCustomDeviceVSCPU": APITestCustomDeviceVSCPU, + "APITestPaddleDeviceVSGPU": APITestPaddleDeviceVSGPU, + } + ) + return test_classes + + +def _select_test_class(options): + test_classes = _load_test_classes(options) + option_to_class_name = { + "paddle_only": "APITestPaddleOnly", + "paddle_cinn": "APITestCINNVSDygraph", + "accuracy": "APITestAccuracy", + "paddle_gpu_performance": "APITestPaddleGPUPerformance", + "torch_gpu_performance": "APITestTorchGPUPerformance", + "paddle_torch_gpu_performance": "APITestPaddleTorchGPUPerformance", + "accuracy_stable": "APITestAccuracyStable", + "paddle_custom_device": "APITestCustomDeviceVSCPU", + "custom_device_vs_gpu": "APITestPaddleDeviceVSGPU", + } + for opt, class_name in option_to_class_name.items(): + if getattr(options, opt, False): + return test_classes[class_name] + return test_classes["APITestAccuracy"] + + +def _clear_device_cache(options): + import paddle + + if _mode_uses_torch(options): + import torch + + torch.cuda.empty_cache() + paddle.device.cuda.empty_cache() + + def _parse_gpu_ids(gpu_ids_arg, device_count): gpu_ids = [] for raw_part in gpu_ids_arg.split(","): @@ -1098,22 +1149,7 @@ def run_test_case(api_config_str, options): print(f"[config parse error] {api_config_str} {err!s}", flush=True) return - option_to_class = { - "paddle_only": APITestPaddleOnly, - "paddle_cinn": APITestCINNVSDygraph, - "accuracy": APITestAccuracy, - "paddle_gpu_performance": APITestPaddleGPUPerformance, - "torch_gpu_performance": APITestTorchGPUPerformance, - "paddle_torch_gpu_performance": APITestPaddleTorchGPUPerformance, - "accuracy_stable": APITestAccuracyStable, - "paddle_custom_device": APITestCustomDeviceVSCPU, - "custom_device_vs_gpu": APITestPaddleDeviceVSGPU, - } - - test_class = next( - (cls for opt, cls in option_to_class.items() if getattr(options, opt, False)), - APITestAccuracy, # default fallback - ) + test_class = _select_test_class(options) kwargs = {k: v for k, v in vars(options).items() if k in VALID_TEST_ARGS} case = test_class(api_config, **kwargs) try: @@ -1140,8 +1176,7 @@ def run_test_case(api_config_str, options): "paddle_torch_gpu_performance", ) ) and not getattr(options, "use_gpu_cache_mode", False): - torch.cuda.empty_cache() - paddle.device.cuda.empty_cache() + _clear_device_cache(options) def main(): @@ -1509,18 +1544,7 @@ def main(): except ImportError: pass - from tester import ( - APIConfig, - APITestAccuracy, - APITestAccuracyStable, - APITestCINNVSDygraph, - APITestCustomDeviceVSCPU, - APITestPaddleDeviceVSGPU, - APITestPaddleGPUPerformance, - APITestPaddleOnly, - APITestPaddleTorchGPUPerformance, - APITestTorchGPUPerformance, - ) + globals().update(_load_test_classes(options)) # set log_writer set_engineV2() @@ -1536,22 +1560,7 @@ def main(): print(f"[config parse error] {options.api_config} {err!s}", flush=True) return - option_to_class = { - "paddle_only": APITestPaddleOnly, - "paddle_cinn": APITestCINNVSDygraph, - "accuracy": APITestAccuracy, - "paddle_gpu_performance": APITestPaddleGPUPerformance, - "torch_gpu_performance": APITestTorchGPUPerformance, - "paddle_torch_gpu_performance": APITestPaddleTorchGPUPerformance, - "accuracy_stable": APITestAccuracyStable, - "paddle_custom_device": APITestCustomDeviceVSCPU, - "custom_device_vs_gpu": APITestPaddleDeviceVSGPU, - } - - test_class = next( - (cls for opt, cls in option_to_class.items() if getattr(options, opt, False)), - APITestAccuracy, # default fallback - ) + test_class = _select_test_class(options) if options.test_cpu: import paddle diff --git a/tester/api_config/config_analyzer.py b/tester/api_config/config_analyzer.py index 0f3d5a74..756a87ad 100644 --- a/tester/api_config/config_analyzer.py +++ b/tester/api_config/config_analyzer.py @@ -9,7 +9,17 @@ import numpy import paddle -import torch + + +class _LazyTorch: + def __getattr__(self, name): + import torch + + globals()["torch"] = torch + return getattr(torch, name) + + +torch = _LazyTorch() USE_CACHED_NUMPY = os.getenv("USE_CACHED_NUMPY", "False").lower() == "true" TEST_NON_CONTIGUOUS = os.getenv("TEST_NON_CONTIGUOUS", "0").lower() in ("true", "1") @@ -230,10 +240,10 @@ def _use_gpu_cache(self, dtype=None): dtype = dtype or self.dtype if not is_gpu_cache_mode(): return False - if not torch.cuda.is_available(): - return False if self.place is not None and "cpu" in str(self.place).lower(): return False + if "gpu" not in paddle.device.get_device(): + return False if not self.is_contiguous or self.strides is not None: return False if dtype in ["float8_e5m2", "float8_e4m3fn"]: @@ -249,6 +259,24 @@ def _gpu_cache_key(self, api_config, dtype=None): ) return (api_config.config, location, dtype, _shape_tuple(self.shape)) + def _make_gpu_paddle_tensor(self, dtype=None): + dtype = dtype or self.dtype + shape = tuple(self.shape) + if dtype == "bool": + paddle_tensor = paddle.randint(0, 2, shape, dtype="int32").cast("bool") + elif "int" in dtype or dtype == "uint8": + paddle_tensor = paddle.randint(-65535, 65535, shape, dtype="int64").cast(dtype) + elif dtype.startswith("complex"): + real_dtype = "float32" if dtype == "complex64" else "float64" + real_part = (paddle.rand(shape, dtype=real_dtype) - 0.5) * 1.2 + imag_part = (paddle.rand(shape, dtype=real_dtype) - 0.5) * 1.2 + paddle_tensor = (real_part + 1j * imag_part).cast(dtype) + else: + base = (paddle.rand(shape, dtype="float32") - 0.5) * 1.2 + paddle_tensor = base.cast(dtype) + paddle_tensor.stop_gradient = False + return paddle_tensor + def _make_gpu_cache_tensors(self, dtype=None): dtype = dtype or self.dtype torch_dtype = self.convert_dtype_to_torch_type(dtype) @@ -293,8 +321,11 @@ def _get_gpu_cache_entry(self, api_config, dtype=None): return cached_gpu_inputs[key] def get_gpu_paddle_tensor(self, api_config, dtype=None): - entry = self._get_gpu_cache_entry(api_config, dtype) - self.paddle_tensor = entry["paddle"] + dtype = dtype or self.dtype + key = self._gpu_cache_key(api_config, dtype) + if key not in cached_gpu_inputs: + cached_gpu_inputs[key] = {"paddle": self._make_gpu_paddle_tensor(dtype)} + self.paddle_tensor = cached_gpu_inputs[key]["paddle"] return self.paddle_tensor def get_gpu_torch_tensor(self, api_config, dtype=None): @@ -2979,7 +3010,7 @@ def get_exponent_max(value, dtype_max, default_max=5): scalar_val = (numpy.random.random() - 0.5) * 1.2 self.numpy_tensor = numpy.array(scalar_val, dtype=self.dtype) elif self._use_gpu_cache(original_dtype): - self._get_gpu_cache_entry(api_config, original_dtype) + self.get_gpu_paddle_tensor(api_config, original_dtype) elif USE_CACHED_NUMPY and self.dtype not in ["int64", "float64"]: self.numpy_tensor = self.get_cached_numpy(self.dtype, self.shape, scale=1.2) else: diff --git a/tester/base.py b/tester/base.py index cc4fc89b..55e71bf8 100644 --- a/tester/base.py +++ b/tester/base.py @@ -5,7 +5,6 @@ import numpy import paddle -import torch import yaml from .api_config.config_analyzer import ( @@ -35,6 +34,18 @@ del config + +class _LazyTorch: + def __getattr__(self, name): + import torch + + globals()["torch"] = torch + return getattr(torch, name) + + +torch = _LazyTorch() + + CUDA_ERROR = frozenset( [ "CUDA error", @@ -175,11 +186,13 @@ def get_arg(api_config, arg_pos, arg_name, default=None): class APITestBase: - def __init__(self, api_config): + def __init__(self, api_config, use_torch=True): self.api_config = api_config self.outputs_grad_numpy = [] - torch.set_num_threads(8) - torch.set_printoptions(threshold=100, linewidth=120) + self.outputs_grad_paddleonly = [] + if use_torch: + torch.set_num_threads(8) + torch.set_printoptions(threshold=100, linewidth=120) def need_skip(self, paddle_only=False): # not support @@ -744,12 +757,36 @@ def _make_torch_output_grad(self, shape, dtype): dtype=torch_dtype ) + def _make_paddle_output_grad(self, shape, dtype): + if "int" in dtype: + return paddle.randint(-65535, 65535, tuple(shape), dtype="int64").cast(dtype) + if dtype in ["float8_e5m2", "float8_e4m3fn"]: + base_dtype = "float16" + elif dtype == "bfloat16": + base_dtype = "float32" + elif dtype.startswith("complex"): + real_dtype = "float32" if dtype == "complex64" else "float64" + real_part = paddle.rand(tuple(shape), dtype=real_dtype) - 0.5 + imag_part = paddle.rand(tuple(shape), dtype=real_dtype) - 0.5 + return (real_part + 1j * imag_part).cast(dtype) + else: + base_dtype = dtype + return (paddle.rand(tuple(shape), dtype=base_dtype) - 0.5).cast(dtype) + def _use_gpu_output_grad(self, output): - if not is_gpu_cache_mode() or not torch.cuda.is_available(): + if not is_gpu_cache_mode() or "gpu" not in paddle.device.get_device(): return False dtype = str(output.dtype).split(".")[-1] return dtype in ["float32", "float64", "float16", "bfloat16", "complex64", "complex128"] + def _get_gpu_output_grad_paddleonly(self, output, index): + if len(self.outputs_grad_paddleonly) <= index: + dtype = str(output.dtype).split(".")[-1] + paddle_grad = self._make_paddle_output_grad(output.shape, dtype) + paddle_grad.stop_gradient = False + self.outputs_grad_paddleonly.append(paddle_grad) + return self.outputs_grad_paddleonly[index] + def _get_gpu_output_grad_pair(self, output, index): if len(self.outputs_grad_numpy) <= index: dtype = str(output.dtype).split(".")[-1] @@ -807,10 +844,10 @@ def gen_paddle_output_and_output_grad(self, outputs): raise ValueError("outputs format not support") result_outputs_grads = [] - if len(self.outputs_grad_numpy) == 0: + if len(self.outputs_grad_numpy) == 0 and len(self.outputs_grad_paddleonly) == 0: for i, output in enumerate(result_outputs): if self._use_gpu_output_grad(output): - self._get_gpu_output_grad_pair(output, i) + self._get_gpu_output_grad_paddleonly(output, i) continue dtype = str(output.dtype).split(".")[-1] if USE_CACHED_NUMPY: @@ -830,6 +867,8 @@ def gen_paddle_output_and_output_grad(self, outputs): numpy_dtype = dtype numpy_tensor = (numpy.random.random(output.shape) - 0.5).astype(numpy_dtype) self.outputs_grad_numpy.append(numpy_tensor) + for paddle_grad in self.outputs_grad_paddleonly: + result_outputs_grads.append(paddle_grad) for i, numpy_tensor in enumerate(self.outputs_grad_numpy): if isinstance(numpy_tensor, tuple): result_outputs_grads.append(numpy_tensor[0]) diff --git a/tester/paddle_only.py b/tester/paddle_only.py index 085600c4..1bac7a21 100644 --- a/tester/paddle_only.py +++ b/tester/paddle_only.py @@ -10,7 +10,7 @@ class APITestPaddleOnly(APITestBase): def __init__(self, api_config, **kwargs): - super().__init__(api_config) + super().__init__(api_config, use_torch=False) self.test_amp = kwargs.get("test_amp", False) # @func_set_timeout(600)