Tolerances¶
Every comparison that doesn't pass rtol/atol itself uses a default. Set those defaults
once for the whole project instead of repeating them in every test.
In pyproject.toml¶
[tool.pytest_torch.tolerance]
bfloat16 = { rtol = 2e-2, atol = 1e-2 } # every comparison of bf16 tensors
"cuda.float32" = { rtol = 1e-4, atol = 1e-5 } # float32, only when testing on CUDA (TF32)
compile_parity = { rtol = 1e-3, atol = 1e-3 } # default of assert_compile_parity
device_parity = { atol = 1e-3 } # the contract's cross-device check; rtol stays built-in
A key is one of:
| Key | Applies to |
|---|---|
a dtype: float64, float32, float16, bfloat16, complex64, complex128, float8_* |
any comparison of tensors of that dtype: assert_tensors_close, assert_outputs_close, golden files, invariance and batch checks, the contract's same-device checks, assert_matches_reference |
a check: compile_parity, export_parity, aoti_parity, torchscript_parity, onnx_parity, autocast_parity, device_parity, dtype_parity, divergence, gradcheck, checkpoint, layout_invariance, streaming, training_resume, grad_accumulation |
the default of that assertion (or contract check) |
<device>.<dtype or check>, device one of cpu, cuda, xpu, mps |
the same, only when the test runs on that device |
An entry may set only rtol or only atol; the other value comes from the next layer.
Mistakes (an unknown key or device, a negative or non-numeric value) stop pytest at startup
with a message saying what is wrong.
For one test, class or module¶
@pytest.mark.torch_tolerance(bfloat16=(5e-2, 1e-2), compile_parity={"atol": 1e-3})
def test_low_precision(model, make_tensor):
...
@pytest.mark.torch_tolerance(**{"cuda.float32": (1e-3, 1e-4)}) # device keys need **
class TestOnAmpere:
...
pytestmark = pytest.mark.torch_tolerance(float16=(1e-2, 1e-3)) # the whole module
Values are (rtol, atol) or {"rtol": ..., "atol": ...}. Markers on the module, the class
and the test all apply; the closest one wins for the keys they share.
Outside pytest (or for one block), use the context manager:
from pytest_torch import tolerance_overrides
with tolerance_overrides(bfloat16=(5e-2, 1e-2)):
assert_outputs_close(out_bf16, reference)
Resolution order¶
For each of rtol and atol separately:
- the argument passed to the assertion;
@pytest.mark.torch_tolerance(closest marker first) ortolerance_overrides;[tool.pytest_torch.tolerance]inpyproject.toml;- the built-in default.
Within steps 2 and 3, a <device>. entry beats the generic one. The device is the test's
torch_device when it has one, even if outputs were moved to the CPU before comparing;
otherwise it is the device of the tensors or model being compared.
Failure messages always print the tolerance that was used, e.g.
(rtol=0.02, atol=0.01), so you can tell which layer applied.
Built-in defaults¶
| Dtype | rtol | atol |
|---|---|---|
float64, complex128 |
1e-7 | 1e-7 |
float32, complex64 (and other dtypes) |
1.3e-6 | 1e-5 |
float16 |
1e-3 | 1e-5 |
bfloat16 |
1.6e-2 | 1e-5 |
| Check | rtol | atol |
|---|---|---|
compile_parity, aoti_parity, device_parity, divergence |
1e-4 | 1e-4 |
export_parity, torchscript_parity |
1e-5 | 1e-5 |
onnx_parity |
1e-3 | 1e-4 |
autocast_parity, dtype_parity |
2e-2 | 2e-2 |
gradcheck |
1e-3 | 1e-5 |