Relax test_bf16_stochastic_round tolerance#4576
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/ao/4576
Note: Links to docs will display an error until the docs builds have been completed. ❌ 3 New FailuresAs of commit 907671e with merge base eec7681 ( NEW FAILURES - The following jobs have failed:
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
6527d7b to
6a2fa2d
Compare
|
|
6a2fa2d to
8549700
Compare
8549700 to
4bb7456
Compare
4bb7456 to
907671e
Compare
Detailed analysis and rationaleSummary of the problem
# test/test_low_bit_optim.py
def test_bf16_stochastic_round(self, device, compile):
x = torch.rand(32, device=device) * 100
x_rep = x.view(-1, 1).repeat(1, 100_000)
func = torch.compile(_fp32_to_bf16_sr, fullgraph=True, dynamic=False, disable=not compile)
x_rep_bf16 = func(x_rep)
...
torch.testing.assert_close(x_rep_bf16.float().mean(1), x, atol=3e-5, rtol=3e-5)
Problem analysisDue to seeding, the rounding draws are identical on every invocation. This makes the outcome fully deterministic per machine. That explains why we have the same results on the same machine. On the other hand, the same seed does not produce the same random bits on every device: PyTorch's on-device RNG (counter-based, Philox-style) partitions its counter space according to the kernel launch geometry, which depends on the GPU's execution resources (tile/EU count, SIMD width). So a fixed seed lands on a slightly different sample per GPU model. This explains why the test may behave differently on PVC 1100. We can use the following script (Monte Carlo like experiment that repeats the test logic multiple times) to measure the true statistical behavior (independent of the fixed-seed), and real error distribution on a given device: The results are:
It shows two things:
Proposed fixI propose loosening the test tolerance to torch.testing.assert_close(x_rep_bf16.float().mean(1), x, atol=5e-3, rtol=5e-3)This is justified by the measured error distribution. This makes the test pass in CI, while eliminating false positives from sampling variance alone. |
SummaryThis failure is not device-specific. After changing the test seed configuration, the same failure was reproduced on other hardware platforms as well:
Reproduce:def test_bf16_stochastic_round(self, device, compile):
torch.seed(42) # For cuda, set it to 16
x = torch.rand(32, device=device) * 100
x_rep = x.view(-1, 1).repeat(1, 100_000)
func = torch.compile(_fp32_to_bf16_sr, fullgraph=True, dynamic=False, disable=not compile)
x_rep_bf16 = func(x_rep)
...
torch.testing.assert_close(x_rep_bf16.float().mean(1), x, atol=3e-5, rtol=3e-5)LOGCPU log ======================================================================== test session starts ========================================================================
test/test_low_bit_optim.py::TestQuantize::test_bf16_stochastic_round_device_cpu_compile_False
FAILED
============================================================================= FAILURES ==============================================================================
_________________________________________________ TestQuantize.test_bf16_stochastic_round_device_cpu_compile_False __________________________________________________
self = <test.test_low_bit_optim.TestQuantize testMethod=test_bf16_stochastic_round_device_cpu_compile_False>, device = 'cpu', compile = False
@parametrize("device", _DEVICES)
@parametrize("compile", [False, True])
def test_bf16_stochastic_round(self, device, compile):
torch.manual_seed(42)
x = torch.rand(32, device=device) * 100
x_rep = x.view(-1, 1).repeat(1, 100_000)
func = torch.compile(
_fp32_to_bf16_sr, fullgraph=True, dynamic=False, disable=not compile
)
x_rep_bf16 = func(x_rep)
assert x_rep_bf16.dtype is torch.bfloat16
# must cast BF16 tensor back to FP32 so that .mean() is accurate
> torch.testing.assert_close(x_rep_bf16.float().mean(1), x, atol=3e-5, rtol=3e-5)
E AssertionError: Tensor-likes are not close!
E
E Mismatched elements: 1 / 32 (3.1%)
E Greatest absolute difference: 0.0028076171875 at index (0,) (up to 3e-05 allowed)
E Greatest relative difference: 3.18226775561925e-05 at index (0,) (up to 3e-05 allowed)
E
E To execute this test, run the following from the base repo dir:
E python test/test_low_bit_optim.py TestQuantize.test_bf16_stochastic_round_device_cpu_compile_False
E
E This message can be suppressed by setting PYTORCH_PRINT_REPRO_ON_FAILURE=0
test/test_low_bit_optim.py:122: AssertionError
====================================================================== short test summary info ======================================================================
FAILED test/test_low_bit_optim.py::TestQuantize::test_bf16_stochastic_round_device_cpu_compile_False - AssertionError: Tensor-likes are not close!
========================================================================= 1 failed in 2.29s =========================================================================CUDA log ======================================================================== test session starts ========================================================================
test/test_low_bit_optim.py::TestQuantize::test_bf16_stochastic_round_device_cuda_compile_False
FAILED
============================================================================= FAILURES ==============================================================================
_________________________________________________ TestQuantize.test_bf16_stochastic_round_device_cuda_compile_False _________________________________________________
self = <test.test_low_bit_optim.TestQuantize testMethod=test_bf16_stochastic_round_device_cuda_compile_False>, device = 'cuda', compile = False
@parametrize("device", _DEVICES)
@parametrize("compile", [False, True])
def test_bf16_stochastic_round(self, device, compile):
torch.manual_seed(16)
x = torch.rand(32, device=device) * 100
x_rep = x.view(-1, 1).repeat(1, 100_000)
func = torch.compile(
_fp32_to_bf16_sr, fullgraph=True, dynamic=False, disable=not compile
)
x_rep_bf16 = func(x_rep)
assert x_rep_bf16.dtype is torch.bfloat16
# must cast BF16 tensor back to FP32 so that .mean() is accurate
> torch.testing.assert_close(x_rep_bf16.float().mean(1), x, atol=3e-5, rtol=3e-5)
E AssertionError: Tensor-likes are not close!
E
E Mismatched elements: 1 / 32 (3.1%)
E Greatest absolute difference: 0.001636505126953125 at index (0,) (up to 3e-05 allowed)
E Greatest relative difference: 4.938915662933141e-05 at index (0,) (up to 3e-05 allowed)
E
E To execute this test, run the following from the base repo dir:
E python test/test_low_bit_optim.py TestQuantize.test_bf16_stochastic_round_device_cuda_compile_False
E
E This message can be suppressed by setting PYTORCH_PRINT_REPRO_ON_FAILURE=0
test/test_low_bit_optim.py:122: AssertionError
====================================================================== short test summary info ======================================================================
FAILED test/test_low_bit_optim.py::TestQuantize::test_bf16_stochastic_round_device_cuda_compile_False - AssertionError: Tensor-likes are not close!
========================================================================= 1 failed in 3.95s ========================================================================= |
|
The test_bf16_stochastic_round test failure is unrelated to the device (CPU/CUDA/XPU) and is purely a statistical design flaw in the test itself: The test uses 32 random samples, each repeated over 100,000 stochastic rounding draws, and takes the mean to verify the unbiasedness of stochastic rounding. Fix recommendation: |
|
@karol-brejna-i Could you please investigate whether analogous operations exist in PyTorch, or examine relevant fp32-to-bf16 casting cases to determine their tolerance settings, and ensure that torchao is aligned with PyTorch in this regard. |
PR Description
TL;DR
This PR enables
test/test_low_bit_optim.pyin XPU CI (ci_test_xpu.sh).It also fixes
test_low_bit_optim.py::TestQuantize::test_bf16_stochastic_round_device_xpu_compile_False.test_bf16_stochastic_round's tolerance was too tight for the stochastic-rounding estimator's natural sampling variance, causing a ~2-3% flake rate that appeared as a deterministic PVC-only failure (fixed RNG seed in the test harness). Widened the tolerance to match the actual variance and enabledtest/test_low_bit_optim.pyin XPU CI.Details
xin the sampled range, the tolerance (rtol·x, up to ~3e-3) was only about 7 standard deviations above the estimator's real noise (std≈4.3e-4) — not enough margin, so it occasionally failed. Fixed seeding then turned that rare flake into a result that always repeats on the same machine.atol/rtolin the test's finalassert_close(no changes to the SR kernel or seeding).test/test_low_bit_optim.pyinci_test_xpu.sh.