-
Notifications
You must be signed in to change notification settings - Fork 174
Recurrent Residual Quantization (RRQ) for LLMs #2308
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
luoyu-intel
wants to merge
31
commits into
main
Choose a base branch
from
feat/rrq-phase1
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 18 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
3299eb3
feat(rrq): Phase 1 - Recurrent Residual Quantization (packed INT2 2+2…
luoyu-intel 6afb9a7
feat(rrq): Phase 2 - generate_rrq_residual (incremental from existing…
luoyu-intel 5c7c12e
feat(rrq): Phase 3 - add per-plane sign-SGD tuning
luoyu-intel 0fd545f
fix(rrq): accumulate optimized residual prefix
luoyu-intel d0c60ea
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] ed2f737
feat(rrq): match AutoRound per-plane quality + configurable mixed-pre…
luoyu-intel 584e0ac
docs(rrq): add Recurrent Residual Quantization entry to README
luoyu-intel 25efe2f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 254b3e9
Merge branch 'main' into feat/rrq-phase1
luoyu-intel 0ba0b03
fix(cli): match shared argparse options before falling back to dest i…
luoyu-intel 11597ed
perf(rrq): replace 4-plane matmul accumulation with single dequant+ma…
luoyu-intel 2632c1a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] c851ced
fix(rrq): declare tunable fields as named __init__ params
luoyu-intel 5da4987
Merge branch 'main' into feat/rrq-phase1
luoyu-intel ad15c7d
fix(export): include unquantized vision layers in AWQ modules_to_not_…
luoyu-intel 31e0a14
refactor(rrq): minimize common-code changes to preserve main behavior
luoyu-intel 4e78c2b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 6085da1
revert(export): restore AWQ _collect_modules_to_not_convert to main l…
luoyu-intel 5c765bf
Apply batched suggestions from code review
luoyu-intel 664510b
revert log info
luoyu-intel 22e9fff
fix(rrq): raise ValueError for explicit model_free=True with RRQConfig
luoyu-intel f26d807
fix(rrq): enforce disable_opt_rtn=True in RRQConfig.check_config()
luoyu-intel 389d93e
Refactor RRQ exports to sub-package entry points and add eval scripts
luoyu-intel 0722945
test(rrq): add lm-eval accuracy test for RRQ W2A16 quantization
luoyu-intel 533e29e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 3094057
docs(README): note that RRQ does not support production-level deploym…
luoyu-intel 7a77c98
Merge branch 'main' into feat/rrq-phase1
a32543254 06f3d58
feat(rrq): hide RRQ from user-facing listings, auto-select via format
luoyu-intel 74f3f00
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] 30f2634
fix(rrq): auto-select W2A16 scheme and force disable_opt_rtn for RRQ
luoyu-intel 8a53c1b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # Copyright (c) 2026 Intel Corporation | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| """Recurrent Residual Quantization (RRQ) algorithm. | ||
|
|
||
| RRQ quantizes weights into multiple sequential INT2 planes (base + residuals) | ||
| using recursive RTN. Each plane is independently quantized in the weight | ||
| domain, so the accumulated representation at any prefix is the best | ||
| achievable within that bit budget. | ||
|
|
||
| Phase 1: RTN only (no sign-SGD tuning). | ||
|
luoyu-intel marked this conversation as resolved.
|
||
| Phase 3: per-plane sign-SGD tuning with a frozen prefix. | ||
| """ | ||
|
|
||
| from auto_round.algorithms.quantization.rrq.config import RRQConfig | ||
| from auto_round.algorithms.quantization.rrq.quantizer import RRQRTNQuantizer, RRQSignRoundQuantizer | ||
|
|
||
| __all__ = ["RRQConfig", "RRQRTNQuantizer", "RRQSignRoundQuantizer"] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,196 @@ | ||
| # Copyright (c) 2026 Intel Corporation | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| """Configuration for Recurrent Residual Quantization (RRQ). | ||
|
|
||
| RRQ quantizes each weight tensor into K sequential INT2 planes (1 base + | ||
| K-1 residual planes). The total effective bit-width is K * plane_bits. | ||
|
|
||
| By default RRQ follows AutoRound's default SignRound optimization settings | ||
| (``iters=200``, automatic learning rates, zero momentum, and min/max tuning). | ||
| Passing ``iters=0`` explicitly selects the RTN-only mode. Every plane uses the | ||
| same optimization settings; residual planes differ only in their frozen prefix | ||
| and target residual. | ||
| """ | ||
|
|
||
| from auto_round.algorithms.config import AlgorithmParameterRegistry | ||
| from auto_round.algorithms.quantization.rtn.config import RTNConfig | ||
| from auto_round.algorithms.registry import register_algorithm | ||
|
|
||
|
|
||
| class RRQConfig(RTNConfig): | ||
| """Configuration for Recurrent Residual Quantization. | ||
|
|
||
| Fixed in this version: | ||
| - bits = 2 (per plane) | ||
| - data_type = "int" | ||
| - act_bits = 16 (weight-only) | ||
| - num_residual_planes = 3 (total planes = 4, effective bits 2/4/6/8) | ||
|
|
||
| With the default ``iters=200``, every plane uses the same SignRound | ||
| optimization parameters as ordinary AutoRound. Passing ``iters=0`` | ||
| explicitly selects RTN-only quantization without calibration. | ||
|
luoyu-intel marked this conversation as resolved.
Outdated
|
||
| """ | ||
|
|
||
| #: Number of INT2 residual planes (after the base plane). | ||
| #: Total planes = 1 (base) + num_residual_planes. | ||
| num_residual_planes: int = 3 | ||
|
|
||
| def __init__( | ||
| self, | ||
| *, | ||
| iters: int = 200, | ||
| lr: float | None = None, | ||
| minmax_lr: float | None = None, | ||
| momentum: float = 0.0, | ||
| lr_scheduler=None, | ||
| enable_minmax_tuning: bool = True, | ||
| gradient_accumulate_steps: int = 1, | ||
| enable_quanted_input: bool = True, | ||
| not_use_best_mse: bool = False, | ||
| dynamic_max_gap: int = -1, | ||
| enable_lfq: bool = False, | ||
| num_residual_planes: int = 3, | ||
| disable_opt_rtn: bool | None = True, | ||
| **kwargs, | ||
| ): | ||
| # Enforce fixed values | ||
| if "bits" in kwargs and kwargs["bits"] != 2: | ||
| raise ValueError(f"RRQ only supports bits=2 per plane, got {kwargs['bits']}") | ||
| if "data_type" in kwargs and kwargs["data_type"] != "int": | ||
| raise ValueError(f"RRQ only supports data_type='int', got {kwargs['data_type']!r}") | ||
| if "act_bits" in kwargs and kwargs["act_bits"] != 16: | ||
| raise ValueError(f"RRQ is weight-only; act_bits must be 16, got {kwargs['act_bits']}") | ||
|
|
||
| # RRQ-tunable fields (not scheme fields). Declared as named parameters so | ||
| # the CLI field-acceptance contract (see test_cli_usage) holds; stored | ||
| # before super() so the inherited RTN/Quantization __init__ doesn't drop | ||
| # them. Match SignRoundConfig's AutoRound default. RTN remains available | ||
| # via an explicit ``iters=0``. | ||
| self._rrq_iters = iters | ||
| self._rrq_lr = lr | ||
| self._rrq_minmax_lr = minmax_lr | ||
| self._rrq_momentum = momentum | ||
| self._rrq_lr_scheduler = lr_scheduler | ||
| self._rrq_enable_minmax_tuning = enable_minmax_tuning | ||
| self._rrq_gradient_accumulate_steps = gradient_accumulate_steps | ||
| self._rrq_enable_quanted_input = enable_quanted_input | ||
| self._rrq_not_use_best_mse = not_use_best_mse | ||
| self._rrq_dynamic_max_gap = dynamic_max_gap | ||
| self._rrq_enable_lfq = enable_lfq | ||
|
|
||
| # Inject fixed values | ||
| kwargs.setdefault("bits", 2) | ||
| kwargs.setdefault("data_type", "int") | ||
| kwargs.setdefault("act_bits", 16) | ||
|
|
||
| # num_residual_planes is not a scheme field | ||
| if num_residual_planes not in (1, 3): | ||
| raise ValueError(f"RRQ supports num_residual_planes=1 or 3, got {num_residual_planes}") | ||
| if num_residual_planes <= 0: | ||
| raise ValueError("num_residual_planes must be positive") | ||
| self._num_residual_planes = num_residual_planes | ||
|
|
||
| # ``disable_opt_rtn`` stays True at the config level purely to keep RRQ | ||
| # routed to its own quantizer: an RTNConfig subclass with | ||
| # ``disable_opt_rtn=False`` is silently coerced to OptimizedRTNConfig by | ||
| # the AutoRound entry, which would drop every residual plane. The | ||
| # per-plane RTN quality is matched to standard AutoRound (opt-RTN) | ||
| # inside the quantizer instead (see RRQRTNQuantizer). Passed explicitly | ||
| # (not via ``**kwargs``) since it is a named parameter here. | ||
| super().__init__(disable_opt_rtn=disable_opt_rtn, **kwargs) | ||
|
luoyu-intel marked this conversation as resolved.
|
||
|
|
||
| self.iters = int(self._rrq_iters or 0) | ||
| self.lr = self._rrq_lr | ||
| self.minmax_lr = self._rrq_minmax_lr | ||
| self.momentum = self._rrq_momentum | ||
| self.lr_scheduler = self._rrq_lr_scheduler | ||
| self.enable_minmax_tuning = self._rrq_enable_minmax_tuning | ||
| self.gradient_accumulate_steps = self._rrq_gradient_accumulate_steps | ||
| self.enable_quanted_input = self._rrq_enable_quanted_input | ||
| self.not_use_best_mse = self._rrq_not_use_best_mse | ||
| self.dynamic_max_gap = self._rrq_dynamic_max_gap | ||
| self.enable_lfq = self._rrq_enable_lfq | ||
| # Both paths use block calibration data: SignRound needs it for tuning, | ||
| # and the RTN path needs it to collect the imatrix for imatrix-weighted | ||
| # opt-RTN (matching an ordinary AutoRound W2A16 OptimizedRTN base). | ||
| self.need_calib = True | ||
|
|
||
| @property | ||
| def total_planes(self) -> int: | ||
| """Total number of INT2 planes (base + residual).""" | ||
| return 1 + self._num_residual_planes | ||
|
|
||
| @property | ||
| def total_bits(self) -> int: | ||
| """Total effective bit-width of the full representation.""" | ||
| return self.bits * self.total_planes | ||
|
|
||
| @classmethod | ||
| def register_args(cls, registry): | ||
| """Register CLI args for RRQ (Phase 1 common args + optional tuning).""" | ||
| super().register_args(registry) | ||
| registry.add_argument( | ||
| "--iters", | ||
| field="iters", | ||
| default=200, | ||
| type=int, | ||
| help="Iterations of per-plane sign-SGD tuning. 0 explicitly selects " | ||
| "pure RTN; the default 200 matches AutoRound SignRound.", | ||
| ) | ||
| registry.add_argument("--lr", field="lr", default=None, type=float, help="Learning rate for the RRQ tuning.") | ||
| registry.add_argument( | ||
| "--minmax_lr", field="minmax_lr", default=None, type=float, help="Learning rate for min-max tuning." | ||
| ) | ||
| registry.add_argument( | ||
| "--momentum", field="momentum", default=0.0, type=float, help="Momentum for the RRQ optimizer." | ||
| ) | ||
|
|
||
| def _lr_for_bits(self, bits): | ||
| """Auto lr heuristic for sign-SGD tuning (mirrors SignRound).""" | ||
| if self.iters <= 0: | ||
| return None | ||
| # Match SignRoundConfig._lr_for_bits: low-bit layers get a higher lr | ||
| # when the iteration budget is large. | ||
| if self.iters >= 1000 and bits is not None and bits <= 3: | ||
| return 2.0 / self.iters | ||
| return 1.0 / self.iters | ||
|
|
||
| def compute_lr(self, bits): | ||
| """Resolve the rounding lr for a layer bit-width.""" | ||
| if self.lr is not None: | ||
| return self.lr | ||
| return self._lr_for_bits(bits) | ||
|
|
||
| def compute_minmax_lr(self, bits): | ||
| """Resolve the min-max tuning lr for a layer bit-width.""" | ||
| if self.minmax_lr is not None: | ||
| return self.minmax_lr | ||
| return self.compute_lr(bits) | ||
|
|
||
| def check_config(self) -> None: | ||
| super().check_config() | ||
| # RRQ-specific validation | ||
| assert self.bits == 2, "RRQ requires bits=2" | ||
| assert self.data_type == "int", "RRQ only supports int data_type" | ||
| assert self.act_bits == 16, "RRQ is weight-only" | ||
| if self.iters < 0: | ||
| raise ValueError("`iters` must be non-negative") | ||
|
|
||
|
|
||
| register_algorithm( | ||
| "rrq", | ||
| aliases=("rrq", "rrq_rtn"), | ||
| config_factory=RRQConfig, | ||
| summary="Recurrent Residual Quantization: INT2 base + 3 residual planes (2/4/6/8-bit).", | ||
| ) | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.