|
4 | 4 | # This source code is licensed under the BSD-style license found in the |
5 | 5 | # LICENSE file in the root directory of this source tree. |
6 | 6 | import itertools |
| 7 | +import logging |
7 | 8 | import operator |
8 | 9 | from dataclasses import dataclass |
9 | 10 | from enum import IntEnum, unique |
10 | | -from functools import partial, reduce |
| 11 | +from functools import partial |
11 | 12 | from operator import attrgetter |
12 | 13 | from typing import Callable, Dict, List, Optional, Sequence, Set, Tuple |
13 | 14 |
|
14 | 15 | # To support quantize op lowering in AOT |
15 | 16 | try: |
16 | 17 | import executorch.kernels.quantized # noqa[F401] |
17 | 18 | except: |
18 | | - import logging |
19 | | - |
20 | 19 | logging.info( |
21 | 20 | "Failed to load quantized_aot_lib. To run on LPAI backend, please make sure that quantized_aot_lib is accessible." |
22 | 21 | ) |
23 | | - del logging |
24 | 22 | import torch |
25 | 23 | from executorch.backends.qualcomm._passes.qnn_pass_manager import ( |
26 | 24 | get_qnn_pass_manager_cls, |
|
47 | 45 | from torch.fx import GraphModule |
48 | 46 | from torch.fx.passes.utils.source_matcher_utils import get_source_partitions |
49 | 47 | from torchao.quantization.pt2e import UniformQuantizationObserverBase |
50 | | -from torchao.quantization.pt2e.quantizer import Quantizer |
| 48 | +from torchao.quantization.pt2e.quantizer import Quantizer, SharedQuantizationSpec |
51 | 49 |
|
52 | 50 | from .qconfig import ( |
53 | 51 | get_16a16w_qnn_ptq_config, |
@@ -401,21 +399,26 @@ def recipe(self): |
401 | 399 | def _get_quant_range(self, node): |
402 | 400 | if quant_info := node.meta.get(QCOM_QUANT_ANNOTATION_KEY, None): |
403 | 401 | try: |
404 | | - dtype_info = torch.iinfo( |
405 | | - reduce(getattr, ["output_qspec", "dtype"], quant_info) |
406 | | - ) |
| 402 | + # SharedQuantizationSpec has not quant info, so we need to find source node |
| 403 | + # that this node is sharing quant info with and use source node's quant info. |
| 404 | + qspec = quant_info.output_qspec |
| 405 | + while isinstance(qspec, SharedQuantizationSpec): |
| 406 | + edge_or_node = qspec.edge_or_node |
| 407 | + if isinstance(edge_or_node, tuple): |
| 408 | + input_node, user_node = edge_or_node |
| 409 | + shared_info = user_node.meta[QCOM_QUANT_ANNOTATION_KEY] |
| 410 | + qspec = shared_info.input_qspec_map[input_node] |
| 411 | + else: |
| 412 | + shared_info = edge_or_node.meta[QCOM_QUANT_ANNOTATION_KEY] |
| 413 | + qspec = shared_info.output_qspec |
| 414 | + dtype_info = torch.iinfo(qspec.dtype) |
407 | 415 | except: |
| 416 | + logging.warning(f"Could not resolve quant range for node: {node.name}") |
408 | 417 | return |
409 | 418 |
|
410 | 419 | quant_range = ( |
411 | | - dtype_info.max |
412 | | - if quant_info.output_qspec.quant_max is None |
413 | | - else quant_info.output_qspec.quant_max |
414 | | - ) - ( |
415 | | - dtype_info.min |
416 | | - if quant_info.output_qspec.quant_min is None |
417 | | - else quant_info.output_qspec.quant_min |
418 | | - ) |
| 420 | + dtype_info.max if qspec.quant_max is None else qspec.quant_max |
| 421 | + ) - (dtype_info.min if qspec.quant_min is None else qspec.quant_min) |
419 | 422 | return quant_range |
420 | 423 |
|
421 | 424 | def _get_candidates_with_infinity_args(self, graph_module: GraphModule): |
|
0 commit comments