Skip to content

Commit e116040

Browse files
ryan-monroefacebook-github-bot
authored andcommitted
Support activation-only PTQ (weight_qspec=None)
Summary: The Ethos/arm PT2E quantization annotator (`quantization_annotator.py`, fbcode + xplat) assumed every weighted op carries a weight qspec and unconditionally annotated the weight input. Activation-only PTQ -- int16 activations with fp32 (un-quantized) weights -- sets `weight_qspec=None`, which tripped the annotator. This skips weight annotation when the weight qspec is None, enabling activation-only PTQ on the arm/Ethos backend. Required by the `cascade_detector_ceres_u55_a16_only` recipe (D108781360), which isolates the activation-quant contribution of the grip-force int8 collapse. Differential Revision: D108781361
1 parent ce9a7f5 commit e116040

1 file changed

Lines changed: 33 additions & 28 deletions

File tree

backends/arm/quantizer/quantization_annotator.py

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,27 @@ def __init__(self):
8181
self.quant_output: Optional[_QuantProperty] = None
8282

8383

84+
def _conv_linear_quant_inputs(
85+
input_act_qspec: QuantizationSpecBase | None,
86+
weight_qspec: QuantizationSpecBase | None,
87+
bias_qspec: QuantizationSpecBase | None,
88+
) -> List[_QuantProperty]:
89+
"""Build conv/linear input quant properties, tolerating partial quant.
90+
91+
Activation-only PTQ recipes leave ``weight_qspec`` (and the bias derived
92+
from it) None; omit those QuantProperties so weight/bias stay fp32 instead of
93+
asserting a non-None weight spec. Weight-only and full configs keep the
94+
weight (and bias) quantized exactly as before.
95+
"""
96+
quant_inputs: List[_QuantProperty] = [_QuantProperty(0, input_act_qspec)]
97+
if weight_qspec is not None:
98+
quant_inputs.append(_QuantProperty(1, weight_qspec, mark_annotated=True))
99+
quant_inputs.append(
100+
_QuantProperty(2, bias_qspec, optional=True, mark_annotated=True)
101+
)
102+
return quant_inputs
103+
104+
84105
class _QParams(NamedTuple):
85106
scale: float
86107
zero_point: int
@@ -716,12 +737,9 @@ def any_or_hardtanh_min_zero(n: Node):
716737
filter_fn=any_or_hardtanh_min_zero,
717738
):
718739
if node.target in _conv_ops:
719-
conv_weight_qspec = ensure_type(QuantizationSpec, weight_qspec) # For MyPy
720-
quant_properties.quant_inputs = [
721-
_QuantProperty(0, input_act_qspec),
722-
_QuantProperty(1, conv_weight_qspec, mark_annotated=True),
723-
_QuantProperty(2, bias_qspec, optional=True, mark_annotated=True),
724-
]
740+
quant_properties.quant_inputs = _conv_linear_quant_inputs(
741+
input_act_qspec, weight_qspec, bias_qspec
742+
)
725743
elif node.target in (
726744
torch.ops.aten.relu.default,
727745
torch.ops.aten.relu_.default,
@@ -738,12 +756,9 @@ def any_or_hardtanh_min_zero(n: Node):
738756
],
739757
):
740758
if node.target in _conv_ops:
741-
conv_weight_qspec = ensure_type(QuantizationSpec, weight_qspec) # For MyPy
742-
quant_properties.quant_inputs = [
743-
_QuantProperty(0, input_act_qspec),
744-
_QuantProperty(1, conv_weight_qspec, mark_annotated=True),
745-
_QuantProperty(2, bias_qspec, optional=True, mark_annotated=True),
746-
]
759+
quant_properties.quant_inputs = _conv_linear_quant_inputs(
760+
input_act_qspec, weight_qspec, bias_qspec
761+
)
747762
elif node.target in {torch.ops.aten.batch_norm.default}:
748763
quant_properties.quant_output = _QuantProperty(0, output_act_qspec)
749764
elif not is_symmetric and _match_pattern(
@@ -766,28 +781,18 @@ def any_or_hardtanh_min_zero(n: Node):
766781
*_conv_ops,
767782
torch.ops.aten.linear.default,
768783
):
769-
conv_or_linear_weight_qspec = ensure_type(
770-
QuantizationSpec, weight_qspec
771-
) # For MyPy
772-
quant_properties.quant_inputs = [
773-
_QuantProperty(0, input_act_qspec),
774-
_QuantProperty(1, conv_or_linear_weight_qspec, mark_annotated=True),
775-
_QuantProperty(2, bias_qspec, optional=True, mark_annotated=True),
776-
]
784+
quant_properties.quant_inputs = _conv_linear_quant_inputs(
785+
input_act_qspec, weight_qspec, bias_qspec
786+
)
777787
else:
778788
quant_properties.quant_output = _QuantProperty(0, output_act_qspec)
779789
elif node.target in (
780790
*_conv_ops,
781791
torch.ops.aten.linear.default,
782792
):
783-
conv_or_linear_weight_qspec = ensure_type(
784-
QuantizationSpec, weight_qspec
785-
) # For MyPy
786-
quant_properties.quant_inputs = [
787-
_QuantProperty(0, input_act_qspec),
788-
_QuantProperty(1, conv_or_linear_weight_qspec, mark_annotated=True),
789-
_QuantProperty(2, bias_qspec, optional=True, mark_annotated=True),
790-
]
793+
quant_properties.quant_inputs = _conv_linear_quant_inputs(
794+
input_act_qspec, weight_qspec, bias_qspec
795+
)
791796
quant_properties.quant_output = _QuantProperty(0, output_act_qspec)
792797
elif node.target in (
793798
torch.ops.aten.add.Tensor,

0 commit comments

Comments
 (0)