nmitchko commited on
Commit
3129e95
Β·
verified Β·
1 Parent(s): 55889a2

Refresh README; document sft-c16 (latent-only reasoning, c=16, learned stop)

Browse files
Files changed (1) hide show
  1. README.md +137 -113
README.md CHANGED
@@ -14,51 +14,71 @@ tags:
14
  - chain-of-thought
15
  ---
16
 
17
- # DeepSeek-V4-Flash CoLaR β€” Reasoning Compression Head
18
 
19
- A **CoLaR-style reasoning compression head** that attaches to the frozen
20
- [`nvidia/DeepSeek-V4-Flash-NVFP4`](https://huggingface.co/nvidia/DeepSeek-V4-Flash-NVFP4)
21
- backbone. It learns a compact latent representation of the model's chain-of-thought
22
- and injects it back into the backbone so the model **reasons from a compressed
23
- latent** rather than emitting a long token-by-token trace.
24
 
25
- > **This is an adapter, not a standalone model.** These weights (~136 MB per
26
- > checkpoint) are useless without the DeepSeek-V4-Flash backbone. You must load
27
- > the backbone separately.
28
 
29
- **Headline result (preliminary):** on GSM8K the head cuts **median "thinking"
30
- tokens by ~40%** and shrinks the **longest trace by ~4Γ—** while serving at
31
- **~65 tok/s** on the compile-safe fast path β€” with no separate reasoning model.
32
- Task-accuracy numbers are small-n (n=30) and reported below with caveats.
33
 
34
- The method follows **CoLaR** (Compressed Latent Reasoning, [arXiv:2505.16552](https://arxiv.org/abs/2505.16552)).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  ---
37
 
38
- ## What's in this repo
 
 
 
 
 
 
 
 
 
 
 
39
 
40
- | Path | Description |
41
- |---|---|
42
- | `sft/colar_head_sft.safetensors` | Head after **SFT** (soft-MSE latent regression). |
43
- | `grpo/colar_head_grpo.safetensors` | Head after **SFT β†’ GRPO** (latent-policy RL). **Recommended for serving.** |
44
- | `sft/colar_head_sft.pt`, `grpo/colar_head_grpo.pt` | The original v2 bundle `.pt` files (same weights; pickle format). |
45
- | `*/config.json` | Per-checkpoint geometry + which sub-modules are present. |
46
- | `config.json` | Top-level architecture description. |
47
- | `PAPER.md` | Short technical report (method, serving, results). |
48
- | `results/` | Raw eval JSON + HTML bar charts backing the results table. |
49
 
50
- **Which to use:** `grpo` is the checkpoint used for the results below and for
51
- serving. `sft` is the pre-RL stage, useful for comparison/ablation.
 
 
52
 
53
- > **Code is not released yet.** The training scripts and the vLLM serving addon
54
- > will be published separately later. This repo ships weights + docs only; the
55
- > loader snippet below is fully self-contained and needs no first-party code.
56
 
57
  ---
58
 
59
- ## Architecture
60
 
61
- Three components, all bundled in each checkpoint:
62
 
63
  ```
64
  layer 35 hidden (4096-d)
@@ -68,6 +88,9 @@ Three components, all bundled in each checkpoint:
68
  β”‚ Linear 4096β†’2048 Β· SiLU β”‚
69
  β”‚ Linear 2048β†’2048 Β· SiLU β”‚
70
  β”‚ Linear 2048β†’2048 β†’ [mu, log_sigma] (1024-d) β”‚
 
 
 
71
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
72
  β”‚ mu (1024-d latent)
73
  β–Ό LayerNorm
@@ -77,67 +100,53 @@ Three components, all bundled in each checkpoint:
77
  β”‚ Linear 2048β†’4096 β†’ hidden vector (4096-d) β”‚
78
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
79
  β”‚
80
- β–Ό injected at the final <think> prompt position
81
  DeepSeek-V4-Flash backbone (frozen)
82
  ```
83
 
84
- - **`target_proj`** β€” a frozen `Linear(4096, 1024, bias=False)` that defines the
85
- SFT regression target (a stable readout of the layer-42 hidden state). Included
86
- for reproducibility; not needed at inference.
87
- - **Source layer 35 β†’ target layer 42**, **`compression_factor = 4`** (4
88
- consecutive reasoning tokens fold into one latent step), **`latent_dim = 1024`**,
89
- **`hidden_size = 4096`**.
90
-
91
- | Config | Value |
92
- |---|---|
93
- | base model | `nvidia/DeepSeek-V4-Flash-NVFP4` |
94
- | hidden_size | 4096 |
95
- | latent_dim | 1024 |
96
- | mlp_dim | 2048 |
97
- | source_layer / target_layer | 35 / 42 |
98
- | compression_factor | 4 |
99
- | activation | SiLU |
100
- | checkpoint format | v2 bundle (`reasoning_head` + `decoder` + `target_proj` + `config`) |
101
 
102
  ---
103
 
104
- ## Checkpoint layout
105
 
106
- The `.safetensors` files hold a single flat tensor dict; the original three
107
- sub-modules are distinguished by key prefix:
108
 
109
  ```
110
- reasoning_head.net.0.weight [2048, 4096] reasoning_head.net.0.bias [2048]
111
- reasoning_head.net.2.weight [2048, 2048] reasoning_head.net.2.bias [2048]
112
- reasoning_head.net.4.weight [2048, 2048] reasoning_head.net.4.bias [2048]
113
- decoder.net.0.weight [2048, 1024] decoder.net.0.bias [2048]
114
- decoder.net.2.weight [2048, 2048] decoder.net.2.bias [2048]
115
- decoder.net.4.weight [4096, 2048] decoder.net.4.bias [4096]
116
- target_proj.weight [1024, 4096]
 
 
117
  ```
118
 
119
- The geometry is also stored in the safetensors metadata (`config`,
120
- `format_version`, `subdicts`) and in the sibling `config.json`.
121
 
122
  ---
123
- **FAQ**:
124
 
125
-
126
- | Question | Answer |
127
- |---|---|
128
- | What does this repo provide? | A **CoLaR-style reasoning compression head** that attaches to the frozen [`nvidia/DeepSeek-V4-Flash-NVFP4`](https://huggingface.co/nvidia/DeepSeek-V4-Flash-NVFP4) backbone. It learns a compact latent representation of the model's chain-of-thought and injects it back into the backbone so the model **reasons from a compressed latent** rather than emitting a long token-by-token trace. |
129
- | Which checkpoint is recommended for production use? | Use the `grpo` checkpoint (e.g., `grpo/colar_head_grpo.safetensors`). The `sft` checkpoint is the pre-RL stage, useful for comparison/ablation. |
130
- | What license applies? | Other β€” see [`LICENSE`](./LICENSE) file. |
131
- | Which backbone model does CoLaR require? | The frozen DeepSeek-V4-Flash-NVFP4 backbone (~136 MB per checkpoint); these weights are useless without the backbone, which must be loaded separately. |
132
- | How do I load the head weights without importing the repository? | Load using `safe_open` and `load_file` (see the self-contained loader snippet in README); the code requires only PyTorch, safetensors, and torch.nn.functional β€” no first-party imports. |
133
- | Is this compatible with vLLM or other inference engines? | Not yet β€” vLLM support is planned in a fork; full details are in [`PAPER.md`](./PAPER.md). |
134
- | What improvements does CoLaR bring compared to the base model? | Median "thinking" tokens drop by **~40%** and the longest trace shrinks **~4Γ—**, with service speed **~65 tok/s** on the compile-safe fast path; preliminary lm_eval shows **10–20% better results** (GSM8K n=30). |
135
- | What are the known limitations or caveats of using CoLaR? | Evaluation is **small-n (30 docs, GSM8K only)**; no full-benchmark or multi-task evaluation yet; closed-loop latent decoding (generating a step with no token id) is future work; current injection is at the prompt/`` position only. |
136
-
137
-
138
- ---
139
-
140
- ## Load the head (self-contained, no repo import)
141
 
142
  ```python
143
  import json
@@ -147,10 +156,10 @@ from torch import nn
147
  from safetensors.torch import load_file
148
  from safetensors import safe_open
149
 
150
- CKPT = "grpo/colar_head_grpo.safetensors" # or sft/colar_head_sft.safetensors
151
 
152
  class ReasoningCompressionHead(nn.Module):
153
- def __init__(self, hidden_size, latent_dim, mlp_dim=None):
154
  super().__init__()
155
  mlp_dim = mlp_dim or hidden_size // 2
156
  self.net = nn.Sequential(
@@ -158,10 +167,19 @@ class ReasoningCompressionHead(nn.Module):
158
  nn.Linear(mlp_dim, mlp_dim), nn.SiLU(),
159
  nn.Linear(mlp_dim, 2 * latent_dim),
160
  )
 
 
 
 
 
 
161
  def forward(self, h):
162
  mu, log_sigma = self.net(h).chunk(2, dim=-1)
163
  return mu, log_sigma.clamp(-10.0, 2.0)
164
 
 
 
 
165
  class LatentDecoder(nn.Module):
166
  def __init__(self, hidden_size, latent_dim, mlp_dim=None):
167
  super().__init__()
@@ -183,73 +201,79 @@ flat = load_file(CKPT)
183
  def sub(prefix):
184
  return {k[len(prefix):]: v for k, v in flat.items() if k.startswith(prefix)}
185
 
186
- head = ReasoningCompressionHead(hs, ld); head.load_state_dict(sub("reasoning_head.")); head.eval()
187
- decoder = LatentDecoder(hs, ld); decoder.load_state_dict(sub("decoder.")); decoder.eval()
 
 
188
  target_proj = nn.Linear(hs, ld, bias=False); target_proj.load_state_dict(sub("target_proj."))
189
 
190
- # usage: h35 is the layer-35 hidden state at the final <think> position, shape (B, 4096)
191
- # mu, _ = head(F.layer_norm(h35, (hs,)))
192
- # inject = decoder(F.layer_norm(mu, (ld,))) # (B, 4096) -> overwrite the embedding at that position
 
193
  ```
194
 
195
  ---
196
 
197
- ## How it's served
198
 
199
- DeepSeek-V4 uses **hash-based MoE expert routing keyed on `input_ids`**, so
200
- vLLM's native `prompt_embeds` injection path crashes the engine
201
- (`hash MoE routing requires input_ids`). Injection therefore uses an
202
- **`embed_tokens` forward hook** that overwrites the embedding at chosen positions
203
- with the decoded latent while token ids keep flowing for routing. Combined with a
204
- compile-safe capture buffer, this runs on the **cudagraph fast path (~65 tok/s)**
205
- instead of `enforce_eager`. Full details in [`PAPER.md`](./PAPER.md). The serving
206
- addon itself is not released yet.
207
 
208
  ---
209
 
210
- ## Results (preliminary)
211
 
212
  GSM8K, 8-shot, temperature 0, DeepSeek-V4-Flash-NVFP4 backbone, GRPO head.
213
- **n = 30 documents** β€” accuracy is small-n and noisy; the **robust signal is the
214
- reduction in reasoning length**, not the exact-match score.
215
 
216
  | Metric | Base (no injection) | +Head (2k budget) | +Head (14.5k budget) |
217
  |---|---|---|---|
218
- | exact-match | 40.0 / 33.3 | 40.0 | 46.7 |
219
  | closed `</think>` % | 97–100 | 30 | 40 |
220
  | median think tokens | 146–187 | 106 | **103** |
221
  | max think tokens | 1740–2048 | 472 | **415** |
222
 
223
  - **~40% fewer median thinking tokens** and a **~4Γ— shorter worst-case trace.**
224
- - The head **never skips** reasoning (skip% = 0) β€” it compresses it.
225
- - The low closed-`</think>`% is a **formatting artifact**: the GRPO reward
226
- (token-F1) never rewarded emitting the closing tag. A larger 78Γ— budget did not
227
- make traces close, confirming it is not truncation. Adding a closure bonus to
228
- the reward is the obvious next step.
229
- - For context only, the published DeepSeek-V4-Flash-Base scores **90.8** on GSM8K
230
- under its own full harness; that is **not** a baseline we reproduce here (our
231
- base column is the same backbone under our small-n thinking-mode harness).
232
 
233
  Raw numbers and bar charts are in [`results/`](./results).
234
 
235
  ---
236
 
237
- ## Limitations
238
 
239
  - Evaluation is **small-n (30 docs, GSM8K only)**; treat accuracy as directional.
240
  - No full-benchmark or multi-task evaluation yet.
241
- - Closed-loop latent decoding (generating a step with no token id) is future work;
242
- current injection is at the prompt/`<think>` position only.
243
  - Measured on 2Γ— RTX PRO 6000 (96 GiB); usable context β‰ˆ 15.8k tokens on that box.
 
 
 
 
 
244
 
245
- ## Citation
246
 
247
- Method after CoLaR β€” Compressed Latent Reasoning:
248
 
249
  ```bibtex
250
  @article{colar2025,
251
- title = {CoLaR: Compressed Latent Reasoning},
252
  journal = {arXiv preprint arXiv:2505.16552},
253
- year = {2025}
254
  }
255
  ```
 
14
  - chain-of-thought
15
  ---
16
 
17
+ <div align="center">
18
 
19
+ # 🧠 DeepSeek-V4-Flash · CoLaR Reasoning Compression Head
 
 
 
 
20
 
21
+ **Reason in a compact latent space β€” not a long token-by-token trace.**
 
 
22
 
23
+ *A lightweight adapter for the frozen [`nvidia/DeepSeek-V4-Flash-NVFP4`](https://huggingface.co/nvidia/DeepSeek-V4-Flash-NVFP4) backbone.*
 
 
 
24
 
25
+ [![Method: CoLaR](https://img.shields.io/badge/method-CoLaR-6c5ce7)](https://arxiv.org/abs/2505.16552)
26
+ [![Base: DeepSeek--V4--Flash](https://img.shields.io/badge/base-DeepSeek--V4--Flash--NVFP4-0984e3)](https://huggingface.co/nvidia/DeepSeek-V4-Flash-NVFP4)
27
+ [![Type: adapter](https://img.shields.io/badge/type-adapter-00b894)](#-this-is-an-adapter)
28
+ [![Format: safetensors](https://img.shields.io/badge/format-safetensors-fdcb6e)](#-checkpoint-layout)
29
+
30
+ </div>
31
+
32
+ ---
33
+
34
+ The **CoLaR reasoning compression head** learns a compact latent representation of the
35
+ model's chain-of-thought and feeds it back into the backbone, so the model **reasons from
36
+ a compressed latent** instead of spelling out every reasoning token. The backbone stays
37
+ frozen; only this small head (~136 MB) is trained.
38
+
39
+ Method: **CoLaR β€” Compressed Latent Reasoning** ([arXiv:2505.16552](https://arxiv.org/abs/2505.16552)).
40
+
41
+ > ### ⚠️ This is an adapter
42
+ > These weights are **useless on their own**. You must load the
43
+ > [`nvidia/DeepSeek-V4-Flash-NVFP4`](https://huggingface.co/nvidia/DeepSeek-V4-Flash-NVFP4)
44
+ > backbone separately and attach this head to it.
45
 
46
  ---
47
 
48
+ ## πŸ“¦ Checkpoints
49
+
50
+ | Variant | Path | Stage | Reasoning mode |
51
+ |---|---|---|---|
52
+ | **`sft-c16`** ✨ *latest* | `sft-c16/` | closed-loop SFT, `c = 16` | **Latent-only reasoning** β€” see below |
53
+ | `grpo` | `grpo/` | SFT β†’ GRPO (latent-policy RL) | Prompt-position latent injection |
54
+ | `sft` | `sft/` | SFT (soft-MSE latent regression) | Prompt-position latent injection |
55
+
56
+ Each variant folder holds `colar_head_sft.{safetensors,pt}` (identical weights, two formats)
57
+ and a `config.json` with its geometry.
58
+
59
+ ### ✨ `sft-c16` β€” latent-only reasoning
60
 
61
+ `sft-c16` is the newest head and works differently from the earlier checkpoints. It is a
62
+ **latent-only reasoning** head: the model performs its *entire* reasoning phase inside the
63
+ compressed latent space β€” one latent step stands in for **`c = 16`** reasoning tokens β€” and
64
+ a **learned stop head** decides when the reasoning is complete and the model should begin
65
+ emitting its answer. There is no accompanying token-by-token thinking trace to read; the
66
+ reasoning happens in the latents, and the model surfaces only the final answer.
 
 
 
67
 
68
+ This is what the extra `stop_head` sub-module (present only in `sft-c16`) provides: a small
69
+ classifier over the running latent state that fires a learned "end-of-reasoning" signal, so
70
+ the latent phase self-terminates at a variable, content-dependent depth rather than running
71
+ a fixed number of steps.
72
 
73
+ > **Serving parameters (temperature, stop threshold, latent budget, etc.) are intentionally
74
+ > not prescribed here.** They interact with your prompts and decoding setup β€” find the
75
+ > settings that work best for your use case.
76
 
77
  ---
78
 
79
+ ## πŸ—οΈ Architecture
80
 
81
+ Three components, bundled in every checkpoint (`sft-c16` adds a fourth, the stop head):
82
 
83
  ```
84
  layer 35 hidden (4096-d)
 
88
  β”‚ Linear 4096β†’2048 Β· SiLU β”‚
89
  β”‚ Linear 2048β†’2048 Β· SiLU β”‚
90
  β”‚ Linear 2048β†’2048 β†’ [mu, log_sigma] (1024-d) β”‚
91
+ β”‚ β”‚
92
+ β”‚ stop_head (sft-c16 only): β”‚
93
+ β”‚ Linear 4096β†’1024 Β· SiLU Β· Linear 1024β†’1 β”‚ β†’ learned end-of-reasoning
94
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
95
  β”‚ mu (1024-d latent)
96
  β–Ό LayerNorm
 
100
  β”‚ Linear 2048β†’4096 β†’ hidden vector (4096-d) β”‚
101
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
102
  β”‚
103
+ β–Ό injected back into the residual stream
104
  DeepSeek-V4-Flash backbone (frozen)
105
  ```
106
 
107
+ - **`target_proj`** β€” a frozen `Linear(4096, 1024, bias=False)` defining the SFT regression
108
+ target (a stable readout of the layer-42 hidden state). Kept for reproducibility; not
109
+ needed at inference.
110
+ - **`stop_head`** β€” *(`sft-c16` only)* the learned end-of-reasoning classifier that enables
111
+ latent-only reasoning.
112
+
113
+ | Config | `sft` / `grpo` | `sft-c16` |
114
+ |---|---|---|
115
+ | base model | `nvidia/DeepSeek-V4-Flash-NVFP4` | ← same |
116
+ | hidden_size | 4096 | 4096 |
117
+ | latent_dim | 1024 | 1024 |
118
+ | mlp_dim | 2048 | 2048 |
119
+ | source_layer / target_layer | 35 / 42 | 35 / 42 |
120
+ | **compression_factor** | **4** | **16** |
121
+ | learned stop head | β€” | βœ… |
122
+ | activation | SiLU | SiLU |
123
+ | checkpoint format | v2 bundle | v3 bundle (adds `stop_head`) |
124
 
125
  ---
126
 
127
+ ## πŸ—‚οΈ Checkpoint layout
128
 
129
+ Each `.safetensors` file holds a single flat tensor dict; the sub-modules are distinguished
130
+ by key prefix. For `sft-c16`:
131
 
132
  ```
133
+ reasoning_head.net.0.weight [2048, 4096] reasoning_head.net.0.bias [2048]
134
+ reasoning_head.net.2.weight [2048, 2048] reasoning_head.net.2.bias [2048]
135
+ reasoning_head.net.4.weight [2048, 2048] reasoning_head.net.4.bias [2048]
136
+ reasoning_head.stop_head.0.weight [1024, 4096] reasoning_head.stop_head.0.bias [1024] ← sft-c16 only
137
+ reasoning_head.stop_head.2.weight [1, 1024] reasoning_head.stop_head.2.bias [1] ← sft-c16 only
138
+ decoder.net.0.weight [2048, 1024] decoder.net.0.bias [2048]
139
+ decoder.net.2.weight [2048, 2048] decoder.net.2.bias [2048]
140
+ decoder.net.4.weight [4096, 2048] decoder.net.4.bias [4096]
141
+ target_proj.weight [1024, 4096]
142
  ```
143
 
144
+ The geometry is mirrored in the safetensors metadata (`config`, `format_version`,
145
+ `subdicts`) and in the sibling `config.json`.
146
 
147
  ---
 
148
 
149
+ ## πŸš€ Load a head (self-contained β€” no repo import)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
 
151
  ```python
152
  import json
 
156
  from safetensors.torch import load_file
157
  from safetensors import safe_open
158
 
159
+ CKPT = "sft-c16/colar_head_sft.safetensors" # or grpo/…, sft/…
160
 
161
  class ReasoningCompressionHead(nn.Module):
162
+ def __init__(self, hidden_size, latent_dim, mlp_dim=None, stop_head=False):
163
  super().__init__()
164
  mlp_dim = mlp_dim or hidden_size // 2
165
  self.net = nn.Sequential(
 
167
  nn.Linear(mlp_dim, mlp_dim), nn.SiLU(),
168
  nn.Linear(mlp_dim, 2 * latent_dim),
169
  )
170
+ # sft-c16 (v3): learned end-of-reasoning classifier over the latent state
171
+ self.stop_head = nn.Sequential(
172
+ nn.Linear(hidden_size, latent_dim), nn.SiLU(),
173
+ nn.Linear(latent_dim, 1),
174
+ ) if stop_head else None
175
+
176
  def forward(self, h):
177
  mu, log_sigma = self.net(h).chunk(2, dim=-1)
178
  return mu, log_sigma.clamp(-10.0, 2.0)
179
 
180
+ def stop_logit(self, h):
181
+ return self.stop_head(h) # sigmoid(stop_logit) > threshold β‡’ end reasoning
182
+
183
  class LatentDecoder(nn.Module):
184
  def __init__(self, hidden_size, latent_dim, mlp_dim=None):
185
  super().__init__()
 
201
  def sub(prefix):
202
  return {k[len(prefix):]: v for k, v in flat.items() if k.startswith(prefix)}
203
 
204
+ has_stop = any(k.startswith("reasoning_head.stop_head.") for k in flat)
205
+ head = ReasoningCompressionHead(hs, ld, stop_head=has_stop)
206
+ head.load_state_dict(sub("reasoning_head.")); head.eval()
207
+ decoder = LatentDecoder(hs, ld); decoder.load_state_dict(sub("decoder.")); decoder.eval()
208
  target_proj = nn.Linear(hs, ld, bias=False); target_proj.load_state_dict(sub("target_proj."))
209
 
210
+ # One latent step, given h35 = layer-35 hidden at the current position, shape (B, 4096):
211
+ # mu, _ = head(F.layer_norm(h35, (hs,)))
212
+ # inject = decoder(F.layer_norm(mu, (ld,))) # (B, 4096) β†’ back into the residual stream
213
+ # p_stop = head.stop_logit(F.layer_norm(h35, (hs,))).sigmoid() # sft-c16: end reasoning when high
214
  ```
215
 
216
  ---
217
 
218
+ ## πŸ”¬ How it's served (design note)
219
 
220
+ DeepSeek-V4 uses **hash-based MoE expert routing keyed on `input_ids`**, so vLLM's native
221
+ `prompt_embeds` injection path crashes the engine (`hash MoE routing requires input_ids`).
222
+ Injection instead uses an **`embed_tokens` forward hook** that overwrites the embedding at
223
+ the chosen position with the decoded latent while token ids keep flowing for routing.
224
+ Combined with a compile-safe capture buffer, this runs on the **cudagraph fast path** rather
225
+ than `enforce_eager`. Full details in [`PAPER.md`](./PAPER.md). *The serving addon is not
226
+ released yet.*
 
227
 
228
  ---
229
 
230
+ ## πŸ“Š Results (preliminary)
231
 
232
  GSM8K, 8-shot, temperature 0, DeepSeek-V4-Flash-NVFP4 backbone, GRPO head.
233
+ **n = 30 documents** β€” accuracy is small-n and noisy; the **robust signal is the reduction
234
+ in reasoning length**, not the exact-match score.
235
 
236
  | Metric | Base (no injection) | +Head (2k budget) | +Head (14.5k budget) |
237
  |---|---|---|---|
238
+ | exact-match | 40.0 / 33.3 | 40.0 | **46.7** |
239
  | closed `</think>` % | 97–100 | 30 | 40 |
240
  | median think tokens | 146–187 | 106 | **103** |
241
  | max think tokens | 1740–2048 | 472 | **415** |
242
 
243
  - **~40% fewer median thinking tokens** and a **~4Γ— shorter worst-case trace.**
244
+ - The head **never skips** reasoning (skip% = 0) β€” it *compresses* it.
245
+ - The low closed-`</think>`% for `grpo` is a **formatting artifact**: its token-F1 reward
246
+ never rewarded emitting the closing tag (a larger 78Γ— budget did not make traces close,
247
+ confirming it is not truncation). The `sft-c16` head's learned **stop** addresses exactly
248
+ this by terminating the latent phase on a learned signal.
249
+ - For context only, published DeepSeek-V4-Flash-Base scores **90.8** on GSM8K under its own
250
+ full harness β€” **not** a baseline reproduced here.
 
251
 
252
  Raw numbers and bar charts are in [`results/`](./results).
253
 
254
  ---
255
 
256
+ ## ⚠️ Limitations
257
 
258
  - Evaluation is **small-n (30 docs, GSM8K only)**; treat accuracy as directional.
259
  - No full-benchmark or multi-task evaluation yet.
260
+ - `sft` / `grpo` inject at the prompt/`<think>` position only. `sft-c16` runs the full
261
+ latent-only closed loop with a learned stop; broader eval of it is ongoing.
262
  - Measured on 2Γ— RTX PRO 6000 (96 GiB); usable context β‰ˆ 15.8k tokens on that box.
263
+ - **Code is not released yet.** Training scripts and the vLLM serving addon will be
264
+ published separately; this repo ships weights + docs, and the loader above needs no
265
+ first-party code.
266
+
267
+ ---
268
 
269
+ ## πŸ“„ Citation
270
 
271
+ Method after **CoLaR β€” Compressed Latent Reasoning**:
272
 
273
  ```bibtex
274
  @article{colar2025,
275
+ title = {CoLaR: Compressed Latent Reasoning},
276
  journal = {arXiv preprint arXiv:2505.16552},
277
+ year = {2025}
278
  }
279
  ```