Skip to content

Commit cf558e9

Browse files
Arm backend: Add FP8 VGF operator tests (pytorch#24148)
Add E4M3 and E5M2 operator coverage with numerical comparisons where PyTorch provides the required FP8 CPU kernels. Centralize missing CPU reference handling in VgfPipelineFP8. Check VGF execution and the expected missing CPU kernel error in one test instead of two separate tests that each compile the model. Keeping this logic in the pipeline makes future changes to the testing policy easier. For cases marked expect_missing_reference=True, run VGF first without output comparison, then check for the expected missing FP8 CPU kernel error. Keep normal comparisons for cases with an available reference. Handle expected errors only during reference execution so compiler and runtime failures cannot be hidden. Fail when an expected missing CPU reference starts working, prompting the test to enable comparison. Authored with assistance from OpenAI Codex. Change-Id: I762a13f5dd05c1682a2dd1b3a9631e51cd041eef Signed-off-by: Yufeng Shi <yufeng.shi@arm.com>
1 parent cf6d4f2 commit cf558e9

25 files changed

Lines changed: 523 additions & 61 deletions

‎backends/arm/test/ops/test_adaptive_avg_pool2d.py‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
TosaPipelineFP,
1919
TosaPipelineINT,
2020
VgfPipeline,
21+
VgfPipelineFP8,
2122
)
2223

2324
exir_op = "executorch_exir_dialects_edge__ops_aten_avg_pool2d_default"
@@ -112,7 +113,7 @@ def forward(self, *args, **kwargs):
112113
),
113114
}
114115

