|
24 | 24 | from executorch.backends.arm.common.arm_compile_spec import ( |
25 | 25 | ArmCompileSpec, |
26 | 26 | ) # isort: skip |
| 27 | +from executorch.backends.arm._passes.arm_pass_utils import ( |
| 28 | + get_cond_while_submodules_nested, |
| 29 | + is_submodule_node, |
| 30 | +) |
27 | 31 | from executorch.backends.arm.vgf import VgfCompileSpec |
28 | | -from executorch.exir.graph_module import _get_control_flow_submodules |
29 | 32 |
|
30 | 33 | from torch.fx import GraphModule, Node |
31 | 34 | from torchao.quantization.pt2e import ( |
@@ -639,27 +642,6 @@ def validate(self, model: GraphModule) -> None: |
639 | 642 | f"Quantizer detected operator {node.name} with different device inputs: {devices}." |
640 | 643 | ) |
641 | 644 |
|
642 | | - @staticmethod |
643 | | - def _get_submodules_not_handled_by_torchao( |
644 | | - graph_module: GraphModule, |
645 | | - ): |
646 | | - """Returns control flow submodules that torchao's |
647 | | - prepare_pt2e/convert_pt2e do not handle natively. torchao now |
648 | | - recursively handles while_loop body_fn. |
649 | | -
|
650 | | - (arg 1), so we only need to manually handle: |
651 | | - - cond true/false branches (args 1, 2) |
652 | | - - while_loop cond_fn (arg 0) |
653 | | -
|
654 | | - """ |
655 | | - return _get_control_flow_submodules( |
656 | | - graph_module, |
657 | | - { |
658 | | - torch.ops.higher_order.cond: [1, 2], |
659 | | - torch.ops.higher_order.while_loop: [0], |
660 | | - }, |
661 | | - ) |
662 | | - |
663 | 645 | def quantize_with_submodules( |
664 | 646 | self, |
665 | 647 | model: GraphModule, |
@@ -691,18 +673,40 @@ def quantize_with_submodules( |
691 | 673 | prepare_fn = prepare_qat_pt2e if is_qat else prepare_pt2e |
692 | 674 |
|
693 | 675 | prepared = prepare_fn(model, self) |
694 | | - for name, submodule, _ in self._get_submodules_not_handled_by_torchao(prepared): |
| 676 | + # Prepare conditional submodules (e.g., if/while bodies) |
| 677 | + # prepare only cond branches and while_loop cond_fn |
| 678 | + for name, submodule, _ in get_cond_while_submodules_nested( |
| 679 | + prepared, apply_quantization=True |
| 680 | + ): |
695 | 681 | prepared.set_submodule(name, prepare_fn(submodule, self), strict=True) |
| 682 | + for submodule_node in submodule.graph.nodes: |
| 683 | + if is_submodule_node(submodule_node): |
| 684 | + for nested_name, nested_sub, _ in get_cond_while_submodules_nested( |
| 685 | + submodule, apply_quantization=True |
| 686 | + ): |
| 687 | + prepared.set_submodule( |
| 688 | + nested_name, prepare_fn(nested_sub, self), strict=True |
| 689 | + ) |
| 690 | + |
696 | 691 | for inp in calibration_samples: |
697 | 692 | prepared(*inp) |
698 | 693 |
|
699 | | - for name, submodule, _ in self._get_submodules_not_handled_by_torchao(prepared): |
700 | | - prepared.set_submodule( |
701 | | - name, convert_pt2e(submodule, fold_quantize=fold_quantize), strict=True |
702 | | - ) |
703 | | - converted = convert_pt2e(prepared, fold_quantize=fold_quantize) |
| 694 | + # Prepare conditional submodules (e.g., if/while bodies) |
| 695 | + # convert only cond branches and while_loop cond_fn |
| 696 | + for _, submodule, _ in get_cond_while_submodules_nested( |
| 697 | + prepared, apply_quantization=True |
| 698 | + ): |
| 699 | + converted = convert_pt2e(submodule) |
| 700 | + for submodule_node in submodule.graph.nodes: |
| 701 | + if is_submodule_node(submodule_node): |
| 702 | + for nested_name, nested_sub, _ in get_cond_while_submodules_nested( |
| 703 | + submodule, apply_quantization=True |
| 704 | + ): |
| 705 | + converted.set_submodule( |
| 706 | + nested_name, convert_pt2e(nested_sub), strict=True |
| 707 | + ) |
704 | 708 |
|
705 | | - return converted |
| 709 | + return convert_pt2e(prepared) |
706 | 710 |
|
707 | 711 |
|
708 | 712 | class EthosUQuantizer(TOSAQuantizer): |
|
0 commit comments