chopratejas commited on
Commit
e00cc5e
·
verified ·
1 Parent(s): b156363

model card: metrics re-measured on the leak-free v2.1 test split

Browse files
Files changed (1) hide show
  1. README.md +109 -70
README.md CHANGED
@@ -16,123 +16,162 @@ pipeline_tag: token-classification
16
 
17
  Extractive prompt compressor for LLM proxies. Predicts a keep/drop label per
18
  token; the surviving tokens form a compressed version of the input that
19
- preserves meaning while reducing token count.
 
20
 
21
- Based on **ModernBERT-base** (149M params) with a LoRA adapter (3.4M trainable
22
- params, 2.2%) plus a custom dual head (token classifier + 1-D span conv).
23
- Trained on 126,617 accepted Pipeline A+B labels (compressor + faithfulness
24
- judge) across 17 domains: narrative, dialog, code, agent traces, healthcare,
25
- finance, government, scientific, web, summary, and tool-calling.
 
26
 
27
- ## Quick start
28
 
29
- ```python
30
- import torch
31
- from transformers import AutoTokenizer
32
 
33
- # Option A: load the merged checkpoint (no LoRA needed)
34
- state = torch.load("merged.pt", map_location="cpu")
35
 
36
- # Option B: load via the kompress package
37
- from kompress.model.architecture import HeadroomCompressorV2
38
- from kompress.model.config import V2_BASE
39
- import json
 
 
 
40
 
41
- with open("config.json") as f:
42
- cfg_dict = json.load(f)
43
- cfg = V2_BASE # or rebuild from cfg_dict
44
- model = HeadroomCompressorV2(cfg)
45
- model.load_state_dict(torch.load("merged.pt", map_location="cpu"), strict=False)
46
- model.eval().cuda()
47
 
48
- tokenizer = AutoTokenizer.from_pretrained("chopratejas/kompress-v2-base")
49
 
50
- # Compress
51
- text = "The quick brown fox jumps over the lazy dog."
52
- enc = tokenizer(text, return_tensors="pt").to("cuda")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  with torch.no_grad():
54
- out = model(**enc)
55
- scores = out["final_scores"][0] # P(keep) per subword
56
- keep = (scores >= 0.5)
57
- kept_tokens = enc["input_ids"][0][keep]
58
- print(tokenizer.decode(kept_tokens, skip_special_tokens=True))
 
59
  ```
60
 
 
 
 
 
 
61
  ## Threshold tuning
62
 
63
- The model emits `final_scores ∈ [0, 1]` per subword. Adjust the threshold to
64
- trade compression aggressiveness for must-keep recall.
 
 
 
 
 
 
 
 
 
 
65
 
66
- | Threshold | keep_rate | must_keep_recall | F1 | best for |
67
- |---|---|---|---|---|
68
- | **0.30** | 0.917 (8% drop) | 0.994 | 0.904 | Conservative |
69
- | **0.40** | 0.867 (13% drop) | 0.987 | 0.913 | Safe |
70
- | **0.50** (default) | 0.815 (18% drop) | 0.974 | **0.918** | Balanced |
71
- | **0.60** | 0.765 (23% drop) | 0.950 | 0.915 | Aggressive |
72
- | **0.70** | 0.705 (30% drop) | 0.908 | 0.898 | Very aggressive |
73
 
74
- Evaluated on the held-out test split (n=7,037 examples, stratified by domain).
75
 
76
  ## Training data
77
 
78
  - **126,617 labeled examples** after `min_drop_ratio=0.05` filtering and
79
- same-conversation packing.
80
- - **Sources**: arxiv, pubmed-scientific, govreport, swe-smith, swe-gym-openhands,
81
- toolmind, xlam-fc, fineweb-edu, cnn-dailymail, xsum, glaive-fc, lmsys-chat,
82
- claude-code-sessions, meetingbank, the-stack-smol-md, samsum, swe-bench-verified.
83
  - **Labeler**: DeepSeek-V4-Flash (compressor) + DeepSeek-V4-Pro (judge) with
84
  Pipeline A + B faithfulness loop. Hard-keep overlay enforces names, dates,
85
  numbers, URLs, code identifiers via GLiNER + regex + lexicons.
86
- - **Bucket split**: short=48%, mid=31%, long=21% (max_length 8,192 native
87
- ModernBERT context).
88
  - **Split**: train=126,617 / val=7,037 / test=7,037.
 
 
89
 
90
  ## Training details