115-
test_modules_fp8 = {
116+
test_modules_fp8_no_comparing = {
116117
"output_2x2_fp8e4m3": lambda: (
117118
AdaptiveAvgPool2d((2, 2)),
118119
(torch.rand(1, 4, 10, 10).to(torch.float8_e4m3fn),),
@@ -139,7 +140,7 @@ def test_adaptive_avg_pool2d_tosa_FP(test_module):
139140
pipeline.run()
140141

141142

142-
@common.parametrize("test_module", test_modules_fp8)
143+
@common.parametrize("test_module", test_modules_fp8_no_comparing)
143144
def test_adaptive_avg_pool2d_tosa_FP_fp8(test_module):
144145
model, input_tensor, tosa_extension = test_module()
145146

@@ -250,6 +251,20 @@ def test_adaptive_avg_pool2d_u85_INT_a16w8(test_module):
250251
pipeline.run()
251252

252253

254+
@common.parametrize("test_module", test_modules_fp8_no_comparing)
255+
@common.SkipIfNoModelConverter
256+
def test_adaptive_avg_pool2d_vgf_no_quant_fp8(test_module):
257+
model, input_tensor, _ = test_module()
258+
pipeline = VgfPipelineFP8[input_t](
259+
model,
260+
input_tensor,
261+
aten_op=[],
262+
exir_op=exir_op,
263+
expect_missing_reference=True,
264+
)
265+
pipeline.run()
266+
267+
253268
@common.parametrize("test_module", test_modules)
254269
@common.SkipIfNoModelConverter
255270
def test_adaptive_avg_pool2d_vgf_no_quant(test_module):

‎backends/arm/test/ops/test_avg_pool2d.py‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
TosaPipelineFP,
2121
TosaPipelineINT,
2222
VgfPipeline,
23+
VgfPipelineFP8,
2324
)
2425

2526
aten_op = "avg_pool2d.default"
@@ -152,7 +153,7 @@ def forward(self, x: torch.Tensor):
152153
(torch.rand(1, 4, 12, 12, dtype=torch.float16),),
153154
),
154155
}
155-
test_modules_fp8 = {
156+
test_modules_fp8_no_comparing = {
156157
"rand_fp8e4m3": lambda: (
157158
AvgPool2d(4, 2, 0, False),
158159
(torch.rand(1, 16, 50, 32).to(torch.float8_e4m3fn),),
@@ -180,7 +181,7 @@ def test_avg_pool2d_tosa_FP(test_module):
180181
pipeline.run()
181182

182183

183-
@common.parametrize("test_module", test_modules_fp8)
184+
@common.parametrize("test_module", test_modules_fp8_no_comparing)
184185
def test_avg_pool2d_tosa_FP_fp8(test_module):
185186
model, input_tensor, tosa_extension = test_module()
186187
pipeline = TosaPipelineFP[input_t](
@@ -288,6 +289,20 @@ def test_avg_pool2d_16a8w_u85_INT(test_module):
288289
pipeline.run()
289290

290291

292+
@common.parametrize("test_module", test_modules_fp8_no_comparing)
293+
@common.SkipIfNoModelConverter
294+
def test_avg_pool2d_vgf_no_quant_fp8(test_module):
295+
model, input_tensor, _ = test_module()
296+
pipeline = VgfPipelineFP8[input_t](
297+
model,
298+
input_tensor,
299+
aten_op,
300+
exir_op,
301+
expect_missing_reference=True,
302+
)
303+
pipeline.run()
304+
305+
291306
@common.parametrize(
292307
"test_module",
293308
test_modules | test_modules_bf16 | test_modules_fp16,

‎backends/arm/test/ops/test_cat.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,23 @@ def test_cat_u85_INT(test_data: Tuple):
201201
pipeline.run()
202202

203203

204+
@common.parametrize("test_data", Cat.test_parameters_fp8)
205+
@common.SkipIfNoModelConverter
206+
def test_cat_vgf_no_quant_fp8(test_data: Tuple):
207+
tensors, dim, _ = test_data()
208+
pipeline = VgfPipeline[input_t1](
209+
Cat(),
210+
(tensors, dim),
211+
aten_op,
212+
exir_op,
213+
tosa_extensions=["fp8e4m3", "fp8e5m2"],
214+
quantize=False,
215+
atol=0,
216+
rtol=0,
217+
)
218+
pipeline.run()
219+
220+
204221
@common.parametrize(
205222
"test_data",
206223
Cat.test_parameters | Cat.test_parameters_bf16 | Cat.test_parameters_fp16,

‎backends/arm/test/ops/test_constant_pad_nd.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,23 @@ def test_constant_pad_nd_u55_INT():
404404
pipeline.run()
405405

406406

407+
@common.parametrize("test_data", test_data_suite_fp8)
408+
@common.SkipIfNoModelConverter
409+
def test_constant_pad_nd_vgf_no_quant_fp8(test_data: Tuple):
410+
test_data, padding, value, mode, _ = test_data()
411+
pipeline = VgfPipeline[input_t1](
412+
ConstantPadND(padding, value, mode),
413+
(test_data,),
414+
aten_op,
415+
exir_op,
416+
tosa_extensions=["fp8e4m3", "fp8e5m2"],
417+
quantize=False,
418+
atol=0,
419+
rtol=0,
420+
)
421+
pipeline.run()
422+
423+
407424
@common.parametrize(
408425
"test_data", test_data_suite | test_data_suite_bf16 | test_data_suite_fp16
409426
)

‎backends/arm/test/ops/test_conv2d.py‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
TosaPipelineFP,
2020
TosaPipelineINT,
2121
VgfPipeline,
22+
VgfPipelineFP8,
2223
)
2324

2425
aten_op = "torch.ops.aten.conv2d.default"
@@ -522,7 +523,7 @@ def conv2d_fp16_1x1():
522523
"fp16_3x3": conv2d_fp16_3x3,
523524
"fp16_1x1": conv2d_fp16_1x1,
524525
}
525-
test_data_FP_fp8 = {
526+
test_data_FP_fp8_no_comparing = {
526527
"fp8e4m3": lambda: (
527528
Conv2d(
528529
height=8,
@@ -607,7 +608,7 @@ def test_convolution_2d_tosa_FP(test_data):
607608
pipeline.run()
608609

609610

610-
@common.parametrize("test_data", test_data_FP_fp8)
611+
@common.parametrize("test_data", test_data_FP_fp8_no_comparing)
611612
def test_convolution_2d_tosa_FP_fp8(test_data):
612613
model, tosa_extension = test_data()
613614
pipeline = TosaPipelineFP[input_t](
@@ -718,6 +719,20 @@ def test_convolution_2d_u85_INT_a8w4(test_data):
718719
pipeline.run()
719720

720721

722+
@common.parametrize("test_data", test_data_FP_fp8_no_comparing)
723+
@common.SkipIfNoModelConverter
724+
def test_convolution_2d_vgf_no_quant_fp8(test_data):
725+
model, _ = test_data()
726+
pipeline = VgfPipelineFP8[input_t](
727+
model,
728+
model.get_inputs(),
729+
aten_op,
730+
exir_op,
731+
expect_missing_reference=True,
732+
)
733+
pipeline.run()
734+
735+
721736
@common.parametrize("test_data", test_data_FP | test_data_FP_bf16 | test_data_FP_fp16)
722737
@common.SkipIfNoModelConverter
723738
def test_convolution_2d_vgf_no_quant(test_data):

‎backends/arm/test/ops/test_conv3d.py‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
TosaPipelineFP,
2121
TosaPipelineINT,
2222
VgfPipeline,
23+
VgfPipelineFP8,
2324
)
2425

2526
aten_op = "torch.ops.aten.conv3d.default"
@@ -483,7 +484,7 @@ def forward(self, x):
483484
"5x5_3x2x24x24_st1": lambda: conv3d_5x5_3x2x24x24_st1,
484485
"3x3_1x3x28x28_st2_pd1": lambda: conv3d_3x3_1x3x28x28_st2_pd1,
485486
}
486-
test_data_FP_fp8 = {
487+
test_data_FP_fp8_no_comparing = {
487488
"basic_fp8e4m3": lambda: (
488489
Conv3d(
489490
height=6,
@@ -608,7 +609,7 @@ def test_convolution_3d_tosa_FP(test_data):
608609
pipeline.run()
609610

610611

611-
@common.parametrize("test_data", test_data_FP_fp8)
612+
@common.parametrize("test_data", test_data_FP_fp8_no_comparing)
612613
def test_convolution_3d_tosa_FP_fp8(test_data):
613614
model, tosa_extension = test_data()
614615
pipeline = TosaPipelineFP[input_t](
@@ -773,6 +774,20 @@ def test_convolution_3d_u85_INT_a8w4(test_data):
773774
pipeline.run()
774775

775776

777+
@common.parametrize("test_data", test_data_FP_fp8_no_comparing)
778+
@common.SkipIfNoModelConverter
779+
def test_convolution_3d_vgf_no_quant_fp8(test_data):
780+
model, _ = test_data()
781+
pipeline = VgfPipelineFP8[input_t](
782+
model,
783+
model.get_inputs(),
784+
aten_op,
785+
exir_op,
786+
expect_missing_reference=True,
787+
)
788+
pipeline.run()
789+
790+
776791
@common.parametrize("test_data", test_data_FP | test_data_FP_bf16 | test_data_FP_fp16)
777792
@common.SkipIfNoModelConverter
778793
def test_convolution_3d_vgf_no_quant(test_data):

‎backends/arm/test/ops/test_depthwise_conv.py‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
TosaPipelineFP,
2121
TosaPipelineINT,
2222
VgfPipeline,
23+
VgfPipelineFP8,
2324
)
2425

2526
input_t = Tuple[torch.Tensor] # Input x
@@ -195,7 +196,7 @@
195196
dtype=torch.float16,
196197
),
197198
}
198-
test_data_conv2d_FP_fp8 = {
199+
test_data_conv2d_FP_fp8_no_comparing = {
199200
"fp8e4m3_3x3_gp3": lambda: (
200201
Conv2d(
201202
in_channels=3,
@@ -289,7 +290,7 @@ def test_convolution_2d_tosa_FP_depthwise(test_data: torch.nn.Module):
289290
pipeline.run()
290291

291292

292-
@common.parametrize("test_data", test_data_conv2d_FP_fp8)
293+
@common.parametrize("test_data", test_data_conv2d_FP_fp8_no_comparing)
293294
def test_convolution_2d_tosa_FP_fp8_depthwise(test_data):
294295
model, tosa_extension = test_data()
295296
pipeline = TosaPipelineFP[input_t](
@@ -340,6 +341,20 @@ def test_convolution_2d_tosa_INT_a8w4_depthwise(test_data):
340341
pipeline.run()
341342

342343

344+
@common.parametrize("test_data", test_data_conv2d_FP_fp8_no_comparing)
345+
@common.SkipIfNoModelConverter
346+
def test_convolution_2d_vgf_no_quant_fp8_depthwise(test_data):
347+
model, _ = test_data()
348+
pipeline = VgfPipelineFP8[input_t](
349+
model,
350+
model.get_inputs(),
351+
aten_op=[],
352+
exir_op=exir_op,
353+
expect_missing_reference=True,
354+
)
355+
pipeline.run()
356+
357+
343358
@common.parametrize(
344359
"test_data",
345360
test_data_conv1d_FP

‎backends/arm/test/ops/test_embedding.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,25 @@ def test_embedding_tosa_INT_expand():
141141
pipeline.run()
142142

143143

144+
@common.parametrize("test_input", test_input_fp8)
145+
@common.SkipIfNoModelConverter
146+
def test_embedding_vgf_no_quant_fp8(test_input):
147+
inputs, _ = test_input
148+
op = Embedding()
149+
pipeline = VgfPipeline[input_params](
150+
op,
151+
inputs,
152+
op.aten_op,
153+
op.exir_op,
154+
transform_passes=[InsertInt32CastsAfterInt64PlaceholdersPass()],
155+
tosa_extensions=["fp8e4m3", "fp8e5m2"],
156+
quantize=False,
157+
atol=0,
158+
rtol=0,
159+
)
160+
pipeline.run()
161+
162+
144163
@pytest.mark.skip("reason=MLETORCH-1274 Improve data type checks during partitioning")
145164
@common.parametrize("test_input", test_input)
146165
@common.SkipIfNoModelConverter

‎backends/arm/test/ops/test_flip.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,23 @@ def test_flip_u85_INT(test_data):
225225
pipeline.run()
226226

227227

228+
@common.parametrize("test_data", test_data_suite_fp8)
229+
@common.SkipIfNoModelConverter
230+
def test_flip_vgf_no_quant_fp8(test_data):
231+
data, dims, _ = test_data()
232+
pipeline = VgfPipeline[input_t1](
233+
Flip(dims),
234+
(data,),
235+
aten_op,
236+
exir_op,
237+
tosa_extensions=["fp8e4m3", "fp8e5m2"],
238+
quantize=False,
239+
atol=0,
240+
rtol=0,
241+
)
242+
pipeline.run()
243+
244+
228245
@common.parametrize("test_data", test_data_suite)
229246
@common.SkipIfNoModelConverter
230247
def test_flip_vgf_no_quant(test_data):

‎backends/arm/test/ops/test_gather.py‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
TosaPipelineFP,
1717
TosaPipelineINT,
1818
VgfPipeline,
19+
VgfPipelineFP8,
1920
)
2021

2122

@@ -87,7 +88,7 @@ def forward(self, input_: torch.Tensor, dim_, index_: torch.Tensor):
8788
), # Shape: [N=2, W=2, C=2]
8889
),
8990
}
90-
test_data_fp_fp8: dict[str, tuple[input_params, str]] = {
91+
test_data_fp_fp8_no_comparing: dict[str, tuple[input_params, str]] = {
9192
"test_fp8e4m3_2d": (
9293
(
9394
torch.tensor(
@@ -175,7 +176,7 @@ def test_gather_tosa_FP(test_data: input_params):
175176
pipeline.run()
176177

177178

178-
@common.parametrize("test_data", test_data_fp_fp8)
179+
@common.parametrize("test_data", test_data_fp_fp8_no_comparing)
179180
def test_gather_tosa_FP_fp8(test_data: tuple[input_params, str]):
180181
input_data, tosa_extension = test_data
181182
pipeline = TosaPipelineFP[input_params](
@@ -231,6 +232,23 @@ def test_gather_u85_INT(test_data: input_params):
231232
pipeline.run()
232233

233234

235+
@common.parametrize("test_data", test_data_fp_fp8_no_comparing)
236+
@common.SkipIfNoModelConverter
237+
def test_gather_vgf_no_quant_fp8(test_data: tuple[input_params, str]):
238+
input_data, _ = test_data
239+
pipeline = VgfPipelineFP8[input_params](
240+
Gather(),
241+
input_data,
242+
aten_op=Gather.aten_op,
243+
exir_op=Gather.exir_op,
244+
transform_passes=[InsertInt32CastsAfterInt64PlaceholdersPass()],
245+
expect_missing_reference=True,
246+
atol=0,
247+
rtol=0,
248+
)
249+
pipeline.run()
250+
251+
234252
@common.parametrize("test_data", test_data_fp | test_data_fp_bf16 | test_data_int)
235253
@common.SkipIfNoModelConverter
236254
def test_gather_vgf_no_quant(test_data: input_params):

0 commit comments

Comments
 (0)