Skip to content

Commit 4d22f27

Browse files
authored
Arm backend: Enable disallowing transforming prior to quantization (pytorch#15958)
ReplaceInfValues is provided with extra logic to handle this new flag. A file test_replace_inf_values_pass.py that test the pass in general as well as the flag has been added. A test that verifies the new capability of the quantizer has been added to a new file test_partial_quantization.py. Signed-off-by: Martin Lindström <Martin.Lindstroem@arm.com> Co-authored-by: Martin Lindström <Martin.Lindstroem@arm.com>
1 parent 051667e commit 4d22f27

46 files changed

Lines changed: 564 additions & 194 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎backends/arm/_passes/arm_pass.py‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from abc import abstractmethod
99
from typing import Any, List, Optional, Set, Type
1010

11+
from executorch.backends.arm.constants import DISALLOW_TFA_META_KEY
1112
from executorch.exir.pass_base import ExportPass, NodeMetadata
1213
from torch.fx import GraphModule
1314
from torch.fx.passes.infra.pass_base import PassResult
@@ -16,9 +17,23 @@
1617
class ArmPass(ExportPass):
1718
"""Base class for Arm passes"""
1819

19-
def __init__(self) -> None:
20-
super().__init__()
20+
def __init__(self, tfa_pass: bool = False, *args, **kwargs) -> None:
21+
super().__init__(*args, **kwargs)
2122
self.submodule_depth = 0
23+
self.is_tfa_pass = tfa_pass
24+
25+
def allowed_to_transform(self, meta: NodeMetadata | dict[str, Any]) -> bool:
26+
if not self.is_tfa_pass:
27+
return True
28+
29+
if isinstance(meta, NodeMetadata):
30+
meta_dict = meta.data
31+
else:
32+
meta_dict = meta
33+
34+
disallow_tfa = meta_dict.get(DISALLOW_TFA_META_KEY, False)
35+
36+
return not disallow_tfa
2237

2338
@property
2439
@abstractmethod

‎backends/arm/_passes/arm_pass_manager.py‎

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -376,65 +376,65 @@ def transform_to_backend_pipeline(
376376

377377
def transform_for_annotation_pipeline(self, graph_module: GraphModule):
378378
# Preprocessing passes
379-
self.add_pass(RemoveGraphAssertsPass())
379+
self.add_pass(RemoveGraphAssertsPass(tfa_pass=True))
380380

381381
# Transformation passes (pre scalar -> tensor)
382382
self.add_passes(
383383
[
384-
DecomposeSelectScatterPass(),
385-
ConvertInt64ConstOpsToInt32Pass(),
386-
ConvertInt64OutputOpsToInt32Pass(),
387-
InsertInt32CastsAfterInt64PlaceholdersPass(),
388-
DecomposeEmbeddingPass(),
389-
DecomposeScaledDotProductAttentionPass(),
390-
DecomposeRoundPass(),
391-
DecomposeLogitPass(),
392-
PromoteBoolOperandsPass(),
393-
DecomposeSignPass(),
394-
DecomposeAddmmPass(),
395-
DecomposeRemainderPass(),
396-
DecomposeFloorDividePass(),
397-
DecomposeDivTensorModePass(),
384+
DecomposeSelectScatterPass(tfa_pass=True),
385+
ConvertInt64ConstOpsToInt32Pass(tfa_pass=True),
386+
ConvertInt64OutputOpsToInt32Pass(tfa_pass=True),
387+
InsertInt32CastsAfterInt64PlaceholdersPass(tfa_pass=True),
388+
DecomposeEmbeddingPass(tfa_pass=True),
389+
DecomposeScaledDotProductAttentionPass(tfa_pass=True),
390+
DecomposeRoundPass(tfa_pass=True),
391+
DecomposeLogitPass(tfa_pass=True),
392+
PromoteBoolOperandsPass(tfa_pass=True),
393+
DecomposeSignPass(tfa_pass=True),
394+
DecomposeAddmmPass(tfa_pass=True),
395+
DecomposeRemainderPass(tfa_pass=True),
396+
DecomposeFloorDividePass(tfa_pass=True),
397+
DecomposeDivTensorModePass(tfa_pass=True),
398398
]
399399
)
400400

401401
# Scalars -> tensors
402402
self.add_passes(
403403
[
404-
ReplaceScalarWithTensorByProfilePass(),
405-
ScalarsToAttributePass(),
404+
ReplaceScalarWithTensorByProfilePass(tfa_pass=True),
405+
ScalarsToAttributePass(tfa_pass=True),
406406
]
407407
)
408408

409409
# Transformation passes (post scalar removal)
410410
self.add_passes(
411411
[
412-
NormalizeWhileInitialArgsPass(use_exir_clone=False),
413-
DecomposeAddSubAlphaPass(),
414-
DecomposeGroupNormPass(),
415-
DecomposeLayerNormPass(),
416-
DecomposeVarPass(),
417-
DecomposeMeanDimPass(graph_module, self.tosa_spec),
418-
DecomposeNotEqualPass(),
419-
DecomposeCosineSimilarityPass(),
420-
DecomposeGluPass(),
421-
DecomposeDivPass(),
422-
DecomposeLeakyReLUPass(),
423-
DecomposeLinalgVectorNormPass(),
424-
DecomposeSqrtPass(),
425-
DecomposeSiluPass(),
426-
DecomposeAvgPool2dPass(),
427-
DecomposeSoftmaxUnstablePass(),
428-
DecomposeSoftmaxPass(),
429-
ConvertMinMaxPass(),
412+
NormalizeWhileInitialArgsPass(use_exir_clone=False, tfa_pass=True),
413+
DecomposeAddSubAlphaPass(tfa_pass=True),
414+
DecomposeGroupNormPass(tfa_pass=True),
415+
DecomposeLayerNormPass(tfa_pass=True),
416+
DecomposeVarPass(tfa_pass=True),
417+
DecomposeMeanDimPass(graph_module, self.tosa_spec, tfa_pass=True),
418+
DecomposeNotEqualPass(tfa_pass=True),
419+
DecomposeCosineSimilarityPass(tfa_pass=True),
420+
DecomposeGluPass(tfa_pass=True),
421+
DecomposeDivPass(tfa_pass=True),
422+
DecomposeLeakyReLUPass(tfa_pass=True),
423+
DecomposeLinalgVectorNormPass(tfa_pass=True),
424+
DecomposeSqrtPass(tfa_pass=True),
425+
DecomposeSiluPass(tfa_pass=True),
426+
DecomposeAvgPool2dPass(tfa_pass=True),
427+
DecomposeSoftmaxUnstablePass(tfa_pass=True),
428+
DecomposeSoftmaxPass(tfa_pass=True),
429+
ConvertMinMaxPass(tfa_pass=True),
430430
]
431431
)
432432

433433
# Postprocessing passes
434434
self.add_passes(
435435
[
436-
ReplaceInfAndLimitValuesPass(),
437-
DecomposeMaskedFillPass(),
436+
ReplaceInfAndLimitValuesPass(tfa_pass=True),
437+
DecomposeMaskedFillPass(tfa_pass=True),
438438
]
439439
)
440440

‎backends/arm/_passes/cast_int64_pass.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ class CastInt64BuffersToInt32Pass(ArmPass):
2323

2424
_passes_required_after: Set[Type[ExportPass]] = set()
2525

26-
def __init__(self, exported_program: ExportedProgram):
27-
super().__init__()
26+
def __init__(self, exported_program: ExportedProgram, *args, **kwargs):
27+
super().__init__(*args, **kwargs)
2828
self.exported_program = exported_program
2929

3030
def _assert_within_int32(self, tensor: torch.Tensor, node: torch.fx.Node):

‎backends/arm/_passes/convert_elu_params.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def call(self, graph_module: torch.fx.GraphModule):
3535
is_quantized = (
3636
input_node.op == "call_function" and input_node.target in DQ_OPS
3737
)
38-
if not is_quantized:
38+
if not is_quantized or not self.allowed_to_transform(node.meta):
3939
continue
4040
with graph.inserting_after(node):
4141
replace_node = create_node(

‎backends/arm/_passes/convert_minmax_pass.py‎

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ class ConvertMinMaxPass(ArmPass):
4141

4242
_passes_required_after: Set[Type[ExportPass]] = {ConvertSqueezesToViewPass}
4343

44+
_TARGET_OPS = {
45+
exir_ops.edge.aten.amax.default,
46+
exir_ops.edge.aten.amin.default,
47+
exir_ops.edge.aten.max.dim,
48+
exir_ops.edge.aten.min.dim,
49+
torch.ops.aten.max.dim,
50+
torch.ops.aten.min.dim,
51+
}
52+
4453
def check_argmax(self, node):
4554
"""
4655
Raises a RuntimeError if the argmax value returned by the min/max op is used in the graph.
@@ -88,16 +97,11 @@ def get_variables(self, node):
8897
def call(self, graph_module: torch.fx.GraphModule):
8998
modified = False
9099
for node in graph_module.graph.nodes:
91-
if node.op != "call_function":
92-
continue
93-
if node.target not in [
94-
exir_ops.edge.aten.amax.default,
95-
exir_ops.edge.aten.amin.default,
96-
exir_ops.edge.aten.max.dim,
97-
exir_ops.edge.aten.min.dim,
98-
torch.ops.aten.max.dim,
99-
torch.ops.aten.min.dim,
100-
]:
100+
if (
101+
node.op != "call_function"
102+
or node.target not in ConvertMinMaxPass._TARGET_OPS
103+
or not self.allowed_to_transform(node.meta)
104+
):
101105
continue
102106

103107
self.check_argmax(

‎backends/arm/_passes/convert_to_clamp_pass.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class ConvertToClampPass(ArmPass):
3333
_passes_required_after: Set[Type[ExportPass]] = {QuantizeClampArgumentsPass}
3434

3535
def call_operator(self, op, args, kwargs, meta):
36-
if op not in edge_operators:
36+
if op not in edge_operators or not self.allowed_to_transform(meta):
3737
return super().call_operator(op, args, kwargs, meta)
3838

3939
return super().call_operator(

‎backends/arm/_passes/decompose_addmm_pass.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class DecomposeAddmmPass(ArmPass):
4949
}
5050

5151
def call_operator(self, op, args, kwargs, meta):
52-
if op not in [edge_addmm, aten_addmm]:
52+
if op not in [edge_addmm, aten_addmm] or not self.allowed_to_transform(meta):
5353
return super().call_operator(op, args, kwargs, meta)
5454

5555
input, mat1, mat2 = args

‎backends/arm/_passes/decompose_avg_pool2d_pass.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ class DecomposeAvgPool2dPass(ArmPass):
4343
_passes_required_after: Set[Type[ExportPass]] = {ComputeConstantOpsAOTPass}
4444

4545
def call_operator(self, op, args, kwargs, meta):
46-
if op not in (edge_div_ops + aten_div_ops):
46+
if op not in (edge_div_ops + aten_div_ops) or not self.allowed_to_transform(
47+
meta
48+
):
4749
return super().call_operator(op, args, kwargs, meta)
4850

4951
full_op, cat_op, avgpool_op, mul_op = get_decomposition(op)

‎backends/arm/_passes/decompose_batch_norm_no_stats.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ def call(self, graph_module: torch.fx.GraphModule) -> PassResult: # noqa: C901
5353
)
5454

5555
for node in graph_module.graph.nodes:
56-
if node.op != "call_function" or node.target not in bn_ops:
56+
if (
57+
node.op != "call_function"
58+
or node.target not in bn_ops
59+
or not self.allowed_to_transform(node.meta)
60+
):
5761
continue
5862

5963
if node.target in (

‎backends/arm/_passes/decompose_cosine_similarity_pass.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class DecomposeCosineSimilarityPass(ArmPass):
4040
}
4141

4242
def call_operator(self, op, args, kwargs, meta):
43-
if op not in torch_cosine_similarity:
43+
if op not in torch_cosine_similarity or not self.allowed_to_transform(meta):
4444
return super().call_operator(op, args, kwargs, meta)
4545

4646
x1, x2 = args[0], args[1]

0 commit comments

Comments
 (0)