91
 
92
- - Base: ModernBERT-base (149M params)
93
  - Encoder fine-tuning: **LoRA** (r=16, alpha=32, target_modules=Wqkv/Wi/Wo)
94
  - Heads: per-token CE (must-keep loss weight = 3.0) + 1-D span conv (BCE,
95
  weight 0.3 on total loss)
96
- - Trainable params: 3.4M (2.2% of total)
97
- - Loss: weighted cross-entropy on token head + BCE-with-logits on span head
98
  - Optim: AdamW (lr=2e-4 cosine, warmup_ratio=0.06, weight_decay=0.01)
99
- - Effective batch: 48 (12 × 4 grad-accum)
100
- - Epochs: 3
101
- - Precision: bf16 with FlashAttention-2 + gradient checkpointing
102
  - Hardware: 1×H100 80GB, ~39 min wall-clock
103
 
104
- ## Final metrics (test split, threshold=0.5)
105
 
106
- - eval_f1: 0.918
107
- - eval_must_keep_recall: 0.974
108
- - eval_keep_rate: 0.815 (18% compression)
109
- - eval_loss: 0.34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
 
111
  ## Files in this repo
112
 
113
  ```
114
- config.json # KompressV2Config + arch metadata
115
- model.safetensors # ~600 MB — best checkpoint, LoRA merged into the encoder
116
- merged.pt # ~600 MB full state dict, alias for safetensors load
117
- tokenizer.json # ModernBERT-base tokenizer
118
- tokenizer_config.json
119
- special_tokens_map.json
120
- adapter/ # LoRA adapter ONLY (~30 MB), for stacking per-org adapters
121
- adapter_config.json
122
- adapter_model.safetensors
123
  token_head.pt
124
  span_conv.pt
125
- README.md # this file
 
 
 
126
  ```
127
 
128
  ## License
129
 
130
- Apache 2.0. Free for commercial use. ModernBERT base is also Apache 2.0.
 
131
 
132
  ## See also
133
 
 
 
