Downloads · 30 days
0
Gavin-chen/Qwen-Compress
Qwen-Compress is a machine learning model from Gavin-chen. Use it for the machine learning task on the model card, and read the license before you ship it in a product. It is set up for transformers. The card lists the license as mit.
Downloads · 30 days
0
Access
Public
Updated Jul 11, 2026
Repo size
205 KB
Likes
0
Public
Click a slice to open those files.
.pt205 KB · 84%
From the Hugging Face model README
(有提供繁體中文版readme)
A drop-in KV cache compression method that selectively compresses hidden states via learned weighted pooling between every 4th transformer layer, reducing prefill KV size by up to ~1.75× without retraining the base model.
Standard autoregressive transformers pay a KV cache cost proportional to total prefill length. Qwen-Compress mitigates this by inserting small HiddenStateCompressor modules at selected layers. Each compressor performs learned weighted pooling: it computes an importance score per token via a learned linear projection, then applies softmax over a sliding window of ratio=4 consecutive hidden states and takes the weighted sum, producing 1 compressed token from 4. This shrinks the KV cache while preserving the final window_size=128 tokens unchanged (tail retention).
The key insight: compress hidden states before they enter the attention QKV projection at the compressor layer. Downstream layers attend to compressed KV positions via correct rotary position embedding (RoPE) indices, avoiding position mismatch.
This work is inspired by DeepSeek's compressed attention mechanism (used in DeepSeek-V4), where inter-layer compression reduces KV cache footprint. Qwen-Compress adapts this concept to the Qwen architecture with a per-sequence compression schedule and decode-phase buffer management.
A single HiddenStateCompressor is a lightweight learned weight layer:
Input: (B, 4, D) — 4 consecutive hidden states
│
┌─────┴─────┐
│ wgate │ Linear(D, 1) → per-token importance score
│ + ape │ Learned position bias (4, 1)
└─────┬─────┘
│ softmax over 4 tokens → normalized weights
│
Weighted sum → (B, 1, D) — 1 compressed token
Parameters: ~D (one Linear layer + 4 learned scalars) — negligible vs. base model. No latent bottleneck or QKV attention involved.
Compressors are inserted at layers where layer_idx % 4 == 3 (every 4th layer). At non-compressor layers, attention runs unchanged.
For each sequence at a compressor layer:
true_len = sequence length (after left-padding)
window = min(window_size=128, true_len) ← kept verbatim
compressible = true_len - window
to_compress = compressible - (compressible % ratio=4)
compressed = to_compress / 4
residual = compressible % ratio ← kept verbatim (0–3 tokens)
tail = window ← last 128 tokens verbatim
KV positions are tracked per-token for correct RoPE indexing. Zero-padded batch entries are masked via kv_valid throughout generation.
During autoregressive decode, new tokens accumulate in an uncompressed buffer (buf_k, buf_v, buf_h). Once the buffer reaches window_size + ratio = 132 tokens, the oldest ratio=4 tokens are compressed into 1 and merged into the persistent KV cache, keeping the buffer at window_size tokens. This bounds the decode-phase KV overhead at window tokens per compressor layer.
Tested on Qwen3.6-27B (NF4, 64 layers). Compression applied at every 4th layer (i % 4 == 3), totaling 16 compressors.
| Filter | Baseline | Compressed | Δ |
|---|---|---|---|
| flexible-extract | 0.8749 | 0.7331 | −16.2% |
| strict-match | 0.8658 | 0.5785 | −33.2% |
| Filter | Baseline | Compressed | Δ |
|---|---|---|---|
| inst_level_loose_acc | 0.8849 | 0.8897 | +0.5% |
| inst_level_strict_acc | 0.8525 | 0.8513 | −0.1% |
| prompt_level_loose_acc | 0.8299 | 0.8355 | +0.7% |
| prompt_level_strict_acc | 0.7856 | 0.7856 | ±0.0% |
#### N).The reference implementation is a FastAPI server (server.py) that patches a Qwen model with compressors and serves an OpenAI-compatible API.
# Install dependencies
pip install torch transformers accelerate bitsandbytes
# Start the server (loads model, patches compressors, serves on :8001)
python server.py
# Send requests via curl or any OpenAI client
curl http://localhost:8001/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "qwen-compress", "messages": [{"role": "user", "content": "1+1="}]}'
The patching happens in build_franken_qwen() (server.py:344): every 4th layer's attention forward is replaced with get_custom_qwen_forward(compressor, window_size=128, ratio=4), and the compressor weights are loaded from a checkpoint.