phanerozoic commited on
Commit
418a182
·
verified ·
1 Parent(s): 2fc8e3b

Uploaded using `kernel-builder`.

Browse files
Files changed (42) hide show
  1. build/torch212-cxx11-cu126-x86_64-linux/__init__.py +23 -0
  2. build/torch212-cxx11-cu126-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
  3. build/torch212-cxx11-cu126-x86_64-linux/_ops.py +9 -0
  4. build/torch212-cxx11-cu126-x86_64-linux/drafter.py +236 -0
  5. build/torch212-cxx11-cu126-x86_64-linux/gguf_io.py +61 -0
  6. build/torch212-cxx11-cu126-x86_64-linux/metadata.json +39 -0
  7. build/torch212-cxx11-cu126-x86_64-linux/reference.py +188 -0
  8. build/torch212-cxx11-cu130-x86_64-linux/__init__.py +23 -0
  9. build/torch212-cxx11-cu130-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
  10. build/torch212-cxx11-cu130-x86_64-linux/_ops.py +9 -0
  11. build/torch212-cxx11-cu130-x86_64-linux/drafter.py +236 -0
  12. build/torch212-cxx11-cu130-x86_64-linux/gguf_io.py +61 -0
  13. build/torch212-cxx11-cu130-x86_64-linux/metadata.json +41 -0
  14. build/torch212-cxx11-cu130-x86_64-linux/reference.py +188 -0
  15. build/torch212-cxx11-cu132-x86_64-linux/__init__.py +23 -0
  16. build/torch212-cxx11-cu132-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
  17. build/torch212-cxx11-cu132-x86_64-linux/_ops.py +9 -0
  18. build/torch212-cxx11-cu132-x86_64-linux/drafter.py +236 -0
  19. build/torch212-cxx11-cu132-x86_64-linux/gguf_io.py +61 -0
  20. build/torch212-cxx11-cu132-x86_64-linux/metadata.json +41 -0
  21. build/torch212-cxx11-cu132-x86_64-linux/reference.py +188 -0
  22. build/torch213-cxx11-cu126-x86_64-linux/__init__.py +23 -0
  23. build/torch213-cxx11-cu126-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
  24. build/torch213-cxx11-cu126-x86_64-linux/_ops.py +9 -0
  25. build/torch213-cxx11-cu126-x86_64-linux/drafter.py +236 -0
  26. build/torch213-cxx11-cu126-x86_64-linux/gguf_io.py +61 -0
  27. build/torch213-cxx11-cu126-x86_64-linux/metadata.json +39 -0
  28. build/torch213-cxx11-cu126-x86_64-linux/reference.py +188 -0
  29. build/torch213-cxx11-cu130-x86_64-linux/__init__.py +23 -0
  30. build/torch213-cxx11-cu130-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
  31. build/torch213-cxx11-cu130-x86_64-linux/_ops.py +9 -0
  32. build/torch213-cxx11-cu130-x86_64-linux/drafter.py +236 -0
  33. build/torch213-cxx11-cu130-x86_64-linux/gguf_io.py +61 -0
  34. build/torch213-cxx11-cu130-x86_64-linux/metadata.json +41 -0
  35. build/torch213-cxx11-cu130-x86_64-linux/reference.py +188 -0
  36. build/torch213-cxx11-cu132-x86_64-linux/__init__.py +23 -0
  37. build/torch213-cxx11-cu132-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
  38. build/torch213-cxx11-cu132-x86_64-linux/_ops.py +9 -0
  39. build/torch213-cxx11-cu132-x86_64-linux/drafter.py +236 -0
  40. build/torch213-cxx11-cu132-x86_64-linux/gguf_io.py +61 -0
  41. build/torch213-cxx11-cu132-x86_64-linux/metadata.json +41 -0
  42. build/torch213-cxx11-cu132-x86_64-linux/reference.py +188 -0
