Skip to content

Commit 20fe4d6

Browse files
Arm backend: Fix FP8 mismatch diagnostics (#23991)
Use FP32 for diagnostic statistics when either output has dtype torch.float8_e4m3fn or torch.float8_e5m2, avoiding unsupported CPU operations. Preserve the original tensor dtypes in saved artifacts. Correct the dump callback argument order so reference and result tensors are saved to the right files. Change-Id: I854c7985ee0eb598af78f025dc520a1821b7f178 Signed-off-by: Yufeng Shi <yufeng.shi@arm.com>
1 parent 405bd61 commit 20fe4d6

2 files changed

Lines changed: 60 additions & 1 deletion

File tree

‎backends/arm/test/misc/test_debug_feats.py‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from executorch.backends.arm.common.arm_compile_spec import ArmCompileSpec
1818
from executorch.backends.arm.test import common
1919
from executorch.backends.arm.test.runner_utils import dbg_tosa_fb_to_json
20+
from executorch.backends.arm.test.tester.arm_tester import ArmTester
2021
from executorch.backends.arm.test.tester.test_pipeline import (
2122
EthosU55PipelineINT,
2223
TosaPipelineFP,
@@ -128,6 +129,59 @@ def test_tosa_FP_can_skip_ref_model_output_comparison(test_data: input_t1):
128129
assert validation_compare_stage.kwargs["inputs"] == test_data
129130

130131

132+
@common.parametrize(
133+
"dtype_extension",
134+
{
135+
"e4m3": (torch.float8_e4m3fn, torch.float8_e4m3fn, "fp8e4m3"),
136+
"e5m2": (torch.float8_e5m2, torch.float8_e5m2, "fp8e5m2"),
137+
"e4m3_fp32": (torch.float8_e4m3fn, torch.float32, "fp8e4m3"),
138+
"fp32_e4m3": (torch.float32, torch.float8_e4m3fn, "fp8e4m3"),
139+
"e5m2_fp32": (torch.float8_e5m2, torch.float32, "fp8e5m2"),
140+
"fp32_e5m2": (torch.float32, torch.float8_e5m2, "fp8e5m2"),
141+
},
142+
)
143+
def test_fp8_mismatch_reports_and_saves_diagnostics(dtype_extension, tmp_path, caplog):
144+
reference_dtype, result_dtype, extension = dtype_extension
145+
reference = (
146+
torch.tensor([1.0, 2.0, 3.0, 4.0]).reshape(1, 2, 1, 2).to(reference_dtype)
147+
)
148+
result = torch.tensor([1.0, 2.0, 4.0, 5.0]).reshape(1, 2, 1, 2).to(result_dtype)
149+
tester = ArmTester(
150+
torch.nn.Identity(),
151+
(reference,),
152+
common.get_vgf_compile_spec(
153+
f"TOSA-1.0+FP+{extension}", custom_path=str(tmp_path)
154+
),
155+
)
156+
157+
# The base comparator only widens inputs when the result is FP8.
158+
def compare_in_fp32(reference, result, _):
159+
ArmTester._assert_outputs_equal(
160+
[result.float()], [reference.float()], atol=0, rtol=0
161+
)
162+
163+
with pytest.raises(
164+
AssertionError, match="Output 0 does not match reference output"
165+
):
166+
tester._compare_outputs(
167+
reference,
168+
result,
169+
atol=0,
170+
rtol=0,
171+
compare_callback=compare_in_fp32 if result_dtype == torch.float32 else None,
172+
)
173+
174+
assert "ERROR DIFFERENCE" in caplog.text
175+
assert "MEAN MEDIAN MAX MIN" in caplog.text
176+
for filename, expected in (
177+
("torch_tosa_output.pt", result),
178+
("torch_ref_output.pt", reference),
179+
):
180+
saved = torch.load(tmp_path / filename, weights_only=True)
181+
assert saved.dtype == expected.dtype
182+
torch.testing.assert_close(saved.float(), expected.float(), atol=0, rtol=0)
183+
184+
131185
@common.parametrize("test_data", Linear.inputs)
132186
def test_artifact_tosa_FP(test_data: input_t1):
133187
model = Linear()

‎backends/arm/test/tester/analyze_output_utils.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ def print_error_diffs( # noqa: C901
173173
result = _ensure_tensor(result_or_reference)
174174
reference_tensor = _ensure_tensor(reference)
175175

176+
fp8_dtypes = (torch.float8_e4m3fn, torch.float8_e5m2)
177+
if result.dtype in fp8_dtypes or reference_tensor.dtype in fp8_dtypes:
178+
result = result.to(torch.float32)
179+
reference_tensor = reference_tensor.to(torch.float32)
180+
176181
if result.shape != reference_tensor.shape:
177182
raise ValueError(
178183
f"Output needs to be of same shape: {result.shape} != {reference_tensor.shape}"
@@ -294,8 +299,8 @@ def print_error_diffs( # noqa: C901
294299

295300
def dump_error_output(
296301
tester: Any,
297-
reference_output: TensorLike,
298302
stage_output: TensorLike,
303+
reference_output: TensorLike,
299304
quantization_scale: float | None = None,
300305
atol: float = 1e-03,
301306
rtol: float = 1e-03,

0 commit comments

Comments
 (0)