Skip to content
Merged
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 docs/guides/observers.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ Observers support multiple quantization strategies via the `QuantizationArgs.str
- `TOKEN`: Per-token statistics along token or sequence dimensions.
- `BLOCK`: Block-wise quantization with configurable block structure.

Note: observers do not handle `g_idx` (group index reordering for actorder). Column reordering for actorder is handled by GPTQ at compression time, not during observer statistics accumulation.
Note: column reordering for actorder is handled by GPTQ at compression time, not during observer statistics accumulation.

## Observer Configuration Parameters

Expand Down
24 changes: 1 addition & 23 deletions src/llmcompressor/modifiers/gptq/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@

__all__ = ["GPTQModifier"]

_GPTQ_Q_PARAMS = ["weight", "weight_scale", "weight_zero_point", "weight_g_idx"]
_GPTQ_Q_PARAMS = ["weight", "weight_scale", "weight_zero_point"]


class GPTQModifier(Modifier, QuantizationMixin):
Expand Down Expand Up @@ -93,7 +93,6 @@ class GPTQModifier(Modifier, QuantizationMixin):
:param actorder: order in which weight columns are quantized. Defaults to "static"
activation ordering, which achieves best accuracy recovery with no runtime cost.
For more information, see https://github.com/vllm-project/vllm/pull/8135.
Note: "group"/ "dynamic" are deprecated and will be removed in a future release.
:param offload_hessians: Set to True for decreased memory usage but increased
runtime.

Expand Down Expand Up @@ -157,13 +156,6 @@ def resolve_actorder(existing):
"remove `actorder` from config groups."
)
Comment thread
kylesayrs marked this conversation as resolved.

# compressed-tensors only accepts actorder=GROUP on these strategies
# on reload; other strategies fall back to None below.
grouped_strategies = (
QuantizationStrategy.GROUP,
QuantizationStrategy.TENSOR_GROUP,
)

for scheme in config.config_groups.values():
assert isinstance(scheme, QuantizationScheme)
strategy = getattr_chain(scheme, "weights.strategy", None)
Expand All @@ -177,20 +169,6 @@ def resolve_actorder(existing):
# Apply modifier-level actorder to already-constructed QuantizationArgs.
scheme.weights.actorder = resolve_actorder(scheme.weights.actorder)

if scheme.weights.actorder == ActivationOrdering.GROUP:
logger.bind(log_once=False).warning(
"ActivationOrdering.GROUP is deprecated and will be removed "
"in a future release. Use default actorder='static' instead. "
)

if strategy not in grouped_strategies:
logger.warning(
f"ActivationOrdering.GROUP is not compatible with "
f"strategy={strategy}; falling back to actorder=None "
f"for this scheme."
)
scheme.weights.actorder = None

return config

def on_initialize(self, state: State, **kwargs) -> bool:
Expand Down
29 changes: 8 additions & 21 deletions src/llmcompressor/modifiers/gptq/gptq_quantize.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def quantize_weight(
hessian: torch.Tensor,
blocksize: int = 128,
percdamp: float = 0.01,
) -> tuple[float, torch.Tensor, torch.Tensor, torch.Tensor | None, torch.Tensor]:
) -> tuple[float, dict[str, torch.Tensor]]:
"""
Quantize a module weight according to the GPTQ algorithm

Expand All @@ -79,7 +79,8 @@ def quantize_weight(
:param hessian: preaccumulated hessian for quantization
:param blocksize: chunk size of quantization updates
:param percdamp: dampening factor on hessian diagonal
:return: loss, quantized_weight, scale, zero_point, g_idx
:return: loss, q_param_dict (with keys: weight, weight_scale, weight_zero_point,
and optionally weight_global_scale)
Comment thread
kylesayrs marked this conversation as resolved.
"""
strategy = quant_args.strategy
actorder = quant_args.actorder
Expand All @@ -93,27 +94,15 @@ def quantize_weight(
num_rows = W.shape[0]
num_columns = W.shape[1]

if actorder == ActivationOrdering.GROUP and strategy not in (
QuantizationStrategy.GROUP,
QuantizationStrategy.TENSOR_GROUP,
):
logger.warning(
"ActivationOrdering.GROUP requires a grouped quantization strategy; "
"falling back to actorder=None for this module."
)
actorder = None

# handle activation ordering
if actorder:
if actorder not in (ActivationOrdering.WEIGHT, ActivationOrdering.STATIC):
raise ValueError(
f"Invalid activation ordering {actorder}. Only 'weight' and 'static'"
"are supported for GPTQ."
)
W, H, perm = _apply_activation_ordering(W, H)

# handle g_idx and activation ordering
if actorder == ActivationOrdering.GROUP:
# re-observe with permuted weight for correct per-group scales
observer.delete_statistics(check_fused=False)
observer(W)
# use identity g_idx (invert permutation later)

# handle g_idx
if strategy in (
Comment thread
dsikka marked this conversation as resolved.
QuantizationStrategy.GROUP,
Expand Down Expand Up @@ -259,8 +248,6 @@ def quantize_weight(
}
if global_scale:
q_param_dict["weight_global_scale"] = global_scale.to(dtype=final_dtype)
if actorder == ActivationOrdering.GROUP:
q_param_dict["weight_g_idx"] = g_idx[invperm]
return (loss, q_param_dict)


Expand Down
6 changes: 0 additions & 6 deletions tests/e2e/configs/w4a16_actorder_group.yaml

This file was deleted.

14 changes: 0 additions & 14 deletions tests/e2e/recipes/actorder/recipe_w4a16_actorder_group.yaml

This file was deleted.

8 changes: 4 additions & 4 deletions tests/llmcompressor/modifiers/calibration/test_observers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,16 @@
[
((1, 1), None, False),
((1, 1), 1, False),
((1, 1), 1, True),
((1, 1), 1, "weight"),
((64, 64), None, False),
((64, 64), 32, False),
((64, 64), 32, True),
((64, 64), 32, "weight"),
((896, 4096), None, False),
((896, 4096), 7, False),
((896, 4096), 7, True),
((896, 4096), 7, "weight"),
((512, 64), None, False),
((512, 64), 128, False),
((512, 64), 128, True),
((512, 64), 128, "weight"),
],
)
def test_observers_update(shape, group_size, actorder):
Expand Down
51 changes: 1 addition & 50 deletions tests/llmcompressor/modifiers/gptq/test_base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from contextlib import nullcontext
from unittest.mock import patch

import pytest
from compressed_tensors.quantization import QuantizationArgs, QuantizationScheme
Expand Down Expand Up @@ -72,25 +71,13 @@ def test_block_strategy_parsing(block_q_config_kwargs):
(False, "N/A", None, None, "static", "static"),
# modifier overrides config if no config provided
(True, "static", None, None, "static", "static"),
(True, "group", None, None, "group", "group"),
(True, None, None, None, None, None),
# modifier overrides if config partially matches anyways
(True, "group", None, "group", "group", "group"),
(True, "group", "group", None, "group", "group"),
# modifier errors if explicitly conflicts with config
(True, "static", None, "group", "error", "error"),
(True, "static", "group", None, "error", "error"),
(True, "group", None, "static", "error", "error"),
(True, "group", "static", None, "error", "error"),
(True, None, "static", None, "error", "error"),
# modifier overrides to static if nothing is provided
(False, "N/A", None, "static", "static", "static"),
(False, "N/A", "static", None, "static", "static"),
(False, "N/A", "static", "static", "static", "static"),
# modifier does not override set config vaules
(False, "N/A", None, "group", "static", "group"),
(False, "N/A", "group", None, "group", "static"),
(False, "N/A", "group", "group", "group", "group"),
],
)
def test_actorder_resolution(
Expand Down Expand Up @@ -126,10 +113,8 @@ def _make_weights(strategy):
[
(["group"], None),
(["group"], "weight"),
(["group"], "group"),
(["tensor_group"], None),
(["tensor_group"], "weight"),
(["tensor_group"], "group"),
(["channel"], None),
(["channel"], "weight"),
(["tensor"], None),
Expand All @@ -138,10 +123,8 @@ def _make_weights(strategy):
(["block"], "weight"),
(["channel", "group"], None),
(["channel", "group"], "weight"),
(["channel", "group"], "group"),
(["group", "channel"], None),
(["group", "channel"], "weight"),
(["group", "channel"], "group"),
],
)
def test_config_resolution(strategies, actorder):
Expand All @@ -154,38 +137,7 @@ def test_config_resolution(strategies, actorder):
modifier.resolve_quantization_config()

for config_group in modifier.config_groups.values():
strategy = config_group.weights.strategy
# actorder=group is only meaningful for group/tensor_group; other
# whitelisted strategies fall back to None.
if actorder == "group" and strategy not in _GROUPED_STRATEGIES:
assert config_group.weights.actorder is None
else:
assert config_group.weights.actorder == actorder


@pytest.mark.parametrize("strategy", ["channel", "tensor", "block"])
def test_actorder_group_falls_back_to_none(strategy):
# compressed-tensors rejects actorder=GROUP on non-grouped strategies on
# reload (per CT #682), so resolve_quantization_config warns and resets
# to None instead of producing an unloadable artifact.
config_groups = {
"0": QuantizationScheme(targets=[], weights=_make_weights(strategy)),
}
modifier = GPTQModifier(config_groups=config_groups, actorder="group")

# Mock both the bound logger (for deprecation warning) and regular logger
with patch("llmcompressor.modifiers.gptq.base.logger.bind") as mock_bind, patch(
"llmcompressor.modifiers.gptq.base.logger.warning"
) as warn:
# The bind() method returns self to allow chaining
mock_bind.return_value.warning = warn
resolved = modifier.resolve_quantization_config()

# Two warnings: deprecation warning + incompatibility warning
assert warn.call_count == 2
# The second call is the incompatibility warning that should mention the strategy
assert strategy in warn.call_args.args[0]
assert resolved.config_groups["0"].weights.actorder is None
assert config_group.weights.actorder == actorder


@pytest.mark.parametrize(
Expand All @@ -194,7 +146,6 @@ def test_actorder_group_falls_back_to_none(strategy):
(False, "N/A", "static"),
(True, None, None),
(True, "static", "static"),
(True, "group", "group"),
],
)
def test_serialize_actorder(has_actorder, actorder, exp_actorder):
Expand Down
5 changes: 1 addition & 4 deletions tests/llmcompressor/modifiers/gptq/test_gptq_quantize.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

@pytest.mark.parametrize(
"actorder",
[None, ActivationOrdering.WEIGHT, ActivationOrdering.GROUP],
[None, ActivationOrdering.WEIGHT],
)
@torch.no_grad()
def test_quantize_weight_group_strategy_actorder(actorder):
Expand Down Expand Up @@ -56,9 +56,6 @@ def test_quantize_weight_group_strategy_actorder(actorder):
assert q_param_dict["weight_scale"].shape == (6, 4)
assert q_param_dict["weight_zero_point"].shape == (6, 4)

if actorder == ActivationOrdering.GROUP:
assert q_param_dict["weight_g_idx"].shape == (8,)


@pytest.mark.parametrize(
"actorder",
Expand Down
2 changes: 1 addition & 1 deletion tests/llmcompressor/observers/test_fusion_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ def test_can_re_observe_after_deletion(self):

_DIST_MODULE = "llmcompressor.utils.dist"
_WEIGHT_Q_PARAMS = ["weight_scale", "weight_zero_point", "weight_global_scale"]
_GPTQ_Q_PARAMS = ["weight", "weight_scale", "weight_zero_point", "weight_g_idx"]
_GPTQ_Q_PARAMS = ["weight", "weight_scale", "weight_zero_point"]


def _simulate_ddp_broadcast(
Expand Down

This file was deleted.

This file was deleted.

23 changes: 1 addition & 22 deletions tests/llmcompressor/transformers/gptq/test_gptq_oneshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,6 @@
},
)

recipe_modifier_group_actorder_group = GPTQModifier(
ignore=["lm_head"],
config_groups={
"group_0": QuantizationScheme(
targets=["re:.*model.layers.2.self_attn.q_proj$"],
weights=QuantizationArgs(
num_bits=4,
strategy="group",
group_size=32,
actorder=ActivationOrdering.GROUP,
),
)
},
)

# Test block quantization variants
recipe_modifier_full_block = GPTQModifier(
ignore=["lm_head"],
Expand Down Expand Up @@ -168,7 +153,6 @@
recipe_modifier_shorthand_a,
recipe_modifier_shorthand_b,
recipe_modifier_group_actorder_weight,
recipe_modifier_group_actorder_group,
recipe_modifier_full_block,
recipe_modifier_block_actorder_weight,
recipe_modifier_channel_actorder_weight,
Expand Down Expand Up @@ -229,12 +213,7 @@ def test_oneshot_application(recipe, tmp_path):
assert not hasattr(not_targetted, "quantization_scheme")

# Verify g_idx behavior for activation ordering
if weight_args.actorder == ActivationOrdering.GROUP:
# GROUP actorder should save g_idx
assert hasattr(
targetted_linear_layer, "weight_g_idx"
), "GROUP actorder should have g_idx"
elif weight_args.actorder == ActivationOrdering.WEIGHT:
if weight_args.actorder == ActivationOrdering.WEIGHT:
# WEIGHT actorder should NOT save g_idx (identity mapping)
assert not hasattr(
targetted_linear_layer, "weight_g_idx"
Expand Down
Loading