1313from executorch .backends .arm ._passes .arm_pass_manager import ArmPassManager
1414from executorch .backends .arm .common .pipeline_config import (
1515 ArmPassPipelineConfig ,
16+ LeakyReLULoweringConfig ,
1617 QuantizeInfConfig ,
1718 SoftmaxDecompositionConfig ,
1819)
20+ from executorch .backends .arm .test import common
21+ from executorch .backends .arm .test .tester .arm_tester import ArmTester
1922from executorch .backends .arm .tosa .compile_spec import TosaCompileSpec
2023from executorch .backends .arm .tosa .specification import TosaSpecification
2124from torch .export import export
@@ -35,6 +38,17 @@ def forward(self, x: torch.Tensor) -> torch.Tensor:
3538 return x
3639
3740
41+ class ModuleWithLeakyReLU (torch .nn .Module ):
42+ def forward (self , x : torch .Tensor ) -> torch .Tensor :
43+ return torch .nn .functional .leaky_relu (x , negative_slope = 0.2 )
44+
45+
46+ def _call_function_targets (graph_module : torch .fx .GraphModule ) -> list [object ]:
47+ return [
48+ node .target for node in graph_module .graph .nodes if node .op == "call_function"
49+ ]
50+
51+
3852def test_pipeline_config_override_outside_compile_spec ():
3953 compile_spec = TosaCompileSpec (
4054 TosaSpecification .create_from_string ("TOSA-1.00+INT" )
@@ -110,3 +124,87 @@ def test_quant_inf_config_reaches_annotation_pipeline():
110124 )
111125
112126 assert tensor_constant_values == [QUANT_NEG_INF , QUANT_POS_INF ]
127+
128+
129+ def test_leaky_relu_config_serializes_roundtrip ():
130+ config = ArmPassPipelineConfig (
131+ leaky_relu = LeakyReLULoweringConfig .DECOMPOSE ,
132+ )
133+ assert config .is_default ()
134+
135+ from_dict = ArmPassPipelineConfig .from_dict (config .to_dict ())
136+ assert from_dict .leaky_relu is LeakyReLULoweringConfig .DECOMPOSE
137+
138+ compile_spec = TosaCompileSpec (
139+ TosaSpecification .create_from_string ("TOSA-1.00+INT" )
140+ )
141+ compile_spec .set_pass_pipeline_config (config )
142+ roundtripped = TosaCompileSpec ._from_list (compile_spec ._to_list ())
143+
144+ assert (
145+ roundtripped ._get_pass_pipeline_config ().leaky_relu
146+ is LeakyReLULoweringConfig .DECOMPOSE
147+ )
148+
149+
150+ def test_leaky_relu_table_config_reaches_annotation_pipeline ():
151+ config = ArmPassPipelineConfig (
152+ leaky_relu = LeakyReLULoweringConfig .TABLE ,
153+ )
154+ compile_spec = TosaCompileSpec (
155+ TosaSpecification .create_from_string ("TOSA-1.00+INT" )
156+ )
157+ compile_spec .set_pass_pipeline_config (config )
158+ manager = ArmPassManager (compile_spec )
159+ exported = export (ModuleWithLeakyReLU (), (torch .randn (4 ),), strict = True )
160+
161+ transformed = manager .transform_for_annotation_pipeline (exported .graph_module )
162+ targets = _call_function_targets (transformed )
163+
164+ assert torch .ops .aten .leaky_relu .default in targets
165+
166+
167+ def test_leaky_relu_decompose_config_reaches_annotation_pipeline ():
168+ config = ArmPassPipelineConfig (
169+ leaky_relu = LeakyReLULoweringConfig .DECOMPOSE ,
170+ )
171+ compile_spec = TosaCompileSpec (
172+ TosaSpecification .create_from_string ("TOSA-1.00+INT" )
173+ )
174+ compile_spec .set_pass_pipeline_config (config )
175+ manager = ArmPassManager (compile_spec )
176+ exported = export (ModuleWithLeakyReLU (), (torch .randn (4 ),), strict = True )
177+
178+ transformed = manager .transform_for_annotation_pipeline (exported .graph_module )
179+ targets = _call_function_targets (transformed )
180+
181+ assert torch .ops .aten .leaky_relu .default not in targets
182+ assert torch .ops .aten .clamp .default in targets
183+ assert torch .ops .aten .mul .Tensor in targets
184+ assert torch .ops .aten .add .Tensor in targets
185+
186+
187+ def test_leaky_relu_decompose_config_reaches_backend_pipeline ():
188+ config = ArmPassPipelineConfig (
189+ leaky_relu = LeakyReLULoweringConfig .DECOMPOSE ,
190+ )
191+ compile_spec = common .get_tosa_compile_spec ("TOSA-1.00+INT" )
192+ compile_spec .set_pass_pipeline_config (config )
193+ tester = ArmTester (
194+ ModuleWithLeakyReLU (),
195+ example_inputs = (torch .linspace (- 1.0 , 1.0 , 16 ),),
196+ compile_spec = compile_spec ,
197+ )
198+
199+ tester .quantize ().export ()
200+ exported_program = tester .get_artifact ()
201+ graph_module = ArmPassManager (compile_spec ).transform_to_backend_pipeline (
202+ exported_program , exported_program .graph_module
203+ )
204+ graph_code = graph_module .code
205+
206+ assert "torch.ops.aten.leaky_relu.default" not in graph_code
207+ assert "torch.ops.backend.tosa.TABLE.default" not in graph_code
208+ assert "torch.ops.aten.clamp.default" in graph_code
209+ assert "torch.ops.aten.mul.Tensor" in graph_code
210+ assert "torch.ops.aten.add.Tensor" in graph_code
0 commit comments