Skip to content

Commit f82cf76

Browse files
authored
Merge branch 'main' into baris_mletorch-1918_layer_test_DeepSeek_R1_Distill_Qwen_1.5B
2 parents 2841651 + d6ad8aa commit f82cf76

45 files changed

Lines changed: 636 additions & 522 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/normalize_while_initial_args_pass.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def _connect_to_output(
6262
(placeholder,),
6363
)
6464
cloned_placeholders.append(clone)
65-
clone.meta = placeholder.meta.copy()
65+
clone.meta = placeholder.meta
6666
output_node = body_module.graph.output_node()
6767
output_values = output_node.args[0]
6868
if not isinstance(output_values, tuple):

backends/arm/public_api_manifests/api_manifest_running.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ signature = "EthosUPartitioner.register_custom_partition_op(self, op: torch._ops
6262

6363
[python.EthosUQuantizer]
6464
kind = "class"
65-
signature = "EthosUQuantizer(compile_spec: 'EthosUCompileSpec', use_composable_quantizer: 'bool' = True) -> 'None'"
65+
signature = "EthosUQuantizer(compile_spec: 'EthosUCompileSpec', use_composable_quantizer: 'bool' = False) -> 'None'"
6666

6767
[python.EthosUQuantizer.annotate]
6868
kind = "function"
@@ -150,7 +150,7 @@ signature = "VgfPartitioner.register_custom_partition_op(self, op: torch._ops.Op
150150

151151
[python.VgfQuantizer]
152152
kind = "class"
153-
signature = "VgfQuantizer(compile_spec: 'VgfCompileSpec', use_composable_quantizer: 'bool' = True) -> 'None'"
153+
signature = "VgfQuantizer(compile_spec: 'VgfCompileSpec', use_composable_quantizer: 'bool' = False) -> 'None'"
154154

155155
[python.VgfQuantizer.annotate]
156156
kind = "function"

backends/arm/quantizer/arm_quantizer.py

Lines changed: 28 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -493,23 +493,21 @@ class TOSAQuantizer(Quantizer):
493493
"""Manage quantization annotations for TOSA-compatible backends.
494494
495495
.. warning::
496-
The composable quantizer is now the default implementation. Setting
497-
``use_composable_quantizer=False`` is deprecated and will be removed in
498-
two minor releases.
496+
Setting ``use_composable_quantizer=True`` enables an experimental API
497+
surface that may change without notice.
499498
500499
"""
501500

