test(tx): scale the MoE LoRA tolerance to the output magnitude - #1987
test(tx): scale the MoE LoRA tolerance to the output magnitude#1987pranavraja99 wants to merge 1 commit into
Conversation
`test_qwen3_moe_layer_lora` compares the fused multi-LoRA MoE output against an equivalent merged-weight computation with `np.allclose(rtol=1e-3, atol=1e-3)`, and trips intermittently in CI. The comparison's error model is wrong for these tensors. Instrumenting the three parametrizations shows outputs reaching a magnitude of 8.5e3 to 4.7e4 with an absolute error of 0.0059 to 0.0625, i.e. ~4e-7 to ~1.4e-6 relative to the magnitude of the tensor -- ordinary float32 accumulation over the hidden dimension. That error is set by the scale of the accumulated terms, not by the value of the individual output element, so a per-element `rtol` budget of `atol + rtol*|b|` grants the largest entries tens of absolute error while leaving near-zero entries only `atol=1e-3`, which is well below the error floor. One parametrization was already consuming 60% of its budget. Compare against a single absolute tolerance scaled to the tensor instead. At `1e-4` of the max magnitude this keeps ~70x headroom over the observed error while being an order of magnitude stricter than `rtol=1e-3` for the entries that dominate the output. `np.testing.assert_allclose` also reports the mismatch count and worst offender when it does fail, instead of just `False`. Closes NovaSky-AI#1604 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request updates the test assertion in test_qwen3_moe_layer_lora to use a dynamically scaled absolute tolerance (atol) based on the maximum value of the merged output, which prevents issues with float32 accumulation errors. The reviewer suggested casting the calculated atol to a standard Python float to avoid potential type compatibility or dispatch issues when passing a JAX DeviceArray scalar to np.testing.assert_allclose.
| # tens of absolute error, so compare against one absolute tolerance scaled to the tensor. | ||
| # The observed error is <= ~1.4e-6 of that scale, so 1e-4 leaves ample headroom while | ||
| # still being an order of magnitude stricter than `rtol=1e-3` for the dominant entries. | ||
| atol = 1e-4 * np.abs(output_merged).max() |
There was a problem hiding this comment.
Since output_merged is a JAX array, np.abs(output_merged).max() returns a JAX DeviceArray scalar. Passing a JAX array directly as the atol parameter to np.testing.assert_allclose can sometimes lead to type compatibility or dispatch issues depending on the JAX and NumPy versions. Converting it to a standard Python float using float(...) ensures robust compatibility.
| atol = 1e-4 * np.abs(output_merged).max() | |
| atol = float(1e-4 * np.abs(output_merged).max()) |
Closes #1604.
test_qwen3_moe_layer_loracompares the fused multi-LoRA MoE output against an equivalent merged-weight computation withnp.allclose(rtol=1e-3, atol=1e-3)and trips intermittently in CI.The issue suspected the tolerance model, so I instrumented all three parametrizations locally to measure what the comparison actually sees:
So the error is ~4e-7 to ~1.4e-6 relative to the magnitude of the tensor — ordinary float32 accumulation over the hidden dimension, not a correctness problem. And one parametrization was already burning 60% of its tolerance budget, which is the flake.
The mismatch is in the error model.
np.allcloseallowsatol + rtol*|b|per element, but this error is set by the scale of the accumulated terms, not by the value of the individual output element. At|b| = 4.7e4that grants ~47 of absolute error, which is meaningless; at|b| ≈ 0it grants onlyatol = 1e-3, which is an order of magnitude below the error floor. The near-zero entries are what fail, exactly as the issue describes.This compares against a single absolute tolerance scaled to the tensor:
At
1e-4of the max magnitude that is ~70x headroom over the worst observed error, while being an order of magnitude stricter thanrtol=1e-3for the entries that dominate the output — so this tightens the meaningful part of the check rather than just loosening it.np.testing.assert_allcloseadditionally reports the mismatch count and worst offender on failure instead of justFalse.I did not reach for vLLM's
check_logprobs_close(also floated in the issue) since these are MoE layer activations rather than logprobs, so there is no top-k ranking to compare.Testing
uv run --isolated --extra jax --extra dev pytest tests/tx/models/test_qwen3.py -k moe_layer_lora— 3 passed, on both the instrumented and final versions. The neighbouringtest_qwen3_moe_layerandtest_qwen3assertions are left alone: their tensors are not in this magnitude range, so the same reasoning does not apply to them.🤖 Generated with Claude Code