From 9a22d32efea8a13778ea44d6f7b4e25f39a8fb3a Mon Sep 17 00:00:00 2001 From: arham766 Date: Mon, 6 Jul 2026 21:48:55 -0700 Subject: [PATCH] fix: reject amax assignment on dynamic quantizers Setting amax on a dynamic TensorQuantizer silently stored a value that dynamic quantization never uses; fail fast instead. getattr (not self._dynamic) because __init__ assigns self.amax = amax before set_from_attribute_config creates the _dynamic attribute. Also adds a regression test pinning the disabled extra_repr detail output (dead code until #1879 made it reachable). Signed-off-by: arham766 --- .../nn/modules/tensor_quantizer.py | 6 ++++++ .../quantization/test_tensor_quantizer_cpu.py | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/modelopt/torch/quantization/nn/modules/tensor_quantizer.py b/modelopt/torch/quantization/nn/modules/tensor_quantizer.py index c7649f9383d..dcb92a1a4a4 100644 --- a/modelopt/torch/quantization/nn/modules/tensor_quantizer.py +++ b/modelopt/torch/quantization/nn/modules/tensor_quantizer.py @@ -348,6 +348,12 @@ def amax(self): @amax.setter def amax(self, value): assert value is not None, "amax cannot be set to None." + # getattr (not self._dynamic): __init__ assigns self.amax = amax before + # set_from_attribute_config creates the _dynamic attribute, so a bare + # attribute access would break the amax= constructor argument. + assert not getattr(self, "_dynamic", False), ( + "Dynamic quantization does not have fixed amax; amax cannot be set." + ) if not isinstance(value, torch.Tensor): value = torch.tensor(value) diff --git a/tests/unit/torch/quantization/test_tensor_quantizer_cpu.py b/tests/unit/torch/quantization/test_tensor_quantizer_cpu.py index 56019d8cf75..60eb4e493cd 100644 --- a/tests/unit/torch/quantization/test_tensor_quantizer_cpu.py +++ b/tests/unit/torch/quantization/test_tensor_quantizer_cpu.py @@ -15,16 +15,35 @@ """Tests of tensor quantizer.""" +import pytest +import torch from _test_utils.torch.quantization.tensor_quantizer_common import ( BlockQuantTester, SequentialQuantizerTester, TensorQuantizerTester, ) +from modelopt.torch.quantization.config import QuantizerAttributeConfig +from modelopt.torch.quantization.nn import TensorQuantizer + class TestTensorQuantizerCPU(TensorQuantizerTester): device = "cpu" + def test_disabled_extra_repr(self): + quantizer = TensorQuantizer(QuantizerAttributeConfig(enable=False)).to(self.device) + assert quantizer.extra_repr() == "disabled" + + quantizer.pre_quant_scale = torch.tensor([0.5, 2.0]).to(self.device) + extra_repr = quantizer.extra_repr() + assert extra_repr.startswith("disabled") + assert "pre_quant_scale=" in extra_repr + + def test_dynamic_amax_set_rejected(self): + quantizer = TensorQuantizer(QuantizerAttributeConfig(type="dynamic")).to(self.device) + with pytest.raises(AssertionError, match="Dynamic quantization"): + quantizer.amax = 1.0 + class TestBlockQuantCPU(BlockQuantTester): device = "cpu"