Skip to content

Commit 441ac6d

Browse files
michaelgtuttleGitHub Enterprise
authored andcommitted
Fuse supergroups to onnx function nodes in QuantSim init
Signed-off-by: Michael Tuttle <mtuttle@qti.qualcomm.com>
1 parent 3ac5c36 commit 441ac6d

15 files changed

Lines changed: 115 additions & 93 deletions

File tree

TrainingExtensions/onnx/src/python/aimet_onnx/experimental/adascale/model_converter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def get_pt_block(
8181
output_names,
8282
)
8383
subgraph_model = onnx_ir.Model(
84-
subgraph, ir_version=model.ir_version, functions=model.functions
84+
subgraph, ir_version=model.ir_version, functions=list(model.functions.values())
8585
)
8686
ir_utils.remove_aimet_quantizers(subgraph_model)
8787
ir_utils.inline_all_supergroups(subgraph_model)

TrainingExtensions/onnx/src/python/aimet_onnx/graph_passes/fusions/fusion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def fuse_supergroups(
3333
unknown_patterns = [p for p in patterns if p not in FUSION_PASS_REGISTRY]
3434
if unknown_patterns:
3535
raise ValueError(
36-
f"Unknown pattern names: {unknown_patterns}. "
36+
f"Graph pass requested but not found: {unknown_patterns}. "
3737
f"Available patterns: {list(FUSION_PASS_REGISTRY.passes.keys())}"
3838
)
3939

TrainingExtensions/onnx/src/python/aimet_onnx/graph_passes/passes/common_patterns.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
def match_rms_norm_pattern(op: Op, model: ModelProto) -> List[Op]:
1818
"""Common pattern for RMSNormalization which can be re-used"""
19+
if op.type == "RMSNormalization":
20+
return [op]
1921
# Match Mul(x, x) or Pow(x, 2)
2022
match = match_pow_2_pattern(op, model)
2123
if not match or len(op.output_ops) != 1:

TrainingExtensions/onnx/src/python/aimet_onnx/quantsim.py

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@
152152
]
153153
_tie_qtzrs = True
154154

155+
_fuse_supergroups = True
156+
155157
data_types_to_quantize = [np.float32, np.float16]
156158

