Add Reasoning-Aware Compression (RAC) pruning example for reasoning LLMs - #1006
Add Reasoning-Aware Compression (RAC) pruning example for reasoning LLMs#1006PKUWZP wants to merge 1 commit into
Conversation
Implements "Reasoning Models Can be Accurately Pruned Via Chain-of-Thought
Reconstruction" (Lucas et al., ICLR 2026, arXiv:2509.12464) under
compression/reasoning_aware_compression.
Layer-wise pruners calibrate on prompt activations, which is the wrong
distribution for reasoning models: decoding dominates their token budget, so
pruned models both lose accuracy and get slower by rambling. RAC calibrates on
the dense model's own on-policy chain-of-thought instead, as a drop-in change
to SparseGPT/Wanda.
Two phases:
collect_traces.py on-policy CoT rollouts -> jsonl, with vLLM, plain HF, or
DeepSpeed ZeRO-Inference (ZeRO-3 with CPU/NVMe parameter
offload) for 32B/70B dense models
prune.py one-shot SparseGPT / Wanda / magnitude pruning against a
c4, prompt-only, or RAC calibration set
Pruning streams the model through the accelerator one transformer block at a
time, so peak device memory is one block plus its Hessians. Supports
unstructured and n:m sparsity, MLP-only scope, and per-third block selection.
Includes bash scripts for the end-to-end run, the c4/prompt/RAC ablation and
lighteval MATH-500 evaluation, plus CPU-only unit tests (pytest tests, 23
tests, no network or GPU).
Signed-off-by: Zhipeng Wang <zhipengbayern@gmail.com>
|
|
||
| if total >= args.trace_tokens: | ||
| break | ||
| return total |
There was a problem hiding this comment.
It might worth to add a guard to assert generated sequence is consistent among all ranks. Just in case people use a different form of zero3 (i.e. zero3 ranks >=2).
| └──────────────────────────────────────┘ | ||
| ``` | ||
|
|
||
| Teacher-forcing a sampled trace reproduces exactly the hidden states the model computed |
There was a problem hiding this comment.
might better use 'almost exactly' because the ids reconstributed from teacher decoded text might not be exactly as the teacher hidden states.
|
Some optional suggestions (non-blocking): use_cache = getattr(model.config, "use_cache", False)
model.config.use_cache = False
# ... pruning ...
model.config.use_cache = use_cache # not reached if pruning throwsIf pruning fails partway, 2. n_completion = int((sequence != tokenizer.pad_token_id).sum())Since 3. README "exactly" wording (L57–59)
Traces are stored as decoded text and re-tokenized in 4. ZeRO-Inference loop termination ( if total >= args.trace_tokens:
break
5. Empty For unsupported architectures (e.g., GPT-2/BLOOM using |
tohtana
left a comment
There was a problem hiding this comment.
Look good to me. I left a comment about the license file of Wanda.
|
|
||
| Adapted from `A Simple and Effective Pruning Approach for Large Language | ||
| Models <https://arxiv.org/abs/2306.11695>`_ (Sun et al., ICLR 2024), | ||
| https://github.com/locuslab/wanda (MIT). |
What
Adds
compression/reasoning_aware_compression/, an example implementing Reasoning-Aware Compression (RAC) from Reasoning Models Can be Accurately Pruned Via Chain-of-Thought Reconstruction (ICLR 2026). Authors' reference code: RyanLucas3/Reasoning-Aware-Compression.Why
Layer-wise pruners (SparseGPT, Wanda, ALPS) minimise
||W X - W' X||_F^2over calibration activations collected from prompts. Reasoning models invert the usual token economics: the prompt is a few hundred tokens and the chain-of-thought answering it is thousands, so pruning optimises the wrong distribution. The failure mode is worse than a plain accuracy drop — the pruned model rambles, so it gets slower as it gets sparser. In the paper, DeepSeek-R1-Distill-Qwen-7B pruned to 50% with C4 calibration takes 135 min on MATH-500 vs 23 min dense, and accuracy falls 0.936 → 0.744.RAC changes only the calibration set: it collects the dense model's on-policy CoT traces and concatenates their activations with the prompt activations, so each layer is reconstructed against the activations it will actually see while decoding. Same 7B model at 50%: 0.900 accuracy in 35 min. No retraining, no distillation, drop-in for any layer-wise pruner.
What's in the PR
collect_traces.py: rollouts from the dense model with vLLM, plain HFgenerate, or DeepSpeed ZeRO-Inference (--backend deepspeed: ZeRO-3 parameter sharding with CPU/NVMe offload, followinginference/huggingface/zero_inference) so 32B/70B dense models can produce traces on a couple of GPUs.prune.py: SparseGPT / Wanda / magnitude against--calibration {c4,prompt,rac}. The model is streamed through the accelerator one transformer block at a time — peak device memory is one block plus its Hessians, which is what lets 70B prune on a single 80GB GPU as in the paper. Supports unstructured and n:m (2:4) sparsity,--scope mlp, and--layer-thirds 1,3for the paper's partial-depth throughput setting.bash_script/run_calibration_ablation.shreproduces the paper's core comparison: same model, same pruner, same 1M-token budget, three calibration sets.Testing
pytest tests— 23 CPU-only tests, no network or GPU, a few seconds. Cover calibration-window packing, RAC-vs-prompt-only token content, target sparsity for all three pruners, 2:4 patterns, block/scope selection, batched-equals-unbatched calibration, dead input channels, and that the calibration set actually changes the mask.collect_traces.py --backend hf→prune.py --calibration rac→ reload the saved checkpoint and verify the sparsity pattern.Notes for reviewers
rac/sparsegpt.pyadapts IST-DASLab/sparsegpt (Apache-2.0),rac/wanda.pyadapts locuslab/wanda (MIT); both are attributed in-file and in the README.