Skip to content

fix: quant_analyse crashes on per-channel/group weight scales - #384

Open
Linxiushen wants to merge 1 commit into
Tencent:mainfrom
Linxiushen:fix-quant-analyse-per-channel
Open

Linxiushen wants to merge 1 commit into
Tencent:mainfrom
Linxiushen:fix-quant-analyse-per-channel

Conversation

@Linxiushen

Copy link
Copy Markdown

Problem

PTQ.save() gates a scale-outlier report behind quantization.quant_analyse and tests each scale like this (angelslim/compressor/quant/ptq.py, lines 199 and 207):

for k in self.quant_model.weight_scales_dict.keys():
    weight_scales_data = self.quant_model.weight_scales_dict[k].data
    if weight_scales_data > 1.5:          # <-- only valid for a 0-dim scalar

if tensor > 1.5 works only when the scale is a 0-dim scalar. Per-channel and group-wise quantization keep one scale per channel/group, so the tensor holds more than one element, Python falls back to Tensor.__bool__(), and it raises:

RuntimeError: Boolean value of Tensor with more than one value is ambiguous

This is reachable from the shipped configs

  • configs/qwen3/ptq/int8_dynamic/*.yaml all set weight: "per-channel" (checked qwen3-0_6b, qwen3-1_7b, qwen3-32b)
  • AbsMaxChannelWiseWeightObserver._cal_min_max computes new_inp.abs().max(dim=self.quant_axis()) without keepdim, i.e. a 1-D per-channel tensor
  • quant_analyse is wired into both the int8 and fp8 branches (quant/core/config.py), so it is meant to be a general switch, not per-tensor-only

So enabling quant_analyse on the default int8_dynamic recipe crashes at save time, after calibration has already run.

Reproduction

The block below is extracted verbatim from ptq.py at main (ee8ddb2) and executed against a per-channel scale tensor shaped exactly like the observer's output:

# current main
for k in self.quant_model.weight_scales_dict.keys():
    weight_scales_data = self.quant_model.weight_scales_dict[k].data
    if weight_scales_data > 1.5:
        print_info(...)

# fed: {"model.layers.0.mlp.down_proj.weight": torch.tensor([0.1, 2.0, 0.3, 0.05])}
RuntimeError: Boolean value of Tensor with more than one value is ambiguous

With the patch applied, the same block reports normally:

[AngelSlim Warning] Weight_scales model.layers.0.mlp.down_proj.weight: The weight is too high:2.0. ...

Minimal standalone check of the root cause:

>>> torch.tensor(2.0) > 1.5 and True          # 0-dim: fine
>>> bool(torch.tensor([0.1, 2.0]) > 1.5)
RuntimeError: Boolean value of Tensor with more than one value is ambiguous

Fix

Use torch.any(), which handles 0-dim and multi-element tensors alike, and print .max().item() so the warning stays readable instead of dumping a whole per-channel tensor.

Behaviour across scale shapes

scale before after
per-tensor, above threshold (0-dim) warns warns (max=2.0)
per-tensor, below threshold (0-dim) silent silent
per-channel, some above (4 elem) RuntimeError warns (max=5.0)
per-channel, none above (4 elem) RuntimeError silent
per-group 2-D (2×3) RuntimeError warns (max=9.9)
single-element 1-D warns warns (max=2.0)

per-tensor behaviour is unchanged in both directions — that was the main thing I wanted to be sure of.

Notes

  • 11 insertions / 4 deletions, one file
  • torch is already imported at the top of ptq.py (line 19), no new dependency
  • I could not run a full end-to-end quantization to confirm (no GPU / no triton wheel on this machine), so the verification above executes the real source block directly rather than driving PTQ.save() through a real calibration run. Happy to adjust if you'd like the warning formatted differently, e.g. also printing the offending channel index.

Investigated and fixed with AI assistance (Claude); I reviewed the change and the verification above myself.

PTQ.save() gates a scale-outlier report behind quantization.quant_analyse and
tests each scale with `if act_scales_data > 1.5:` / `if weight_scales_data > 1.5:`.
That only works for 0-dim scalars. Per-channel and group-wise quantization keep
one scale per channel/group, so the tensor holds more than one element and
Python calls Tensor.__bool__(), which raises:

    RuntimeError: Boolean value of Tensor with more than one value is ambiguous

This is reachable from the shipped configs: configs/qwen3/ptq/int8_dynamic/*.yaml
all set weight: "per-channel", and AbsMaxChannelWiseWeightObserver computes
max(dim=quant_axis()) without keepdim, i.e. a 1-D per-channel tensor.

Use torch.any() so both 0-dim and multi-element scales work, and report
.max().item() so the message stays short instead of printing a whole
per-channel tensor.

per-tensor behaviour is unchanged (still warns above 1.5, silent below).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant