Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions tester/accuracy.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@ def __init__(self, api_config, **kwargs):
torch.set_printoptions(profile="short")
self.converter = get_converter()

def _reset_random_state(self, seed: int = 42):
"""Reset numpy / paddle / torch (CPU+CUDA) RNGs so random APIs
(uniform, normal, randn, bernoulli, dropout, ...) produce
reproducible outputs across the torch run and the paddle run."""
numpy.random.seed(seed)
try:
paddle.seed(seed)
if paddle.device.is_compiled_with_cuda():
# paddle.seed already seeds the GPU default generator,
# but reset all device generators explicitly for safety.
try:
for i in range(paddle.device.cuda.device_count()):
paddle.framework.core.default_cuda_generator(i).manual_seed(seed)
except Exception:
pass
except Exception:
pass
try:
torch.manual_seed(seed)
if torch.cuda.is_available():
torch.cuda.manual_seed_all(seed)
except Exception:
pass

# @func_set_timeout(600)
def test(self):
if self.need_skip():
Expand Down Expand Up @@ -78,6 +102,11 @@ def test(self):
print("gen_torch_input failed", flush=True)
return

# Reseed before executing torch, so that random APIs
# (e.g. torch.rand / uniform / normal / dropout) produce
# deterministic outputs across runs when --random_seed is set.
self._reset_random_state()

# torch_args 与 torch_kwargs 是尚未映射的 torch 参数(即按 paddle 的参数顺序与关键字排列的 torch tensors)
# (弃用)以下代码等价于:
# torch_output = Paddle2TorchConverter.execute(convert_result, self.torch_args, self.torch_kwargs)
Expand Down Expand Up @@ -212,6 +241,11 @@ def process_torch_outputs(obj):
if not self.gen_paddle_input():
print("gen_paddle_input failed")
return

# Reseed before executing paddle so that random APIs
# (paddle.uniform / normal / randn / bernoulli / dropout ...)
# match the torch run with the same seed.
self._reset_random_state()
if "paddle.Tensor." in self.api_config.api_name:
api = getattr(
self.paddle_args[0],
Expand Down
24 changes: 24 additions & 0 deletions tester/accuracy_stable.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,28 @@ def __init__(self, api_config, **kwargs):
torch.set_printoptions(profile="short", edgeitems=2, threshold=100, linewidth=120)
torch.set_default_device("cuda")

def _reset_random_state(self, seed: int = 42):
"""Reset numpy / paddle / torch (CPU+CUDA) RNGs so random APIs
(uniform, normal, randn, bernoulli, dropout, ...) produce
reproducible outputs across the torch run and the paddle run."""
numpy.random.seed(seed)
try:
paddle.seed(seed)
if paddle.device.is_compiled_with_cuda():
try:
for i in range(paddle.device.cuda.device_count()):
paddle.framework.core.default_cuda_generator(i).manual_seed(seed)
except Exception:
pass
except Exception:
pass
try:
torch.manual_seed(seed)
if torch.cuda.is_available():
torch.cuda.manual_seed_all(seed)
except Exception:
pass

def test(self):
if self.need_skip():
print("[Skip]", flush=True)
Expand Down Expand Up @@ -71,6 +93,7 @@ def test(self):
# iter twice
for _i in range(2):
# ======== torch ========
self._reset_random_state()
torch_output, torch_out_grads, torch_grad_success = self.get_torch_output(
convert_result
)
Expand All @@ -79,6 +102,7 @@ def test(self):
torch.cuda.empty_cache()

# ======== paddle ========
self._reset_random_state()
paddle_output, paddle_out_grads = self.get_paddle_output(torch_grad_success)
if paddle_output is None:
return
Expand Down
22 changes: 19 additions & 3 deletions tester/api_config/config_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@
# Format: {api_name: {arg_index: init_method}}
# init_method: "zeros" = fill with 0, "small_positive" = fill with small positive value
optimizer_apis = {
"paddle._C_ops.adamw_": {3: "zeros", 4: "zeros"}, # moment1, moment2
"paddle._C_ops.adam_": {3: "zeros", 4: "zeros"},
"paddle._C_ops.merged_adam_": {3: "zeros", 4: "zeros"},
# moment1, moment2, moment2_max (must be non-negative for amsgrad)
"paddle._C_ops.adamw_": {3: "zeros", 4: "zeros", 5: "zeros"},
"paddle._C_ops.adam_": {3: "zeros", 4: "zeros", 5: "zeros"},
"paddle._C_ops.merged_adam_": {3: "zeros", 4: "zeros", 5: "zeros"},
}

not_zero_apis = frozenset(
Expand Down Expand Up @@ -283,6 +284,21 @@ def get_numpy_tensor(self, api_config, index=None, key=None, **kwargs):
self.numpy_tensor = (numpy.random.random(self.shape) + 0.5).astype(
self.dtype
)
elif api_config.api_name == "paddle._C_ops.adamw_":
if self.check_arg(api_config, 6, "beta1_pow") or self.check_arg(
api_config, 7, "beta2_pow"
):
if not hasattr(api_config, "adamw_step"):
api_config.adamw_step = numpy.random.randint(1, 101)
beta = self.get_arg(api_config, 10, "beta1")
if self.check_arg(api_config, 7, "beta2_pow"):
beta = self.get_arg(api_config, 11, "beta2")
self.numpy_tensor = numpy.full(
self.shape,
beta**api_config.adamw_step,
dtype=self.dtype,
)

elif api_config.api_name == "paddle.arange":
start_val = self.get_arg(api_config, 0, "start", 0)
end_val = self.get_arg(api_config, 1, "end", None)
Expand Down
3 changes: 3 additions & 0 deletions tester/paddle_to_torch/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -7036,6 +7036,9 @@ def _adamw_bool(value):

step = math.log(b2_pow) / math.log(b2)
if math.isfinite(step) and step > 0.0:
# step is the training iteration count, which is always an
# integer. Round to undo float32 round-trip noise from log/log.
step = round(step)
b1_pow_from_step = b1**step
bias_correction1 = 1.0 - b1_pow
fused_bias_correction1 = 1.0 - b1_pow_from_step
Expand Down
Loading