build/torch212-cxx11-cu126-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DFlash block-diffusion drafter ops; the eager reference defines the
2
+ semantics and the CUDA ops are certified against it."""
3
+ from .reference import DFlashConfig, DFlashRef, random_weights # noqa: F401
4
+ from .drafter import DFlashDrafter # noqa: F401
5
+
6
+ try: # built variants ship _ops
7
+ from ._ops import ops # noqa: F401
8
+ except ImportError:
9
+ try: # a local JIT build registers the same ops under torch.ops.dflash_ext
10
+ import torch as _torch
11
+
12
+ _torch.ops.dflash_ext.dflash_accept
13
+ ops = _torch.ops.dflash_ext
14
+ except Exception:
15
+ ops = None
16
+
17
+ try:
18
+ from .gguf_io import load_drafter # noqa: F401
19
+ except ImportError: # gguf-py absent; the reference stays usable
20
+ load_drafter = None
21
+
22
+ __all__ = ["DFlashConfig", "DFlashRef", "DFlashDrafter", "random_weights",
23
+ "load_drafter", "ops"]
build/torch212-cxx11-cu126-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3451aca743d6ce46a183b58a065863c9abd327abc6a877259861334ea409a6ca
3
+ size 893416
build/torch212-cxx11-cu126-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _dflash_ops_cuda_03c9586
3
+ ops = torch.ops._dflash_ops_cuda_03c9586
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_dflash_ops_cuda_03c9586::{op_name}"
build/torch212-cxx11-cu126-x86_64-linux/drafter.py ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """GPU DFlash drafter: cuBLAS GEMMs plus the fused ops, with a CUDA-graphed
2
+ block step."""
3
+ import torch
4
+
5
+ from .reference import DFlashConfig, rms_norm, rope_inv_freq
6
+
7
+
8
+ def _ops():
9
+ from . import ops
10
+ if ops is None:
11
+ raise RuntimeError(
12
+ "dflash-ops compiled kernels are unavailable; build them with "
13
+ "load_local.load() in a source checkout, or install a published "
14
+ "variant with kernels.get_kernel")
15
+ return ops
16
+
17
+
18
+ class DFlashDrafter:
19
+ """Ring-cached DFlash drafter on CUDA. Weight keys match `DFlashRef`."""
20
+
21
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cuda",
22
+ ring_dtype="fp32", dtype="fp32"):
23
+ self.cfg = cfg
24
+ self.device = torch.device(device)
25
+ # dtype sets GEMM weights and activations; residual, norms, softmax stay fp32
26
+ self.wdt = torch.bfloat16 if dtype == "bf16" else torch.float32
27
+ self.w = {}
28
+ for k, v in weights.items():
29
+ dt = self.wdt if v.dim() == 2 else torch.float32
30
+ self.w[k] = v.to(device=self.device, dtype=dt).contiguous()
31
+ C = cfg
32
+ # ring storage dtype; arithmetic stays fp32
33
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
34
+ else torch.float32)
35
+ # host-built fp64 rope table, shared by every op call
36
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base,
37
+ self.device).contiguous()
38
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
39
+ device=self.device, dtype=self.ring_dt)
40
+ self.ring_v = torch.zeros_like(self.ring_k)
41
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int32,
42
+ device=self.device)
43
+
44
+ # ---- encoder --------------------------------------------------------
45
+ def encode(self, feats):
46
+ g = (feats.to(self.device, self.wdt) @ self.w["fc"]).float()
47
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
48
+
49
+ # ---- KV injection ---------------------------------------------------
50
+ def inject(self, g, pos):
51
+ """Ring injection at `pos`, chunked at `window` so no slot is written twice per launch."""
52
+ C = self.cfg
53
+ o = _ops()
54
+ pos = pos.to(self.device, torch.int32).contiguous()
55
+ for beg in range(0, pos.numel(), C.window):
56
+ p = pos[beg:beg + C.window].contiguous()
57
+ gc = g[beg:beg + C.window].to(self.wdt)
58
+ for i in range(C.n_layer):
59
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv,
60
+ C.head_dim).contiguous()
61
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv,
62
+ C.head_dim).contiguous()
63
+ o.dflash_inject(self.ring_k[i], self.ring_v[i], self.ring_pos,
64
+ k, v, self.w[f"k_norm.{i}"], self.rope_inv, p,
65
+ C.rms_eps)
66
+
67
+ # ---- noise-block forward -------------------------------------------
68
+ def block_step(self, id_last, n_past, n_draft=None):
69
+ C = self.cfg
70
+ if n_draft is None:
71
+ n_draft = C.block_size - 1
72
+ B = n_draft + 1
73
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
74
+ device=self.device)
75
+ tokens[0] = int(id_last)
76
+ bpos = (n_past + torch.arange(B, device=self.device)).to(torch.int32)
77
+ return self._forward(tokens, bpos.contiguous())
78
+
79
+ def _forward(self, tokens, bpos):
80
+ """Block forward on caller-owned device tensors; reads no host state."""
81
+ C = self.cfg
82
+ o = _ops()
83
+ B = tokens.numel()
84
+ x = self.w["tok_embd"][tokens].float()
85
+ scale = C.head_dim ** -0.5
86
+
87
+ for i in range(C.n_layer):
88
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps).to(self.wdt)
89
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head,
90
+ C.head_dim).contiguous()
91
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv,
92
+ C.head_dim).contiguous()
93
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv,
94
+ C.head_dim).contiguous()
95
+ o.dflash_qk_rope(q, k, self.w[f"q_norm.{i}"],
96
+ self.w[f"k_norm.{i}"], self.rope_inv, bpos,
97
+ C.rms_eps)
98
+ att = torch.empty_like(q)
99
+ o.dflash_block_attn(att, q, k, v, self.ring_k[i], self.ring_v[i],
100
+ self.ring_pos, bpos, scale)
101
+ x = x + (att.reshape(B, -1) @ self.w[f"wo.{i}"]).float()
102
+
103
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps).to(self.wdt)
104
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
105
+ x = x + ((gate * (f @ self.w[f"ffn_up.{i}"]))
106
+ @ self.w[f"ffn_down.{i}"]).float()
107
+
108
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
109
+ return (x.to(self.wdt) @ self.w["lm_head"]).float()
110
+
111
+ def draft_greedy(self, id_last, n_past, n_draft=None):
112
+ return self.block_step(id_last, n_past, n_draft)[1:].argmax(dim=-1)
113
+
114
+ # ---- graphed step ---------------------------------------------------
115
+ def _static_buffers(self, B):
116
+ """Every tensor a captured step touches, allocated once and held."""
117
+ C = self.cfg
118
+ d = self.device
119
+ wdt = self.wdt
120
+ s = {
121
+ "tokens": torch.full((B,), C.mask_token_id, dtype=torch.int64,
122
+ device=d),
123
+ "arange": torch.arange(B, dtype=torch.int32, device=d),
124
+ "n_past": torch.zeros((), dtype=torch.int32, device=d),
125
+ "bpos": torch.empty(B, dtype=torch.int32, device=d),
126
+ "xw": torch.empty(B, C.n_embd, dtype=wdt, device=d),
127
+ "x": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
128
+ "sq": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
129
+ "ms": torch.empty(B, 1, dtype=torch.float32, device=d),
130
+ "hn": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
131
+ "h": torch.empty(B, C.n_embd, dtype=wdt, device=d),
132
+ "q": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
133
+ "k": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
134
+ "v": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
135
+ "att": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
136
+ "ao": torch.empty(B, C.n_embd, dtype=wdt, device=d),
137
+ "g1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
138
+ "sg": torch.empty(B, C.n_ff, dtype=wdt, device=d),
139
+ "u1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
140
+ "d1": torch.empty(B, C.n_embd, dtype=wdt, device=d),
141
+ "lg": torch.empty(B, C.n_vocab, dtype=wdt, device=d),
142
+ "logits": torch.empty(B, C.n_vocab, dtype=torch.float32,
143
+ device=d),
144
+ }
145
+ return s
146
+
147
+ def _rms_static(self, src, w, s, out):
148
+ """RMS norm of `src` into `out` using only held buffers."""
149
+ torch.pow(src, 2, out=s["sq"])
150
+ torch.mean(s["sq"], -1, keepdim=True, out=s["ms"])
151
+ s["ms"].add_(self.cfg.rms_eps).rsqrt_()
152
+ torch.mul(src, s["ms"], out=out)
153
+ out.mul_(w)
154
+
155
+ def _forward_static(self, s):
156
+ """Allocation-free block forward into held buffers; numerically
157
+ identical to `_forward`."""
158
+ C = self.cfg
159
+ o = _ops()
160
+ B = s["tokens"].numel()
161
+ scale = C.head_dim ** -0.5
162
+ torch.index_select(self.w["tok_embd"], 0, s["tokens"], out=s["xw"])
163
+ s["x"].copy_(s["xw"])
164
+ for i in range(C.n_layer):
165
+ self._rms_static(s["x"], self.w[f"attn_norm.{i}"], s, s["hn"])
166
+ s["h"].copy_(s["hn"])
167
+ torch.matmul(s["h"], self.w[f"wq.{i}"], out=s["q"])
168
+ torch.matmul(s["h"], self.w[f"wk.{i}"], out=s["k"])
169
+ torch.matmul(s["h"], self.w[f"wv.{i}"], out=s["v"])
170
+ qv = s["q"].view(B, C.n_head, C.head_dim)
171
+ kv_ = s["k"].view(B, C.n_head_kv, C.head_dim)
172
+ vv = s["v"].view(B, C.n_head_kv, C.head_dim)
173
+ o.dflash_qk_rope(qv, kv_, self.w[f"q_norm.{i}"],
174
+ self.w[f"k_norm.{i}"], self.rope_inv, s["bpos"],
175
+ C.rms_eps)
176
+ av = s["att"].view(B, C.n_head, C.head_dim)
177
+ o.dflash_block_attn(av, qv, kv_, vv, self.ring_k[i],
178
+ self.ring_v[i], self.ring_pos, s["bpos"],
179
+ scale)
180
+ torch.matmul(s["att"], self.w[f"wo.{i}"], out=s["ao"])
181
+ s["x"].add_(s["ao"])
182
+ self._rms_static(s["x"], self.w[f"ffn_norm.{i}"], s, s["hn"])
183
+ s["h"].copy_(s["hn"])
184
+ torch.matmul(s["h"], self.w[f"ffn_gate.{i}"], out=s["g1"])
185
+ # fused silu keeps the step bitwise-equal to the eager path
186
+ torch.ops.aten.silu.out(s["g1"], out=s["sg"])
187
+ torch.matmul(s["h"], self.w[f"ffn_up.{i}"], out=s["u1"])
188
+ s["sg"].mul_(s["u1"])
189
+ torch.matmul(s["sg"], self.w[f"ffn_down.{i}"], out=s["d1"])
190
+ s["x"].add_(s["d1"])
191
+ self._rms_static(s["x"], self.w["out_norm"], s, s["hn"])
192
+ s["h"].copy_(s["hn"])
193
+ torch.matmul(s["h"], self.w["lm_head"], out=s["lg"])
194
+ s["logits"].copy_(s["lg"])
195
+ return s["logits"]
196
+
197
+ def capture_step(self, n_draft=None):
198
+ """Graph-captured block step over static buffers (the region allocates
199
+ nothing); returns step(id_last, n_past) -> logits, overwritten per replay."""
200
+ C = self.cfg
201
+ if n_draft is None:
202
+ n_draft = C.block_size - 1
203
+ s = self._static_buffers(n_draft + 1)
204
+
205
+ stream = torch.cuda.Stream(device=self.device)
206
+ stream.wait_stream(torch.cuda.current_stream())
207
+ with torch.cuda.stream(stream):
208
+ for _ in range(3): # warm kernels and cuBLAS
209
+ torch.add(s["arange"], s["n_past"], out=s["bpos"])
210
+ self._forward_static(s)
211
+ torch.cuda.current_stream().wait_stream(stream)
212
+ torch.cuda.synchronize()
213
+
214
+ graph = torch.cuda.CUDAGraph()
215
+ with torch.cuda.graph(graph):
216
+ torch.add(s["arange"], s["n_past"], out=s["bpos"]) # in-graph: replay sees updates
217
+ logits = self._forward_static(s)
218
+
219
+ def step(id_last, n_past):
220
+ s["tokens"][0].fill_(int(id_last))
221
+ s["n_past"].fill_(int(n_past))
222
+ graph.replay()
223
+ return logits
224
+
225
+ step.graph = graph
226
+ step.buffers = s
227
+ return step
228
+
229
+ # ---- verification ---------------------------------------------------
230
+ def accept(self, draft, target):
231
+ """Leading agreement count, device-side."""
232
+ o = _ops()
233
+ n = torch.zeros(1, dtype=torch.int32, device=self.device)
234
+ o.dflash_accept(n, draft.to(torch.int32).contiguous(),
235
+ target.to(torch.int32).contiguous())
236
+ return n
build/torch212-cxx11-cu126-x86_64-linux/gguf_io.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Load the DFlash drafter GGUF into reference-layout fp32 tensors; 2-D weights
2
+ transpose from GGUF [out, in] to [in, out]; tok_embd and lm_head are the
3
+ caller's (they belong to the target model)."""
4
+ import numpy as np
5
+ import torch
6
+ from gguf import GGUFReader
7
+ from gguf import quants as gq
8
+
9
+ from .reference import DFlashConfig
10
+
11
+ _BLK = {
12
+ "attn_norm": "attn_norm", "attn_q": "wq", "attn_k": "wk", "attn_v": "wv",
13
+ "attn_output": "wo", "attn_q_norm": "q_norm", "attn_k_norm": "k_norm",
14
+ "ffn_norm": "ffn_norm", "ffn_gate": "ffn_gate", "ffn_up": "ffn_up",
15
+ "ffn_down": "ffn_down",
16
+ }
17
+ _TOP = {"fc": "fc", "enc.output_norm": "enc_norm", "output_norm": "out_norm"}
18
+
19
+
20
+ def _field(reader, key, default=None):
21
+ f = reader.get_field(key)
22
+ if f is None:
23
+ return default
24
+ v = f.contents()
25
+ return v
26
+
27
+
28
+ def load_drafter(path):
29
+ """-> (DFlashConfig, weights dict) with fp32 tensors in reference layout."""
30
+ r = GGUFReader(str(path))
31
+ cfg = DFlashConfig(
32
+ n_layer=int(_field(r, "dflash.block_count")),
33
+ n_embd=int(_field(r, "dflash.embedding_length")),
34
+ n_head=int(_field(r, "dflash.attention.head_count")),
35
+ n_head_kv=int(_field(r, "dflash.attention.head_count_kv")),
36
+ head_dim=int(_field(r, "dflash.attention.key_length")),
37
+ n_ff=int(_field(r, "dflash.feed_forward_length")),
38
+ rope_base=float(_field(r, "dflash.rope.freq_base")),
39
+ rms_eps=float(_field(r, "dflash.attention.layer_norm_rms_epsilon")),
40
+ window=int(_field(r, "dflash.attention.sliding_window")),
41
+ block_size=int(_field(r, "dflash.block_size")),
42
+ target_layers=tuple(_field(r, "dflash.target_layers")),
43
+ )
44
+ w = {}
45
+ for t in r.tensors:
46
+ name = t.name
47
+ assert name.endswith(".weight"), name
48
+ base = name[: -len(".weight")]
49
+ if base.startswith("blk."):
50
+ _, idx, part = base.split(".", 2)
51
+ key = f"{_BLK[part]}.{idx}"
52
+ else:
53
+ key = _TOP[base]
54
+ data = gq.dequantize(t.data, t.tensor_type)
55
+ arr = torch.from_numpy(np.ascontiguousarray(data)).float()
56
+ if arr.dim() == 2:
57
+ arr = arr.t().contiguous()
58
+ w[key] = arr
59
+ expect = 3 + 11 * cfg.n_layer
60
+ assert len(w) == expect, (len(w), expect)
61
+ return cfg, w
build/torch212-cxx11-cu126-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "dflash-ops",
3
+ "id": "_dflash_ops_cuda_03c9586",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "kernel-depends": [],
8
+ "backend": {
9
+ "type": "cuda",
10
+ "archs": [
11
+ "8.0",
12
+ "8.6",
13
+ "8.9",
14
+ "9.0"
15
+ ]
16
+ },
17
+ "digest": {
18
+ "algorithm": "sha256",
19
+ "files": {
20
+ "__init__.py": "wNpuIbQEXTfFNjrmz6aISM46VFgMKAHkqqu+ECJJS20=",
21
+ "_dflash_ops_cuda_03c9586.abi3.so": "NFGsp0PWzkahg7WKBlhjyavTJ6vGqHclmGEzTqQJpso=",
22
+ "_ops.py": "+6e3Oo6lwRkZaeOrhSSZEwWYs4/Fpd/zQgJj4MVEi9I=",
23
+ "drafter.py": "wGU5TWlXWr/ZogxQr4pho5Wku66UUygnczpsTu82dls=",
24
+ "gguf_io.py": "XrgF2dH7LNR1KTNKKu/pKhh6wT90bCjcjCAgmyGsuZA=",
25
+ "reference.py": "InmFS9rUwURZ7ZGVUxwQJCCjJZR/hKWrF3eMfp4zQvY="
26
+ }
27
+ },
28
+ "provenance": {
29
+ "kernel-builder": {
30
+ "version": "0.17.0-dev0",
31
+ "sha": "2c40e10d3da1392245ee81bd05b55fb3103b2b34",
32
+ "dirty": false
33
+ },
34
+ "kernel": {
35
+ "sha": "03c9586154cc2afa6efaa7b111dccef715ec9d69",
36
+ "dirty": false
37
+ }
38
+ }
39
+ }
build/torch212-cxx11-cu126-x86_64-linux/reference.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Eager fp32 DFlash drafter reference, transcribed from llama.cpp's
2
+ llama_model_dflash graph; the CUDA ops are certified against this module."""
3
+ from dataclasses import dataclass, field
4
+
5
+ import torch
6
+
7
+
8
+ @dataclass
9
+ class DFlashConfig:
10
+ n_layer: int = 5
11
+ n_embd: int = 6656
12
+ n_head: int = 32
13
+ n_head_kv: int = 8
14
+ head_dim: int = 128
15
+ n_ff: int = 19968
16
+ n_vocab: int = 202048
17
+ rope_base: float = 500000.0
18
+ rms_eps: float = 1e-6
19
+ window: int = 2048 # SWA width; also the ring capacity
20
+ block_size: int = 16
21
+ mask_token_id: int = 201818
22
+ target_layers: tuple = (2, 14, 26, 38, 50)
23
+
24
+ @property
25
+ def n_feat(self):
26
+ return len(self.target_layers) * self.n_embd
27
+
28
+ @classmethod
29
+ def tiny(cls):
30
+ """Toy sizes with the real structure; head_dim stays a multiple of 32."""
31
+ return cls(n_layer=2, n_embd=64, n_head=4, n_head_kv=2, head_dim=32,
32
+ n_ff=96, n_vocab=997, window=32, block_size=8,
33
+ mask_token_id=990, target_layers=(1, 2))
34
+
35
+
36
+ def rms_norm(x, w, eps):
37
+ """llama.cpp LLM_NORM_RMS: x * w / sqrt(mean(x^2) + eps), fp32."""
38
+ v = x.float()
39
+ return (v * torch.rsqrt(v.pow(2).mean(-1, keepdim=True) + eps)) * w.float()
40
+
41
+
42
+ def rope_inv_freq(head_dim, base, device="cpu"):
43
+ """fp64 NEOX inverse frequencies base^(-2i/head_dim), host-evaluated so the
44
+ table is device-invariant."""
45
+ half = head_dim // 2
46
+ t = base ** (-torch.arange(half, dtype=torch.float64) * 2.0 / head_dim)
47
+ return t.to(device)
48
+
49
+
50
+ def rope_neox(x, pos, base=None, inv=None):
51
+ """NEOX rope over pairs (i, i + d/2), fp32; x [T, H, D], pos [T]; pass
52
+ `inv` to reuse a precomputed table."""
53
+ T, H, D = x.shape
54
+ half = D // 2
55
+ if inv is None:
56
+ inv = rope_inv_freq(D, base, x.device)
57
+ ang = pos.to(torch.float64)[:, None] * inv[None, :] # [T, half]
58
+ cos = ang.cos().to(torch.float32)[:, None, :]
59
+ sin = ang.sin().to(torch.float32)[:, None, :]
60
+ xf = x.float()
61
+ x1, x2 = xf[..., :half], xf[..., half:]
62
+ return torch.cat([x1 * cos - x2 * sin, x1 * sin + x2 * cos], dim=-1)
63
+
64
+
65
+ class DFlashRef:
66
+ """Reference drafter over an fp32 weight dict (layout as in
67
+ `random_weights`) with a sliding ring KV state."""
68
+
69
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cpu",
70
+ ring_dtype="fp32"):
71
+ self.cfg = cfg
72
+ self.w = {k: v.to(device=device, dtype=torch.float32)
73
+ for k, v in weights.items()}
74
+ self.device = torch.device(device)
75
+ C = cfg
76
+ # ring storage dtype; arithmetic stays fp32
77
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
78
+ else torch.float32)
79
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base, device)
80
+ # per-layer ring K/V [window, Hkv, D]; ring_pos = slot's position, -1 empty
81
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
82
+ device=device, dtype=self.ring_dt)
83
+ self.ring_v = torch.zeros_like(self.ring_k)
84
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int64,
85
+ device=device)
86
+
87
+ # ---- encoder --------------------------------------------------------
88
+ def encode(self, feats):
89
+ """Fuse per-position target features [T, n_feat] to g [T, n_embd]."""
90
+ g = feats.float() @ self.w["fc"]
91
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
92
+
93
+ # ---- KV injection ---------------------------------------------------
94
+ def inject(self, g, pos):
95
+ """Project fused features into every layer's ring at `pos` [T], chunked
96
+ at `window` so no two tokens in one pass share a slot."""
97
+ C = self.cfg
98
+ for beg in range(0, len(pos), C.window):
99
+ p = pos[beg:beg + C.window]
100
+ gc = g[beg:beg + C.window]
101
+ slots = p % C.window
102
+ for i in range(C.n_layer):
103
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv, C.head_dim)
104
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv, C.head_dim)
105
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
106
+ k = rope_neox(k, p, inv=self.rope_inv)
107
+ self.ring_k[i, slots] = k.to(self.ring_dt)
108
+ self.ring_v[i, slots] = v.to(self.ring_dt)
109
+ self.ring_pos[slots] = p
110
+
111
+ # ---- noise-block forward -------------------------------------------
112
+ def block_step(self, id_last, n_past, n_draft=None):
113
+ """Denoise [id_last, mask x n_draft] at n_past..; -> [n_draft+1, n_vocab]."""
114
+ C = self.cfg
115
+ if n_draft is None:
116
+ n_draft = C.block_size - 1
117
+ B = n_draft + 1
118
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
119
+ device=self.device)
120
+ tokens[0] = id_last
121
+ pos = n_past + torch.arange(B, device=self.device)
122
+ x = self.w["tok_embd"][tokens]
123
+
124
+ live = self.ring_pos >= 0
125
+ for i in range(C.n_layer):
126
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps)
127
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head, C.head_dim)
128
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv, C.head_dim)
129
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv, C.head_dim)
130
+ q = rms_norm(q, self.w[f"q_norm.{i}"], C.rms_eps)
131
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
132
+ q = rope_neox(q, pos, inv=self.rope_inv)
133
+ k = rope_neox(k, pos, inv=self.rope_inv)
134
+
135
+ # keys = live ring + block; non-causal, SWA masks only the deep past
136
+ keys = torch.cat([self.ring_k[i, live].float(), k], dim=0)
137
+ vals = torch.cat([self.ring_v[i, live].float(), v], dim=0)
138
+ kpos = torch.cat([self.ring_pos[live], pos], dim=0)
139
+
140
+ gq = C.n_head // C.n_head_kv
141
+ qh = q.permute(1, 0, 2) # [H, B, D]
142
+ kh = keys.permute(1, 0, 2).repeat_interleave(gq, dim=0)
143
+ vh = vals.permute(1, 0, 2).repeat_interleave(gq, dim=0)
144
+ att = qh @ kh.transpose(1, 2) / (C.head_dim ** 0.5) # [H, B, S]
145
+ masked = (pos[:, None] - kpos[None, :]) >= C.window # SWA
146
+ att = att.masked_fill(masked[None, :, :], float("-inf"))
147
+ att = att.softmax(dim=-1)
148
+ out = (att @ vh).permute(1, 0, 2).reshape(B, -1) # [B, H*D]
149
+ x = x + out @ self.w[f"wo.{i}"]
150
+
151
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps)
152
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
153
+ x = x + (gate * (f @ self.w[f"ffn_up.{i}"])) @ self.w[f"ffn_down.{i}"]
154
+
155
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
156
+ return x @ self.w["lm_head"]
157
+
158
+ def draft_greedy(self, id_last, n_past, n_draft=None):
159
+ """Greedy drafts from block positions 1..n_draft (position 0 unused)."""
160
+ logits = self.block_step(id_last, n_past, n_draft)
161
+ return logits[1:].argmax(dim=-1)
162
+
163
+
164
+ def random_weights(cfg: DFlashConfig, seed=0, device="cpu"):
165
+ """Gaussian weights at transformer-typical scale, for structural tests."""
166
+ g = torch.Generator(device="cpu").manual_seed(seed)
167
+
168
+ def t(*shape, s=0.02):
169
+ return torch.randn(*shape, generator=g) * s
170
+
171
+ C = cfg
172
+ w = {"fc": t(C.n_feat, C.n_embd), "enc_norm": torch.ones(C.n_embd),
173
+ "out_norm": torch.ones(C.n_embd),
174
+ "tok_embd": t(C.n_vocab, C.n_embd),
175
+ "lm_head": t(C.n_embd, C.n_vocab)}
176
+ for i in range(C.n_layer):
177
+ w[f"attn_norm.{i}"] = torch.ones(C.n_embd)
178
+ w[f"wq.{i}"] = t(C.n_embd, C.n_head * C.head_dim)
179
+ w[f"wk.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
180
+ w[f"wv.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
181
+ w[f"wo.{i}"] = t(C.n_head * C.head_dim, C.n_embd)
182
+ w[f"q_norm.{i}"] = torch.ones(C.head_dim)
183
+ w[f"k_norm.{i}"] = torch.ones(C.head_dim)
184
+ w[f"ffn_norm.{i}"] = torch.ones(C.n_embd)
185
+ w[f"ffn_gate.{i}"] = t(C.n_embd, C.n_ff)
186
+ w[f"ffn_up.{i}"] = t(C.n_embd, C.n_ff)
187
+ w[f"ffn_down.{i}"] = t(C.n_ff, C.n_embd)
188
+ return {k: v.to(device) for k, v in w.items()}
build/torch212-cxx11-cu130-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DFlash block-diffusion drafter ops; the eager reference defines the
2
+ semantics and the CUDA ops are certified against it."""
3
+ from .reference import DFlashConfig, DFlashRef, random_weights # noqa: F401
4
+ from .drafter import DFlashDrafter # noqa: F401
5
+
6
+ try: # built variants ship _ops
7
+ from ._ops import ops # noqa: F401
8
+ except ImportError:
9
+ try: # a local JIT build registers the same ops under torch.ops.dflash_ext
10
+ import torch as _torch
11
+
12
+ _torch.ops.dflash_ext.dflash_accept
13
+ ops = _torch.ops.dflash_ext
14
+ except Exception:
15
+ ops = None
16
+
17
+ try:
18
+ from .gguf_io import load_drafter # noqa: F401
19
+ except ImportError: # gguf-py absent; the reference stays usable
20
+ load_drafter = None
21
+
22
+ __all__ = ["DFlashConfig", "DFlashRef", "DFlashDrafter", "random_weights",
23
+ "load_drafter", "ops"]
build/torch212-cxx11-cu130-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2f92dc3409c1896355af5a96649ff74e918c3d460ea0ea7c73080bd121e75085
3
+ size 1402256
build/torch212-cxx11-cu130-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _dflash_ops_cuda_03c9586
3
+ ops = torch.ops._dflash_ops_cuda_03c9586
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_dflash_ops_cuda_03c9586::{op_name}"
build/torch212-cxx11-cu130-x86_64-linux/drafter.py ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """GPU DFlash drafter: cuBLAS GEMMs plus the fused ops, with a CUDA-graphed
2
+ block step."""
3
+ import torch
4
+
5
+ from .reference import DFlashConfig, rms_norm, rope_inv_freq
6
+
7
+
8
+ def _ops():
9
+ from . import ops
10
+ if ops is None:
11
+ raise RuntimeError(
12
+ "dflash-ops compiled kernels are unavailable; build them with "
13
+ "load_local.load() in a source checkout, or install a published "
14
+ "variant with kernels.get_kernel")
15
+ return ops
16
+
17
+
18
+ class DFlashDrafter:
19
+ """Ring-cached DFlash drafter on CUDA. Weight keys match `DFlashRef`."""
20
+
21
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cuda",
22
+ ring_dtype="fp32", dtype="fp32"):
23
+ self.cfg = cfg
24
+ self.device = torch.device(device)
25
+ # dtype sets GEMM weights and activations; residual, norms, softmax stay fp32
26
+ self.wdt = torch.bfloat16 if dtype == "bf16" else torch.float32
27
+ self.w = {}
28
+ for k, v in weights.items():
29
+ dt = self.wdt if v.dim() == 2 else torch.float32
30
+ self.w[k] = v.to(device=self.device, dtype=dt).contiguous()
31
+ C = cfg
32
+ # ring storage dtype; arithmetic stays fp32
33
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
34
+ else torch.float32)
35
+ # host-built fp64 rope table, shared by every op call
36
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base,
37
+ self.device).contiguous()
38
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
39
+ device=self.device, dtype=self.ring_dt)
40
+ self.ring_v = torch.zeros_like(self.ring_k)
41
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int32,
42
+ device=self.device)
43
+
44
+ # ---- encoder --------------------------------------------------------
45
+ def encode(self, feats):
46
+ g = (feats.to(self.device, self.wdt) @ self.w["fc"]).float()
47
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
48
+
49
+ # ---- KV injection ---------------------------------------------------
50
+ def inject(self, g, pos):
51
+ """Ring injection at `pos`, chunked at `window` so no slot is written twice per launch."""
52
+ C = self.cfg
53
+ o = _ops()
54
+ pos = pos.to(self.device, torch.int32).contiguous()
55
+ for beg in range(0, pos.numel(), C.window):
56
+ p = pos[beg:beg + C.window].contiguous()
57
+ gc = g[beg:beg + C.window].to(self.wdt)
58
+ for i in range(C.n_layer):
59
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv,
60
+ C.head_dim).contiguous()
61
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv,
62
+ C.head_dim).contiguous()
63
+ o.dflash_inject(self.ring_k[i], self.ring_v[i], self.ring_pos,
64
+ k, v, self.w[f"k_norm.{i}"], self.rope_inv, p,
65
+ C.rms_eps)
66
+
67
+ # ---- noise-block forward -------------------------------------------
68
+ def block_step(self, id_last, n_past, n_draft=None):
69
+ C = self.cfg
70
+ if n_draft is None:
71
+ n_draft = C.block_size - 1
72
+ B = n_draft + 1
73
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
74
+ device=self.device)
75
+ tokens[0] = int(id_last)
76
+ bpos = (n_past + torch.arange(B, device=self.device)).to(torch.int32)
77
+ return self._forward(tokens, bpos.contiguous())
78
+
79
+ def _forward(self, tokens, bpos):
80
+ """Block forward on caller-owned device tensors; reads no host state."""
81
+ C = self.cfg
82
+ o = _ops()
83
+ B = tokens.numel()
84
+ x = self.w["tok_embd"][tokens].float()
85
+ scale = C.head_dim ** -0.5
86
+
87
+ for i in range(C.n_layer):
88
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps).to(self.wdt)
89
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head,
90
+ C.head_dim).contiguous()
91
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv,
92
+ C.head_dim).contiguous()
93
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv,
94
+ C.head_dim).contiguous()
95
+ o.dflash_qk_rope(q, k, self.w[f"q_norm.{i}"],
96
+ self.w[f"k_norm.{i}"], self.rope_inv, bpos,
97
+ C.rms_eps)
98
+ att = torch.empty_like(q)
99
+ o.dflash_block_attn(att, q, k, v, self.ring_k[i], self.ring_v[i],
100
+ self.ring_pos, bpos, scale)
101
+ x = x + (att.reshape(B, -1) @ self.w[f"wo.{i}"]).float()
102
+
103
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps).to(self.wdt)
104
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
105
+ x = x + ((gate * (f @ self.w[f"ffn_up.{i}"]))
106
+ @ self.w[f"ffn_down.{i}"]).float()
107
+
108
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
109
+ return (x.to(self.wdt) @ self.w["lm_head"]).float()
110
+
111
+ def draft_greedy(self, id_last, n_past, n_draft=None):
112
+ return self.block_step(id_last, n_past, n_draft)[1:].argmax(dim=-1)
113
+
114
+ # ---- graphed step ---------------------------------------------------
115
+ def _static_buffers(self, B):
116
+ """Every tensor a captured step touches, allocated once and held."""
117
+ C = self.cfg
118
+ d = self.device
119
+ wdt = self.wdt
120
+ s = {
121
+ "tokens": torch.full((B,), C.mask_token_id, dtype=torch.int64,
122
+ device=d),
123
+ "arange": torch.arange(B, dtype=torch.int32, device=d),
124
+ "n_past": torch.zeros((), dtype=torch.int32, device=d),
125
+ "bpos": torch.empty(B, dtype=torch.int32, device=d),
126
+ "xw": torch.empty(B, C.n_embd, dtype=wdt, device=d),
127
+ "x": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
128
+ "sq": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
129
+ "ms": torch.empty(B, 1, dtype=torch.float32, device=d),
130
+ "hn": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
131
+ "h": torch.empty(B, C.n_embd, dtype=wdt, device=d),
132
+ "q": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
133
+ "k": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
134
+ "v": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
135
+ "att": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
136
+ "ao": torch.empty(B, C.n_embd, dtype=wdt, device=d),
137
+ "g1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
138
+ "sg": torch.empty(B, C.n_ff, dtype=wdt, device=d),
139
+ "u1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
140
+ "d1": torch.empty(B, C.n_embd, dtype=wdt, device=d),
141
+ "lg": torch.empty(B, C.n_vocab, dtype=wdt, device=d),
142
+ "logits": torch.empty(B, C.n_vocab, dtype=torch.float32,
143
+ device=d),
144
+ }
145
+ return s
146
+
147
+ def _rms_static(self, src, w, s, out):
148
+ """RMS norm of `src` into `out` using only held buffers."""
149
+ torch.pow(src, 2, out=s["sq"])
150
+ torch.mean(s["sq"], -1, keepdim=True, out=s["ms"])
151
+ s["ms"].add_(self.cfg.rms_eps).rsqrt_()
152
+ torch.mul(src, s["ms"], out=out)
153
+ out.mul_(w)
154
+
155
+ def _forward_static(self, s):
156
+ """Allocation-free block forward into held buffers; numerically
157
+ identical to `_forward`."""
158
+ C = self.cfg
159
+ o = _ops()
160
+ B = s["tokens"].numel()
161
+ scale = C.head_dim ** -0.5
162
+ torch.index_select(self.w["tok_embd"], 0, s["tokens"], out=s["xw"])
163
+ s["x"].copy_(s["xw"])
164
+ for i in range(C.n_layer):
165
+ self._rms_static(s["x"], self.w[f"attn_norm.{i}"], s, s["hn"])
166
+ s["h"].copy_(s["hn"])
167
+ torch.matmul(s["h"], self.w[f"wq.{i}"], out=s["q"])
168
+ torch.matmul(s["h"], self.w[f"wk.{i}"], out=s["k"])
169
+ torch.matmul(s["h"], self.w[f"wv.{i}"], out=s["v"])
170
+ qv = s["q"].view(B, C.n_head, C.head_dim)
171
+ kv_ = s["k"].view(B, C.n_head_kv, C.head_dim)
172
+ vv = s["v"].view(B, C.n_head_kv, C.head_dim)
173
+ o.dflash_qk_rope(qv, kv_, self.w[f"q_norm.{i}"],
174
+ self.w[f"k_norm.{i}"], self.rope_inv, s["bpos"],
175
+ C.rms_eps)
176
+ av = s["att"].view(B, C.n_head, C.head_dim)
177
+ o.dflash_block_attn(av, qv, kv_, vv, self.ring_k[i],
178
+ self.ring_v[i], self.ring_pos, s["bpos"],
179
+ scale)
180
+ torch.matmul(s["att"], self.w[f"wo.{i}"], out=s["ao"])
181
+ s["x"].add_(s["ao"])
182
+ self._rms_static(s["x"], self.w[f"ffn_norm.{i}"], s, s["hn"])
183
+ s["h"].copy_(s["hn"])
184
+ torch.matmul(s["h"], self.w[f"ffn_gate.{i}"], out=s["g1"])
185
+ # fused silu keeps the step bitwise-equal to the eager path
186
+ torch.ops.aten.silu.out(s["g1"], out=s["sg"])
187
+ torch.matmul(s["h"], self.w[f"ffn_up.{i}"], out=s["u1"])
188
+ s["sg"].mul_(s["u1"])
189
+ torch.matmul(s["sg"], self.w[f"ffn_down.{i}"], out=s["d1"])
190
+ s["x"].add_(s["d1"])
191
+ self._rms_static(s["x"], self.w["out_norm"], s, s["hn"])
192
+ s["h"].copy_(s["hn"])
193
+ torch.matmul(s["h"], self.w["lm_head"], out=s["lg"])
194
+ s["logits"].copy_(s["lg"])
195
+ return s["logits"]
196
+
197
+ def capture_step(self, n_draft=None):
198
+ """Graph-captured block step over static buffers (the region allocates
199
+ nothing); returns step(id_last, n_past) -> logits, overwritten per replay."""
200
+ C = self.cfg
201
+ if n_draft is None:
202
+ n_draft = C.block_size - 1
203
+ s = self._static_buffers(n_draft + 1)
204
+
205
+ stream = torch.cuda.Stream(device=self.device)
206
+ stream.wait_stream(torch.cuda.current_stream())
207
+ with torch.cuda.stream(stream):
208
+ for _ in range(3): # warm kernels and cuBLAS
209
+ torch.add(s["arange"], s["n_past"], out=s["bpos"])
210
+ self._forward_static(s)
211
+ torch.cuda.current_stream().wait_stream(stream)
212
+ torch.cuda.synchronize()
213
+
214
+ graph = torch.cuda.CUDAGraph()
215
+ with torch.cuda.graph(graph):
216
+ torch.add(s["arange"], s["n_past"], out=s["bpos"]) # in-graph: replay sees updates
217
+ logits = self._forward_static(s)
218
+
219
+ def step(id_last, n_past):
220
+ s["tokens"][0].fill_(int(id_last))
221
+ s["n_past"].fill_(int(n_past))
222
+ graph.replay()
223
+ return logits
224
+
225
+ step.graph = graph
226
+ step.buffers = s
227
+ return step
228
+
229
+ # ---- verification ---------------------------------------------------
230
+ def accept(self, draft, target):
231
+ """Leading agreement count, device-side."""
232
+ o = _ops()
233
+ n = torch.zeros(1, dtype=torch.int32, device=self.device)
234
+ o.dflash_accept(n, draft.to(torch.int32).contiguous(),
235
+ target.to(torch.int32).contiguous())
236
+ return n
build/torch212-cxx11-cu130-x86_64-linux/gguf_io.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Load the DFlash drafter GGUF into reference-layout fp32 tensors; 2-D weights
2
+ transpose from GGUF [out, in] to [in, out]; tok_embd and lm_head are the
3
+ caller's (they belong to the target model)."""
4
+ import numpy as np
5
+ import torch
6
+ from gguf import GGUFReader
7
+ from gguf import quants as gq
8
+
9
+ from .reference import DFlashConfig
10
+
11
+ _BLK = {
12
+ "attn_norm": "attn_norm", "attn_q": "wq", "attn_k": "wk", "attn_v": "wv",
13
+ "attn_output": "wo", "attn_q_norm": "q_norm", "attn_k_norm": "k_norm",
14
+ "ffn_norm": "ffn_norm", "ffn_gate": "ffn_gate", "ffn_up": "ffn_up",
15
+ "ffn_down": "ffn_down",
16
+ }
17
+ _TOP = {"fc": "fc", "enc.output_norm": "enc_norm", "output_norm": "out_norm"}
18
+
19
+
20
+ def _field(reader, key, default=None):
21
+ f = reader.get_field(key)
22
+ if f is None:
23
+ return default
24
+ v = f.contents()
25
+ return v
26
+
27
+
28
+ def load_drafter(path):
29
+ """-> (DFlashConfig, weights dict) with fp32 tensors in reference layout."""
30
+ r = GGUFReader(str(path))
31
+ cfg = DFlashConfig(
32
+ n_layer=int(_field(r, "dflash.block_count")),
33
+ n_embd=int(_field(r, "dflash.embedding_length")),
34
+ n_head=int(_field(r, "dflash.attention.head_count")),
35
+ n_head_kv=int(_field(r, "dflash.attention.head_count_kv")),
36
+ head_dim=int(_field(r, "dflash.attention.key_length")),
37
+ n_ff=int(_field(r, "dflash.feed_forward_length")),
38
+ rope_base=float(_field(r, "dflash.rope.freq_base")),
39
+ rms_eps=float(_field(r, "dflash.attention.layer_norm_rms_epsilon")),
40
+ window=int(_field(r, "dflash.attention.sliding_window")),
41
+ block_size=int(_field(r, "dflash.block_size")),
42
+ target_layers=tuple(_field(r, "dflash.target_layers")),
43
+ )
44
+ w = {}
45
+ for t in r.tensors:
46
+ name = t.name
47
+ assert name.endswith(".weight"), name
48
+ base = name[: -len(".weight")]
49
+ if base.startswith("blk."):
50
+ _, idx, part = base.split(".", 2)
51
+ key = f"{_BLK[part]}.{idx}"
52
+ else:
53
+ key = _TOP[base]
54
+ data = gq.dequantize(t.data, t.tensor_type)
55
+ arr = torch.from_numpy(np.ascontiguousarray(data)).float()
56
+ if arr.dim() == 2:
57
+ arr = arr.t().contiguous()
58
+ w[key] = arr
59
+ expect = 3 + 11 * cfg.n_layer
60
+ assert len(w) == expect, (len(w), expect)
61
+ return cfg, w
build/torch212-cxx11-cu130-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "dflash-ops",
3
+ "id": "_dflash_ops_cuda_03c9586",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "kernel-depends": [],
8
+ "backend": {
9
+ "type": "cuda",
10
+ "archs": [
11
+ "10.0",
12
+ "12.0",
13
+ "8.0",
14
+ "8.6",
15
+ "8.9",
16
+ "9.0"
17
+ ]
18
+ },
19
+ "digest": {
20
+ "algorithm": "sha256",
21
+ "files": {
22
+ "__init__.py": "wNpuIbQEXTfFNjrmz6aISM46VFgMKAHkqqu+ECJJS20=",
23
+ "_dflash_ops_cuda_03c9586.abi3.so": "L5LcNAnBiWNVr1qWZJ/3TpGMPUYOoOp8cwgL0SHnUIU=",
24
+ "_ops.py": "+6e3Oo6lwRkZaeOrhSSZEwWYs4/Fpd/zQgJj4MVEi9I=",
25
+ "drafter.py": "wGU5TWlXWr/ZogxQr4pho5Wku66UUygnczpsTu82dls=",
26
+ "gguf_io.py": "XrgF2dH7LNR1KTNKKu/pKhh6wT90bCjcjCAgmyGsuZA=",
27
+ "reference.py": "InmFS9rUwURZ7ZGVUxwQJCCjJZR/hKWrF3eMfp4zQvY="
28
+ }
29
+ },
30
+ "provenance": {
31
+ "kernel-builder": {
32
+ "version": "0.17.0-dev0",
33
+ "sha": "2c40e10d3da1392245ee81bd05b55fb3103b2b34",
34
+ "dirty": false
35
+ },
36
+ "kernel": {
37
+ "sha": "03c9586154cc2afa6efaa7b111dccef715ec9d69",
38
+ "dirty": false
39
+ }
40
+ }
41
+ }
build/torch212-cxx11-cu130-x86_64-linux/reference.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Eager fp32 DFlash drafter reference, transcribed from llama.cpp's
2
+ llama_model_dflash graph; the CUDA ops are certified against this module."""
3
+ from dataclasses import dataclass, field
4
+
5
+ import torch
6
+
7
+
8
+ @dataclass
9
+ class DFlashConfig:
10
+ n_layer: int = 5
11
+ n_embd: int = 6656
12
+ n_head: int = 32
13
+ n_head_kv: int = 8
14
+ head_dim: int = 128
15
+ n_ff: int = 19968
16
+ n_vocab: int = 202048
17
+ rope_base: float = 500000.0
18
+ rms_eps: float = 1e-6
19
+ window: int = 2048 # SWA width; also the ring capacity
20
+ block_size: int = 16
21
+ mask_token_id: int = 201818
22
+ target_layers: tuple = (2, 14, 26, 38, 50)
23
+
24
+ @property
25
+ def n_feat(self):
26
+ return len(self.target_layers) * self.n_embd
27
+
28
+ @classmethod
29
+ def tiny(cls):
30
+ """Toy sizes with the real structure; head_dim stays a multiple of 32."""
31
+ return cls(n_layer=2, n_embd=64, n_head=4, n_head_kv=2, head_dim=32,
32
+ n_ff=96, n_vocab=997, window=32, block_size=8,
33
+ mask_token_id=990, target_layers=(1, 2))
34
+
35
+
36
+ def rms_norm(x, w, eps):
37
+ """llama.cpp LLM_NORM_RMS: x * w / sqrt(mean(x^2) + eps), fp32."""
38
+ v = x.float()
39
+ return (v * torch.rsqrt(v.pow(2).mean(-1, keepdim=True) + eps)) * w.float()
40
+
41
+
42
+ def rope_inv_freq(head_dim, base, device="cpu"):
43
+ """fp64 NEOX inverse frequencies base^(-2i/head_dim), host-evaluated so the
44
+ table is device-invariant."""
45
+ half = head_dim // 2
46
+ t = base ** (-torch.arange(half, dtype=torch.float64) * 2.0 / head_dim)
47
+ return t.to(device)
48
+
49
+
50
+ def rope_neox(x, pos, base=None, inv=None):
51
+ """NEOX rope over pairs (i, i + d/2), fp32; x [T, H, D], pos [T]; pass
52
+ `inv` to reuse a precomputed table."""
53
+ T, H, D = x.shape
54
+ half = D // 2
55
+ if inv is None:
56
+ inv = rope_inv_freq(D, base, x.device)
57
+ ang = pos.to(torch.float64)[:, None] * inv[None, :] # [T, half]
58
+ cos = ang.cos().to(torch.float32)[:, None, :]
59
+ sin = ang.sin().to(torch.float32)[:, None, :]
60
+ xf = x.float()
61
+ x1, x2 = xf[..., :half], xf[..., half:]
62
+ return torch.cat([x1 * cos - x2 * sin, x1 * sin + x2 * cos], dim=-1)
63
+
64
+
65
+ class DFlashRef:
66
+ """Reference drafter over an fp32 weight dict (layout as in
67
+ `random_weights`) with a sliding ring KV state."""
68
+
69
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cpu",
70
+ ring_dtype="fp32"):
71
+ self.cfg = cfg
72
+ self.w = {k: v.to(device=device, dtype=torch.float32)
73
+ for k, v in weights.items()}
74
+ self.device = torch.device(device)
75
+ C = cfg
76
+ # ring storage dtype; arithmetic stays fp32
77
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
78
+ else torch.float32)
79
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base, device)
80
+ # per-layer ring K/V [window, Hkv, D]; ring_pos = slot's position, -1 empty
81
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
82
+ device=device, dtype=self.ring_dt)
83
+ self.ring_v = torch.zeros_like(self.ring_k)
84
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int64,
85
+ device=device)
86
+
87
+ # ---- encoder --------------------------------------------------------
88
+ def encode(self, feats):
89
+ """Fuse per-position target features [T, n_feat] to g [T, n_embd]."""
90
+ g = feats.float() @ self.w["fc"]
91
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
92
+
93
+ # ---- KV injection ---------------------------------------------------
94
+ def inject(self, g, pos):
95
+ """Project fused features into every layer's ring at `pos` [T], chunked
96
+ at `window` so no two tokens in one pass share a slot."""
97
+ C = self.cfg
98
+ for beg in range(0, len(pos), C.window):
99
+ p = pos[beg:beg + C.window]
100
+ gc = g[beg:beg + C.window]
101
+ slots = p % C.window
102
+ for i in range(C.n_layer):
103
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv, C.head_dim)
104
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv, C.head_dim)
105
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
106
+ k = rope_neox(k, p, inv=self.rope_inv)
107
+ self.ring_k[i, slots] = k.to(self.ring_dt)
108
+ self.ring_v[i, slots] = v.to(self.ring_dt)
109
+ self.ring_pos[slots] = p
110
+
111
+ # ---- noise-block forward -------------------------------------------
112
+ def block_step(self, id_last, n_past, n_draft=None):
113
+ """Denoise [id_last, mask x n_draft] at n_past..; -> [n_draft+1, n_vocab]."""
114
+ C = self.cfg
115
+ if n_draft is None:
116
+ n_draft = C.block_size - 1
117
+ B = n_draft + 1
118
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
119
+ device=self.device)
120
+ tokens[0] = id_last
121
+ pos = n_past + torch.arange(B, device=self.device)
122
+ x = self.w["tok_embd"][tokens]
123
+
124
+ live = self.ring_pos >= 0
125
+ for i in range(C.n_layer):
126
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps)
127
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head, C.head_dim)
128
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv, C.head_dim)
129
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv, C.head_dim)
130
+ q = rms_norm(q, self.w[f"q_norm.{i}"], C.rms_eps)
131
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
132
+ q = rope_neox(q, pos, inv=self.rope_inv)
133
+ k = rope_neox(k, pos, inv=self.rope_inv)
134
+
135
+ # keys = live ring + block; non-causal, SWA masks only the deep past
136
+ keys = torch.cat([self.ring_k[i, live].float(), k], dim=0)
137
+ vals = torch.cat([self.ring_v[i, live].float(), v], dim=0)
138
+ kpos = torch.cat([self.ring_pos[live], pos], dim=0)
139
+
140
+ gq = C.n_head // C.n_head_kv
141
+ qh = q.permute(1, 0, 2) # [H, B, D]
142
+ kh = keys.permute(1, 0, 2).repeat_interleave(gq, dim=0)
143
+ vh = vals.permute(1, 0, 2).repeat_interleave(gq, dim=0)
144
+ att = qh @ kh.transpose(1, 2) / (C.head_dim ** 0.5) # [H, B, S]
145
+ masked = (pos[:, None] - kpos[None, :]) >= C.window # SWA
146
+ att = att.masked_fill(masked[None, :, :], float("-inf"))
147
+ att = att.softmax(dim=-1)
148
+ out = (att @ vh).permute(1, 0, 2).reshape(B, -1) # [B, H*D]
149
+ x = x + out @ self.w[f"wo.{i}"]
150
+
151
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps)
152
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
153
+ x = x + (gate * (f @ self.w[f"ffn_up.{i}"])) @ self.w[f"ffn_down.{i}"]
154
+
155
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
156
+ return x @ self.w["lm_head"]
157
+
158
+ def draft_greedy(self, id_last, n_past, n_draft=None):
159
+ """Greedy drafts from block positions 1..n_draft (position 0 unused)."""
160
+ logits = self.block_step(id_last, n_past, n_draft)
161
+ return logits[1:].argmax(dim=-1)
162
+
163
+
164
+ def random_weights(cfg: DFlashConfig, seed=0, device="cpu"):
165
+ """Gaussian weights at transformer-typical scale, for structural tests."""
166
+ g = torch.Generator(device="cpu").manual_seed(seed)
167
+
168
+ def t(*shape, s=0.02):
169
+ return torch.randn(*shape, generator=g) * s
170
+
171
+ C = cfg
172
+ w = {"fc": t(C.n_feat, C.n_embd), "enc_norm": torch.ones(C.n_embd),
173
+ "out_norm": torch.ones(C.n_embd),
174
+ "tok_embd": t(C.n_vocab, C.n_embd),
175
+ "lm_head": t(C.n_embd, C.n_vocab)}
176
+ for i in range(C.n_layer):
177
+ w[f"attn_norm.{i}"] = torch.ones(C.n_embd)
178
+ w[f"wq.{i}"] = t(C.n_embd, C.n_head * C.head_dim)
179
+ w[f"wk.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
180
+ w[f"wv.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
181
+ w[f"wo.{i}"] = t(C.n_head * C.head_dim, C.n_embd)
182
+ w[f"q_norm.{i}"] = torch.ones(C.head_dim)
183
+ w[f"k_norm.{i}"] = torch.ones(C.head_dim)
184
+ w[f"ffn_norm.{i}"] = torch.ones(C.n_embd)
185
+ w[f"ffn_gate.{i}"] = t(C.n_embd, C.n_ff)
186
+ w[f"ffn_up.{i}"] = t(C.n_embd, C.n_ff)
187
+ w[f"ffn_down.{i}"] = t(C.n_ff, C.n_embd)
188
+ return {k: v.to(device) for k, v in w.items()}
build/torch212-cxx11-cu132-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DFlash block-diffusion drafter ops; the eager reference defines the
2
+ semantics and the CUDA ops are certified against it."""
3
+ from .reference import DFlashConfig, DFlashRef, random_weights # noqa: F401
4
+ from .drafter import DFlashDrafter # noqa: F401
5
+
6
+ try: # built variants ship _ops
7
+ from ._ops import ops # noqa: F401
8
+ except ImportError:
9
+ try: # a local JIT build registers the same ops under torch.ops.dflash_ext
10
+ import torch as _torch
11
+
12
+ _torch.ops.dflash_ext.dflash_accept
13
+ ops = _torch.ops.dflash_ext
14
+ except Exception:
15
+ ops = None
16
+
17
+ try:
18
+ from .gguf_io import load_drafter # noqa: F401
19
+ except ImportError: # gguf-py absent; the reference stays usable
20
+ load_drafter = None
21
+
22
+ __all__ = ["DFlashConfig", "DFlashRef", "DFlashDrafter", "random_weights",
23
+ "load_drafter", "ops"]
build/torch212-cxx11-cu132-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cd91be1764fb31dd2579c7f2e9f079227873de5405a162b14324ad4b35cc1f35
3
+ size 1402256
build/torch212-cxx11-cu132-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _dflash_ops_cuda_03c9586
3
+ ops = torch.ops._dflash_ops_cuda_03c9586
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_dflash_ops_cuda_03c9586::{op_name}"
build/torch212-cxx11-cu132-x86_64-linux/drafter.py ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """GPU DFlash drafter: cuBLAS GEMMs plus the fused ops, with a CUDA-graphed
2
+ block step."""
3
+ import torch
4
+
5
+ from .reference import DFlashConfig, rms_norm, rope_inv_freq
6
+
7
+
8
+ def _ops():
9
+ from . import ops
10
+ if ops is None:
11
+ raise RuntimeError(
12
+ "dflash-ops compiled kernels are unavailable; build them with "
13
+ "load_local.load() in a source checkout, or install a published "
14
+ "variant with kernels.get_kernel")
15
+ return ops
16
+
17
+
18
+ class DFlashDrafter:
19
+ """Ring-cached DFlash drafter on CUDA. Weight keys match `DFlashRef`."""
20
+
21
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cuda",
22
+ ring_dtype="fp32", dtype="fp32"):
23
+ self.cfg = cfg
24
+ self.device = torch.device(device)
25
+ # dtype sets GEMM weights and activations; residual, norms, softmax stay fp32
26
+ self.wdt = torch.bfloat16 if dtype == "bf16" else torch.float32
27
+ self.w = {}
28
+ for k, v in weights.items():
29
+ dt = self.wdt if v.dim() == 2 else torch.float32
30
+ self.w[k] = v.to(device=self.device, dtype=dt).contiguous()
31
+ C = cfg
32
+ # ring storage dtype; arithmetic stays fp32
33
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
34
+ else torch.float32)
35
+ # host-built fp64 rope table, shared by every op call
36
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base,
37
+ self.device).contiguous()
38
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
39
+ device=self.device, dtype=self.ring_dt)
40
+ self.ring_v = torch.zeros_like(self.ring_k)
41
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int32,
42
+ device=self.device)
43
+
44
+ # ---- encoder --------------------------------------------------------
45
+ def encode(self, feats):
46
+ g = (feats.to(self.device, self.wdt) @ self.w["fc"]).float()
47
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
48
+
49
+ # ---- KV injection ---------------------------------------------------
50
+ def inject(self, g, pos):
51
+ """Ring injection at `pos`, chunked at `window` so no slot is written twice per launch."""
52
+ C = self.cfg
53
+ o = _ops()
54
+ pos = pos.to(self.device, torch.int32).contiguous()
55
+ for beg in range(0, pos.numel(), C.window):
56
+ p = pos[beg:beg + C.window].contiguous()
57
+ gc = g[beg:beg + C.window].to(self.wdt)
58
+ for i in range(C.n_layer):
59
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv,
60
+ C.head_dim).contiguous()
61
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv,
62
+ C.head_dim).contiguous()
63
+ o.dflash_inject(self.ring_k[i], self.ring_v[i], self.ring_pos,
64
+ k, v, self.w[f"k_norm.{i}"], self.rope_inv, p,
65
+ C.rms_eps)
66
+
67
+ # ---- noise-block forward -------------------------------------------
68
+ def block_step(self, id_last, n_past, n_draft=None):
69
+ C = self.cfg
70
+ if n_draft is None:
71
+ n_draft = C.block_size - 1
72
+ B = n_draft + 1
73
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
74
+ device=self.device)
75
+ tokens[0] = int(id_last)
76
+ bpos = (n_past + torch.arange(B, device=self.device)).to(torch.int32)
77
+ return self._forward(tokens, bpos.contiguous())
78
+
79
+ def _forward(self, tokens, bpos):
80
+ """Block forward on caller-owned device tensors; reads no host state."""
81
+ C = self.cfg
82
+ o = _ops()
83
+ B = tokens.numel()
84
+ x = self.w["tok_embd"][tokens].float()
85
+ scale = C.head_dim ** -0.5
86
+
87
+ for i in range(C.n_layer):
88
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps).to(self.wdt)
89
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head,
90
+ C.head_dim).contiguous()
91
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv,
92
+ C.head_dim).contiguous()
93
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv,
94
+ C.head_dim).contiguous()
95
+ o.dflash_qk_rope(q, k, self.w[f"q_norm.{i}"],
96
+ self.w[f"k_norm.{i}"], self.rope_inv, bpos,
97
+ C.rms_eps)
98
+ att = torch.empty_like(q)
99
+ o.dflash_block_attn(att, q, k, v, self.ring_k[i], self.ring_v[i],
100
+ self.ring_pos, bpos, scale)
101
+ x = x + (att.reshape(B, -1) @ self.w[f"wo.{i}"]).float()
102
+
103
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps).to(self.wdt)
104
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
105
+ x = x + ((gate * (f @ self.w[f"ffn_up.{i}"]))
106
+ @ self.w[f"ffn_down.{i}"]).float()
107
+
108
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
109
+ return (x.to(self.wdt) @ self.w["lm_head"]).float()
110
+
111
+ def draft_greedy(self, id_last, n_past, n_draft=None):
112
+ return self.block_step(id_last, n_past, n_draft)[1:].argmax(dim=-1)
113
+
114
+ # ---- graphed step ---------------------------------------------------
115
+ def _static_buffers(self, B):
116
+ """Every tensor a captured step touches, allocated once and held."""
117
+ C = self.cfg
118
+ d = self.device
119
+ wdt = self.wdt
120
+ s = {
121
+ "tokens": torch.full((B,), C.mask_token_id, dtype=torch.int64,
122
+ device=d),
123
+ "arange": torch.arange(B, dtype=torch.int32, device=d),
124
+ "n_past": torch.zeros((), dtype=torch.int32, device=d),
125
+ "bpos": torch.empty(B, dtype=torch.int32, device=d),
126
+ "xw": torch.empty(B, C.n_embd, dtype=wdt, device=d),
127
+ "x": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
128
+ "sq": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
129
+ "ms": torch.empty(B, 1, dtype=torch.float32, device=d),
130
+ "hn": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
131
+ "h": torch.empty(B, C.n_embd, dtype=wdt, device=d),
132
+ "q": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
133
+ "k": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
134
+ "v": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
135
+ "att": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
136
+ "ao": torch.empty(B, C.n_embd, dtype=wdt, device=d),
137
+ "g1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
138
+ "sg": torch.empty(B, C.n_ff, dtype=wdt, device=d),
139
+ "u1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
140
+ "d1": torch.empty(B, C.n_embd, dtype=wdt, device=d),
141
+ "lg": torch.empty(B, C.n_vocab, dtype=wdt, device=d),
142
+ "logits": torch.empty(B, C.n_vocab, dtype=torch.float32,
143
+ device=d),
144
+ }
145
+ return s
146
+
147
+ def _rms_static(self, src, w, s, out):
148
+ """RMS norm of `src` into `out` using only held buffers."""
149
+ torch.pow(src, 2, out=s["sq"])
150
+ torch.mean(s["sq"], -1, keepdim=True, out=s["ms"])
151
+ s["ms"].add_(self.cfg.rms_eps).rsqrt_()
152
+ torch.mul(src, s["ms"], out=out)
153
+ out.mul_(w)
154
+
155
+ def _forward_static(self, s):
156
+ """Allocation-free block forward into held buffers; numerically
157
+ identical to `_forward`."""
158
+ C = self.cfg
159
+ o = _ops()
160
+ B = s["tokens"].numel()
161
+ scale = C.head_dim ** -0.5
162
+ torch.index_select(self.w["tok_embd"], 0, s["tokens"], out=s["xw"])
163
+ s["x"].copy_(s["xw"])
164
+ for i in range(C.n_layer):
165
+ self._rms_static(s["x"], self.w[f"attn_norm.{i}"], s, s["hn"])
166
+ s["h"].copy_(s["hn"])
167
+ torch.matmul(s["h"], self.w[f"wq.{i}"], out=s["q"])
168
+ torch.matmul(s["h"], self.w[f"wk.{i}"], out=s["k"])
169
+ torch.matmul(s["h"], self.w[f"wv.{i}"], out=s["v"])
170
+ qv = s["q"].view(B, C.n_head, C.head_dim)
171
+ kv_ = s["k"].view(B, C.n_head_kv, C.head_dim)
172
+ vv = s["v"].view(B, C.n_head_kv, C.head_dim)
173
+ o.dflash_qk_rope(qv, kv_, self.w[f"q_norm.{i}"],
174
+ self.w[f"k_norm.{i}"], self.rope_inv, s["bpos"],
175
+ C.rms_eps)
176
+ av = s["att"].view(B, C.n_head, C.head_dim)
177
+ o.dflash_block_attn(av, qv, kv_, vv, self.ring_k[i],
178
+ self.ring_v[i], self.ring_pos, s["bpos"],
179
+ scale)
180
+ torch.matmul(s["att"], self.w[f"wo.{i}"], out=s["ao"])
181
+ s["x"].add_(s["ao"])
182
+ self._rms_static(s["x"], self.w[f"ffn_norm.{i}"], s, s["hn"])
183
+ s["h"].copy_(s["hn"])
184
+ torch.matmul(s["h"], self.w[f"ffn_gate.{i}"], out=s["g1"])
185
+ # fused silu keeps the step bitwise-equal to the eager path
186
+ torch.ops.aten.silu.out(s["g1"], out=s["sg"])
187
+ torch.matmul(s["h"], self.w[f"ffn_up.{i}"], out=s["u1"])
188
+ s["sg"].mul_(s["u1"])
189
+ torch.matmul(s["sg"], self.w[f"ffn_down.{i}"], out=s["d1"])
190
+ s["x"].add_(s["d1"])
191
+ self._rms_static(s["x"], self.w["out_norm"], s, s["hn"])
192
+ s["h"].copy_(s["hn"])
193
+ torch.matmul(s["h"], self.w["lm_head"], out=s["lg"])
194
+ s["logits"].copy_(s["lg"])
195
+ return s["logits"]
196
+
197
+ def capture_step(self, n_draft=None):
198
+ """Graph-captured block step over static buffers (the region allocates
199
+ nothing); returns step(id_last, n_past) -> logits, overwritten per replay."""
200
+ C = self.cfg
201
+ if n_draft is None:
202
+ n_draft = C.block_size - 1
203
+ s = self._static_buffers(n_draft + 1)
204
+
205
+ stream = torch.cuda.Stream(device=self.device)
206
+ stream.wait_stream(torch.cuda.current_stream())
207
+ with torch.cuda.stream(stream):
208
+ for _ in range(3): # warm kernels and cuBLAS
209
+ torch.add(s["arange"], s["n_past"], out=s["bpos"])
210
+ self._forward_static(s)
211
+ torch.cuda.current_stream().wait_stream(stream)
212
+ torch.cuda.synchronize()
213
+
214
+ graph = torch.cuda.CUDAGraph()
215
+ with torch.cuda.graph(graph):
216
+ torch.add(s["arange"], s["n_past"], out=s["bpos"]) # in-graph: replay sees updates
217
+ logits = self._forward_static(s)
218
+
219
+ def step(id_last, n_past):
220
+ s["tokens"][0].fill_(int(id_last))
221
+ s["n_past"].fill_(int(n_past))
222
+ graph.replay()
223
+ return logits
224
+
225
+ step.graph = graph
226
+ step.buffers = s
227
+ return step
228
+
229
+ # ---- verification ---------------------------------------------------
230
+ def accept(self, draft, target):
231
+ """Leading agreement count, device-side."""
232
+ o = _ops()
233
+ n = torch.zeros(1, dtype=torch.int32, device=self.device)
234
+ o.dflash_accept(n, draft.to(torch.int32).contiguous(),
235
+ target.to(torch.int32).contiguous())
236
+ return n
build/torch212-cxx11-cu132-x86_64-linux/gguf_io.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Load the DFlash drafter GGUF into reference-layout fp32 tensors; 2-D weights
2
+ transpose from GGUF [out, in] to [in, out]; tok_embd and lm_head are the
3
+ caller's (they belong to the target model)."""
4
+ import numpy as np
5
+ import torch
6
+ from gguf import GGUFReader
7
+ from gguf import quants as gq
8
+
9
+ from .reference import DFlashConfig
10
+
11
+ _BLK = {
12
+ "attn_norm": "attn_norm", "attn_q": "wq", "attn_k": "wk", "attn_v": "wv",
13
+ "attn_output": "wo", "attn_q_norm": "q_norm", "attn_k_norm": "k_norm",
14
+ "ffn_norm": "ffn_norm", "ffn_gate": "ffn_gate", "ffn_up": "ffn_up",
15
+ "ffn_down": "ffn_down",
16
+ }
17
+ _TOP = {"fc": "fc", "enc.output_norm": "enc_norm", "output_norm": "out_norm"}
18
+
19
+
20
+ def _field(reader, key, default=None):
21
+ f = reader.get_field(key)
22
+ if f is None:
23
+ return default
24
+ v = f.contents()
25
+ return v
26
+
27
+
28
+ def load_drafter(path):
29
+ """-> (DFlashConfig, weights dict) with fp32 tensors in reference layout."""
30
+ r = GGUFReader(str(path))
31
+ cfg = DFlashConfig(
32
+ n_layer=int(_field(r, "dflash.block_count")),
33
+ n_embd=int(_field(r, "dflash.embedding_length")),
34
+ n_head=int(_field(r, "dflash.attention.head_count")),
35
+ n_head_kv=int(_field(r, "dflash.attention.head_count_kv")),
36
+ head_dim=int(_field(r, "dflash.attention.key_length")),
37
+ n_ff=int(_field(r, "dflash.feed_forward_length")),
38
+ rope_base=float(_field(r, "dflash.rope.freq_base")),
39
+ rms_eps=float(_field(r, "dflash.attention.layer_norm_rms_epsilon")),
40
+ window=int(_field(r, "dflash.attention.sliding_window")),
41
+ block_size=int(_field(r, "dflash.block_size")),
42
+ target_layers=tuple(_field(r, "dflash.target_layers")),
43
+ )
44
+ w = {}
45
+ for t in r.tensors:
46
+ name = t.name
47
+ assert name.endswith(".weight"), name
48
+ base = name[: -len(".weight")]
49
+ if base.startswith("blk."):
50
+ _, idx, part = base.split(".", 2)
51
+ key = f"{_BLK[part]}.{idx}"
52
+ else:
53
+ key = _TOP[base]
54
+ data = gq.dequantize(t.data, t.tensor_type)
55
+ arr = torch.from_numpy(np.ascontiguousarray(data)).float()
56
+ if arr.dim() == 2:
57
+ arr = arr.t().contiguous()
58
+ w[key] = arr
59
+ expect = 3 + 11 * cfg.n_layer
60
+ assert len(w) == expect, (len(w), expect)
61
+ return cfg, w
build/torch212-cxx11-cu132-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "dflash-ops",
3
+ "id": "_dflash_ops_cuda_03c9586",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "kernel-depends": [],
8
+ "backend": {
9
+ "type": "cuda",
10
+ "archs": [
11
+ "10.0",
12
+ "12.0",
13
+ "8.0",
14
+ "8.6",
15
+ "8.9",
16
+ "9.0"
17
+ ]
18
+ },
19
+ "digest": {
20
+ "algorithm": "sha256",
21
+ "files": {
22
+ "__init__.py": "wNpuIbQEXTfFNjrmz6aISM46VFgMKAHkqqu+ECJJS20=",
23
+ "_dflash_ops_cuda_03c9586.abi3.so": "zZG+F2T7Md0lecfy6fB5Inhz3lQFoWKxQyStSzXMHzU=",
24
+ "_ops.py": "+6e3Oo6lwRkZaeOrhSSZEwWYs4/Fpd/zQgJj4MVEi9I=",
25
+ "drafter.py": "wGU5TWlXWr/ZogxQr4pho5Wku66UUygnczpsTu82dls=",
26
+ "gguf_io.py": "XrgF2dH7LNR1KTNKKu/pKhh6wT90bCjcjCAgmyGsuZA=",
27
+ "reference.py": "InmFS9rUwURZ7ZGVUxwQJCCjJZR/hKWrF3eMfp4zQvY="
28
+ }
29
+ },
30
+ "provenance": {
31
+ "kernel-builder": {
32
+ "version": "0.17.0-dev0",
33
+ "sha": "2c40e10d3da1392245ee81bd05b55fb3103b2b34",
34
+ "dirty": false
35
+ },
36
+ "kernel": {
37
+ "sha": "03c9586154cc2afa6efaa7b111dccef715ec9d69",
38
+ "dirty": false
39
+ }
40
+ }
41
+ }
build/torch212-cxx11-cu132-x86_64-linux/reference.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Eager fp32 DFlash drafter reference, transcribed from llama.cpp's
2
+ llama_model_dflash graph; the CUDA ops are certified against this module."""
3
+ from dataclasses import dataclass, field
4
+
5
+ import torch
6
+
7
+
8
+ @dataclass
9
+ class DFlashConfig:
10
+ n_layer: int = 5
11
+ n_embd: int = 6656
12
+ n_head: int = 32
13
+ n_head_kv: int = 8
14
+ head_dim: int = 128
15
+ n_ff: int = 19968
16
+ n_vocab: int = 202048
17
+ rope_base: float = 500000.0
18
+ rms_eps: float = 1e-6
19
+ window: int = 2048 # SWA width; also the ring capacity
20
+ block_size: int = 16
21
+ mask_token_id: int = 201818
22
+ target_layers: tuple = (2, 14, 26, 38, 50)
23
+
24
+ @property
25
+ def n_feat(self):
26
+ return len(self.target_layers) * self.n_embd
27
+
28
+ @classmethod
29
+ def tiny(cls):
30
+ """Toy sizes with the real structure; head_dim stays a multiple of 32."""
31
+ return cls(n_layer=2, n_embd=64, n_head=4, n_head_kv=2, head_dim=32,
32
+ n_ff=96, n_vocab=997, window=32, block_size=8,
33
+ mask_token_id=990, target_layers=(1, 2))
34
+
35
+
36
+ def rms_norm(x, w, eps):
37
+ """llama.cpp LLM_NORM_RMS: x * w / sqrt(mean(x^2) + eps), fp32."""
38
+ v = x.float()
39
+ return (v * torch.rsqrt(v.pow(2).mean(-1, keepdim=True) + eps)) * w.float()
40
+
41
+
42
+ def rope_inv_freq(head_dim, base, device="cpu"):
43
+ """fp64 NEOX inverse frequencies base^(-2i/head_dim), host-evaluated so the
44
+ table is device-invariant."""
45
+ half = head_dim // 2
46
+ t = base ** (-torch.arange(half, dtype=torch.float64) * 2.0 / head_dim)
47
+ return t.to(device)
48
+
49
+
50
+ def rope_neox(x, pos, base=None, inv=None):
51
+ """NEOX rope over pairs (i, i + d/2), fp32; x [T, H, D], pos [T]; pass
52
+ `inv` to reuse a precomputed table."""
53
+ T, H, D = x.shape
54
+ half = D // 2
55
+ if inv is None:
56
+ inv = rope_inv_freq(D, base, x.device)
57
+ ang = pos.to(torch.float64)[:, None] * inv[None, :] # [T, half]
58
+ cos = ang.cos().to(torch.float32)[:, None, :]
59
+ sin = ang.sin().to(torch.float32)[:, None, :]
60
+ xf = x.float()
61
+ x1, x2 = xf[..., :half], xf[..., half:]
62
+ return torch.cat([x1 * cos - x2 * sin, x1 * sin + x2 * cos], dim=-1)
63
+
64
+
65
+ class DFlashRef:
66
+ """Reference drafter over an fp32 weight dict (layout as in
67
+ `random_weights`) with a sliding ring KV state."""
68
+
69
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cpu",
70
+ ring_dtype="fp32"):
71
+ self.cfg = cfg
72
+ self.w = {k: v.to(device=device, dtype=torch.float32)
73
+ for k, v in weights.items()}
74
+ self.device = torch.device(device)
75
+ C = cfg
76
+ # ring storage dtype; arithmetic stays fp32
77
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
78
+ else torch.float32)
79
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base, device)
80
+ # per-layer ring K/V [window, Hkv, D]; ring_pos = slot's position, -1 empty
81
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
82
+ device=device, dtype=self.ring_dt)
83
+ self.ring_v = torch.zeros_like(self.ring_k)
84
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int64,
85
+ device=device)
86
+
87
+ # ---- encoder --------------------------------------------------------
88
+ def encode(self, feats):
89
+ """Fuse per-position target features [T, n_feat] to g [T, n_embd]."""
90
+ g = feats.float() @ self.w["fc"]
91
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
92
+
93
+ # ---- KV injection ---------------------------------------------------
94
+ def inject(self, g, pos):
95
+ """Project fused features into every layer's ring at `pos` [T], chunked
96
+ at `window` so no two tokens in one pass share a slot."""
97
+ C = self.cfg
98
+ for beg in range(0, len(pos), C.window):
99
+ p = pos[beg:beg + C.window]
100
+ gc = g[beg:beg + C.window]
101
+ slots = p % C.window
102
+ for i in range(C.n_layer):
103
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv, C.head_dim)
104
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv, C.head_dim)
105
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
106
+ k = rope_neox(k, p, inv=self.rope_inv)
107
+ self.ring_k[i, slots] = k.to(self.ring_dt)
108
+ self.ring_v[i, slots] = v.to(self.ring_dt)
109
+ self.ring_pos[slots] = p
110
+
111
+ # ---- noise-block forward -------------------------------------------
112
+ def block_step(self, id_last, n_past, n_draft=None):
113
+ """Denoise [id_last, mask x n_draft] at n_past..; -> [n_draft+1, n_vocab]."""
114
+ C = self.cfg
115
+ if n_draft is None:
116
+ n_draft = C.block_size - 1
117
+ B = n_draft + 1
118
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
119
+ device=self.device)
120
+ tokens[0] = id_last
121
+ pos = n_past + torch.arange(B, device=self.device)
122
+ x = self.w["tok_embd"][tokens]
123
+
124
+ live = self.ring_pos >= 0
125
+ for i in range(C.n_layer):
126
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps)
127
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head, C.head_dim)
128
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv, C.head_dim)
129
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv, C.head_dim)
130
+ q = rms_norm(q, self.w[f"q_norm.{i}"], C.rms_eps)
131
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
132
+ q = rope_neox(q, pos, inv=self.rope_inv)
133
+ k = rope_neox(k, pos, inv=self.rope_inv)
134
+
135
+ # keys = live ring + block; non-causal, SWA masks only the deep past
136
+ keys = torch.cat([self.ring_k[i, live].float(), k], dim=0)
137
+ vals = torch.cat([self.ring_v[i, live].float(), v], dim=0)
138
+ kpos = torch.cat([self.ring_pos[live], pos], dim=0)
139
+
140
+ gq = C.n_head // C.n_head_kv
141
+ qh = q.permute(1, 0, 2) # [H, B, D]
142
+ kh = keys.permute(1, 0, 2).repeat_interleave(gq, dim=0)
143
+ vh = vals.permute(1, 0, 2).repeat_interleave(gq, dim=0)
144
+ att = qh @ kh.transpose(1, 2) / (C.head_dim ** 0.5) # [H, B, S]
145
+ masked = (pos[:, None] - kpos[None, :]) >= C.window # SWA
146
+ att = att.masked_fill(masked[None, :, :], float("-inf"))
147
+ att = att.softmax(dim=-1)
148
+ out = (att @ vh).permute(1, 0, 2).reshape(B, -1) # [B, H*D]
149
+ x = x + out @ self.w[f"wo.{i}"]
150
+
151
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps)
152
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
153
+ x = x + (gate * (f @ self.w[f"ffn_up.{i}"])) @ self.w[f"ffn_down.{i}"]
154
+
155
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
156
+ return x @ self.w["lm_head"]
157
+
158
+ def draft_greedy(self, id_last, n_past, n_draft=None):
159
+ """Greedy drafts from block positions 1..n_draft (position 0 unused)."""
160
+ logits = self.block_step(id_last, n_past, n_draft)
161
+ return logits[1:].argmax(dim=-1)
162
+
163
+
164
+ def random_weights(cfg: DFlashConfig, seed=0, device="cpu"):
165
+ """Gaussian weights at transformer-typical scale, for structural tests."""
166
+ g = torch.Generator(device="cpu").manual_seed(seed)
167
+
168
+ def t(*shape, s=0.02):
169
+ return torch.randn(*shape, generator=g) * s
170
+
171
+ C = cfg
172
+ w = {"fc": t(C.n_feat, C.n_embd), "enc_norm": torch.ones(C.n_embd),
173
+ "out_norm": torch.ones(C.n_embd),
174
+ "tok_embd": t(C.n_vocab, C.n_embd),
175
+ "lm_head": t(C.n_embd, C.n_vocab)}
176
+ for i in range(C.n_layer):
177
+ w[f"attn_norm.{i}"] = torch.ones(C.n_embd)
178
+ w[f"wq.{i}"] = t(C.n_embd, C.n_head * C.head_dim)
179
+ w[f"wk.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
180
+ w[f"wv.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
181
+ w[f"wo.{i}"] = t(C.n_head * C.head_dim, C.n_embd)
182
+ w[f"q_norm.{i}"] = torch.ones(C.head_dim)
183
+ w[f"k_norm.{i}"] = torch.ones(C.head_dim)
184
+ w[f"ffn_norm.{i}"] = torch.ones(C.n_embd)
185
+ w[f"ffn_gate.{i}"] = t(C.n_embd, C.n_ff)
186
+ w[f"ffn_up.{i}"] = t(C.n_embd, C.n_ff)
187
+ w[f"ffn_down.{i}"] = t(C.n_ff, C.n_embd)
188
+ return {k: v.to(device) for k, v in w.items()}
build/torch213-cxx11-cu126-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DFlash block-diffusion drafter ops; the eager reference defines the
2
+ semantics and the CUDA ops are certified against it."""
3
+ from .reference import DFlashConfig, DFlashRef, random_weights # noqa: F401
4
+ from .drafter import DFlashDrafter # noqa: F401
5
+
6
+ try: # built variants ship _ops
7
+ from ._ops import ops # noqa: F401
8
+ except ImportError:
9
+ try: # a local JIT build registers the same ops under torch.ops.dflash_ext
10
+ import torch as _torch
11
+
12
+ _torch.ops.dflash_ext.dflash_accept
13
+ ops = _torch.ops.dflash_ext
14
+ except Exception:
15
+ ops = None
16
+
17
+ try:
18
+ from .gguf_io import load_drafter # noqa: F401
19
+ except ImportError: # gguf-py absent; the reference stays usable
20
+ load_drafter = None
21
+
22
+ __all__ = ["DFlashConfig", "DFlashRef", "DFlashDrafter", "random_weights",
23
+ "load_drafter", "ops"]
build/torch213-cxx11-cu126-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9584d73d21d10eb16f12f42a0e5658fa8c2718b4df0dd748ba5b6c6e0f41b7ac
3
+ size 893256
build/torch213-cxx11-cu126-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _dflash_ops_cuda_03c9586
3
+ ops = torch.ops._dflash_ops_cuda_03c9586
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_dflash_ops_cuda_03c9586::{op_name}"
build/torch213-cxx11-cu126-x86_64-linux/drafter.py ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """GPU DFlash drafter: cuBLAS GEMMs plus the fused ops, with a CUDA-graphed
2
+ block step."""
3
+ import torch
4
+
5
+ from .reference import DFlashConfig, rms_norm, rope_inv_freq
6
+
7
+
8
+ def _ops():
9
+ from . import ops
10
+ if ops is None:
11
+ raise RuntimeError(
12
+ "dflash-ops compiled kernels are unavailable; build them with "
13
+ "load_local.load() in a source checkout, or install a published "
14
+ "variant with kernels.get_kernel")
15
+ return ops
16
+
17
+
18
+ class DFlashDrafter:
19
+ """Ring-cached DFlash drafter on CUDA. Weight keys match `DFlashRef`."""
20
+
21
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cuda",
22
+ ring_dtype="fp32", dtype="fp32"):
23
+ self.cfg = cfg
24
+ self.device = torch.device(device)
25
+ # dtype sets GEMM weights and activations; residual, norms, softmax stay fp32
26
+ self.wdt = torch.bfloat16 if dtype == "bf16" else torch.float32
27
+ self.w = {}
28
+ for k, v in weights.items():
29
+ dt = self.wdt if v.dim() == 2 else torch.float32
30
+ self.w[k] = v.to(device=self.device, dtype=dt).contiguous()
31
+ C = cfg
32
+ # ring storage dtype; arithmetic stays fp32
33
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
34
+ else torch.float32)
35
+ # host-built fp64 rope table, shared by every op call
36
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base,
37
+ self.device).contiguous()
38
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
39
+ device=self.device, dtype=self.ring_dt)
40
+ self.ring_v = torch.zeros_like(self.ring_k)
41
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int32,
42
+ device=self.device)
43
+
44
+ # ---- encoder --------------------------------------------------------
45
+ def encode(self, feats):
46
+ g = (feats.to(self.device, self.wdt) @ self.w["fc"]).float()
47
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
48
+
49
+ # ---- KV injection ---------------------------------------------------
50
+ def inject(self, g, pos):
51
+ """Ring injection at `pos`, chunked at `window` so no slot is written twice per launch."""
52
+ C = self.cfg
53
+ o = _ops()
54
+ pos = pos.to(self.device, torch.int32).contiguous()
55
+ for beg in range(0, pos.numel(), C.window):
56
+ p = pos[beg:beg + C.window].contiguous()
57
+ gc = g[beg:beg + C.window].to(self.wdt)
58
+ for i in range(C.n_layer):
59
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv,
60
+ C.head_dim).contiguous()
61
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv,
62
+ C.head_dim).contiguous()
63
+ o.dflash_inject(self.ring_k[i], self.ring_v[i], self.ring_pos,
64
+ k, v, self.w[f"k_norm.{i}"], self.rope_inv, p,
65
+ C.rms_eps)
66
+
67
+ # ---- noise-block forward -------------------------------------------
68
+ def block_step(self, id_last, n_past, n_draft=None):
69
+ C = self.cfg
70
+ if n_draft is None:
71
+ n_draft = C.block_size - 1
72
+ B = n_draft + 1
73
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
74
+ device=self.device)
75
+ tokens[0] = int(id_last)
76
+ bpos = (n_past + torch.arange(B, device=self.device)).to(torch.int32)
77
+ return self._forward(tokens, bpos.contiguous())
78
+
79
+ def _forward(self, tokens, bpos):
80
+ """Block forward on caller-owned device tensors; reads no host state."""
81
+ C = self.cfg
82
+ o = _ops()
83
+ B = tokens.numel()
84
+ x = self.w["tok_embd"][tokens].float()
85
+ scale = C.head_dim ** -0.5
86
+
87
+ for i in range(C.n_layer):
88
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps).to(self.wdt)
89
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head,
90
+ C.head_dim).contiguous()
91
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv,
92
+ C.head_dim).contiguous()
93
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv,
94
+ C.head_dim).contiguous()
95
+ o.dflash_qk_rope(q, k, self.w[f"q_norm.{i}"],
96
+ self.w[f"k_norm.{i}"], self.rope_inv, bpos,
97
+ C.rms_eps)
98
+ att = torch.empty_like(q)
99
+ o.dflash_block_attn(att, q, k, v, self.ring_k[i], self.ring_v[i],
100
+ self.ring_pos, bpos, scale)
101
+ x = x + (att.reshape(B, -1) @ self.w[f"wo.{i}"]).float()
102
+
103
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps).to(self.wdt)
104
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
105
+ x = x + ((gate * (f @ self.w[f"ffn_up.{i}"]))
106
+ @ self.w[f"ffn_down.{i}"]).float()
107
+
108
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
109
+ return (x.to(self.wdt) @ self.w["lm_head"]).float()
110
+
111
+ def draft_greedy(self, id_last, n_past, n_draft=None):
112
+ return self.block_step(id_last, n_past, n_draft)[1:].argmax(dim=-1)
113
+
114
+ # ---- graphed step ---------------------------------------------------
115
+ def _static_buffers(self, B):
116
+ """Every tensor a captured step touches, allocated once and held."""
117
+ C = self.cfg
118
+ d = self.device
119
+ wdt = self.wdt
120
+ s = {
121
+ "tokens": torch.full((B,), C.mask_token_id, dtype=torch.int64,
122
+ device=d),
123
+ "arange": torch.arange(B, dtype=torch.int32, device=d),
124
+ "n_past": torch.zeros((), dtype=torch.int32, device=d),
125
+ "bpos": torch.empty(B, dtype=torch.int32, device=d),
126
+ "xw": torch.empty(B, C.n_embd, dtype=wdt, device=d),
127
+ "x": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
128
+ "sq": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
129
+ "ms": torch.empty(B, 1, dtype=torch.float32, device=d),
130
+ "hn": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
131
+ "h": torch.empty(B, C.n_embd, dtype=wdt, device=d),
132
+ "q": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
133
+ "k": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
134
+ "v": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
135
+ "att": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
136
+ "ao": torch.empty(B, C.n_embd, dtype=wdt, device=d),
137
+ "g1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
138
+ "sg": torch.empty(B, C.n_ff, dtype=wdt, device=d),
139
+ "u1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
140
+ "d1": torch.empty(B, C.n_embd, dtype=wdt, device=d),
141
+ "lg": torch.empty(B, C.n_vocab, dtype=wdt, device=d),
142
+ "logits": torch.empty(B, C.n_vocab, dtype=torch.float32,
143
+ device=d),
144
+ }
145
+ return s
146
+
147
+ def _rms_static(self, src, w, s, out):
148
+ """RMS norm of `src` into `out` using only held buffers."""
149
+ torch.pow(src, 2, out=s["sq"])
150
+ torch.mean(s["sq"], -1, keepdim=True, out=s["ms"])
151
+ s["ms"].add_(self.cfg.rms_eps).rsqrt_()
152
+ torch.mul(src, s["ms"], out=out)
153
+ out.mul_(w)
154
+
155
+ def _forward_static(self, s):
156
+ """Allocation-free block forward into held buffers; numerically
157
+ identical to `_forward`."""
158
+ C = self.cfg
159
+ o = _ops()
160
+ B = s["tokens"].numel()
161
+ scale = C.head_dim ** -0.5
162
+ torch.index_select(self.w["tok_embd"], 0, s["tokens"], out=s["xw"])
163
+ s["x"].copy_(s["xw"])
164
+ for i in range(C.n_layer):
165
+ self._rms_static(s["x"], self.w[f"attn_norm.{i}"], s, s["hn"])
166
+ s["h"].copy_(s["hn"])
167
+ torch.matmul(s["h"], self.w[f"wq.{i}"], out=s["q"])
168
+ torch.matmul(s["h"], self.w[f"wk.{i}"], out=s["k"])
169
+ torch.matmul(s["h"], self.w[f"wv.{i}"], out=s["v"])
170
+ qv = s["q"].view(B, C.n_head, C.head_dim)
171
+ kv_ = s["k"].view(B, C.n_head_kv, C.head_dim)
172
+ vv = s["v"].view(B, C.n_head_kv, C.head_dim)
173
+ o.dflash_qk_rope(qv, kv_, self.w[f"q_norm.{i}"],
174
+ self.w[f"k_norm.{i}"], self.rope_inv, s["bpos"],
175
+ C.rms_eps)
176
+ av = s["att"].view(B, C.n_head, C.head_dim)
177
+ o.dflash_block_attn(av, qv, kv_, vv, self.ring_k[i],
178
+ self.ring_v[i], self.ring_pos, s["bpos"],
179
+ scale)
180
+ torch.matmul(s["att"], self.w[f"wo.{i}"], out=s["ao"])
181
+ s["x"].add_(s["ao"])
182
+ self._rms_static(s["x"], self.w[f"ffn_norm.{i}"], s, s["hn"])
183
+ s["h"].copy_(s["hn"])
184
+ torch.matmul(s["h"], self.w[f"ffn_gate.{i}"], out=s["g1"])
185
+ # fused silu keeps the step bitwise-equal to the eager path
186
+ torch.ops.aten.silu.out(s["g1"], out=s["sg"])
187
+ torch.matmul(s["h"], self.w[f"ffn_up.{i}"], out=s["u1"])
188
+ s["sg"].mul_(s["u1"])
189
+ torch.matmul(s["sg"], self.w[f"ffn_down.{i}"], out=s["d1"])
190
+ s["x"].add_(s["d1"])
191
+ self._rms_static(s["x"], self.w["out_norm"], s, s["hn"])
192
+ s["h"].copy_(s["hn"])
193
+ torch.matmul(s["h"], self.w["lm_head"], out=s["lg"])
194
+ s["logits"].copy_(s["lg"])
195
+ return s["logits"]
196
+
197
+ def capture_step(self, n_draft=None):
198
+ """Graph-captured block step over static buffers (the region allocates
199
+ nothing); returns step(id_last, n_past) -> logits, overwritten per replay."""
200
+ C = self.cfg
201
+ if n_draft is None:
202
+ n_draft = C.block_size - 1
203
+ s = self._static_buffers(n_draft + 1)
204
+
205
+ stream = torch.cuda.Stream(device=self.device)
206
+ stream.wait_stream(torch.cuda.current_stream())
207
+ with torch.cuda.stream(stream):
208
+ for _ in range(3): # warm kernels and cuBLAS
209
+ torch.add(s["arange"], s["n_past"], out=s["bpos"])
210
+ self._forward_static(s)
211
+ torch.cuda.current_stream().wait_stream(stream)
212
+ torch.cuda.synchronize()
213
+
214
+ graph = torch.cuda.CUDAGraph()
215
+ with torch.cuda.graph(graph):
216
+ torch.add(s["arange"], s["n_past"], out=s["bpos"]) # in-graph: replay sees updates
217
+ logits = self._forward_static(s)
218
+
219
+ def step(id_last, n_past):
220
+ s["tokens"][0].fill_(int(id_last))
221
+ s["n_past"].fill_(int(n_past))
222
+ graph.replay()
223
+ return logits
224
+
225
+ step.graph = graph
226
+ step.buffers = s
227
+ return step
228
+
229
+ # ---- verification ---------------------------------------------------
230
+ def accept(self, draft, target):
231
+ """Leading agreement count, device-side."""
232
+ o = _ops()
233
+ n = torch.zeros(1, dtype=torch.int32, device=self.device)
234
+ o.dflash_accept(n, draft.to(torch.int32).contiguous(),
235
+ target.to(torch.int32).contiguous())
236
+ return n
build/torch213-cxx11-cu126-x86_64-linux/gguf_io.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Load the DFlash drafter GGUF into reference-layout fp32 tensors; 2-D weights
2
+ transpose from GGUF [out, in] to [in, out]; tok_embd and lm_head are the
3
+ caller's (they belong to the target model)."""
4
+ import numpy as np
5
+ import torch
6
+ from gguf import GGUFReader
7
+ from gguf import quants as gq
8
+
9
+ from .reference import DFlashConfig
10
+
11
+ _BLK = {
12
+ "attn_norm": "attn_norm", "attn_q": "wq", "attn_k": "wk", "attn_v": "wv",
13
+ "attn_output": "wo", "attn_q_norm": "q_norm", "attn_k_norm": "k_norm",
14
+ "ffn_norm": "ffn_norm", "ffn_gate": "ffn_gate", "ffn_up": "ffn_up",
15
+ "ffn_down": "ffn_down",
16
+ }
17
+ _TOP = {"fc": "fc", "enc.output_norm": "enc_norm", "output_norm": "out_norm"}
18
+
19
+
20
+ def _field(reader, key, default=None):
21
+ f = reader.get_field(key)
22
+ if f is None:
23
+ return default
24
+ v = f.contents()
25
+ return v
26
+
27
+
28
+ def load_drafter(path):
29
+ """-> (DFlashConfig, weights dict) with fp32 tensors in reference layout."""
30
+ r = GGUFReader(str(path))
31
+ cfg = DFlashConfig(
32
+ n_layer=int(_field(r, "dflash.block_count")),
33
+ n_embd=int(_field(r, "dflash.embedding_length")),
34
+ n_head=int(_field(r, "dflash.attention.head_count")),
35
+ n_head_kv=int(_field(r, "dflash.attention.head_count_kv")),
36
+ head_dim=int(_field(r, "dflash.attention.key_length")),
37
+ n_ff=int(_field(r, "dflash.feed_forward_length")),
38
+ rope_base=float(_field(r, "dflash.rope.freq_base")),
39
+ rms_eps=float(_field(r, "dflash.attention.layer_norm_rms_epsilon")),
40
+ window=int(_field(r, "dflash.attention.sliding_window")),
41
+ block_size=int(_field(r, "dflash.block_size")),
42
+ target_layers=tuple(_field(r, "dflash.target_layers")),
43
+ )
44
+ w = {}
45
+ for t in r.tensors:
46
+ name = t.name
47
+ assert name.endswith(".weight"), name
48
+ base = name[: -len(".weight")]
49
+ if base.startswith("blk."):
50
+ _, idx, part = base.split(".", 2)
51
+ key = f"{_BLK[part]}.{idx}"
52
+ else:
53
+ key = _TOP[base]
54
+ data = gq.dequantize(t.data, t.tensor_type)
55
+ arr = torch.from_numpy(np.ascontiguousarray(data)).float()
56
+ if arr.dim() == 2:
57
+ arr = arr.t().contiguous()
58
+ w[key] = arr
59
+ expect = 3 + 11 * cfg.n_layer
60
+ assert len(w) == expect, (len(w), expect)
61
+ return cfg, w
build/torch213-cxx11-cu126-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "dflash-ops",
3
+ "id": "_dflash_ops_cuda_03c9586",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "kernel-depends": [],
8
+ "backend": {
9
+ "type": "cuda",
10
+ "archs": [
11
+ "8.0",
12
+ "8.6",
13
+ "8.9",
14
+ "9.0"
15
+ ]
16
+ },
17
+ "digest": {
18
+ "algorithm": "sha256",
19
+ "files": {
20
+ "__init__.py": "wNpuIbQEXTfFNjrmz6aISM46VFgMKAHkqqu+ECJJS20=",
21
+ "_dflash_ops_cuda_03c9586.abi3.so": "lYTXPSHRDrFvEvQqDlZY+ownGLTfDddIultsbg9Bt6w=",
22
+ "_ops.py": "+6e3Oo6lwRkZaeOrhSSZEwWYs4/Fpd/zQgJj4MVEi9I=",
23
+ "drafter.py": "wGU5TWlXWr/ZogxQr4pho5Wku66UUygnczpsTu82dls=",
24
+ "gguf_io.py": "XrgF2dH7LNR1KTNKKu/pKhh6wT90bCjcjCAgmyGsuZA=",
25
+ "reference.py": "InmFS9rUwURZ7ZGVUxwQJCCjJZR/hKWrF3eMfp4zQvY="
26
+ }
27
+ },
28
+ "provenance": {
29
+ "kernel-builder": {
30
+ "version": "0.17.0-dev0",
31
+ "sha": "2c40e10d3da1392245ee81bd05b55fb3103b2b34",
32
+ "dirty": false
33
+ },
34
+ "kernel": {
35
+ "sha": "03c9586154cc2afa6efaa7b111dccef715ec9d69",
36
+ "dirty": false
37
+ }
38
+ }
39
+ }
build/torch213-cxx11-cu126-x86_64-linux/reference.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Eager fp32 DFlash drafter reference, transcribed from llama.cpp's
2
+ llama_model_dflash graph; the CUDA ops are certified against this module."""
3
+ from dataclasses import dataclass, field
4
+
5
+ import torch
6
+
7
+
8
+ @dataclass
9
+ class DFlashConfig:
10
+ n_layer: int = 5
11
+ n_embd: int = 6656
12
+ n_head: int = 32
13
+ n_head_kv: int = 8
14
+ head_dim: int = 128
15
+ n_ff: int = 19968
16
+ n_vocab: int = 202048
17
+ rope_base: float = 500000.0
18
+ rms_eps: float = 1e-6
19
+ window: int = 2048 # SWA width; also the ring capacity
20
+ block_size: int = 16
21
+ mask_token_id: int = 201818
22
+ target_layers: tuple = (2, 14, 26, 38, 50)
23
+
24
+ @property
25
+ def n_feat(self):
26
+ return len(self.target_layers) * self.n_embd
27
+
28
+ @classmethod
29
+ def tiny(cls):
30
+ """Toy sizes with the real structure; head_dim stays a multiple of 32."""
31
+ return cls(n_layer=2, n_embd=64, n_head=4, n_head_kv=2, head_dim=32,
32
+ n_ff=96, n_vocab=997, window=32, block_size=8,
33
+ mask_token_id=990, target_layers=(1, 2))
34
+
35
+
36
+ def rms_norm(x, w, eps):
37
+ """llama.cpp LLM_NORM_RMS: x * w / sqrt(mean(x^2) + eps), fp32."""
38
+ v = x.float()
39
+ return (v * torch.rsqrt(v.pow(2).mean(-1, keepdim=True) + eps)) * w.float()
40
+
41
+
42
+ def rope_inv_freq(head_dim, base, device="cpu"):
43
+ """fp64 NEOX inverse frequencies base^(-2i/head_dim), host-evaluated so the
44
+ table is device-invariant."""
45
+ half = head_dim // 2
46
+ t = base ** (-torch.arange(half, dtype=torch.float64) * 2.0 / head_dim)
47
+ return t.to(device)
48
+
49
+
50
+ def rope_neox(x, pos, base=None, inv=None):
51
+ """NEOX rope over pairs (i, i + d/2), fp32; x [T, H, D], pos [T]; pass
52
+ `inv` to reuse a precomputed table."""
53
+ T, H, D = x.shape
54
+ half = D // 2
55
+ if inv is None:
56
+ inv = rope_inv_freq(D, base, x.device)
57
+ ang = pos.to(torch.float64)[:, None] * inv[None, :] # [T, half]
58
+ cos = ang.cos().to(torch.float32)[:, None, :]
59
+ sin = ang.sin().to(torch.float32)[:, None, :]
60
+ xf = x.float()
61
+ x1, x2 = xf[..., :half], xf[..., half:]
62
+ return torch.cat([x1 * cos - x2 * sin, x1 * sin + x2 * cos], dim=-1)
63
+
64
+
65
+ class DFlashRef:
66
+ """Reference drafter over an fp32 weight dict (layout as in
67
+ `random_weights`) with a sliding ring KV state."""
68
+
69
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cpu",
70
+ ring_dtype="fp32"):
71
+ self.cfg = cfg
72
+ self.w = {k: v.to(device=device, dtype=torch.float32)
73
+ for k, v in weights.items()}
74
+ self.device = torch.device(device)
75
+ C = cfg
76
+ # ring storage dtype; arithmetic stays fp32
77
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
78
+ else torch.float32)
79
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base, device)
80
+ # per-layer ring K/V [window, Hkv, D]; ring_pos = slot's position, -1 empty
81
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
82
+ device=device, dtype=self.ring_dt)
83
+ self.ring_v = torch.zeros_like(self.ring_k)
84
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int64,
85
+ device=device)
86
+
87
+ # ---- encoder --------------------------------------------------------
88
+ def encode(self, feats):
89
+ """Fuse per-position target features [T, n_feat] to g [T, n_embd]."""
90
+ g = feats.float() @ self.w["fc"]
91
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
92
+
93
+ # ---- KV injection ---------------------------------------------------
94
+ def inject(self, g, pos):
95
+ """Project fused features into every layer's ring at `pos` [T], chunked
96
+ at `window` so no two tokens in one pass share a slot."""
97
+ C = self.cfg
98
+ for beg in range(0, len(pos), C.window):
99
+ p = pos[beg:beg + C.window]
100
+ gc = g[beg:beg + C.window]
101
+ slots = p % C.window
102
+ for i in range(C.n_layer):
103
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv, C.head_dim)
104
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv, C.head_dim)
105
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
106
+ k = rope_neox(k, p, inv=self.rope_inv)
107
+ self.ring_k[i, slots] = k.to(self.ring_dt)
108
+ self.ring_v[i, slots] = v.to(self.ring_dt)
109
+ self.ring_pos[slots] = p
110
+
111
+ # ---- noise-block forward -------------------------------------------
112
+ def block_step(self, id_last, n_past, n_draft=None):
113
+ """Denoise [id_last, mask x n_draft] at n_past..; -> [n_draft+1, n_vocab]."""
114
+ C = self.cfg
115
+ if n_draft is None:
116
+ n_draft = C.block_size - 1
117
+ B = n_draft + 1
118
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
119
+ device=self.device)
120
+ tokens[0] = id_last
121
+ pos = n_past + torch.arange(B, device=self.device)
122
+ x = self.w["tok_embd"][tokens]
123
+
124
+ live = self.ring_pos >= 0
125
+ for i in range(C.n_layer):
126
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps)
127
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head, C.head_dim)
128
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv, C.head_dim)
129
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv, C.head_dim)
130
+ q = rms_norm(q, self.w[f"q_norm.{i}"], C.rms_eps)
131
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
132
+ q = rope_neox(q, pos, inv=self.rope_inv)
133
+ k = rope_neox(k, pos, inv=self.rope_inv)
134
+
135
+ # keys = live ring + block; non-causal, SWA masks only the deep past
136
+ keys = torch.cat([self.ring_k[i, live].float(), k], dim=0)
137
+ vals = torch.cat([self.ring_v[i, live].float(), v], dim=0)
138
+ kpos = torch.cat([self.ring_pos[live], pos], dim=0)
139
+
140
+ gq = C.n_head // C.n_head_kv
141
+ qh = q.permute(1, 0, 2) # [H, B, D]
142
+ kh = keys.permute(1, 0, 2).repeat_interleave(gq, dim=0)
143
+ vh = vals.permute(1, 0, 2).repeat_interleave(gq, dim=0)
144
+ att = qh @ kh.transpose(1, 2) / (C.head_dim ** 0.5) # [H, B, S]
145
+ masked = (pos[:, None] - kpos[None, :]) >= C.window # SWA
146
+ att = att.masked_fill(masked[None, :, :], float("-inf"))
147
+ att = att.softmax(dim=-1)
148
+ out = (att @ vh).permute(1, 0, 2).reshape(B, -1) # [B, H*D]
149
+ x = x + out @ self.w[f"wo.{i}"]
150
+
151
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps)
152
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
153
+ x = x + (gate * (f @ self.w[f"ffn_up.{i}"])) @ self.w[f"ffn_down.{i}"]
154
+
155
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
156
+ return x @ self.w["lm_head"]
157
+
158
+ def draft_greedy(self, id_last, n_past, n_draft=None):
159
+ """Greedy drafts from block positions 1..n_draft (position 0 unused)."""
160
+ logits = self.block_step(id_last, n_past, n_draft)
161
+ return logits[1:].argmax(dim=-1)
162
+
163
+
164
+ def random_weights(cfg: DFlashConfig, seed=0, device="cpu"):
165
+ """Gaussian weights at transformer-typical scale, for structural tests."""
166
+ g = torch.Generator(device="cpu").manual_seed(seed)
167
+
168
+ def t(*shape, s=0.02):
169
+ return torch.randn(*shape, generator=g) * s
170
+
171
+ C = cfg
172
+ w = {"fc": t(C.n_feat, C.n_embd), "enc_norm": torch.ones(C.n_embd),
173
+ "out_norm": torch.ones(C.n_embd),
174
+ "tok_embd": t(C.n_vocab, C.n_embd),
175
+ "lm_head": t(C.n_embd, C.n_vocab)}
176
+ for i in range(C.n_layer):
177
+ w[f"attn_norm.{i}"] = torch.ones(C.n_embd)
178
+ w[f"wq.{i}"] = t(C.n_embd, C.n_head * C.head_dim)
179
+ w[f"wk.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
180
+ w[f"wv.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
181
+ w[f"wo.{i}"] = t(C.n_head * C.head_dim, C.n_embd)
182
+ w[f"q_norm.{i}"] = torch.ones(C.head_dim)
183
+ w[f"k_norm.{i}"] = torch.ones(C.head_dim)
184
+ w[f"ffn_norm.{i}"] = torch.ones(C.n_embd)
185
+ w[f"ffn_gate.{i}"] = t(C.n_embd, C.n_ff)
186
+ w[f"ffn_up.{i}"] = t(C.n_embd, C.n_ff)
187
+ w[f"ffn_down.{i}"] = t(C.n_ff, C.n_embd)
188
+ return {k: v.to(device) for k, v in w.items()}
build/torch213-cxx11-cu130-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DFlash block-diffusion drafter ops; the eager reference defines the
2
+ semantics and the CUDA ops are certified against it."""
3
+ from .reference import DFlashConfig, DFlashRef, random_weights # noqa: F401
4
+ from .drafter import DFlashDrafter # noqa: F401
5
+
6
+ try: # built variants ship _ops
7
+ from ._ops import ops # noqa: F401
8
+ except ImportError:
9
+ try: # a local JIT build registers the same ops under torch.ops.dflash_ext
10
+ import torch as _torch
11
+
12
+ _torch.ops.dflash_ext.dflash_accept
13
+ ops = _torch.ops.dflash_ext
14
+ except Exception:
15
+ ops = None
16
+
17
+ try:
18
+ from .gguf_io import load_drafter # noqa: F401
19
+ except ImportError: # gguf-py absent; the reference stays usable
20
+ load_drafter = None
21
+
22
+ __all__ = ["DFlashConfig", "DFlashRef", "DFlashDrafter", "random_weights",
23
+ "load_drafter", "ops"]
build/torch213-cxx11-cu130-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b084949c234bf47f45c68cc117ba53eeb7b6fe87854b8fde895d0598dc835641
3
+ size 1402096
build/torch213-cxx11-cu130-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _dflash_ops_cuda_03c9586
3
+ ops = torch.ops._dflash_ops_cuda_03c9586
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_dflash_ops_cuda_03c9586::{op_name}"
build/torch213-cxx11-cu130-x86_64-linux/drafter.py ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """GPU DFlash drafter: cuBLAS GEMMs plus the fused ops, with a CUDA-graphed
2
+ block step."""
3
+ import torch
4
+
5
+ from .reference import DFlashConfig, rms_norm, rope_inv_freq
6
+
7
+
8
+ def _ops():
9
+ from . import ops
10
+ if ops is None:
11
+ raise RuntimeError(
12
+ "dflash-ops compiled kernels are unavailable; build them with "
13
+ "load_local.load() in a source checkout, or install a published "
14
+ "variant with kernels.get_kernel")
15
+ return ops
16
+
17
+
18
+ class DFlashDrafter:
19
+ """Ring-cached DFlash drafter on CUDA. Weight keys match `DFlashRef`."""
20
+
21
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cuda",
22
+ ring_dtype="fp32", dtype="fp32"):
23
+ self.cfg = cfg
24
+ self.device = torch.device(device)
25
+ # dtype sets GEMM weights and activations; residual, norms, softmax stay fp32
26
+ self.wdt = torch.bfloat16 if dtype == "bf16" else torch.float32
27
+ self.w = {}
28
+ for k, v in weights.items():
29
+ dt = self.wdt if v.dim() == 2 else torch.float32
30
+ self.w[k] = v.to(device=self.device, dtype=dt).contiguous()
31
+ C = cfg
32
+ # ring storage dtype; arithmetic stays fp32
33
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
34
+ else torch.float32)
35
+ # host-built fp64 rope table, shared by every op call
36
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base,
37
+ self.device).contiguous()
38
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
39
+ device=self.device, dtype=self.ring_dt)
40
+ self.ring_v = torch.zeros_like(self.ring_k)
41
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int32,
42
+ device=self.device)
43
+
44
+ # ---- encoder --------------------------------------------------------
45
+ def encode(self, feats):
46
+ g = (feats.to(self.device, self.wdt) @ self.w["fc"]).float()
47
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
48
+
49
+ # ---- KV injection ---------------------------------------------------
50
+ def inject(self, g, pos):
51
+ """Ring injection at `pos`, chunked at `window` so no slot is written twice per launch."""
52
+ C = self.cfg
53
+ o = _ops()
54
+ pos = pos.to(self.device, torch.int32).contiguous()
55
+ for beg in range(0, pos.numel(), C.window):
56
+ p = pos[beg:beg + C.window].contiguous()
57
+ gc = g[beg:beg + C.window].to(self.wdt)
58
+ for i in range(C.n_layer):
59
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv,
60
+ C.head_dim).contiguous()
61
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv,
62
+ C.head_dim).contiguous()
63
+ o.dflash_inject(self.ring_k[i], self.ring_v[i], self.ring_pos,
64
+ k, v, self.w[f"k_norm.{i}"], self.rope_inv, p,
65
+ C.rms_eps)
66
+
67
+ # ---- noise-block forward -------------------------------------------
68
+ def block_step(self, id_last, n_past, n_draft=None):
69
+ C = self.cfg
70
+ if n_draft is None:
71
+ n_draft = C.block_size - 1
72
+ B = n_draft + 1
73
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
74
+ device=self.device)
75
+ tokens[0] = int(id_last)
76
+ bpos = (n_past + torch.arange(B, device=self.device)).to(torch.int32)
77
+ return self._forward(tokens, bpos.contiguous())
78
+
79
+ def _forward(self, tokens, bpos):
80
+ """Block forward on caller-owned device tensors; reads no host state."""
81
+ C = self.cfg
82
+ o = _ops()
83
+ B = tokens.numel()
84
+ x = self.w["tok_embd"][tokens].float()
85
+ scale = C.head_dim ** -0.5
86
+
87
+ for i in range(C.n_layer):
88
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps).to(self.wdt)
89
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head,
90
+ C.head_dim).contiguous()
91
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv,
92
+ C.head_dim).contiguous()
93
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv,
94
+ C.head_dim).contiguous()
95
+ o.dflash_qk_rope(q, k, self.w[f"q_norm.{i}"],
96
+ self.w[f"k_norm.{i}"], self.rope_inv, bpos,
97
+ C.rms_eps)
98
+ att = torch.empty_like(q)
99
+ o.dflash_block_attn(att, q, k, v, self.ring_k[i], self.ring_v[i],
100
+ self.ring_pos, bpos, scale)
101
+ x = x + (att.reshape(B, -1) @ self.w[f"wo.{i}"]).float()
102
+
103
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps).to(self.wdt)
104
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
105
+ x = x + ((gate * (f @ self.w[f"ffn_up.{i}"]))
106
+ @ self.w[f"ffn_down.{i}"]).float()
107
+
108
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
109
+ return (x.to(self.wdt) @ self.w["lm_head"]).float()
110
+
111
+ def draft_greedy(self, id_last, n_past, n_draft=None):
112
+ return self.block_step(id_last, n_past, n_draft)[1:].argmax(dim=-1)
113
+
114
+ # ---- graphed step ---------------------------------------------------
115
+ def _static_buffers(self, B):
116
+ """Every tensor a captured step touches, allocated once and held."""
117
+ C = self.cfg
118
+ d = self.device
119
+ wdt = self.wdt
120
+ s = {
121
+ "tokens": torch.full((B,), C.mask_token_id, dtype=torch.int64,
122
+ device=d),
123
+ "arange": torch.arange(B, dtype=torch.int32, device=d),
124
+ "n_past": torch.zeros((), dtype=torch.int32, device=d),
125
+ "bpos": torch.empty(B, dtype=torch.int32, device=d),
126
+ "xw": torch.empty(B, C.n_embd, dtype=wdt, device=d),
127
+ "x": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
128
+ "sq": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
129
+ "ms": torch.empty(B, 1, dtype=torch.float32, device=d),
130
+ "hn": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
131
+ "h": torch.empty(B, C.n_embd, dtype=wdt, device=d),
132
+ "q": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
133
+ "k": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
134
+ "v": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
135
+ "att": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
136
+ "ao": torch.empty(B, C.n_embd, dtype=wdt, device=d),
137
+ "g1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
138
+ "sg": torch.empty(B, C.n_ff, dtype=wdt, device=d),
139
+ "u1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
140
+ "d1": torch.empty(B, C.n_embd, dtype=wdt, device=d),
141
+ "lg": torch.empty(B, C.n_vocab, dtype=wdt, device=d),
142
+ "logits": torch.empty(B, C.n_vocab, dtype=torch.float32,
143
+ device=d),
144
+ }
145
+ return s
146
+
147
+ def _rms_static(self, src, w, s, out):
148
+ """RMS norm of `src` into `out` using only held buffers."""
149
+ torch.pow(src, 2, out=s["sq"])
150
+ torch.mean(s["sq"], -1, keepdim=True, out=s["ms"])
151
+ s["ms"].add_(self.cfg.rms_eps).rsqrt_()
152
+ torch.mul(src, s["ms"], out=out)
153
+ out.mul_(w)
154
+
155
+ def _forward_static(self, s):
156
+ """Allocation-free block forward into held buffers; numerically
157
+ identical to `_forward`."""
158
+ C = self.cfg
159
+ o = _ops()
160
+ B = s["tokens"].numel()
161
+ scale = C.head_dim ** -0.5
162
+ torch.index_select(self.w["tok_embd"], 0, s["tokens"], out=s["xw"])
163
+ s["x"].copy_(s["xw"])
164
+ for i in range(C.n_layer):
165
+ self._rms_static(s["x"], self.w[f"attn_norm.{i}"], s, s["hn"])
166
+ s["h"].copy_(s["hn"])
167
+ torch.matmul(s["h"], self.w[f"wq.{i}"], out=s["q"])
168
+ torch.matmul(s["h"], self.w[f"wk.{i}"], out=s["k"])
169
+ torch.matmul(s["h"], self.w[f"wv.{i}"], out=s["v"])
170
+ qv = s["q"].view(B, C.n_head, C.head_dim)
171
+ kv_ = s["k"].view(B, C.n_head_kv, C.head_dim)
172
+ vv = s["v"].view(B, C.n_head_kv, C.head_dim)
173
+ o.dflash_qk_rope(qv, kv_, self.w[f"q_norm.{i}"],
174
+ self.w[f"k_norm.{i}"], self.rope_inv, s["bpos"],
175
+ C.rms_eps)
176
+ av = s["att"].view(B, C.n_head, C.head_dim)
177
+ o.dflash_block_attn(av, qv, kv_, vv, self.ring_k[i],
178
+ self.ring_v[i], self.ring_pos, s["bpos"],
179
+ scale)
180
+ torch.matmul(s["att"], self.w[f"wo.{i}"], out=s["ao"])
181
+ s["x"].add_(s["ao"])
182
+ self._rms_static(s["x"], self.w[f"ffn_norm.{i}"], s, s["hn"])
183
+ s["h"].copy_(s["hn"])
184
+ torch.matmul(s["h"], self.w[f"ffn_gate.{i}"], out=s["g1"])
185
+ # fused silu keeps the step bitwise-equal to the eager path
186
+ torch.ops.aten.silu.out(s["g1"], out=s["sg"])
187
+ torch.matmul(s["h"], self.w[f"ffn_up.{i}"], out=s["u1"])
188
+ s["sg"].mul_(s["u1"])
189
+ torch.matmul(s["sg"], self.w[f"ffn_down.{i}"], out=s["d1"])
190
+ s["x"].add_(s["d1"])
191
+ self._rms_static(s["x"], self.w["out_norm"], s, s["hn"])
192
+ s["h"].copy_(s["hn"])
193
+ torch.matmul(s["h"], self.w["lm_head"], out=s["lg"])
194
+ s["logits"].copy_(s["lg"])
195
+ return s["logits"]
196
+
197
+ def capture_step(self, n_draft=None):
198
+ """Graph-captured block step over static buffers (the region allocates
199
+ nothing); returns step(id_last, n_past) -> logits, overwritten per replay."""
200
+ C = self.cfg
201
+ if n_draft is None:
202
+ n_draft = C.block_size - 1
203
+ s = self._static_buffers(n_draft + 1)
204
+
205
+ stream = torch.cuda.Stream(device=self.device)
206
+ stream.wait_stream(torch.cuda.current_stream())
207
+ with torch.cuda.stream(stream):
208
+ for _ in range(3): # warm kernels and cuBLAS
209
+ torch.add(s["arange"], s["n_past"], out=s["bpos"])
210
+ self._forward_static(s)
211
+ torch.cuda.current_stream().wait_stream(stream)
212
+ torch.cuda.synchronize()
213
+
214
+ graph = torch.cuda.CUDAGraph()
215
+ with torch.cuda.graph(graph):
216
+ torch.add(s["arange"], s["n_past"], out=s["bpos"]) # in-graph: replay sees updates
217
+ logits = self._forward_static(s)
218
+
219
+ def step(id_last, n_past):
220
+ s["tokens"][0].fill_(int(id_last))
221
+ s["n_past"].fill_(int(n_past))
222
+ graph.replay()
223
+ return logits
224
+
225
+ step.graph = graph
226
+ step.buffers = s
227
+ return step
228
+
229
+ # ---- verification ---------------------------------------------------
230
+ def accept(self, draft, target):
231
+ """Leading agreement count, device-side."""
232
+ o = _ops()
233
+ n = torch.zeros(1, dtype=torch.int32, device=self.device)
234
+ o.dflash_accept(n, draft.to(torch.int32).contiguous(),
235
+ target.to(torch.int32).contiguous())
236
+ return n
build/torch213-cxx11-cu130-x86_64-linux/gguf_io.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Load the DFlash drafter GGUF into reference-layout fp32 tensors; 2-D weights
2
+ transpose from GGUF [out, in] to [in, out]; tok_embd and lm_head are the
3
+ caller's (they belong to the target model)."""
4
+ import numpy as np
5
+ import torch
6
+ from gguf import GGUFReader
7
+ from gguf import quants as gq
8
+
9
+ from .reference import DFlashConfig
10
+
11
+ _BLK = {
12
+ "attn_norm": "attn_norm", "attn_q": "wq", "attn_k": "wk", "attn_v": "wv",
13
+ "attn_output": "wo", "attn_q_norm": "q_norm", "attn_k_norm": "k_norm",
14
+ "ffn_norm": "ffn_norm", "ffn_gate": "ffn_gate", "ffn_up": "ffn_up",
15
+ "ffn_down": "ffn_down",
16
+ }
17
+ _TOP = {"fc": "fc", "enc.output_norm": "enc_norm", "output_norm": "out_norm"}
18
+
19
+
20
+ def _field(reader, key, default=None):
21
+ f = reader.get_field(key)
22
+ if f is None:
23
+ return default
24
+ v = f.contents()
25
+ return v
26
+
27
+
28
+ def load_drafter(path):
29
+ """-> (DFlashConfig, weights dict) with fp32 tensors in reference layout."""
30
+ r = GGUFReader(str(path))
31
+ cfg = DFlashConfig(
32
+ n_layer=int(_field(r, "dflash.block_count")),
33
+ n_embd=int(_field(r, "dflash.embedding_length")),
34
+ n_head=int(_field(r, "dflash.attention.head_count")),
35
+ n_head_kv=int(_field(r, "dflash.attention.head_count_kv")),
36
+ head_dim=int(_field(r, "dflash.attention.key_length")),
37
+ n_ff=int(_field(r, "dflash.feed_forward_length")),
38
+ rope_base=float(_field(r, "dflash.rope.freq_base")),
39
+ rms_eps=float(_field(r, "dflash.attention.layer_norm_rms_epsilon")),
40
+ window=int(_field(r, "dflash.attention.sliding_window")),
41
+ block_size=int(_field(r, "dflash.block_size")),
42
+ target_layers=tuple(_field(r, "dflash.target_layers")),
43
+ )
44
+ w = {}
45
+ for t in r.tensors:
46
+ name = t.name
47
+ assert name.endswith(".weight"), name
48
+ base = name[: -len(".weight")]
49
+ if base.startswith("blk."):
50
+ _, idx, part = base.split(".", 2)
51
+ key = f"{_BLK[part]}.{idx}"
52
+ else:
53
+ key = _TOP[base]
54
+ data = gq.dequantize(t.data, t.tensor_type)
55
+ arr = torch.from_numpy(np.ascontiguousarray(data)).float()
56
+ if arr.dim() == 2:
57
+ arr = arr.t().contiguous()
58
+ w[key] = arr
59
+ expect = 3 + 11 * cfg.n_layer
60
+ assert len(w) == expect, (len(w), expect)
61
+ return cfg, w
build/torch213-cxx11-cu130-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "dflash-ops",
3
+ "id": "_dflash_ops_cuda_03c9586",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "kernel-depends": [],
8
+ "backend": {
9
+ "type": "cuda",
10
+ "archs": [
11
+ "10.0",
12
+ "12.0",
13
+ "8.0",
14
+ "8.6",
15
+ "8.9",
16
+ "9.0"
17
+ ]
18
+ },
19
+ "digest": {
20
+ "algorithm": "sha256",
21
+ "files": {
22
+ "__init__.py": "wNpuIbQEXTfFNjrmz6aISM46VFgMKAHkqqu+ECJJS20=",
23
+ "_dflash_ops_cuda_03c9586.abi3.so": "sISUnCNL9H9FxozBF7pT7re2/oeFS4/eiV0FmNyDVkE=",
24
+ "_ops.py": "+6e3Oo6lwRkZaeOrhSSZEwWYs4/Fpd/zQgJj4MVEi9I=",
25
+ "drafter.py": "wGU5TWlXWr/ZogxQr4pho5Wku66UUygnczpsTu82dls=",
26
+ "gguf_io.py": "XrgF2dH7LNR1KTNKKu/pKhh6wT90bCjcjCAgmyGsuZA=",
27
+ "reference.py": "InmFS9rUwURZ7ZGVUxwQJCCjJZR/hKWrF3eMfp4zQvY="
28
+ }
29
+ },
30
+ "provenance": {
31
+ "kernel-builder": {
32
+ "version": "0.17.0-dev0",
33
+ "sha": "2c40e10d3da1392245ee81bd05b55fb3103b2b34",
34
+ "dirty": false
35
+ },
36
+ "kernel": {
37
+ "sha": "03c9586154cc2afa6efaa7b111dccef715ec9d69",
38
+ "dirty": false
39
+ }
40
+ }
41
+ }
build/torch213-cxx11-cu130-x86_64-linux/reference.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Eager fp32 DFlash drafter reference, transcribed from llama.cpp's
2
+ llama_model_dflash graph; the CUDA ops are certified against this module."""
3
+ from dataclasses import dataclass, field
4
+
5
+ import torch
6
+
7
+
8
+ @dataclass
9
+ class DFlashConfig:
10
+ n_layer: int = 5
11
+ n_embd: int = 6656
12
+ n_head: int = 32
13
+ n_head_kv: int = 8
14
+ head_dim: int = 128
15
+ n_ff: int = 19968
16
+ n_vocab: int = 202048
17
+ rope_base: float = 500000.0
18
+ rms_eps: float = 1e-6
19
+ window: int = 2048 # SWA width; also the ring capacity
20
+ block_size: int = 16
21
+ mask_token_id: int = 201818
22
+ target_layers: tuple = (2, 14, 26, 38, 50)
23
+
24
+ @property
25
+ def n_feat(self):
26
+ return len(self.target_layers) * self.n_embd
27
+
28
+ @classmethod
29
+ def tiny(cls):
30
+ """Toy sizes with the real structure; head_dim stays a multiple of 32."""
31
+ return cls(n_layer=2, n_embd=64, n_head=4, n_head_kv=2, head_dim=32,
32
+ n_ff=96, n_vocab=997, window=32, block_size=8,
33
+ mask_token_id=990, target_layers=(1, 2))
34
+
35
+
36
+ def rms_norm(x, w, eps):
37
+ """llama.cpp LLM_NORM_RMS: x * w / sqrt(mean(x^2) + eps), fp32."""
38
+ v = x.float()
39
+ return (v * torch.rsqrt(v.pow(2).mean(-1, keepdim=True) + eps)) * w.float()
40
+
41
+
42
+ def rope_inv_freq(head_dim, base, device="cpu"):
43
+ """fp64 NEOX inverse frequencies base^(-2i/head_dim), host-evaluated so the
44
+ table is device-invariant."""
45
+ half = head_dim // 2
46
+ t = base ** (-torch.arange(half, dtype=torch.float64) * 2.0 / head_dim)
47
+ return t.to(device)
48
+
49
+
50
+ def rope_neox(x, pos, base=None, inv=None):
51
+ """NEOX rope over pairs (i, i + d/2), fp32; x [T, H, D], pos [T]; pass
52
+ `inv` to reuse a precomputed table."""
53
+ T, H, D = x.shape
54
+ half = D // 2
55
+ if inv is None:
56
+ inv = rope_inv_freq(D, base, x.device)
57
+ ang = pos.to(torch.float64)[:, None] * inv[None, :] # [T, half]
58
+ cos = ang.cos().to(torch.float32)[:, None, :]
59
+ sin = ang.sin().to(torch.float32)[:, None, :]
60
+ xf = x.float()
61
+ x1, x2 = xf[..., :half], xf[..., half:]
62
+ return torch.cat([x1 * cos - x2 * sin, x1 * sin + x2 * cos], dim=-1)
63
+
64
+
65
+ class DFlashRef:
66
+ """Reference drafter over an fp32 weight dict (layout as in
67
+ `random_weights`) with a sliding ring KV state."""
68
+
69
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cpu",
70
+ ring_dtype="fp32"):
71
+ self.cfg = cfg
72
+ self.w = {k: v.to(device=device, dtype=torch.float32)
73
+ for k, v in weights.items()}
74
+ self.device = torch.device(device)
75
+ C = cfg
76
+ # ring storage dtype; arithmetic stays fp32
77
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
78
+ else torch.float32)
79
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base, device)
80
+ # per-layer ring K/V [window, Hkv, D]; ring_pos = slot's position, -1 empty
81
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
82
+ device=device, dtype=self.ring_dt)
83
+ self.ring_v = torch.zeros_like(self.ring_k)
84
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int64,
85
+ device=device)
86
+
87
+ # ---- encoder --------------------------------------------------------
88
+ def encode(self, feats):
89
+ """Fuse per-position target features [T, n_feat] to g [T, n_embd]."""
90
+ g = feats.float() @ self.w["fc"]
91
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
92
+
93
+ # ---- KV injection ---------------------------------------------------
94
+ def inject(self, g, pos):
95
+ """Project fused features into every layer's ring at `pos` [T], chunked
96
+ at `window` so no two tokens in one pass share a slot."""
97
+ C = self.cfg
98
+ for beg in range(0, len(pos), C.window):
99
+ p = pos[beg:beg + C.window]
100
+ gc = g[beg:beg + C.window]
101
+ slots = p % C.window
102
+ for i in range(C.n_layer):
103
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv, C.head_dim)
104
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv, C.head_dim)
105
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
106
+ k = rope_neox(k, p, inv=self.rope_inv)
107
+ self.ring_k[i, slots] = k.to(self.ring_dt)
108
+ self.ring_v[i, slots] = v.to(self.ring_dt)
109
+ self.ring_pos[slots] = p
110
+
111
+ # ---- noise-block forward -------------------------------------------
112
+ def block_step(self, id_last, n_past, n_draft=None):
113
+ """Denoise [id_last, mask x n_draft] at n_past..; -> [n_draft+1, n_vocab]."""
114
+ C = self.cfg
115
+ if n_draft is None:
116
+ n_draft = C.block_size - 1
117
+ B = n_draft + 1
118
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
119
+ device=self.device)
120
+ tokens[0] = id_last
121
+ pos = n_past + torch.arange(B, device=self.device)
122
+ x = self.w["tok_embd"][tokens]
123
+
124
+ live = self.ring_pos >= 0
125
+ for i in range(C.n_layer):
126
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps)
127
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head, C.head_dim)
128
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv, C.head_dim)
129
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv, C.head_dim)
130
+ q = rms_norm(q, self.w[f"q_norm.{i}"], C.rms_eps)
131
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
132
+ q = rope_neox(q, pos, inv=self.rope_inv)
133
+ k = rope_neox(k, pos, inv=self.rope_inv)
134
+
135
+ # keys = live ring + block; non-causal, SWA masks only the deep past
136
+ keys = torch.cat([self.ring_k[i, live].float(), k], dim=0)
137
+ vals = torch.cat([self.ring_v[i, live].float(), v], dim=0)
138
+ kpos = torch.cat([self.ring_pos[live], pos], dim=0)
139
+
140
+ gq = C.n_head // C.n_head_kv
141
+ qh = q.permute(1, 0, 2) # [H, B, D]
142
+ kh = keys.permute(1, 0, 2).repeat_interleave(gq, dim=0)
143
+ vh = vals.permute(1, 0, 2).repeat_interleave(gq, dim=0)
144
+ att = qh @ kh.transpose(1, 2) / (C.head_dim ** 0.5) # [H, B, S]
145
+ masked = (pos[:, None] - kpos[None, :]) >= C.window # SWA
146
+ att = att.masked_fill(masked[None, :, :], float("-inf"))
147
+ att = att.softmax(dim=-1)
148
+ out = (att @ vh).permute(1, 0, 2).reshape(B, -1) # [B, H*D]
149
+ x = x + out @ self.w[f"wo.{i}"]
150
+
151
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps)
152
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
153
+ x = x + (gate * (f @ self.w[f"ffn_up.{i}"])) @ self.w[f"ffn_down.{i}"]
154
+
155
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
156
+ return x @ self.w["lm_head"]
157
+
158
+ def draft_greedy(self, id_last, n_past, n_draft=None):
159
+ """Greedy drafts from block positions 1..n_draft (position 0 unused)."""
160
+ logits = self.block_step(id_last, n_past, n_draft)
161
+ return logits[1:].argmax(dim=-1)
162
+
163
+
164
+ def random_weights(cfg: DFlashConfig, seed=0, device="cpu"):
165
+ """Gaussian weights at transformer-typical scale, for structural tests."""
166
+ g = torch.Generator(device="cpu").manual_seed(seed)
167
+
168
+ def t(*shape, s=0.02):
169
+ return torch.randn(*shape, generator=g) * s
170
+
171
+ C = cfg
172
+ w = {"fc": t(C.n_feat, C.n_embd), "enc_norm": torch.ones(C.n_embd),
173
+ "out_norm": torch.ones(C.n_embd),
174
+ "tok_embd": t(C.n_vocab, C.n_embd),
175
+ "lm_head": t(C.n_embd, C.n_vocab)}
176
+ for i in range(C.n_layer):
177
+ w[f"attn_norm.{i}"] = torch.ones(C.n_embd)
178
+ w[f"wq.{i}"] = t(C.n_embd, C.n_head * C.head_dim)
179
+ w[f"wk.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
180
+ w[f"wv.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
181
+ w[f"wo.{i}"] = t(C.n_head * C.head_dim, C.n_embd)
182
+ w[f"q_norm.{i}"] = torch.ones(C.head_dim)
183
+ w[f"k_norm.{i}"] = torch.ones(C.head_dim)
184
+ w[f"ffn_norm.{i}"] = torch.ones(C.n_embd)
185
+ w[f"ffn_gate.{i}"] = t(C.n_embd, C.n_ff)
186
+ w[f"ffn_up.{i}"] = t(C.n_embd, C.n_ff)
187
+ w[f"ffn_down.{i}"] = t(C.n_ff, C.n_embd)
188
+ return {k: v.to(device) for k, v in w.items()}
build/torch213-cxx11-cu132-x86_64-linux/__init__.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DFlash block-diffusion drafter ops; the eager reference defines the
2
+ semantics and the CUDA ops are certified against it."""
3
+ from .reference import DFlashConfig, DFlashRef, random_weights # noqa: F401
4
+ from .drafter import DFlashDrafter # noqa: F401
5
+
6
+ try: # built variants ship _ops
7
+ from ._ops import ops # noqa: F401
8
+ except ImportError:
9
+ try: # a local JIT build registers the same ops under torch.ops.dflash_ext
10
+ import torch as _torch
11
+
12
+ _torch.ops.dflash_ext.dflash_accept
13
+ ops = _torch.ops.dflash_ext
14
+ except Exception:
15
+ ops = None
16
+
17
+ try:
18
+ from .gguf_io import load_drafter # noqa: F401
19
+ except ImportError: # gguf-py absent; the reference stays usable
20
+ load_drafter = None
21
+
22
+ __all__ = ["DFlashConfig", "DFlashRef", "DFlashDrafter", "random_weights",
23
+ "load_drafter", "ops"]
build/torch213-cxx11-cu132-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1277c1710a3490d86bc886565d2074d1a6f6257b01a42b4e7cd3e268f39fc039
3
+ size 1402096
build/torch213-cxx11-cu132-x86_64-linux/_ops.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from . import _dflash_ops_cuda_03c9586
3
+ ops = torch.ops._dflash_ops_cuda_03c9586
4
+
5
+ def add_op_namespace_prefix(op_name: str):
6
+ """
7
+ Prefix op by namespace.
8
+ """
9
+ return f"_dflash_ops_cuda_03c9586::{op_name}"
build/torch213-cxx11-cu132-x86_64-linux/drafter.py ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """GPU DFlash drafter: cuBLAS GEMMs plus the fused ops, with a CUDA-graphed
2
+ block step."""
3
+ import torch
4
+
5
+ from .reference import DFlashConfig, rms_norm, rope_inv_freq
6
+
7
+
8
+ def _ops():
9
+ from . import ops
10
+ if ops is None:
11
+ raise RuntimeError(
12
+ "dflash-ops compiled kernels are unavailable; build them with "
13
+ "load_local.load() in a source checkout, or install a published "
14
+ "variant with kernels.get_kernel")
15
+ return ops
16
+
17
+
18
+ class DFlashDrafter:
19
+ """Ring-cached DFlash drafter on CUDA. Weight keys match `DFlashRef`."""
20
+
21
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cuda",
22
+ ring_dtype="fp32", dtype="fp32"):
23
+ self.cfg = cfg
24
+ self.device = torch.device(device)
25
+ # dtype sets GEMM weights and activations; residual, norms, softmax stay fp32
26
+ self.wdt = torch.bfloat16 if dtype == "bf16" else torch.float32
27
+ self.w = {}
28
+ for k, v in weights.items():
29
+ dt = self.wdt if v.dim() == 2 else torch.float32
30
+ self.w[k] = v.to(device=self.device, dtype=dt).contiguous()
31
+ C = cfg
32
+ # ring storage dtype; arithmetic stays fp32
33
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
34
+ else torch.float32)
35
+ # host-built fp64 rope table, shared by every op call
36
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base,
37
+ self.device).contiguous()
38
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
39
+ device=self.device, dtype=self.ring_dt)
40
+ self.ring_v = torch.zeros_like(self.ring_k)
41
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int32,
42
+ device=self.device)
43
+
44
+ # ---- encoder --------------------------------------------------------
45
+ def encode(self, feats):
46
+ g = (feats.to(self.device, self.wdt) @ self.w["fc"]).float()
47
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
48
+
49
+ # ---- KV injection ---------------------------------------------------
50
+ def inject(self, g, pos):
51
+ """Ring injection at `pos`, chunked at `window` so no slot is written twice per launch."""
52
+ C = self.cfg
53
+ o = _ops()
54
+ pos = pos.to(self.device, torch.int32).contiguous()
55
+ for beg in range(0, pos.numel(), C.window):
56
+ p = pos[beg:beg + C.window].contiguous()
57
+ gc = g[beg:beg + C.window].to(self.wdt)
58
+ for i in range(C.n_layer):
59
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv,
60
+ C.head_dim).contiguous()
61
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv,
62
+ C.head_dim).contiguous()
63
+ o.dflash_inject(self.ring_k[i], self.ring_v[i], self.ring_pos,
64
+ k, v, self.w[f"k_norm.{i}"], self.rope_inv, p,
65
+ C.rms_eps)
66
+
67
+ # ---- noise-block forward -------------------------------------------
68
+ def block_step(self, id_last, n_past, n_draft=None):
69
+ C = self.cfg
70
+ if n_draft is None:
71
+ n_draft = C.block_size - 1
72
+ B = n_draft + 1
73
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
74
+ device=self.device)
75
+ tokens[0] = int(id_last)
76
+ bpos = (n_past + torch.arange(B, device=self.device)).to(torch.int32)
77
+ return self._forward(tokens, bpos.contiguous())
78
+
79
+ def _forward(self, tokens, bpos):
80
+ """Block forward on caller-owned device tensors; reads no host state."""
81
+ C = self.cfg
82
+ o = _ops()
83
+ B = tokens.numel()
84
+ x = self.w["tok_embd"][tokens].float()
85
+ scale = C.head_dim ** -0.5
86
+
87
+ for i in range(C.n_layer):
88
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps).to(self.wdt)
89
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head,
90
+ C.head_dim).contiguous()
91
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv,
92
+ C.head_dim).contiguous()
93
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv,
94
+ C.head_dim).contiguous()
95
+ o.dflash_qk_rope(q, k, self.w[f"q_norm.{i}"],
96
+ self.w[f"k_norm.{i}"], self.rope_inv, bpos,
97
+ C.rms_eps)
98
+ att = torch.empty_like(q)
99
+ o.dflash_block_attn(att, q, k, v, self.ring_k[i], self.ring_v[i],
100
+ self.ring_pos, bpos, scale)
101
+ x = x + (att.reshape(B, -1) @ self.w[f"wo.{i}"]).float()
102
+
103
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps).to(self.wdt)
104
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
105
+ x = x + ((gate * (f @ self.w[f"ffn_up.{i}"]))
106
+ @ self.w[f"ffn_down.{i}"]).float()
107
+
108
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
109
+ return (x.to(self.wdt) @ self.w["lm_head"]).float()
110
+
111
+ def draft_greedy(self, id_last, n_past, n_draft=None):
112
+ return self.block_step(id_last, n_past, n_draft)[1:].argmax(dim=-1)
113
+
114
+ # ---- graphed step ---------------------------------------------------
115
+ def _static_buffers(self, B):
116
+ """Every tensor a captured step touches, allocated once and held."""
117
+ C = self.cfg
118
+ d = self.device
119
+ wdt = self.wdt
120
+ s = {
121
+ "tokens": torch.full((B,), C.mask_token_id, dtype=torch.int64,
122
+ device=d),
123
+ "arange": torch.arange(B, dtype=torch.int32, device=d),
124
+ "n_past": torch.zeros((), dtype=torch.int32, device=d),
125
+ "bpos": torch.empty(B, dtype=torch.int32, device=d),
126
+ "xw": torch.empty(B, C.n_embd, dtype=wdt, device=d),
127
+ "x": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
128
+ "sq": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
129
+ "ms": torch.empty(B, 1, dtype=torch.float32, device=d),
130
+ "hn": torch.empty(B, C.n_embd, dtype=torch.float32, device=d),
131
+ "h": torch.empty(B, C.n_embd, dtype=wdt, device=d),
132
+ "q": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
133
+ "k": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
134
+ "v": torch.empty(B, C.n_head_kv * C.head_dim, dtype=wdt, device=d),
135
+ "att": torch.empty(B, C.n_head * C.head_dim, dtype=wdt, device=d),
136
+ "ao": torch.empty(B, C.n_embd, dtype=wdt, device=d),
137
+ "g1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
138
+ "sg": torch.empty(B, C.n_ff, dtype=wdt, device=d),
139
+ "u1": torch.empty(B, C.n_ff, dtype=wdt, device=d),
140
+ "d1": torch.empty(B, C.n_embd, dtype=wdt, device=d),
141
+ "lg": torch.empty(B, C.n_vocab, dtype=wdt, device=d),
142
+ "logits": torch.empty(B, C.n_vocab, dtype=torch.float32,
143
+ device=d),
144
+ }
145
+ return s
146
+
147
+ def _rms_static(self, src, w, s, out):
148
+ """RMS norm of `src` into `out` using only held buffers."""
149
+ torch.pow(src, 2, out=s["sq"])
150
+ torch.mean(s["sq"], -1, keepdim=True, out=s["ms"])
151
+ s["ms"].add_(self.cfg.rms_eps).rsqrt_()
152
+ torch.mul(src, s["ms"], out=out)
153
+ out.mul_(w)
154
+
155
+ def _forward_static(self, s):
156
+ """Allocation-free block forward into held buffers; numerically
157
+ identical to `_forward`."""
158
+ C = self.cfg
159
+ o = _ops()
160
+ B = s["tokens"].numel()
161
+ scale = C.head_dim ** -0.5
162
+ torch.index_select(self.w["tok_embd"], 0, s["tokens"], out=s["xw"])
163
+ s["x"].copy_(s["xw"])
164
+ for i in range(C.n_layer):
165
+ self._rms_static(s["x"], self.w[f"attn_norm.{i}"], s, s["hn"])
166
+ s["h"].copy_(s["hn"])
167
+ torch.matmul(s["h"], self.w[f"wq.{i}"], out=s["q"])
168
+ torch.matmul(s["h"], self.w[f"wk.{i}"], out=s["k"])
169
+ torch.matmul(s["h"], self.w[f"wv.{i}"], out=s["v"])
170
+ qv = s["q"].view(B, C.n_head, C.head_dim)
171
+ kv_ = s["k"].view(B, C.n_head_kv, C.head_dim)
172
+ vv = s["v"].view(B, C.n_head_kv, C.head_dim)
173
+ o.dflash_qk_rope(qv, kv_, self.w[f"q_norm.{i}"],
174
+ self.w[f"k_norm.{i}"], self.rope_inv, s["bpos"],
175
+ C.rms_eps)
176
+ av = s["att"].view(B, C.n_head, C.head_dim)
177
+ o.dflash_block_attn(av, qv, kv_, vv, self.ring_k[i],
178
+ self.ring_v[i], self.ring_pos, s["bpos"],
179
+ scale)
180
+ torch.matmul(s["att"], self.w[f"wo.{i}"], out=s["ao"])
181
+ s["x"].add_(s["ao"])
182
+ self._rms_static(s["x"], self.w[f"ffn_norm.{i}"], s, s["hn"])
183
+ s["h"].copy_(s["hn"])
184
+ torch.matmul(s["h"], self.w[f"ffn_gate.{i}"], out=s["g1"])
185
+ # fused silu keeps the step bitwise-equal to the eager path
186
+ torch.ops.aten.silu.out(s["g1"], out=s["sg"])
187
+ torch.matmul(s["h"], self.w[f"ffn_up.{i}"], out=s["u1"])
188
+ s["sg"].mul_(s["u1"])
189
+ torch.matmul(s["sg"], self.w[f"ffn_down.{i}"], out=s["d1"])
190
+ s["x"].add_(s["d1"])
191
+ self._rms_static(s["x"], self.w["out_norm"], s, s["hn"])
192
+ s["h"].copy_(s["hn"])
193
+ torch.matmul(s["h"], self.w["lm_head"], out=s["lg"])
194
+ s["logits"].copy_(s["lg"])
195
+ return s["logits"]
196
+
197
+ def capture_step(self, n_draft=None):
198
+ """Graph-captured block step over static buffers (the region allocates
199
+ nothing); returns step(id_last, n_past) -> logits, overwritten per replay."""
200
+ C = self.cfg
201
+ if n_draft is None:
202
+ n_draft = C.block_size - 1
203
+ s = self._static_buffers(n_draft + 1)
204
+
205
+ stream = torch.cuda.Stream(device=self.device)
206
+ stream.wait_stream(torch.cuda.current_stream())
207
+ with torch.cuda.stream(stream):
208
+ for _ in range(3): # warm kernels and cuBLAS
209
+ torch.add(s["arange"], s["n_past"], out=s["bpos"])
210
+ self._forward_static(s)
211
+ torch.cuda.current_stream().wait_stream(stream)
212
+ torch.cuda.synchronize()
213
+
214
+ graph = torch.cuda.CUDAGraph()
215
+ with torch.cuda.graph(graph):
216
+ torch.add(s["arange"], s["n_past"], out=s["bpos"]) # in-graph: replay sees updates
217
+ logits = self._forward_static(s)
218
+
219
+ def step(id_last, n_past):
220
+ s["tokens"][0].fill_(int(id_last))
221
+ s["n_past"].fill_(int(n_past))
222
+ graph.replay()
223
+ return logits
224
+
225
+ step.graph = graph
226
+ step.buffers = s
227
+ return step
228
+
229
+ # ---- verification ---------------------------------------------------
230
+ def accept(self, draft, target):
231
+ """Leading agreement count, device-side."""
232
+ o = _ops()
233
+ n = torch.zeros(1, dtype=torch.int32, device=self.device)
234
+ o.dflash_accept(n, draft.to(torch.int32).contiguous(),
235
+ target.to(torch.int32).contiguous())
236
+ return n
build/torch213-cxx11-cu132-x86_64-linux/gguf_io.py ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Load the DFlash drafter GGUF into reference-layout fp32 tensors; 2-D weights
2
+ transpose from GGUF [out, in] to [in, out]; tok_embd and lm_head are the
3
+ caller's (they belong to the target model)."""
4
+ import numpy as np
5
+ import torch
6
+ from gguf import GGUFReader
7
+ from gguf import quants as gq
8
+
9
+ from .reference import DFlashConfig
10
+
11
+ _BLK = {
12
+ "attn_norm": "attn_norm", "attn_q": "wq", "attn_k": "wk", "attn_v": "wv",
13
+ "attn_output": "wo", "attn_q_norm": "q_norm", "attn_k_norm": "k_norm",
14
+ "ffn_norm": "ffn_norm", "ffn_gate": "ffn_gate", "ffn_up": "ffn_up",
15
+ "ffn_down": "ffn_down",
16
+ }
17
+ _TOP = {"fc": "fc", "enc.output_norm": "enc_norm", "output_norm": "out_norm"}
18
+
19
+
20
+ def _field(reader, key, default=None):
21
+ f = reader.get_field(key)
22
+ if f is None:
23
+ return default
24
+ v = f.contents()
25
+ return v
26
+
27
+
28
+ def load_drafter(path):
29
+ """-> (DFlashConfig, weights dict) with fp32 tensors in reference layout."""
30
+ r = GGUFReader(str(path))
31
+ cfg = DFlashConfig(
32
+ n_layer=int(_field(r, "dflash.block_count")),
33
+ n_embd=int(_field(r, "dflash.embedding_length")),
34
+ n_head=int(_field(r, "dflash.attention.head_count")),
35
+ n_head_kv=int(_field(r, "dflash.attention.head_count_kv")),
36
+ head_dim=int(_field(r, "dflash.attention.key_length")),
37
+ n_ff=int(_field(r, "dflash.feed_forward_length")),
38
+ rope_base=float(_field(r, "dflash.rope.freq_base")),
39
+ rms_eps=float(_field(r, "dflash.attention.layer_norm_rms_epsilon")),
40
+ window=int(_field(r, "dflash.attention.sliding_window")),
41
+ block_size=int(_field(r, "dflash.block_size")),
42
+ target_layers=tuple(_field(r, "dflash.target_layers")),
43
+ )
44
+ w = {}
45
+ for t in r.tensors:
46
+ name = t.name
47
+ assert name.endswith(".weight"), name
48
+ base = name[: -len(".weight")]
49
+ if base.startswith("blk."):
50
+ _, idx, part = base.split(".", 2)
51
+ key = f"{_BLK[part]}.{idx}"
52
+ else:
53
+ key = _TOP[base]
54
+ data = gq.dequantize(t.data, t.tensor_type)
55
+ arr = torch.from_numpy(np.ascontiguousarray(data)).float()
56
+ if arr.dim() == 2:
57
+ arr = arr.t().contiguous()
58
+ w[key] = arr
59
+ expect = 3 + 11 * cfg.n_layer
60
+ assert len(w) == expect, (len(w), expect)
61
+ return cfg, w
build/torch213-cxx11-cu132-x86_64-linux/metadata.json ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "dflash-ops",
3
+ "id": "_dflash_ops_cuda_03c9586",
4
+ "version": 1,
5
+ "license": "Apache-2.0",
6
+ "python-depends": [],
7
+ "kernel-depends": [],
8
+ "backend": {
9
+ "type": "cuda",
10
+ "archs": [
11
+ "10.0",
12
+ "12.0",
13
+ "8.0",
14
+ "8.6",
15
+ "8.9",
16
+ "9.0"
17
+ ]
18
+ },
19
+ "digest": {
20
+ "algorithm": "sha256",
21
+ "files": {
22
+ "__init__.py": "wNpuIbQEXTfFNjrmz6aISM46VFgMKAHkqqu+ECJJS20=",
23
+ "_dflash_ops_cuda_03c9586.abi3.so": "EnfBcQo0kNhryIZWXSB00ab2JXsBpCtOfNPiaPOfwDk=",
24
+ "_ops.py": "+6e3Oo6lwRkZaeOrhSSZEwWYs4/Fpd/zQgJj4MVEi9I=",
25
+ "drafter.py": "wGU5TWlXWr/ZogxQr4pho5Wku66UUygnczpsTu82dls=",
26
+ "gguf_io.py": "XrgF2dH7LNR1KTNKKu/pKhh6wT90bCjcjCAgmyGsuZA=",
27
+ "reference.py": "InmFS9rUwURZ7ZGVUxwQJCCjJZR/hKWrF3eMfp4zQvY="
28
+ }
29
+ },
30
+ "provenance": {
31
+ "kernel-builder": {
32
+ "version": "0.17.0-dev0",
33
+ "sha": "2c40e10d3da1392245ee81bd05b55fb3103b2b34",
34
+ "dirty": false
35
+ },
36
+ "kernel": {
37
+ "sha": "03c9586154cc2afa6efaa7b111dccef715ec9d69",
38
+ "dirty": false
39
+ }
40
+ }
41
+ }
build/torch213-cxx11-cu132-x86_64-linux/reference.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Eager fp32 DFlash drafter reference, transcribed from llama.cpp's
2
+ llama_model_dflash graph; the CUDA ops are certified against this module."""
3
+ from dataclasses import dataclass, field
4
+
5
+ import torch
6
+
7
+
8
+ @dataclass
9
+ class DFlashConfig:
10
+ n_layer: int = 5
11
+ n_embd: int = 6656
12
+ n_head: int = 32
13
+ n_head_kv: int = 8
14
+ head_dim: int = 128
15
+ n_ff: int = 19968
16
+ n_vocab: int = 202048
17
+ rope_base: float = 500000.0
18
+ rms_eps: float = 1e-6
19
+ window: int = 2048 # SWA width; also the ring capacity
20
+ block_size: int = 16
21
+ mask_token_id: int = 201818
22
+ target_layers: tuple = (2, 14, 26, 38, 50)
23
+
24
+ @property
25
+ def n_feat(self):
26
+ return len(self.target_layers) * self.n_embd
27
+
28
+ @classmethod
29
+ def tiny(cls):
30
+ """Toy sizes with the real structure; head_dim stays a multiple of 32."""
31
+ return cls(n_layer=2, n_embd=64, n_head=4, n_head_kv=2, head_dim=32,
32
+ n_ff=96, n_vocab=997, window=32, block_size=8,
33
+ mask_token_id=990, target_layers=(1, 2))
34
+
35
+
36
+ def rms_norm(x, w, eps):
37
+ """llama.cpp LLM_NORM_RMS: x * w / sqrt(mean(x^2) + eps), fp32."""
38
+ v = x.float()
39
+ return (v * torch.rsqrt(v.pow(2).mean(-1, keepdim=True) + eps)) * w.float()
40
+
41
+
42
+ def rope_inv_freq(head_dim, base, device="cpu"):
43
+ """fp64 NEOX inverse frequencies base^(-2i/head_dim), host-evaluated so the
44
+ table is device-invariant."""
45
+ half = head_dim // 2
46
+ t = base ** (-torch.arange(half, dtype=torch.float64) * 2.0 / head_dim)
47
+ return t.to(device)
48
+
49
+
50
+ def rope_neox(x, pos, base=None, inv=None):
51
+ """NEOX rope over pairs (i, i + d/2), fp32; x [T, H, D], pos [T]; pass
52
+ `inv` to reuse a precomputed table."""
53
+ T, H, D = x.shape
54
+ half = D // 2
55
+ if inv is None:
56
+ inv = rope_inv_freq(D, base, x.device)
57
+ ang = pos.to(torch.float64)[:, None] * inv[None, :] # [T, half]
58
+ cos = ang.cos().to(torch.float32)[:, None, :]
59
+ sin = ang.sin().to(torch.float32)[:, None, :]
60
+ xf = x.float()
61
+ x1, x2 = xf[..., :half], xf[..., half:]
62
+ return torch.cat([x1 * cos - x2 * sin, x1 * sin + x2 * cos], dim=-1)
63
+
64
+
65
+ class DFlashRef:
66
+ """Reference drafter over an fp32 weight dict (layout as in
67
+ `random_weights`) with a sliding ring KV state."""
68
+
69
+ def __init__(self, cfg: DFlashConfig, weights: dict, device="cpu",
70
+ ring_dtype="fp32"):
71
+ self.cfg = cfg
72
+ self.w = {k: v.to(device=device, dtype=torch.float32)
73
+ for k, v in weights.items()}
74
+ self.device = torch.device(device)
75
+ C = cfg
76
+ # ring storage dtype; arithmetic stays fp32
77
+ self.ring_dt = (torch.bfloat16 if ring_dtype == "bf16"
78
+ else torch.float32)
79
+ self.rope_inv = rope_inv_freq(C.head_dim, C.rope_base, device)
80
+ # per-layer ring K/V [window, Hkv, D]; ring_pos = slot's position, -1 empty
81
+ self.ring_k = torch.zeros(C.n_layer, C.window, C.n_head_kv, C.head_dim,
82
+ device=device, dtype=self.ring_dt)
83
+ self.ring_v = torch.zeros_like(self.ring_k)
84
+ self.ring_pos = torch.full((C.window,), -1, dtype=torch.int64,
85
+ device=device)
86
+
87
+ # ---- encoder --------------------------------------------------------
88
+ def encode(self, feats):
89
+ """Fuse per-position target features [T, n_feat] to g [T, n_embd]."""
90
+ g = feats.float() @ self.w["fc"]
91
+ return rms_norm(g, self.w["enc_norm"], self.cfg.rms_eps)
92
+
93
+ # ---- KV injection ---------------------------------------------------
94
+ def inject(self, g, pos):
95
+ """Project fused features into every layer's ring at `pos` [T], chunked
96
+ at `window` so no two tokens in one pass share a slot."""
97
+ C = self.cfg
98
+ for beg in range(0, len(pos), C.window):
99
+ p = pos[beg:beg + C.window]
100
+ gc = g[beg:beg + C.window]
101
+ slots = p % C.window
102
+ for i in range(C.n_layer):
103
+ k = (gc @ self.w[f"wk.{i}"]).view(-1, C.n_head_kv, C.head_dim)
104
+ v = (gc @ self.w[f"wv.{i}"]).view(-1, C.n_head_kv, C.head_dim)
105
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
106
+ k = rope_neox(k, p, inv=self.rope_inv)
107
+ self.ring_k[i, slots] = k.to(self.ring_dt)
108
+ self.ring_v[i, slots] = v.to(self.ring_dt)
109
+ self.ring_pos[slots] = p
110
+
111
+ # ---- noise-block forward -------------------------------------------
112
+ def block_step(self, id_last, n_past, n_draft=None):
113
+ """Denoise [id_last, mask x n_draft] at n_past..; -> [n_draft+1, n_vocab]."""
114
+ C = self.cfg
115
+ if n_draft is None:
116
+ n_draft = C.block_size - 1
117
+ B = n_draft + 1
118
+ tokens = torch.full((B,), C.mask_token_id, dtype=torch.int64,
119
+ device=self.device)
120
+ tokens[0] = id_last
121
+ pos = n_past + torch.arange(B, device=self.device)
122
+ x = self.w["tok_embd"][tokens]
123
+
124
+ live = self.ring_pos >= 0
125
+ for i in range(C.n_layer):
126
+ h = rms_norm(x, self.w[f"attn_norm.{i}"], C.rms_eps)
127
+ q = (h @ self.w[f"wq.{i}"]).view(B, C.n_head, C.head_dim)
128
+ k = (h @ self.w[f"wk.{i}"]).view(B, C.n_head_kv, C.head_dim)
129
+ v = (h @ self.w[f"wv.{i}"]).view(B, C.n_head_kv, C.head_dim)
130
+ q = rms_norm(q, self.w[f"q_norm.{i}"], C.rms_eps)
131
+ k = rms_norm(k, self.w[f"k_norm.{i}"], C.rms_eps)
132
+ q = rope_neox(q, pos, inv=self.rope_inv)
133
+ k = rope_neox(k, pos, inv=self.rope_inv)
134
+
135
+ # keys = live ring + block; non-causal, SWA masks only the deep past
136
+ keys = torch.cat([self.ring_k[i, live].float(), k], dim=0)
137
+ vals = torch.cat([self.ring_v[i, live].float(), v], dim=0)
138
+ kpos = torch.cat([self.ring_pos[live], pos], dim=0)
139
+
140
+ gq = C.n_head // C.n_head_kv
141
+ qh = q.permute(1, 0, 2) # [H, B, D]
142
+ kh = keys.permute(1, 0, 2).repeat_interleave(gq, dim=0)
143
+ vh = vals.permute(1, 0, 2).repeat_interleave(gq, dim=0)
144
+ att = qh @ kh.transpose(1, 2) / (C.head_dim ** 0.5) # [H, B, S]
145
+ masked = (pos[:, None] - kpos[None, :]) >= C.window # SWA
146
+ att = att.masked_fill(masked[None, :, :], float("-inf"))
147
+ att = att.softmax(dim=-1)
148
+ out = (att @ vh).permute(1, 0, 2).reshape(B, -1) # [B, H*D]
149
+ x = x + out @ self.w[f"wo.{i}"]
150
+
151
+ f = rms_norm(x, self.w[f"ffn_norm.{i}"], C.rms_eps)
152
+ gate = torch.nn.functional.silu(f @ self.w[f"ffn_gate.{i}"])
153
+ x = x + (gate * (f @ self.w[f"ffn_up.{i}"])) @ self.w[f"ffn_down.{i}"]
154
+
155
+ x = rms_norm(x, self.w["out_norm"], C.rms_eps)
156
+ return x @ self.w["lm_head"]
157
+
158
+ def draft_greedy(self, id_last, n_past, n_draft=None):
159
+ """Greedy drafts from block positions 1..n_draft (position 0 unused)."""
160
+ logits = self.block_step(id_last, n_past, n_draft)
161
+ return logits[1:].argmax(dim=-1)
162
+
163
+
164
+ def random_weights(cfg: DFlashConfig, seed=0, device="cpu"):
165
+ """Gaussian weights at transformer-typical scale, for structural tests."""
166
+ g = torch.Generator(device="cpu").manual_seed(seed)
167
+
168
+ def t(*shape, s=0.02):
169
+ return torch.randn(*shape, generator=g) * s
170
+
171
+ C = cfg
172
+ w = {"fc": t(C.n_feat, C.n_embd), "enc_norm": torch.ones(C.n_embd),
173
+ "out_norm": torch.ones(C.n_embd),
174
+ "tok_embd": t(C.n_vocab, C.n_embd),
175
+ "lm_head": t(C.n_embd, C.n_vocab)}
176
+ for i in range(C.n_layer):
177
+ w[f"attn_norm.{i}"] = torch.ones(C.n_embd)
178
+ w[f"wq.{i}"] = t(C.n_embd, C.n_head * C.head_dim)
179
+ w[f"wk.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
180
+ w[f"wv.{i}"] = t(C.n_embd, C.n_head_kv * C.head_dim)
181
+ w[f"wo.{i}"] = t(C.n_head * C.head_dim, C.n_embd)
182
+ w[f"q_norm.{i}"] = torch.ones(C.head_dim)
183
+ w[f"k_norm.{i}"] = torch.ones(C.head_dim)
184
+ w[f"ffn_norm.{i}"] = torch.ones(C.n_embd)
185
+ w[f"ffn_gate.{i}"] = t(C.n_embd, C.n_ff)
186
+ w[f"ffn_up.{i}"] = t(C.n_embd, C.n_ff)
187
+ w[f"ffn_down.{i}"] = t(C.n_ff, C.n_embd)
188
+ return {k: v.to(device) for k, v in w.items()}