Skip to content

NeUQI grid search for optimized RTN (--enable_neuqi: joint asym scale/zp search, two-stage sym search, frozen-init anchor) - #2341

Open
avtc wants to merge 1 commit into
intel:mainfrom
avtc:feature/neuqi-search
Open

avtc wants to merge 1 commit into
intel:mainfrom
avtc:feature/neuqi-search

Conversation

@avtc

@avtc avtc commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR adds the NeUQI grid search (arXiv 2505.17595) to the optimized-RTN path, opt-in via --enable_neuqi (CLI, or enable_neuqi=True in the API; carried by both RTNConfig and SignRoundConfig):

  • Asymmetric layers — joint (scale, integer zero-point) search: a two-stage weighted grid search per group (coarse log-spaced scale candidates, then fine refinement; all zero points evaluated per candidate). Asymmetric layers previously had no optimized initializer at all — plain min/max RTN was the only path.
  • Symmetric layers — two-stage signed scale search: replaces the incumbent min/max clip search when enabled; which clamp convention wins per group is searched, not assumed.
  • On the zero-shot path (iters=0) both searches are weighted by the activation imatrix, collected automatically when the flag is set (asymmetric layers previously never consumed one — plain min/max RTN was their only path). With iters > 0 the anchor runs unweighted; tuning itself is data-driven.
  • iters > 0: frozen-init anchor. The search runs once at wrapper init and anchors the SignRound tuning grid — range margins are pinned to the winner, tuning proceeds on the rounding values only. Measured quality-neutral at iters=50 on sym with SignRoundV2 (0.02191 vs 0.02203 without), so the anchor is a no-cost initialization once tuning runs.
  • MoE expert batching: same-shape expert projections (both symmetry classes) quantize in one stacked search call — bit-identical to per-module results.
  • Backends: the search runs on the fastest available backend — a Triton kernel (auto_round_extension), a torch.compile implementation, or plain eager PyTorch — and falls back to the next one if a backend fails at runtime (the failed one is disabled for the rest of the process, with a warning). AR_NEUQI_BACKEND=triton|compile|eager pins a backend, mainly for debugging. Measured on the joint search (2M groups, group size 128, 64+32 candidates, RTX 3090): eager 23.8 s, torch.compile 0.43 s (~55x faster than eager), Triton 0.33 s (~72x).
  • Grid sizes: AR_NEUQI_COARSE / AR_NEUQI_FINE control the grid. Defaults are 256/64 when Triton or torch.compile serves the search and 64/32 with eager — the eager cost is proportional to the grid size and measured quality is flat between the two (Qwen3.8-27B W4A16 g128, iters=0: mean KL 0.02570 at 64/32 vs 0.02579 at 256/64). Explicit values always win.

Validation — full-vocabulary fp32 KL vs the BF16 base, openwebtext 8x8192 positions; Qwen3.8-27B, W4A16, group size 128, single RTX 3090. Protocol and full statistics: docs/neuqi_acc.md. Sorted by mean KL (lower is better):

mean median p90 p99 top1 top5 wall recipe
0.01921 0.00905 0.03591 0.17297 0.9370 0.8727 2:57:21 iters=200, asym, SignRoundV2 + NeUQI (64/32 grid)
0.02106 0.01050 0.04071 0.18038 0.9317 0.8661 0:49:07 iters=50, asym, SignRoundV2 + NeUQI
0.02191 0.01116 0.04237 0.18473 0.9304 0.8627 0:56:52 iters=50, sym, SignRoundV2 + NeUQI
0.02203 0.01112 0.04307 0.18239 0.9295 0.8630 0:55:40 iters=50, sym, SignRoundV2, no NeUQI
0.02579 0.01361 0.05046 0.21753 0.9234 0.8514 0:11:00 iters=0, asym, NeUQI
0.02734 0.01468 0.05358 0.22014 0.9213 0.8463 0:09:00 iters=0, sym, NeUQI
0.02852 0.01533 0.05678 0.23453 0.9191 0.8429 0:13:19 iters=0, sym, incumbent OptRTN search (no NeUQI)

All iters > 0 rows use SignRoundV2 (enable_alg_ext).

Type of Change

New feature

Related Issues

Relates to #2010 — NeUQI support was requested there.

Checklist Before Submitting

  • My code has been tested locally.
  • Documentation has been updated as needed.
  • New or updated tests are included where applicable.
  • The CUDA CI has passed.

@avtc
avtc force-pushed the feature/neuqi-search branch from 29293d3 to 50633b9 Compare September 10, 2026 11:02
@avtc

avtc commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator Author

/azp run Unit-Test-CUDA-AutoRound.

@azure-pipelines

Copy link
Copy Markdown
Commenter does not have sufficient privileges for PR 2341 in repo intel/auto-round

@avtc
avtc force-pushed the feature/neuqi-search branch from 50633b9 to e2a66f9 Compare September 10, 2026 11:55
Opt-in joint/two-stage grid search (arXiv 2505.17595) for the
optimized-RTN path, carried by RTNConfig and SignRoundConfig:

- asym: joint (scale, integer zero-point) two-stage search per group;
  asymmetric layers had no optimized initializer before (plain min/max
  RTN only). sym: two-stage signed scale search replacing the incumbent
  clip search; the winning clamp convention is searched per group.
- zero-shot (iters=0): both searches weighted by the activation imatrix,
  collected automatically. iters>0: the search anchors the SignRound
  tuning grid (range margins pinned, tuning proceeds on rounding values).
- backends: extension Triton kernels (full sweep + shared-multiplier
  coarse pass), torch.compile, eager fallback; a failing backend is
  disabled for the rest of the process with a warning. Benchmark (2M
  groups, g128, 64+32 candidates, RTX 3090): eager 23.8s, compile 0.43s
  (~55x), Triton 0.33s (~72x).
- MoE: same-shape expert projections quantize in one stacked call,
  bit-identical to per-module.
- AR_NEUQI_COARSE/AR_NEUQI_FINE: backend-aware defaults (256/64 on the
  Triton/compile backends, 64/32 with eager); AR_NEUQI_BACKEND pins a
  backend for debugging.

Validation (full-vocab fp32 KL vs the BF16 base, openwebtext 8x8192,
Qwen3.8-27B W4A16 g128, single RTX 3090; details in docs/neuqi_acc.md):
sym iters=0 -4.1% mean KL and -32% wall vs the incumbent search
(0.02734/9m vs 0.02852/13m19s); SignRoundV2 iters=50 sym -16.6% vs the
same recipe without NeUQI (0.02191 vs 0.02626); asym 0.02579 (iters=0),
0.02106 (iters=50), 0.01921 (iters=200).

Tests: CPU unit suite (search math, backend-ladder parity with an fp64
tie-oracle, dispatch/config contract, expert batching, anchor invariants
incl. bf16/fp16 storage robustness); CUDA tier (Triton kernel parity,
tiny-model e2e on the real backend ladder). Docs: environments and
step_by_step (EN+CN), neuqi_acc.md, README What's New (EN+CN).

Signed-off-by: avtc <tarasenkov@gmail.com>
@avtc
avtc force-pushed the feature/neuqi-search branch from e2a66f9 to b9311af Compare September 10, 2026 11:56
@chensuyue

Copy link
Copy Markdown
Contributor

/azp run Unit-Test-CUDA-AutoRound

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 1 pipeline(s).

@wenhuach21

Copy link
Copy Markdown
Contributor

@avtc Really appreciate this PR! May I know the additional quantization cost and accuracy results on a few representative tasks, like mmlu? If the accuracy looks good and cost is low, we could consider setting it as the default.

@avtc

avtc commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator Author

@wenhuach21

Both NeUQI sym/asym are faster than opt-rtn sym at least on CUDA (triton or torch.compile backend), as can be seen in table for iters=0: sym optrtn=13m, sym optrtn+neuqi=9m, asym optrtn+neuqi=11m.
eager mode is 74x times slower than triton and 54x times slower than torch.compile, so on CPU could be slow.

iters=50 passes were running in parallel on the same host, so could be less representative.

mmlu score stderr
iters=0, optrtn, sym 0.8281 ± 0.0030
iters=0, optrtn, neuqi, sym 0.8271 ± 0.0031
iters=0, optrtn, neuqi, asym 0.8294 ± 0.0030

path and is a strict generalization of the symmetric ``search_scales`` grid (which
fixes ``z = 0``).

The symmetric counterpart (:func:`neuqi_search_scale_sym`) fixes the zero point at

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about moving this to the algorithm? It feels more like an algorithm than a data type, although there may be some coupling if different algorithms want to use it.

@n1ck-guo, what do you suggest?

)
registry.add_argument(
"--enable_neuqi",
field="enable_neuqi",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@n1ck-guo Should we consolidate this with disable_opt_rtn into a unified qparams_init_method ?

Comment thread docs/step_by_step.md

For the GGUF format, we have optimized the RTN algorithm inspired by llamacpp. To use the original (pure) RTN algorithm instead, enable the `--disable_opt_rtn` option.

Passing `--enable_neuqi` opts the optimized path into the **NeUQI** grid search ([arXiv 2505.17595](https://arxiv.org/abs/2505.17595)): asymmetric layers run a joint (scale, integer zero-point) search and symmetric layers a two-stage signed scale search, both weighted by the activation imatrix on the zero-shot path, which is collected automatically (with `iters > 0` the anchor runs unweighted). With `iters > 0`, the search result anchors the SignRound tuning grid (frozen init). Grid sizes are tunable via `AR_NEUQI_COARSE`/`AR_NEUQI_FINE` (see [environments](./environments.md)); the unpinned default is backend-aware (wide only on the Triton/torch.compile lanes). Accuracy and wall-time results are shown in [NeUQI accuracy validation](./neuqi_acc.md).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WeiweiZhang1 If the author doesn’t have enough resources to evaluate accuracy on some typical models and tasks, could you help run some evaluations and link the results as we usually do? It would also be helpful to provide users with some guidance on when to trigger this.

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.

3 participants