Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backends/arm/quantizer/quantization_annotator.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ def _get_fixed_qparams_qspec(
torch.ops.aten.pow.Tensor_Scalar,
torch.ops.aten.gelu.default,
torch.ops.aten.silu.default,
torch.ops.aten.silu_.default,
torch.ops.aten.sinh.default,
torch.ops.aten.atan.default,
torch.ops.aten.log1p.default,
Expand Down Expand Up @@ -654,7 +655,6 @@ def _get_fixed_qparams_qspec(
torch.ops.aten.hardtanh_.default,
torch.ops.aten.relu.default,
torch.ops.aten.relu_.default,
torch.ops.aten.silu_.default,
torch.ops.aten.mean.default,
torch.ops.aten.mean.dim,
torch.ops.aten.permute.default,
Expand Down
4 changes: 2 additions & 2 deletions backends/arm/quantizer/quantization_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ class TOSAQuantizationConfig(QuantizationConfig):

quantize_grid_sampler_grid = False

# Ops whose output range matches their input's, so reusing the input qspec
# costs no resolution. Ops that compress the value range do not belong here.
SHARED_OUTPUT_ACT_QSPEC_PATTERNS = {
torch.ops.aten.adaptive_avg_pool2d.default,
torch.ops.aten.upsample_bilinear2d.vec,
Expand All @@ -269,8 +271,6 @@ class TOSAQuantizationConfig(QuantizationConfig):
torch.ops.aten.max_pool2d.default,
torch.ops.aten.mean.default,
torch.ops.aten.mean.dim,
torch.ops.aten.silu.default,
torch.ops.aten.silu_.default,
}

SHARED_INPUT_ACT_QSPEC_PATTERNS = {
Expand Down
47 changes: 47 additions & 0 deletions backends/arm/test/misc/test_shared_qspecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,33 @@ def forward(self, x):
return torch.maximum(self.int16(x), self.int8(x))


class NonSharedQspecSilu(torch.nn.Module):
"""SiLU's output range is always narrower than its input's, so reusing the
input scale misaligns the quantization bins with the output distribution and
wastes resolution.
"""

qspecs = {
"quantized_decomposed.quantize_per_tensor.default": {None: 2},
"quantized_decomposed.dequantize_per_tensor.default": {None: 2},
}
input_qspecs = {_INT8_QSPEC: 1}
output_qspecs = {_INT8_QSPEC: 1}
quant_params = {
"quantized_decomposed.quantize_per_tensor.default": {
(0.03919654, 76, -128, 127, torch.int8): 1,
(0.007980779, -94, -128, 127, torch.int8): 1,
},
"quantized_decomposed.dequantize_per_tensor.default": {
(0.03919654, 76, -128, 127, torch.int8): 1,
(0.007980779, -94, -128, 127, torch.int8): 1,
},
}

def forward(self, x):
return torch.nn.functional.silu(x)


test_cases = {
"multiple_clusters": McuTestCase(
SharedQspecMulipleClusters(),
Expand Down Expand Up @@ -687,3 +714,23 @@ def test_maximum_mixed_int8_int16_inputs():
)
pipeline.run()
_check_quant_params(pipeline, model.quant_params)


def test_silu_does_not_share_input_qspec():
"""Sharing saves nothing in return for that lost resolution: SiLU runs as a
lookup table whose entries are precomputed from both the input and the output
qparams, so a distinct output scale costs nothing at runtime.
"""
model = NonSharedQspecSilu()
inputs = (ramp_tensor(-8, 2, (2, 3, 4)),)

pipeline = QuantizationPipeline(
model,
inputs,
quantizer=_get_quantizer(),
qspecs=model.qspecs,
input_qspecs=model.input_qspecs,
output_qspecs=model.output_qspecs,
)
pipeline.run()
_check_quant_params(pipeline, model.quant_params)
4 changes: 3 additions & 1 deletion backends/arm/test/ops/test_silu.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ def forward(
_input: torch.Tensor,
_inplace: Optional[bool] = False,
):
return torch.nn.SiLU(inplace=_inplace)(_input)
# Clone so the in-place variant does not overwrite the caller's tensor,
# which the pipeline reuses for the comparison run.
return torch.nn.SiLU(inplace=_inplace)(_input.clone())

test_data: list[input_t] = {
"op_silu_rank1_ones": lambda: torch.ones(5),
Expand Down
Loading