Uploaded using `kernel-builder`.
Browse files- build/torch212-cxx11-cu126-x86_64-linux/__init__.py +23 -0
- build/torch212-cxx11-cu126-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
- build/torch212-cxx11-cu126-x86_64-linux/_ops.py +9 -0
- build/torch212-cxx11-cu126-x86_64-linux/drafter.py +236 -0
- build/torch212-cxx11-cu126-x86_64-linux/gguf_io.py +61 -0
- build/torch212-cxx11-cu126-x86_64-linux/metadata.json +39 -0
- build/torch212-cxx11-cu126-x86_64-linux/reference.py +188 -0
- build/torch212-cxx11-cu130-x86_64-linux/__init__.py +23 -0
- build/torch212-cxx11-cu130-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
- build/torch212-cxx11-cu130-x86_64-linux/_ops.py +9 -0
- build/torch212-cxx11-cu130-x86_64-linux/drafter.py +236 -0
- build/torch212-cxx11-cu130-x86_64-linux/gguf_io.py +61 -0
- build/torch212-cxx11-cu130-x86_64-linux/metadata.json +41 -0
- build/torch212-cxx11-cu130-x86_64-linux/reference.py +188 -0
- build/torch212-cxx11-cu132-x86_64-linux/__init__.py +23 -0
- build/torch212-cxx11-cu132-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
- build/torch212-cxx11-cu132-x86_64-linux/_ops.py +9 -0
- build/torch212-cxx11-cu132-x86_64-linux/drafter.py +236 -0
- build/torch212-cxx11-cu132-x86_64-linux/gguf_io.py +61 -0
- build/torch212-cxx11-cu132-x86_64-linux/metadata.json +41 -0
- build/torch212-cxx11-cu132-x86_64-linux/reference.py +188 -0
- build/torch213-cxx11-cu126-x86_64-linux/__init__.py +23 -0
- build/torch213-cxx11-cu126-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
- build/torch213-cxx11-cu126-x86_64-linux/_ops.py +9 -0
- build/torch213-cxx11-cu126-x86_64-linux/drafter.py +236 -0
- build/torch213-cxx11-cu126-x86_64-linux/gguf_io.py +61 -0
- build/torch213-cxx11-cu126-x86_64-linux/metadata.json +39 -0
- build/torch213-cxx11-cu126-x86_64-linux/reference.py +188 -0
- build/torch213-cxx11-cu130-x86_64-linux/__init__.py +23 -0
- build/torch213-cxx11-cu130-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
- build/torch213-cxx11-cu130-x86_64-linux/_ops.py +9 -0
- build/torch213-cxx11-cu130-x86_64-linux/drafter.py +236 -0
- build/torch213-cxx11-cu130-x86_64-linux/gguf_io.py +61 -0
- build/torch213-cxx11-cu130-x86_64-linux/metadata.json +41 -0
- build/torch213-cxx11-cu130-x86_64-linux/reference.py +188 -0
- build/torch213-cxx11-cu132-x86_64-linux/__init__.py +23 -0
- build/torch213-cxx11-cu132-x86_64-linux/_dflash_ops_cuda_03c9586.abi3.so +3 -0
- build/torch213-cxx11-cu132-x86_64-linux/_ops.py +9 -0
- build/torch213-cxx11-cu132-x86_64-linux/drafter.py +236 -0
- build/torch213-cxx11-cu132-x86_64-linux/gguf_io.py +61 -0
- build/torch213-cxx11-cu132-x86_64-linux/metadata.json +41 -0
- 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()}
|