134
  - [`chopratejas/kompress-v2-large`](https://huggingface.co/chopratejas/kompress-v2-large)
135
- larger variant (ModernBERT-large, 395M params, private/enterprise)
136
  - Headroom proxy integration guide:
137
  [docs/CUSTOMER_QUICKSTART.md](https://github.com/chopratejas/kompress/blob/main/docs/CUSTOMER_QUICKSTART.md)
138
  - Per-org fine-tuning (LoRA stacking):
 
16
 
17
  Extractive prompt compressor for LLM proxies. Predicts a keep/drop label per
18
  token; the surviving tokens form a compressed version of the input that
19
+ preserves meaning while reducing token count. It has no decoder: the output is
20
+ always a subsequence of the input, in the original order.
21
 
22
+ Based on **ModernBERT-base** (150M params) with a LoRA adapter
23
+ (4.4M trainable params, 2.9%) plus a custom dual head
24
+ (token classifier + 1-D span conv). Trained on 126,617 accepted Pipeline A+B
25
+ labels (compressor + faithfulness judge) across 17 sources: narrative, dialog,
26
+ code, agent traces, healthcare, finance, government, scientific, web, summary,
27
+ and tool-calling.
28
 
29
+ **Distribution.** Public. Apache 2.0, free for commercial use.
30
 
31
+ ## Use with Headroom (recommended)
 
 
32
 
33
+ Headroom's proxy loads `onnx/kompress-int8-wo.onnx` from this repo and runs it
34
+ on CPU with ONNX Runtime; no torch needed. Point it at this repo:
35
 
36
+ ```python
37
+ from headroom.transforms.kompress_compressor import KompressCompressor, KompressConfig
38
+
39
+ compressor = KompressCompressor(KompressConfig(model_id="chopratejas/kompress-v2-base"))
40
+ result = compressor.compress(long_tool_output)
41
+ print(result.compressed, result.compression_ratio)
42
+ ```
43
 
44
+ Or serve it as an endpoint from this repository's `modal_jobs/modal_serve.py`
45
+ with `KOMPRESS_MODEL_ID=chopratejas/kompress-v2-base` set at deploy time.
 
 
 
 
46
 
47
+ ## Use directly (PyTorch)
48
 
49
+ ```python
50
+ import torch
51
+ from transformers import AutoModel, AutoTokenizer
52
+ from huggingface_hub import hf_hub_download
53
+
54
+ ckpt = torch.load(hf_hub_download("chopratejas/kompress-v2-base", "merged.pt"), map_location="cpu", weights_only=False)
55
+ encoder = AutoModel.from_pretrained("answerdotai/ModernBERT-base", attn_implementation="eager")
56
+ encoder.load_state_dict({k: v.float() for k, v in ckpt["encoder_state_dict"].items()})
57
+ H = encoder.config.hidden_size
58
+ token_head = torch.nn.Linear(H, 2)
59
+ span_conv = torch.nn.Sequential(torch.nn.Conv1d(H, 256, 5, padding=2), torch.nn.GELU(),
60
+ torch.nn.Conv1d(256, 1, 3, padding=1))
61
+ token_head.load_state_dict(ckpt["token_head_state_dict"])
62
+ span_conv.load_state_dict(ckpt["span_conv_state_dict"])
63
+
64
+ tok = AutoTokenizer.from_pretrained("chopratejas/kompress-v2-base")
65
+ enc = tok("The quick brown fox jumps over the lazy dog.", return_tensors="pt")
66
  with torch.no_grad():
67
+ h = encoder(**enc).last_hidden_state
68
+ p_keep = torch.softmax(token_head(h), -1)[..., 1]
69
+ span = torch.sigmoid(span_conv(h.transpose(1, 2)).squeeze(1))
70
+ scores = p_keep * (0.5 + 0.5 * span) # final_scores in [0, 1]
71
+ kept = enc["input_ids"][0][scores[0] >= 0.5]
72
+ print(tok.decode(kept, skip_special_tokens=True))
73
  ```
74
 
75
+ `model.safetensors` is the HF Trainer checkpoint of `HeadroomCompressorV2`
76
+ (PEFT-wrapped encoder + LoRA + heads) and loads through the `kompress` package;
77
+ `merged.pt` is the same model with LoRA folded into the encoder and is what the
78
+ ONNX exports were traced from.
79
+
80
  ## Threshold tuning
81
 
82
+ The model emits `final_scores ∈ [0, 1]` per subword. Raise the threshold
83
+ to compress harder; lower it to protect must-keep recall.
84
+
85
+ | Threshold | keep_rate | must_keep_recall | F1 | precision | recall |
86
+ |---|---|---|---|---|---|
87
+ | **0.30** | 0.946 (5% drop) | 0.997 | 0.942 | 0.920 | 0.964 |
88
+ | **0.40** | 0.910 (9% drop) | 0.994 | 0.933 | 0.929 | 0.937 |
89
+ | **0.50** (default) | 0.866 (13% drop) | 0.989 | 0.920 | 0.940 | 0.901 |
90
+ | **0.60** | 0.818 (18% drop) | 0.980 | 0.902 | 0.949 | 0.860 |
91
+ | **0.70** | 0.752 (25% drop) | 0.953 | 0.870 | 0.958 | 0.798 |
92
+
93
+ Measured on the held-out test split (n=12,697 rows, 16,827,490 scored subwords), checkpoint `best`, PyTorch bf16 on H100.
94
 
95
+ **Test split.** `dataset_v2_v2.1-f00` test: split by source document, exact and near duplicates of training rows removed. An earlier version of this card reported metrics on the v2.0 split, where 12.2% of test rows were byte-identical to training rows; those numbers were optimistic by roughly 0.02 F1 and have been replaced.
96
+ **At the default threshold (0.5):** F1 0.920, must-keep recall 0.989, keep rate 0.866 (13% of subwords removed).
 
 
 
 
 
97
 
98
+ On the subset the labeller actually compressed (it dropped at least 5% of the words, 6,559,681 subwords), at 0.5: F1 0.893, must-keep recall 0.986, keep rate 0.853. The rest of the split is text where almost every word should be kept, which inflates F1 for any model.
99
 
100
  ## Training data
101
 
102
  - **126,617 labeled examples** after `min_drop_ratio=0.05` filtering and
103
+ same-conversation packing (from 367,525 accepted labels).
104
+ - **Sources**: arxiv, pubmed-scientific, govreport, swe-smith, swe-gym-openhands, toolmind, xlam-fc, fineweb-edu, cnn-dailymail, xsum, glaive-fc, lmsys-chat, claude-code-sessions, meetingbank, the-stack-smol-md, samsum, swe-bench-verified.
 
 
105
  - **Labeler**: DeepSeek-V4-Flash (compressor) + DeepSeek-V4-Pro (judge) with
106
  Pipeline A + B faithfulness loop. Hard-keep overlay enforces names, dates,
107
  numbers, URLs, code identifiers via GLiNER + regex + lexicons.
108
+ - **Bucket split**: short=48%, mid=31%, long=21% (max_length 8,192 native ModernBERT context).
 
109
  - **Split**: train=126,617 / val=7,037 / test=7,037.
110
+ - Data card, per-source licences and the two non-commercial sources (4.78% of
111
+ the corpus): `DATA.md` and `LICENSES.md` in the training repository.
112
 
113
  ## Training details
114
 
115
+ - Base: ModernBERT-base (150M params)
116
  - Encoder fine-tuning: **LoRA** (r=16, alpha=32, target_modules=Wqkv/Wi/Wo)
117
  - Heads: per-token CE (must-keep loss weight = 3.0) + 1-D span conv (BCE,
118
  weight 0.3 on total loss)
119
+ - Trainable params: 4.4M (2.9% of total)
 
120
  - Optim: AdamW (lr=2e-4 cosine, warmup_ratio=0.06, weight_decay=0.01)
121
+ - Effective batch: 48; epochs: 3; bf16 with FlashAttention-2 + gradient checkpointing
 
 
122
  - Hardware: 1×H100 80GB, ~39 min wall-clock
123
 
124
+ ## Validation curve (n=7,037, threshold=0.5)
125
 
126
+ | step | epoch | eval_loss | F1 | must_keep_recall | keep_rate | precision |
127
+ |---|---|---|---|---|---|---|
128
+ | 2000 | 0.76 | 0.347 | 0.905 | 0.9849 | 0.867 | 0.868 |
129
+ | 4000 ← selected (best must_keep_recall) | 1.52 | 0.342 | 0.905 | 0.9909 | 0.900 | 0.852 |
130
+ | 6000 | 2.27 | 0.338 | 0.907 | 0.9865 | 0.881 | 0.863 |
131
+
132
+ The shipped weights are the checkpoint with the best validation must-keep recall (`metric_for_best_model`), evaluated every 2,000 steps.
133
+
134
+
135
+ ## ONNX (what Headroom loads)
136
+
137
+ | artifact | size | notes |
138
+ |---|---|---|
139
+ | `onnx/kompress-int8-wo.onnx` | 274 MB | weight-only int8 (MatMulNBits), the default artifact; needs `onnxruntime>=1.24` |
140
+ | `onnx/kompress-fp32.onnx` | 601 MB | lossless reference |
141
+
142
+ Weight-only int8 agrees with fp32 on 99.6% of keep decisions. Headroom tries
143
+ `int8-wo` first and falls back to `fp32` on runtimes without the 8-bit kernel.
144
 
145
  ## Files in this repo
146
 
147
  ```
148
+ config.json # KompressV2Config + arch metadata
149
+ model.safetensors # HF Trainer checkpoint (PEFT-wrapped encoder + LoRA + heads)
150
+ merged.pt # LoRA merged into the encoder; source of the ONNX exports
151
+ onnx/kompress-int8-wo.onnx # weight-only int8, Headroom's default artifact
152
+ onnx/kompress-fp32.onnx # lossless reference
153
+ adapter/ # LoRA adapter + heads only, for stacking per-org adapters
154
+ adapter/adapter_config.json
155
+ adapter/adapter_model.safetensors
 
156
  token_head.pt
157
  span_conv.pt
158
+ tokenizer.json # answerdotai/ModernBERT-base tokenizer
159
+ tokenizer_config.json
160
+ special_tokens_map.json
161
+ README.md # this file
162
  ```
163
 
164
  ## License
165
 
166
+ Apache 2.0 for the model artifact. ModernBERT-base is also Apache 2.0. Training-data
167
+ licences are per source; see `LICENSES.md` in the training repository.
168
 
169
  ## See also
170
 
171
+ - [`chopratejas/kompress-v2-base`](https://huggingface.co/chopratejas/kompress-v2-base)
172
+ — ModernBERT-base variant (149M params, public)
173
  - [`chopratejas/kompress-v2-large`](https://huggingface.co/chopratejas/kompress-v2-large)
174
+ — ModernBERT-large variant (395M params, private/enterprise)
175
  - Headroom proxy integration guide:
176
  [docs/CUSTOMER_QUICKSTART.md](https://github.com/chopratejas/kompress/blob/main/docs/CUSTOMER_QUICKSTART.md)
177
  - Per-org fine-tuning (LoRA stacking):