Skip to content

Commit 13e2668

Browse files
authored
Arm backend: Add VGF tests to add op unit tests (#12058)
Note that tests are skipped until model-converter is available.
1 parent 268806c commit 13e2668

File tree

5 files changed

+189
-1
lines changed

5 files changed

+189
-1
lines changed

backends/arm/test/common.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,39 @@ def get_tosa_compile_spec_unbuilt(
8989
return compile_spec_builder
9090

9191

92+
def get_vgf_compile_spec(
93+
tosa_spec: str | TosaSpecification,
94+
compiler_flags: Optional[str] = "",
95+
custom_path=None,
96+
) -> list[CompileSpec]:
97+
"""
98+
Default compile spec for VGF tests.
99+
"""
100+
return get_vgf_compile_spec_unbuilt(tosa_spec, compiler_flags, custom_path).build()
101+
102+
103+
def get_vgf_compile_spec_unbuilt(
104+
tosa_spec: str | TosaSpecification,
105+
compiler_flags: Optional[str] = "",
106+
custom_path=None,
107+
) -> ArmCompileSpecBuilder:
108+
"""Get the ArmCompileSpecBuilder for the default VGF tests, to modify
109+
the compile spec before calling .build() to finalize it.
110+
"""
111+
if not custom_path:
112+
custom_path = maybe_get_tosa_collate_path()
113+
114+
if custom_path is not None:
115+
os.makedirs(custom_path, exist_ok=True)
116+
compile_spec_builder = (
117+
ArmCompileSpecBuilder()
118+
.vgf_compile_spec(tosa_spec, compiler_flags)
119+
.dump_intermediate_artifacts_to(custom_path)
120+
)
121+
122+
return compile_spec_builder
123+
124+
92125
def get_u55_compile_spec(
93126
macs: int = 128,
94127
system_config: str = "Ethos_U55_High_End_Embedded",

backends/arm/test/ops/test_add.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
from typing import Tuple
99

10+
import pytest
11+
1012
import torch
1113
from executorch.backends.arm.arm_backend import get_tosa_spec
1214
from executorch.backends.arm.quantizer import arm_quantizer
@@ -16,6 +18,7 @@
1618
EthosU85PipelineBI,
1719
TosaPipelineBI,
1820
TosaPipelineMI,
21+
VgfPipeline,
1922
)
2023
from executorch.backends.arm.tosa_specification import TosaSpecification
2124
from executorch.backends.xnnpack.test.tester import Quantize
@@ -184,3 +187,26 @@ def test_add_tensor_u85_BI_2(test_data: input_t2):
184187
Add2(), test_data(), aten_op, exir_op, run_on_fvp=True
185188
)
186189
pipeline.run()
190+
191+
192+
@common.parametrize("test_data", Add.test_data)
193+
@pytest.mark.skip(reason="Model converter not yet made available")
194+
def test_add_tensor_vgf_fp(test_data: input_t1):
195+
pipeline = VgfPipeline[input_t1](
196+
Add(), test_data(), aten_op, exir_op, tosa_version="TOSA-1.0+FP"
197+
)
198+
pipeline.run()
199+
200+
201+
@common.parametrize("test_data", Add.test_data)
202+
@pytest.mark.skip(reason="Model converter not yet made available")
203+
def test_add_tensor_vgf_int(test_data: input_t1):
204+
pipeline = VgfPipeline[input_t1](
205+
Add(),
206+
test_data(),
207+
aten_op,
208+
exir_op,
209+
tosa_version="TOSA-1.0+INT",
210+
symmetric_io_quantization=True,
211+
)
212+
pipeline.run()

backends/arm/test/tester/arm_tester.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
get_tosa_spec,
3737
is_ethosu,
3838
is_tosa,
39+
is_vgf,
3940
)
4041
from executorch.backends.arm.ethosu_partitioner import EthosUPartitioner
4142
from executorch.backends.arm.quantizer import (
@@ -61,6 +62,8 @@
6162
from executorch.backends.arm.tosa_partitioner import TOSAPartitioner
6263
from executorch.backends.arm.tosa_specification import TosaSpecification
6364

65+
from executorch.backends.arm.vgf_partitioner import VgfPartitioner
66+
6467
from executorch.backends.test.harness.stages import Stage, StageType
6568
from executorch.backends.xnnpack.test.tester import Tester
6669
from executorch.devtools.backend_debug import get_delegation_info
@@ -384,6 +387,11 @@ def to_edge_transform_and_lower(
384387
compile_spec=self.compile_spec,
385388
additional_checks=additional_checks,
386389
)
390+
elif is_vgf(self.compile_spec):
391+
arm_partitioner = VgfPartitioner(
392+
compile_spec=self.compile_spec,
393+
additional_checks=additional_checks,
394+
)
387395
else:
388396
raise ValueError("compile spec doesn't target any Arm Partitioner")
389397
partitioners = [arm_partitioner]

backends/arm/test/tester/test_pipeline.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
EthosUQuantizer,
2626
get_symmetric_quantization_config,
2727
TOSAQuantizer,
28+
VgfQuantizer,
2829
)
2930
from executorch.backends.arm.test import common, conftest
3031
from executorch.backends.arm.test.tester.arm_tester import ArmTester, RunPasses
@@ -827,3 +828,123 @@ def __init__(
827828
},
828829
)
829830
self.pop_stage("to_executorch")
831+
832+
833+
class VgfPipeline(BasePipelineMaker, Generic[T]):
834+
"""
835+
Lowers a graph based on TOSA spec (with or without quantization) and converts TOSA to VFG.
836+
837+
Attributes:
838+
module: The module which the pipeline is applied to.
839+
test_data: Data used for quantizing and testing the module.
840+
841+
aten_ops: Aten dialect ops expected to be found in the graph after export.
842+
exir_ops: Exir dialect ops expected to be found in the graph after to_edge.
843+
if not using use_edge_to_transform_and_lower.
844+
845+
run_on_vulkan_runtime: Not yet supported.
846+
847+
vgf_compiler_flags: Optional compiler flags.
848+
849+
tosa_version: A string for identifying the TOSA version.
850+
851+
use_edge_to_transform_and_lower: Selects betweeen two possible ways of lowering the module.
852+
custom_path : Path to dump intermediate artifacts such as tosa and pte to.
853+
"""
854+
855+
def __init__(
856+
self,
857+
module: torch.nn.Module,
858+
test_data: T,
859+
aten_op: str | List[str],
860+
exir_op: Optional[str | List[str]] = None,
861+
run_on_vulkan_runtime: bool = False,
862+
vgf_compiler_flags: Optional[str] = "",
863+
tosa_version: str = "TOSA-1.0+FP",
864+
symmetric_io_quantization: bool = False,
865+
per_channel_quantization: bool = False,
866+
use_to_edge_transform_and_lower: bool = True,
867+
custom_path: str = None,
868+
atol: float = 1e-03,
869+
rtol: float = 1e-03,
870+
qtol: int = 1,
871+
dynamic_shapes: Optional[Tuple[Any]] = None,
872+
):
873+
874+
if (
875+
symmetric_io_quantization or per_channel_quantization
876+
) and tosa_version == "TOSA-1.0+FP":
877+
raise ValueError("Dont configure quantization with FP TOSA profile.")
878+
if (
879+
symmetric_io_quantization is False
880+
and per_channel_quantization is False
881+
and tosa_version == "TOSA-1.0+INT"
882+
):
883+
raise ValueError("Missing quantization options for INT TOSA profile.")
884+
885+
tosa_profile = TosaSpecification.create_from_string(tosa_version)
886+
compile_spec = common.get_vgf_compile_spec(
887+
tosa_profile, compiler_flags=vgf_compiler_flags, custom_path=custom_path
888+
)
889+
890+
super().__init__(
891+
module,
892+
test_data,
893+
aten_op,
894+
compile_spec,
895+
exir_op,
896+
use_to_edge_transform_and_lower,
897+
dynamic_shapes,
898+
)
899+
900+
if symmetric_io_quantization or per_channel_quantization:
901+
quantizer = VgfQuantizer(compile_spec)
902+
quantization_config = get_symmetric_quantization_config(
903+
is_per_channel=per_channel_quantization
904+
)
905+
if symmetric_io_quantization:
906+
quantizer.set_io(quantization_config)
907+
quant_stage = Quantize(quantizer, quantization_config)
908+
else:
909+
quant_stage = None
910+
911+
if quant_stage:
912+
self.add_stage(self.tester.quantize, quant_stage, pos=0)
913+
914+
self.add_stage_after(
915+
"quantize",
916+
self.tester.check,
917+
[
918+
"torch.ops.quantized_decomposed.dequantize_per_tensor.default",
919+
"torch.ops.quantized_decomposed.quantize_per_tensor.default",
920+
],
921+
suffix="quant_nodes",
922+
)
923+
924+
remove_quant_nodes_stage = (
925+
"to_edge_transform_and_lower"
926+
if use_to_edge_transform_and_lower
927+
else "partition"
928+
)
929+
self.add_stage_after(
930+
remove_quant_nodes_stage,
931+
self.tester.check_not,
932+
[
933+
"torch.ops.quantized_decomposed.dequantize_per_tensor.default",
934+
"torch.ops.quantized_decomposed.quantize_per_tensor.default",
935+
],
936+
suffix="quant_nodes",
937+
)
938+
else:
939+
self.add_stage_after(
940+
"export",
941+
self.tester.check_not,
942+
[
943+
"torch.ops.quantized_decomposed.dequantize_per_tensor.default",
944+
"torch.ops.quantized_decomposed.quantize_per_tensor.default",
945+
],
946+
suffix="quant_nodes",
947+
)
948+
949+
if run_on_vulkan_runtime:
950+
pass

backends/arm/vgf_backend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def vgf_compile(
103103
additional_flags = " ".join(compile_flags)
104104
vgf_path = tosa_path + ".vgf"
105105
conversion_command = (
106-
f"converter-backend {additional_flags} -i {tosa_path} -o {vgf_path}"
106+
f"model-converter {additional_flags} -i {tosa_path} -o {vgf_path}"
107107
)
108108
try:
109109
subprocess.run(

0 commit comments

Comments
 (0)