AbstractPhil commited on
Commit
fa82fde
·
verified ·
1 Parent(s): d1537ac

mirror alephllm 0.9.0 (same-session law): presets.py (AlephLMConfig.fusion field, default None; the v3 preset builder + registrations guarded for copies without the data stack), governor.py (raw_block), alephlm.py (the optional fusion stage imported lazily — unfused crafts load without model/fusion.py; the trunk loop factored into _trunk). Gated: strict load of model.safetensors through the vendored path, logits parity 0.0 vs geolip.

Browse files
Files changed (1) hide show
  1. alephlm.py +132 -9
alephlm.py CHANGED
@@ -32,6 +32,8 @@ from .attention import CausalSDPA, CausalSplatHUB
32
  from .bank import AnchoredBank
33
  from .embedding import TrigramByteEmbedding, TokenEmbedding
34
  from .head import DualHead
 
 
35
 
36
 
37
  class Block(nn.Module):
@@ -94,6 +96,43 @@ class AlephLM(nn.Module):
94
  self.nf = nn.LayerNorm(cfg.d_model)
95
  self.head = DualHead(cfg.d_model, cfg.vocab_size, cfg.head_K,
96
  cfg.head_D, cfg.tau, tied_weight=tied)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
 
98
  def forward(self, idx=None, targets=None, disable_bank=False,
99
  disable_hub=False, disable_head_aleph=False,
@@ -107,8 +146,7 @@ class AlephLM(nn.Module):
107
  if idx is None:
108
  idx = input_ids
109
  x = self.embed(idx)
110
- for b in self.blocks:
111
- x = b(x, disable_bank=disable_bank, disable_hub=disable_hub)
112
  h = self.nf(x)
113
  logits = self.head(h, disable_aleph=disable_head_aleph)
114
  if targets is not None: # pre-shifted (ours)
@@ -130,6 +168,8 @@ class AlephLM(nn.Module):
130
  The cache carries per-layer attention state, the trigram history
131
  bytes, and the absolute position cursor."""
132
  self.eval()
 
 
133
  from .embedding import PAD_ROW
134
  caches = []
135
  x = self.embed(idx)
@@ -143,26 +183,109 @@ class AlephLM(nn.Module):
143
  return logits, {"layers": caches, "t": n,
144
  "prev1": idx[:, -1], "prev2": prev2}
145
 
146
- @torch.no_grad()
147
- def decode_step(self, next_id, cache):
148
- """One token through the cached path. next_id: (B,) or (B,1)."""
149
- next_id = next_id.reshape(-1)
150
- t = cache["t"]
151
- assert t < self.cfg.context, "decode exceeded the position table"
152
  if isinstance(self.embed, TrigramByteEmbedding):
153
  e = (self.embed.emb0(next_id) + self.embed.emb1(cache["prev1"])
154
  + self.embed.emb2(cache["prev2"])).unsqueeze(1) \
155
  + self.embed.pos[:, t:t + 1]
 
156
  cache["prev2"] = cache["prev1"]
157
  cache["prev1"] = next_id
158
  else:
159
  e = self.embed.emb(next_id).unsqueeze(1) + self.embed.pos[:, t:t + 1]
160
- x = e
 
 
 
 
 
 
 
 
 
 
161
  for b, c in zip(self.blocks, cache["layers"]):
162
  x = b.step(x, c)
163
  cache["t"] = t + 1
164
  return self.head(self.nf(x))
165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  @staticmethod
167
  def _sample(logits, temperature, top_p):
168
  logits = logits[:, -1].float()
 
32
  from .bank import AnchoredBank
33
  from .embedding import TrigramByteEmbedding, TokenEmbedding
34
  from .head import DualHead
35
+ # model/fusion.py is imported lazily (only when a config asks for fusion),
36
+ # so a vendored copy of this file without it keeps loading unfused crafts.
37
 
38
 
39
  class Block(nn.Module):
 
96
  self.nf = nn.LayerNorm(cfg.d_model)
97
  self.head = DualHead(cfg.d_model, cfg.vocab_size, cfg.head_K,
98
  cfg.head_D, cfg.tau, tied_weight=tied)
99
+ # v3: weak-token fusion (model/fusion.py). None keeps the byte-
100
+ # resolution trunk verbatim; otherwise the middle blocks run over
101
+ # units and the front/back blocks stay at byte resolution.
102
+ spec = getattr(cfg, "fusion", None)
103
+ if spec:
104
+ from .fusion import Fusion
105
+ self.fusion = Fusion(spec, cfg.d_model)
106
+ else:
107
+ self.fusion = None
108
+ if self.fusion is not None:
109
+ assert self.fusion.k_lo + self.fusion.k_hi <= cfg.n_layers, \
110
+ "fusion: k_lo + k_hi must not exceed n_layers"
111
+
112
+ def _ranges(self):
113
+ L = len(self.blocks)
114
+ lo, hi = self.fusion.k_lo, L - self.fusion.k_hi
115
+ return self.blocks[:lo], self.blocks[lo:hi], self.blocks[hi:]
116
+
117
+ def _trunk(self, x, idx, disable_bank=False, disable_hub=False):
118
+ if self.fusion is None:
119
+ for b in self.blocks:
120
+ x = b(x, disable_bank=disable_bank, disable_hub=disable_hub)
121
+ return x
122
+ front, middle, back = self._ranges()
123
+ plan = self.fusion.plan(idx)
124
+ for b in front:
125
+ x = b(x, disable_bank=disable_bank, disable_hub=disable_hub)
126
+ if len(middle):
127
+ u = plan.pool(x)
128
+ for b in middle:
129
+ u = b(u, disable_bank=disable_bank, disable_hub=disable_hub)
130
+ x = x + plan.unpool(u, self.fusion.null)
131
+ else:
132
+ x = x + self.fusion.null.to(x.dtype)
133
+ for b in back:
134
+ x = b(x, disable_bank=disable_bank, disable_hub=disable_hub)
135
+ return x
136
 
137
  def forward(self, idx=None, targets=None, disable_bank=False,
138
  disable_hub=False, disable_head_aleph=False,
 
146
  if idx is None:
147
  idx = input_ids
148
  x = self.embed(idx)
149
+ x = self._trunk(x, idx, disable_bank=disable_bank, disable_hub=disable_hub)
 
150
  h = self.nf(x)
151
  logits = self.head(h, disable_aleph=disable_head_aleph)
152
  if targets is not None: # pre-shifted (ours)
 
168
  The cache carries per-layer attention state, the trigram history
169
  bytes, and the absolute position cursor."""
170
  self.eval()
171
+ if self.fusion is not None:
172
+ return self._prefill_fused(idx)
173
  from .embedding import PAD_ROW
174
  caches = []
175
  x = self.embed(idx)
 
183
  return logits, {"layers": caches, "t": n,
184
  "prev1": idx[:, -1], "prev2": prev2}
185
 
186
+ def _embed_step(self, next_id, cache, t):
 
 
 
 
 
187
  if isinstance(self.embed, TrigramByteEmbedding):
188
  e = (self.embed.emb0(next_id) + self.embed.emb1(cache["prev1"])
189
  + self.embed.emb2(cache["prev2"])).unsqueeze(1) \
190
  + self.embed.pos[:, t:t + 1]
191
+ cache["prev3"] = cache.get("prev2")
192
  cache["prev2"] = cache["prev1"]
193
  cache["prev1"] = next_id
194
  else:
195
  e = self.embed.emb(next_id).unsqueeze(1) + self.embed.pos[:, t:t + 1]
196
+ return e
197
+
198
+ @torch.no_grad()
199
+ def decode_step(self, next_id, cache):
200
+ """One token through the cached path. next_id: (B,) or (B,1)."""
201
+ next_id = next_id.reshape(-1)
202
+ t = cache["t"]
203
+ assert t < self.cfg.context, "decode exceeded the position table"
204
+ if self.fusion is not None:
205
+ return self._decode_step_fused(next_id, cache, t)
206
+ x = self._embed_step(next_id, cache, t)
207
  for b, c in zip(self.blocks, cache["layers"]):
208
  x = b.step(x, c)
209
  cache["t"] = t + 1
210
  return self.head(self.nf(x))
211
 
212
+ # ------------------------------------------------- fused decode path
213
+ @torch.no_grad()
214
+ def _prefill_fused(self, idx):
215
+ """The prompt through the hourglass: front blocks at byte
216
+ resolution (batched), the middle over each row's COMPLETED units
217
+ (the last unit stays open until a later byte starts the next), the
218
+ back blocks at byte resolution. The middle's caches are merged
219
+ across rows (the hub's prefix state has one shape per row)."""
220
+ from .embedding import PAD_ROW
221
+ from .governor import raw_block
222
+ from .fusion import cat_caches, zero_cache_rows
223
+ front, middle, back = self._ranges()
224
+ for b in middle:
225
+ assert raw_block(b).is_hub, "fused decode needs hub blocks in the middle"
226
+ B, T = idx.shape
227
+ plan = self.fusion.plan(idx)
228
+ x = self.embed(idx)
229
+ front_c = []
230
+ for b in front:
231
+ x, c = b.prefill(x)
232
+ front_c.append(c)
233
+ x_front = x
234
+ u_all = plan.pool(x_front) # (B, J, d) incl. the open unit
235
+ n_closed = plan.n_units - 1
236
+ d = x.shape[-1]
237
+ v_pad = torch.zeros(B, plan.J, d, device=x.device, dtype=x.dtype)
238
+ mid_rows = []
239
+ for r in range(B):
240
+ nc = int(n_closed[r])
241
+ u = u_all[r:r + 1, :max(nc, 1)]
242
+ row_c = []
243
+ for b in middle:
244
+ u, c = b.prefill(u)
245
+ row_c.append(c)
246
+ if nc > 0:
247
+ v_pad[r, :nc] = u[0]
248
+ mid_rows.append(row_c)
249
+ mid_c = [cat_caches([row[i] for row in mid_rows]) for i in range(len(middle))]
250
+ empty = n_closed == 0
251
+ if bool(empty.any()):
252
+ mid_c = [zero_cache_rows(c, empty) for c in mid_c]
253
+ g = plan.unpool(v_pad, self.fusion.null) # (B, T, d)
254
+ x = x_front + g
255
+ back_c = []
256
+ for b in back:
257
+ x, c = b.prefill(x)
258
+ back_c.append(c)
259
+ logits = self.head(self.nf(x)[:, -1:])
260
+ pad = lambda k: idx[:, -k] if T >= k else torch.full_like(idx[:, -1], PAD_ROW) # noqa: E731
261
+ return logits, {"front": front_c, "mid": mid_c, "back": back_c, "t": T,
262
+ "prev1": idx[:, -1], "prev2": pad(2), "prev3": pad(3),
263
+ "front_last": x_front[:, -1], "g": g[:, -1]}
264
+
265
+ @torch.no_grad()
266
+ def _decode_step_fused(self, next_id, cache, t):
267
+ from .embedding import PAD_ROW
268
+ from .fusion import snapshot, restore_rows
269
+ front, middle, back = self._ranges()
270
+ prev1, prev2, prev3 = cache["prev1"], cache["prev2"], cache["prev3"]
271
+ st = self.fusion.starts_step(next_id, prev1, prev2, prev3, PAD_ROW) # (B,) closes the open unit
272
+ if bool(st.any()) and len(middle):
273
+ u = cache["front_last"].unsqueeze(1)
274
+ for b, c in zip(middle, cache["mid"]):
275
+ old = snapshot(c)
276
+ u = b.step(u, c)
277
+ restore_rows(c, old, st)
278
+ cache["g"] = torch.where(st.unsqueeze(-1), u[:, 0], cache["g"])
279
+ x = self._embed_step(next_id, cache, t)
280
+ for b, c in zip(front, cache["front"]):
281
+ x = b.step(x, c)
282
+ cache["front_last"] = x[:, 0]
283
+ x = x + cache["g"].unsqueeze(1)
284
+ for b, c in zip(back, cache["back"]):
285
+ x = b.step(x, c)
286
+ cache["t"] = t + 1
287
+ return self.head(self.nf(x))
288
+
289
  @staticmethod
290
  def _sample(logits, temperature, top_p):
291
  logits = logits[:, -1].float()