502501
def __init__(
503502
self,
504503
compile_spec_or_tosa_spec,
505-
use_composable_quantizer: bool = True,
504+
use_composable_quantizer: bool = False,
506505
) -> None:
507506
"""Create a TOSA quantizer from a TOSA spec or Arm compile spec.
508507
509508
.. warning::
510-
The composable quantizer is now the default implementation.
511-
Setting ``use_composable_quantizer=False`` is deprecated and will
512-
be removed in two minor releases.
509+
Setting ``use_composable_quantizer=True`` enables an experimental
510+
API surface that may change without notice.
513511
514512
"""
515513
self.use_composable_quantizer = use_composable_quantizer
@@ -521,45 +519,10 @@ def __init__(
521519
self.quantizer = _TOSAQuantizerV2(compile_spec_or_tosa_spec)
522520
else:
523521
logger.info(
524-
"Using deprecated legacy quantizer implementation in the arm backend. Setting use_composable_quantizer=False will be removed in two minor releases. See https://github.com/pytorch/executorch/issues/17701"
522+
"Using default quantizer in the arm backend. This quantizer is planned to be replaced by the composable quantizer implementation in the future, see https://github.com/pytorch/executorch/issues/17701"
525523
)
526524
self.quantizer = _TOSAQuantizerV1(compile_spec_or_tosa_spec)
527525

528-
@staticmethod
529-
def _validate_optional_quantization_config(
530-
config_name: str, value: object, value_description: str = "value"
531-
) -> None:
532-
if value is not None and not isinstance(value, QuantizationConfig):
533-
raise TypeError(
534-
f"{config_name} {value_description} must be "
535-
"QuantizationConfig or None, "
536-
f"got {type(value).__name__}."
537-
)
538-
539-
@staticmethod
540-
def _validate_config_dict(
541-
config_name: str,
542-
value: object,
543-
is_valid_key: Callable[[object], bool],
544-
key_description: str,
545-
) -> Dict[Any, Optional[QuantizationConfig]]:
546-
if not isinstance(value, dict):
547-
raise TypeError(
548-
f"{config_name} must be a dict, got {type(value).__name__}."
549-
)
550-
551-
for key, quantization_config in value.items():
552-
if not is_valid_key(key):
553-
raise TypeError(
554-
f"{config_name} keys must be {key_description}, "
555-
f"got {type(key).__name__}."
556-
)
557-
TOSAQuantizer._validate_optional_quantization_config(
558-
config_name, quantization_config, "values"
559-
)
560-
561-
return value
562-
563526
@property
564527
def tosa_spec(self):
565528
"""Return the TOSA specification used by the active quantizer."""
@@ -577,11 +540,12 @@ def global_config(self):
577540

578541
@global_config.setter
579542
def global_config(self, value: Optional[QuantizationConfig]) -> None:
580-
self._validate_optional_quantization_config("global_config", value)
581543
if isinstance(self.quantizer, _TOSAQuantizerV1):
582544
self.quantizer.global_config = value
583545
else:
584-
self.quantizer.set_global(value)
546+
raise NotImplementedError(
547+
"Composable quantizer does not allow setting global_config directly. Please use set_global() instead."
548+
)
585549

586550
@property
587551
def io_config(self):
@@ -595,12 +559,12 @@ def io_config(self):
595559

596560
@io_config.setter
597561
def io_config(self, value: Optional[QuantizationConfig]) -> None:
598-
self._validate_optional_quantization_config("io_config", value)
599562
if isinstance(self.quantizer, _TOSAQuantizerV1):
600563
self.quantizer.io_config = value
601564
else:
602-
self.quantizer.clear_io_config()
603-
self.quantizer.set_io(value)
565+
raise NotImplementedError(
566+
"Composable quantizer does not allow setting io_config directly. Please use set_io() instead."
567+
)
604568

605569
@property
606570
def module_type_config(self):
@@ -616,18 +580,12 @@ def module_type_config(self):
616580
def module_type_config(
617581
self, value: Dict[Callable, Optional[QuantizationConfig]]
618582
) -> None:
619-
module_type_config = self._validate_config_dict(
620-
"module_type_config",
621-
value,
622-
callable,
623-
"callable",
624-
)
625583
if isinstance(self.quantizer, _TOSAQuantizerV1):
626-
self.quantizer.module_type_config = module_type_config
584+
self.quantizer.module_type_config = value
627585
else:
628-
self.quantizer.clear_module_type_config()
629-
for module_type, quantization_config in module_type_config.items():
630-
self.quantizer.set_module_type(module_type, quantization_config)
586+
raise NotImplementedError(
587+
"Composable quantizer does not allow setting module_type_config directly. Please use set_module_type() instead."
588+
)
631589

632590
@property
633591
def module_name_config(self):
@@ -643,18 +601,12 @@ def module_name_config(self):
643601
def module_name_config(
644602
self, value: Dict[str, Optional[QuantizationConfig]]
645603
) -> None:
646-
module_name_config = self._validate_config_dict(
647-
"module_name_config",
648-
value,
649-
lambda key: isinstance(key, str),
650-
"str",
651-
)
652604
if isinstance(self.quantizer, _TOSAQuantizerV1):
653-
self.quantizer.module_name_config = module_name_config
605+
self.quantizer.module_name_config = value
654606
else:
655-
self.quantizer.clear_module_name_config()
656-
for module_name, quantization_config in module_name_config.items():
657-
self.quantizer.set_module_name(module_name, quantization_config)
607+
raise NotImplementedError(
608+
"Composable quantizer does not allow setting module_name_config directly. Please use set_module_name() instead."
609+
)
658610

659611
def set_global(
660612
self, quantization_config: Optional[QuantizationConfig]
@@ -1179,30 +1131,6 @@ def quantizers(self, value: List[Quantizer]) -> None:
11791131
"""Update quantizers without accessing self._quantizers directly."""
11801132
self._quantizers = value
11811133

1182-
def _remove_quantizers_by_node_finder_type(
1183-
self, node_finder_types: type[NodeFinder] | tuple[type[NodeFinder], ...]
1184-
) -> None:
1185-
self._quantizers = [
1186-
quantizer
1187-
for quantizer in self._quantizers
1188-
if not (
1189-
isinstance(quantizer, PatternQuantizer)
1190-
and isinstance(quantizer.node_finder, node_finder_types)
1191-
)
1192-
]
1193-
1194-
def clear_module_type_config(self) -> _TOSAQuantizerV2:
1195-
self._remove_quantizers_by_node_finder_type(ModuleTypeNodeFinder)
1196-
return self
1197-
1198-
def clear_module_name_config(self) -> _TOSAQuantizerV2:
1199-
self._remove_quantizers_by_node_finder_type(ModuleNameNodeFinder)
1200-
return self
1201-
1202-
def clear_io_config(self) -> _TOSAQuantizerV2:
1203-
self._remove_quantizers_by_node_finder_type((InputNodeFinder, OutputNodeFinder))
1204-
return self
1205-
12061134
def annotate(self, model):
12071135
reporter = QuantizerReporter(self.quantizers, "FINAL QUANTIZATION REPORT")
12081136
model = super().annotate(model)
@@ -1356,25 +1284,20 @@ class EthosUQuantizer(TOSAQuantizer):
13561284
"""Quantizer supported by the Arm Ethos-U backend.
13571285
13581286
.. warning::
1359-
The composable quantizer is now the default implementation. Setting
1360-
``use_composable_quantizer=False`` is deprecated and will be removed in
1361-
two minor releases.
1287+
Setting ``use_composable_quantizer=True`` enables an experimental API
1288+
surface that may change without notice.
13621289
13631290
Args:
13641291
compile_spec (EthosUCompileSpec): Backend compile specification for
13651292
Ethos-U targets.
1366-
use_composable_quantizer (bool): Whether to use the composable
1367-
quantizer implementation. Setting this to ``False`` is deprecated
1368-
and will be removed in two minor releases. See
1369-
[issue #17701](https://github.com/pytorch/executorch/issues/17701)
1370-
for details.
1293+
use_composable_quantizer (bool): Whether to use the composable quantizer implementation. See https://github.com/pytorch/executorch/issues/17701" for details.
13711294
13721295
"""
13731296

13741297
def __init__(
13751298
self,
13761299
compile_spec: EthosUCompileSpec,
1377-
use_composable_quantizer: bool = True,
1300+
use_composable_quantizer: bool = False,
13781301
) -> None:
13791302
super().__init__(compile_spec, use_composable_quantizer)
13801303

@@ -1383,24 +1306,19 @@ class VgfQuantizer(TOSAQuantizer):
13831306
"""Quantizer supported by the Arm Vgf backend.
13841307
13851308
.. warning::
1386-
The composable quantizer is now the default implementation. Setting
1387-
``use_composable_quantizer=False`` is deprecated and will be removed in
1388-
two minor releases.
1309+
Setting ``use_composable_quantizer=True`` enables an experimental API
1310+
surface that may change without notice.
13891311
13901312
Args:
13911313
compile_spec (VgfCompileSpec): Backend compile specification for Vgf
13921314
targets.
1393-
use_composable_quantizer (bool): Whether to use the composable
1394-
quantizer implementation. Setting this to ``False`` is deprecated
1395-
and will be removed in two minor releases. See
1396-
[issue #17701](https://github.com/pytorch/executorch/issues/17701)
1397-
for details.
1315+
use_composable_quantizer (bool): Whether to use the composable quantizer implementation. See https://github.com/pytorch/executorch/issues/17701" for details.
13981316
13991317
"""
14001318

14011319
def __init__(
14021320
self,
14031321
compile_spec: VgfCompileSpec,
1404-
use_composable_quantizer: bool = True,
1322+
use_composable_quantizer: bool = False,
14051323
) -> None:
14061324
super().__init__(compile_spec, use_composable_quantizer)

backends/arm/quantizer/arm_quantizer_utils.py

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -598,11 +598,14 @@ def _model_has_uint8_io(self, model: torch.fx.GraphModule) -> bool:
598598
self._is_uint8_quantized_io_boundary(node) for node in model.graph.nodes
599599
)
600600

601-
def _get_shared_clique(self, root_node: Node) -> tuple[set[Node], list[Any], bool]:
601+
def _get_shared_clique(
602+
self, root_node: Node
603+
) -> tuple[set[Node], list[Any], bool, bool]:
602604
shared_nodes = set()
603605
bfs_queue = [root_node]
604606
adjacent_qspecs: list[Any] = []
605607
touches_quantized_io = False
608+
touches_uint8_quantized_io = False
606609

607610
while bfs_queue:
608611
node = bfs_queue.pop(0)
@@ -612,13 +615,24 @@ def _get_shared_clique(self, root_node: Node) -> tuple[set[Node], list[Any], boo
612615
self._maybe_enqueue_shared_node(input_node, shared_nodes, bfs_queue)
613616
self._append_output_qspec(input_node, adjacent_qspecs)
614617
touches_quantized_io |= self._is_quantized_io_boundary(input_node)
618+
touches_uint8_quantized_io |= self._is_uint8_quantized_io_boundary(
619+
input_node
620+
)
615621

616622
for output_node in node.users.keys():
617623
self._maybe_enqueue_shared_node(output_node, shared_nodes, bfs_queue)
618624
self._append_input_qspec(output_node, node, adjacent_qspecs)
619625
touches_quantized_io |= self._is_quantized_io_boundary(output_node)
626+
touches_uint8_quantized_io |= self._is_uint8_quantized_io_boundary(
627+
output_node
628+
)
620629

621-
return shared_nodes, adjacent_qspecs, touches_quantized_io
630+
return (
631+
shared_nodes,
632+
adjacent_qspecs,
633+
touches_quantized_io,
634+
touches_uint8_quantized_io,
635+
)
622636

623637
def _should_skip_while_shared_qspec(self, node: Node) -> bool:
624638
return node.target == torch.ops.higher_order.while_loop and bool(
@@ -673,9 +687,12 @@ def _annotate_shared_cluster(self, root_node: Node) -> None:
673687
)
674688
return
675689

676-
shared_nodes, adjacent_qspecs, touches_quantized_io = self._get_shared_clique(
677-
root_node
678-
)
690+
(
691+
shared_nodes,
692+
adjacent_qspecs,
693+
touches_quantized_io,
694+
touches_uint8_quantized_io,
695+
) = self._get_shared_clique(root_node)
679696

680697
# If there is no neighbor qspec to propagate but the cluster sits on the
681698
# quantized I/O boundary (e.g. a state-passthrough cat whose only neighbors
@@ -695,6 +712,15 @@ def _annotate_shared_cluster(self, root_node: Node) -> None:
695712
node_order = {node: index for index, node in enumerate(root_node.graph.nodes)}
696713
ordered_nodes = sorted(shared_nodes, key=lambda node: node_order.get(node, 0))
697714

715+
if touches_uint8_quantized_io and any(
716+
node.target in self._UINT8_IO_BRIDGE_OPS for node in shared_nodes
717+
):
718+
self.report_reject(
719+
ordered_nodes,
720+
"Shared-qspec bridge cluster touches uint8 model IO.",
721+
)
722+
return
723+
698724
if self._annotate_while_with_additional_inputs(root_node, adjacent_qspecs):
699725
return
700726

@@ -734,20 +760,9 @@ def _annotate_shared_cluster(self, root_node: Node) -> None:
734760
return
735761

736762
def annotate(self, model: torch.fx.GraphModule) -> None: # type: ignore[override]
737-
targets = self.targets
738-
if self._model_has_uint8_io(model):
739-
targets = [
740-
target for target in targets if target not in self._UINT8_IO_BRIDGE_OPS
741-
]
742-
743-
original_targets = self.targets
744-
self.targets = targets
745-
try:
746-
for node in model.graph.nodes:
747-
if node.target in self.targets and not self._is_annotated(node):
748-
self._annotate_shared_cluster(node)
749-
finally:
750-
self.targets = original_targets
763+
for node in model.graph.nodes:
764+
if node.target in self.targets and not self._is_annotated(node):
765+
self._annotate_shared_cluster(node)
751766

752767
def validate(self, model: torch.fx.GraphModule) -> bool: # type: ignore[override]
753768
return True

backends/arm/quantizer/quantization_config.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ def get_output_act_qspec(
356356
357357
If node is a pooling or upsample operator, returns a shared quantization spec.
358358
If no weight spec is configured, return ``None``.
359-
If node is a `to.dtype` operator, returns a fixed quantization spec if the input is integer and the output is float32.
359+
If node is a `to.dtype` operator, returns a fixed quantization spec if the input is integer and the output is floating-point.
360360
361361
"""
362362

@@ -391,7 +391,6 @@ def get_output_act_qspec(
391391
isinstance(input_val, torch.Tensor)
392392
and isinstance(output_val, torch.Tensor)
393393
and CastCheck.is_integer_to_float(input_val.dtype, output_val.dtype)
394-
and output_val.dtype == torch.float32
395394
):
396395
return FixedQParamsQuantizationSpec(
397396
dtype=input_val.dtype,

backends/arm/test/misc/test_quant_custom_meta.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,5 @@ def test_quantized_to_float_transition_tosa_INT_FP(fp_extension: bool):
105105
)
106106
pipeline.quantizer.set_module_type(torch.nn.Sigmoid, None) # type: ignore
107107
pipeline.quantizer.set_module_type(torch.nn.Conv1d, None) # type: ignore
108-
pipeline.quantizer.set_io(None) # type: ignore
109108

110109
pipeline.run()

0 commit comments

Comments
 (0)