157159
_DEPRECATED_ARGS = {
@@ -443,20 +445,13 @@ def __init__(
443445
"Quantizing models with BFLOAT16 tensors is not supported"
444446
)
445447

446-
self.model = model
447448
self._op_domain = op_domain
448449
self.providers = providers
449450

450451
if not dummy_input:
451-
dummy_input = make_dummy_input(self.model.model)
452+
dummy_input = make_dummy_input(model.model)
452453

453454
self.qc_quantize_op_dict = {}
454-
self.connected_graph = ConnectedGraph(self.model)
455-
if _has_unfolded_batchnorms(self.model.model, self.connected_graph):
456-
logger.warning(
457-
"Model contains unfolded BatchNormalization layers. To accurately simulate quantization behavior, "
458-
"please call aimet_onnx.batch_norm_fold.fold_all_batch_norms_to_weight(model) before creating QuantizationSimModel."
459-
)
460455
self._quant_scheme = quant_scheme
461456
self._param_type = param_type
462457
self._activation_type = activation_type
@@ -473,6 +468,23 @@ def __init__(
473468
for lib in user_onnx_libs or []:
474469
self._ort_session_options.register_custom_ops_library(lib)
475470

471+
quantsim_configurator = QuantSimConfigurator(
472+
config_file,
473+
self._param_type,
474+
self._activation_type,
475+
)
476+
if _fuse_supergroups:
477+
model = quantsim_configurator.apply_fusions(model)
478+
479+
self.model = model
480+
self.connected_graph = ConnectedGraph(self.model)
481+
482+
if _has_unfolded_batchnorms(self.model.model, self.connected_graph):
483+
logger.warning(
484+
"Model contains unfolded BatchNormalization layers. To accurately simulate quantization behavior, "
485+
"please call aimet_onnx.batch_norm_fold.fold_all_batch_norms_to_weight(model) before creating QuantizationSimModel."
486+
)
487+
476488
# Get names of parameters and activations to quantize
477489
self._get_param_names()
478490
self._get_activations_to_quantize(dummy_input)
@@ -485,7 +497,14 @@ def __init__(
485497
}
486498

487499
# Apply configurations based on provided config file.
488-
quantsim_configurator = self._add_configuration_(config_file)
500+
quantsim_configurator.configure_quantizers(
501+
self.model,
502+
self.connected_graph,
503+
self.qc_quantize_op_dict,
504+
self.param_names,
505+
self.activation_names,
506+
self.input_quantizers_name,
507+
)
489508
self._hw_version = quantsim_configurator._get_hw_version()
490509
self._supported_kernels = quantsim_configurator.get_supported_kernels()
491510
self._op_to_supported_kernel = (
@@ -663,28 +682,6 @@ def get_supported_kernels(self) -> Dict:
663682
"""
664683
return self._supported_kernels
665684

666-
def _add_configuration_(self, config_file: str):
667-
"""
668-
Add configuration based on config file
669-
670-
:param config_file: Path to Configuration file for model quantizers
671-
"""
672-
quantsim_configurator = QuantSimConfigurator(
673-
self.model,
674-
self.connected_graph,
675-
config_file,
676-
self._param_type,
677-
self._activation_type,
678-
)
679-
quantsim_configurator.configure_quantizers(
680-
self.qc_quantize_op_dict,
681-
self.param_names,
682-
self.activation_names,
683-
self.input_quantizers_name,
684-
)
685-
686-
return quantsim_configurator
687-
688685
def _get_param_names(self):
689686
"""
690687
Get the names of params

TrainingExtensions/onnx/src/python/aimet_onnx/quantsim_config/quantsim_config.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010

1111
import numpy as np
1212
import onnx
13+
import onnx_ir
1314
from packaging import version
15+
from onnxruntime.quantization.onnx_quantizer import ONNXModel
1416

1517
from aimet_onnx.common.defs import QuantizationDataType, qtype
1618
from aimet_onnx.common.graph_searcher import (
@@ -41,6 +43,7 @@
4143
from aimet_onnx.utils import get_product_name_from_quantized_name
4244
from aimet_onnx.qc_quantize_op import OpMode, QcQuantizeOp
4345
from aimet_onnx.graph_passes.pass_registry import apply_graph_passes, find_all_matches
46+
from aimet_onnx.graph_passes.fusions import fuse_supergroups
4447

4548
# pylint: disable=no-name-in-module, ungrouped-imports
4649
if version.parse(onnx.__version__) >= version.parse("1.14.0"):
@@ -86,16 +89,14 @@ class QuantSimConfigurator(AimetCommonQuantSimConfigurator):
8689

8790
def __init__(
8891
self,
89-
model: ModelProto,
90-
conn_graph: ConnectedGraph,
9192
config_file: str,
9293
param_type: qtype,
9394
activation_type: qtype,
9495
):
9596
super().__init__(config_file, param_type, activation_type)
9697

97-
self._model = model
98-
self._conn_graph = conn_graph
98+
self._model = None
99+
self._conn_graph = None
99100
self._quant_ops_dict = {}
100101
self._param_names = {}
101102
self._activation_names = {}
@@ -121,6 +122,8 @@ def get_supported_kernels(self) -> Dict:
121122

122123
def configure_quantizers(
123124
self,
125+
model: ONNXModel,
126+
conn_graph: ConnectedGraph,
124127
quant_ops_dict: Dict,
125128
param_names: List[str],
126129
activation_names: List[str],
@@ -129,6 +132,8 @@ def configure_quantizers(
129132
"""
130133
Configures quantizers based on config file
131134
"""
135+
self._model = model
136+
self._conn_graph = conn_graph
132137
self._quant_ops_dict = quant_ops_dict
133138
self._param_names = param_names
134139
self._activation_names = activation_names
@@ -150,12 +155,21 @@ def configure_quantizers(
150155
# Run supergroup passes if specified in config
151156
supergroup_pass_list = self._get_supergroup_pass_list()
152157
apply_graph_passes(
153-
self._model.model,
154-
self._conn_graph,
158+
model.model,
159+
conn_graph,
155160
self._quant_ops_dict,
156161
supergroup_pass_list,
157162
)
158163

164+
def apply_fusions(self, model: ONNXModel):
165+
"""
166+
Fuse supergroups into onnx functions based on config file supergroup list
167+
"""
168+
fusion_patterns = self._get_supergroup_pass_list()
169+
ir_model = onnx_ir.from_proto(model.model)
170+
fused_model = fuse_supergroups(ir_model, fusion_patterns)
171+
return ONNXModel(onnx_ir.to_proto(fused_model))
172+
159173
def _map_quantizers_to_ops(self) -> Dict[str, OpToQuantizers]:
160174
"""
161175
Creates a dict where key is the name of the op and value is OpToQuantizers which comprises of input quantizers

TrainingExtensions/onnx/test/python/test_enpu_config.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,8 @@ def test_batchnorm_params(
226226
*(
227227
nn.LayerNorm(
228228
normalized_shape=10,
229-
elementwise_affine=elementwise_affine,
230229
bias=bias,
231230
)
232-
for elementwise_affine in (True, False)
233231
for bias in (True, False)
234232
),
235233
*(
@@ -301,7 +299,6 @@ def test_supergroup(self, tmp_path: Path, model: nn.Module, tie_quantizers: bool
301299
intermediate_activations = (
302300
sim.qc_quantize_op_dict.keys() - param_names - input_names - output_names
303301
)
304-
assert intermediate_activations # Sanity check
305302

306303
for name in intermediate_activations:
307304
qtzr = sim.qc_quantize_op_dict[name]

TrainingExtensions/onnx/test/python/test_find_transformer_blocks.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ def verify_find_blocks(sim, model_type):
2121
end_points_names = [(op1.name, op2.name) for op1, op2 in end_points]
2222
assert end_points_names == [
2323
(
24-
"/model/model/layers.0/input_layernorm/Pow",
25-
"/model/model/layers.1/input_layernorm/Pow",
24+
"/model/model/layers.0/input_layernorm",
25+
"/model/model/layers.1/input_layernorm",
2626
),
27-
("/model/model/layers.1/input_layernorm/Pow", "/model/model/norm/Pow"),
27+
("/model/model/layers.1/input_layernorm", "/model/model/norm"),
2828
]
2929
conv_linear_blocks = get_conv_linear_layers_decoder_block(sim, end_points)
3030
conv_linear_blocks_names = []
@@ -89,10 +89,10 @@ def test_get_decoder_blocks_phi(add_genai_tests_path):
8989
end_points_names = [(op1.name, op2.name) for op1, op2 in end_points]
9090
assert end_points_names == [
9191
(
92-
"/model/model/layers.0/input_layernorm/Pow",
93-
"/model/model/layers.1/input_layernorm/Pow",
92+
"/model/model/layers.0/input_layernorm",
93+
"/model/model/layers.1/input_layernorm",
9494
),
95-
("/model/model/layers.1/input_layernorm/Pow", "/model/model/norm/Pow"),
95+
("/model/model/layers.1/input_layernorm", "/model/model/norm"),
9696
]
9797
conv_linear_blocks = get_conv_linear_layers_decoder_block(
9898
collection.backbone, end_points

TrainingExtensions/onnx/test/python/test_graph_passes/test_fusions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ def test_unknown_pattern_raises_error(self, tmp_path):
660660
model_proto = create_layernorm_model(tmp_path)
661661
model = onnx_ir.from_proto(model_proto)
662662

663-
with pytest.raises(ValueError, match="Unknown pattern names"):
663+
with pytest.raises(ValueError, match="Graph pass requested but not found"):
664664
fuse_supergroups(model, patterns=["UnknownPattern"])
665665

666666
@pytest.mark.parametrize(

TrainingExtensions/onnx/test/python/test_graph_passes/test_graph_registry.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import tempfile
1818

1919
from ..models.models_for_tests import build_dummy_model
20-
from ..utils import tmp_dir
20+
from ..utils import tmp_dir, patch_fuse_supergroups
2121

2222

2323
def _generate_quantsim_config(supergroup_pass_name: str, file_path: str) -> dict:
@@ -62,14 +62,15 @@ def test_register_and_apply_graph_pass(tmp_dir):
6262

6363
config_file = str(os.path.join(tmp_dir, "quantsim_config.json"))
6464
_generate_quantsim_config("DummyTestGraphPass", config_file)
65-
sim = QuantizationSimModel(
66-
model,
67-
input_data,
68-
quant_scheme=QuantScheme.post_training_tf,
69-
default_param_bw=8,
70-
default_activation_bw=8,
71-
config_file=config_file,
72-
)
65+
with patch_fuse_supergroups(False):
66+
sim = QuantizationSimModel(
67+
model,
68+
input_data,
69+
quant_scheme=QuantScheme.post_training_tf,
70+
default_param_bw=8,
71+
default_activation_bw=8,
72+
config_file=config_file,
73+
)
7374

7475
graph = ConnectedGraph(model)
7576
disable_quantizers = set(

TrainingExtensions/onnx/test/python/test_graph_passes/test_layernorm.py

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import pytest
1010

1111
from ..models.test_models import layernorm_model
12+
from ..utils import patch_fuse_supergroups
1213
from .utils import assert_on_const_quantizers, assert_on_output_quantizers
1314

1415

@@ -20,14 +21,15 @@ def test_layer_norm(elementwise_affine, bias):
2021
graph = ConnectedGraph(model)
2122

2223
input_data = {"x": np.random.rand(1, 3, dim, dim).astype(np.float32)}
23-
sim = QuantizationSimModel(
24-
model,
25-
input_data,
26-
quant_scheme=QuantScheme.post_training_tf,
27-
default_param_bw=8,
28-
default_activation_bw=8,
29-
config_file="htp_v81",
30-
)
24+
with patch_fuse_supergroups(False):
25+
sim = QuantizationSimModel(
26+
model,
27+
input_data,
28+
quant_scheme=QuantScheme.post_training_tf,
29+
default_param_bw=8,
30+
default_activation_bw=8,
31+
config_file="htp_v81",
32+
)
3133

3234
all_ops = graph.ordered_ops
3335
# Check if quantization is disabled for LayerNormalization intermediate op outputs
@@ -52,14 +54,15 @@ def test_layer_norm_intermediate():
5254
graph = ConnectedGraph(model)
5355

5456
input_data = {"x": np.random.rand(1, 3, dim, dim).astype(np.float32)}
55-
sim = QuantizationSimModel(
56-
model,
57-
input_data,
58-
quant_scheme=QuantScheme.post_training_tf,
59-
default_param_bw=8,
60-
default_activation_bw=8,
61-
config_file="htp_v81",
62-
)
57+
with patch_fuse_supergroups(False):
58+
sim = QuantizationSimModel(
59+
model,
60+
input_data,
61+
quant_scheme=QuantScheme.post_training_tf,
62+
default_param_bw=8,
63+
default_activation_bw=8,
64+
config_file="htp_v81",
65+
)
6366

6467
all_ops = graph.ordered_ops
6568
# Check if quantization is disabled for LayerNormalization intermediate op outputs

0 commit comments

Comments
 (0)