Download offload/dspark/worker/ops.py from ProprietaryLegal/dsv41-offload: direct link, hf CLI and curl.
- Browser
- Download file 12.7 kB
-
https://huggingface.co/ProprietaryLegal/dsv41-offload/resolve/main/offload/dspark/worker/ops.py
- Command line
-
hf download hf://ProprietaryLegal/dsv41-offload/offload/dspark/worker/ops.py
-
curl -L -o ops.py https://huggingface.co/ProprietaryLegal/dsv41-offload/resolve/main/offload/dspark/worker/ops.py
12.7 kB
| """Small ops of the DSpark drafter forward, written to the engine's semantics (NOTES.md). | |
| Everything here is plain torch except `markov_bias_rows`, a copy of the serve's Triton kernel | |
| (vllm/models/deepseek_v41/nvidia/ops/markov_cache.py, Apache-2.0) so cached and computed Markov rows have the same | |
| bits as on the Spark's code path. Float formats follow the engine: the hyper-connection stream and every activation | |
| handed between modules are bf16; norms, mixes, RoPE, attention scores and routing are computed in fp32. | |
| """ | |
| from __future__ import annotations | |
| import math | |
| import torch | |
| import triton | |
| import triton.language as tl | |
| # --------------------------------------------------------------------------------------------- RoPE | |
| def rope_cos_sin(max_pos: int, rope_dim: int = 64, base: float = 10000.0, beta_fast: int = 32, beta_slow: int = 1, | |
| orig_max_pos: int = 1048576) -> torch.Tensor: | |
| """fp32 [max_pos, rope_dim] = cat(cos, sin) exactly as vLLM's DeepseekV4ScalingRotaryEmbedding builds it for the | |
| pure sliding-window layers (common/rope.py: rope_type deepseek_yarn, factor 1.0, mscale 1, original max position = | |
| max_position_embeddings): the YaRN blend of two equal frequency sets, then an fp32 outer product with the | |
| positions and cos / sin of each row. Built on the CPU like vLLM's (at module init, before .to(device)).""" | |
| pos_freqs = base ** (torch.arange(0, rope_dim, 2, dtype=torch.float) / rope_dim) | |
| inv_freq_extrapolation = 1.0 / pos_freqs | |
| inv_freq_interpolation = 1.0 / (1.0 * pos_freqs) | |
| def corr_dim(num_rot: float) -> float: | |
| return (rope_dim * math.log(orig_max_pos / (num_rot * 2 * math.pi))) / (2 * math.log(base)) | |
| low = max(math.floor(corr_dim(beta_fast)), 0) | |
| high = min(math.ceil(corr_dim(beta_slow)), rope_dim - 1) | |
| if low == high: | |
| high += 0.001 | |
| ramp = torch.clamp((torch.arange(rope_dim // 2, dtype=torch.float) - low) / (high - low), 0, 1) | |
| mask = 1 - ramp | |
| inv_freq = inv_freq_interpolation * (1 - mask) + inv_freq_extrapolation * mask | |
| t = torch.arange(max_pos, dtype=torch.float32) | |
| freqs = torch.einsum("i,j -> ij", t, inv_freq) | |
| return torch.cat((freqs.cos() * 1.0, freqs.sin() * 1.0), dim=-1) | |
| def apply_rope(x: torch.Tensor, pos: torch.Tensor, cos_sin: torch.Tensor, inverse: bool = False) -> torch.Tensor: | |
| """Rotate the last rope_dim channels of x (interleaved pairs, as is_neox_style=False), in fp32, at positions pos. | |
| x: [N, ..., D] (any float dtype), pos: [N] int64. Returns a new tensor in x's dtype; the NoPE channels are copied.""" | |
| rd = cos_sin.shape[-1] | |
| cs = cos_sin[pos] # [N, rd] | |
| cos, sin = cs[:, : rd // 2], cs[:, rd // 2:] | |
| shape = [x.shape[0]] + [1] * (x.dim() - 2) + [rd // 2] | |
| cos, sin = cos.view(shape), sin.view(shape) | |
| if inverse: | |
| sin = -sin | |
| r = x[..., -rd:].float().unflatten(-1, (rd // 2, 2)) | |
| x0, x1 = r[..., 0], r[..., 1] | |
| y = torch.stack((x0 * cos - x1 * sin, x1 * cos + x0 * sin), dim=-1).flatten(-2) | |
| out = x.clone() | |
| out[..., -rd:] = y.to(x.dtype) | |
| return out | |
| # --------------------------------------------------------------------------------------------- KV record | |
| def kv_record_qdq(kv: torch.Tensor, nope: int = 448, group: int = 64) -> torch.Tensor: | |
| """Values of the V4 fp8_ds_mla record (SM12x, 584 B): the NoPE channels as e4m3 with one power-of-two (UE8M0) scale | |
| per `group` channels, scale = 2^ceil(log2(amax / 448)); the RoPE channels kept bf16. Returns bf16 [.., 512] holding | |
| exactly the values the engine's attention reads back (e4m3 x 2^k is exact in bf16). | |
| The ceil(log2) is taken from the IEEE bits of amax * (1/448) (DeepSeek's fast_round_scale, the plugin's | |
| _qdq_ue8m0 kernel): exact at powers of two, where log2f-then-ceil can round the wrong way.""" | |
| n = kv[..., :nope].float().unflatten(-1, (nope // group, group)) | |
| a = (n.abs().amax(-1, keepdim=True) * (1.0 / 448.0)).clamp_min(2.0 ** -126) | |
| bits = a.view(torch.int32) | |
| e = ((bits >> 23) & 0xFF) - 127 + ((bits & 0x7FFFFF) != 0).to(torch.int32) | |
| scale = ((e + 127) << 23).view(torch.float32) | |
| q = (n / scale).clamp(-448.0, 448.0).to(torch.float8_e4m3fn).float() * scale | |
| out = kv.to(torch.bfloat16).clone() | |
| out[..., :nope] = q.flatten(-2).to(torch.bfloat16) | |
| return out | |
| # --------------------------------------------------------------------------------------------- norms / mHC | |
| def rms_norm(x: torch.Tensor, w: torch.Tensor, eps: float) -> torch.Tensor: | |
| """DeepSeek reference RMSNorm: fp32 math, weight applied in fp32, one rounding to x's dtype (bf16).""" | |
| xf = x.float() | |
| xf = xf * torch.rsqrt(xf.square().mean(-1, keepdim=True) + eps) | |
| return (w.float() * xf).to(x.dtype) | |
| def hc_mixes(stream: torch.Tensor, fn: torch.Tensor, scale: torch.Tensor, base: torch.Tensor, rms_eps: float, | |
| hc_eps: float, iters: int) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: | |
| """pre [T, hc], post [T, hc], comb [T, hc, hc] (fp32) from the bf16 stream [T, hc, H] (mhc_pre_delayed_torch).""" | |
| hc = stream.shape[1] | |
| x = stream.flatten(1).float() | |
| mixes = (x @ fn.t()) * torch.rsqrt(x.square().mean(-1, keepdim=True) + rms_eps) | |
| pre = torch.sigmoid(mixes[:, :hc] * scale[0] + base[:hc]) + hc_eps | |
| post = torch.sigmoid(mixes[:, hc:2 * hc] * scale[1] + base[hc:2 * hc]) * 2.0 | |
| comb = mixes[:, 2 * hc:].view(-1, hc, hc) * scale[2] + base[2 * hc:].view(1, hc, hc) | |
| comb = torch.softmax(comb, dim=-1) + hc_eps | |
| comb = comb / (comb.sum(dim=-2, keepdim=True) + hc_eps) | |
| for _ in range(iters - 1): | |
| comb = comb / (comb.sum(dim=-1, keepdim=True) + hc_eps) | |
| comb = comb / (comb.sum(dim=-2, keepdim=True) + hc_eps) | |
| return pre, post, comb | |
| def hc_collapse(stream: torch.Tensor, pre_mix: torch.Tensor | None) -> torch.Tensor: | |
| """[T, hc, H] -> [T, H]: copy 0 when pre_mix is None (the first stage), else sum_i pre_i * stream_i in fp32 -> bf16.""" | |
| if pre_mix is None: | |
| return stream[:, 0].contiguous() | |
| return (pre_mix.unsqueeze(-1) * stream.float()).sum(dim=1).to(stream.dtype) | |
| def hc_post(y: torch.Tensor, stream: torch.Tensor, post: torch.Tensor, comb: torch.Tensor) -> torch.Tensor: | |
| """new stream_j = post_j * y + sum_i comb[i, j] * stream_i, fp32 -> bf16 (mhc_post_torch).""" | |
| mixed = torch.einsum("tij,tih->tjh", comb, stream.float()) | |
| return (mixed + post.unsqueeze(-1) * y.float().unsqueeze(1)).to(stream.dtype) | |
| # --------------------------------------------------------------------------------------------- routing | |
| def route(x: torch.Tensor, gate_w: torch.Tensor, bias: torch.Tensor, top_k: int, route_scale: float | |
| ) -> tuple[torch.Tensor, torch.Tensor]: | |
| """sqrtsoftplus / noaux_tc: experts by top-k of score + bias, weights = the unbiased scores renormalized x scale. | |
| gate_w fp32 [E, H]. Returns (ids int64 [T, k], weights fp32 [T, k]).""" | |
| logits = x.float() @ gate_w.t() | |
| scores = torch.nn.functional.softplus(logits).sqrt() | |
| ids = (scores + bias).topk(top_k, dim=-1)[1] | |
| w = scores.gather(1, ids) | |
| w = w / (w.sum(dim=-1, keepdim=True) + 1e-20) * route_scale | |
| return ids, w | |
| # --------------------------------------------------------------------------------------------- attention | |
| def block_attention(q: torch.Tensor, ctx_kv: torch.Tensor, ctx_valid: torch.Tensor, blk_kv: torch.Tensor, | |
| sink: torch.Tensor, scale: float) -> torch.Tensor: | |
| """The DSpark block attention: every block row sees the request's valid context window and the whole block. | |
| q [B, k, Hh, D] bf16; ctx_kv [B, W, D] bf16 (keys = values, MQA); ctx_valid [B, W] bool; blk_kv [B, k, D] bf16; | |
| sink [Hh] fp32 (joins the softmax denominator only). fp32 scores; the probabilities are rounded to bf16 for the | |
| weighted sum (as DeepSeek's sparse_attn kernel and FlashInfer do), the denominator stays fp32; bf16 out.""" | |
| B, k, Hh, D = q.shape | |
| keys = torch.cat((ctx_kv, blk_kv), dim=1).float() # [B, W + k, D] (exact bf16 values) | |
| s = torch.bmm(q.reshape(B, k * Hh, D).float(), keys.transpose(1, 2)) * scale # [B, k*Hh, W+k] | |
| valid = torch.cat((ctx_valid, torch.ones(B, k, dtype=torch.bool, device=q.device)), dim=1) | |
| s = s.masked_fill(~valid.unsqueeze(1), float("-inf")) | |
| sk = sink.view(1, 1, Hh).expand(B, k, Hh).reshape(B, k * Hh, 1) | |
| m = torch.maximum(s.amax(-1, keepdim=True), sk) | |
| p = torch.exp(s - m) | |
| denom = p.sum(-1, keepdim=True) + torch.exp(sk - m) | |
| o = torch.bmm(p.to(torch.bfloat16).float(), keys) / denom | |
| return o.view(B, k, Hh, D).to(torch.bfloat16) | |
| # --------------------------------------------------------------------------------------------- Markov bias | |
| # Copied from vllm/models/deepseek_v41/nvidia/ops/markov_cache.py (the running image, Apache-2.0): one program per | |
| # (row, 64 vocab columns); cached rows are read back, others computed as an fp32 dot over the rank, stored in the | |
| # output dtype. The cache is filled by this same kernel, so a token's bias has the same bits either way. | |
| _BLOCK_V = 64 | |
| def _markov_bias_kernel(ids_ptr, slot_ptr, cache_ptr, emb_ptr, w2_ptr, out_ptr, V, cache_stride, w2_stride, | |
| emb_stride, out_stride, R: tl.constexpr, BLOCK_V: tl.constexpr): | |
| b = tl.program_id(0) | |
| cols = tl.program_id(1) * BLOCK_V + tl.arange(0, BLOCK_V) | |
| mask = cols < V | |
| tok = tl.load(ids_ptr + b).to(tl.int64) | |
| slot = tl.load(slot_ptr + tok) | |
| if slot >= 0: | |
| row = tl.load(cache_ptr + slot.to(tl.int64) * cache_stride + cols, mask=mask) | |
| tl.store(out_ptr + b * out_stride + cols, row, mask=mask) | |
| else: | |
| r = tl.arange(0, R) | |
| e = tl.load(emb_ptr + b * emb_stride + r).to(tl.float32) | |
| w = tl.load(w2_ptr + cols[:, None].to(tl.int64) * w2_stride + r[None, :], mask=mask[:, None], other=0.0) | |
| acc = tl.sum(w.to(tl.float32) * e[None, :], axis=1) | |
| tl.store(out_ptr + b * out_stride + cols, acc.to(out_ptr.dtype.element_ty), mask=mask) | |
| def markov_bias_rows(token_ids: torch.Tensor, slot_of_token: torch.Tensor, cache: torch.Tensor, | |
| markov_embed: torch.Tensor, w2: torch.Tensor, out: torch.Tensor) -> torch.Tensor: | |
| """out[b] = cache[slot_of_token[t_b]] if cached, else w2 @ markov_embed[b] (fp32 dot, one rounding).""" | |
| num_rows, rank = markov_embed.shape | |
| vocab = w2.shape[0] | |
| assert w2.stride(1) == 1 and markov_embed.stride(1) == 1 and out.stride(1) == 1 | |
| if num_rows == 0: | |
| return out | |
| grid = (num_rows, triton.cdiv(vocab, _BLOCK_V)) | |
| _markov_bias_kernel[grid](token_ids, slot_of_token, cache, markov_embed, w2, out, vocab, | |
| cache.stride(0) if cache.numel() else 0, w2.stride(0), markov_embed.stride(0), | |
| out.stride(0), R=rank, BLOCK_V=_BLOCK_V, num_warps=4) | |
| return out | |
| class MarkovBias: | |
| """The Markov bias with cached rows for the serve's most frequent tokens (VLLM_DSPARK_MARKOV_CACHE list, first | |
| `rows` distinct ids, default 4096 like VLLM_DSPARK_MARKOV_CACHE_ROWS).""" | |
| def __init__(self, w1: torch.Tensor, w2: torch.Tensor, token_list: list[int] | None, rows: int = 4096): | |
| self.w1, self.w2 = w1, w2 | |
| vocab, dev = w1.shape[0], w2.device | |
| ids: list[int] = [] | |
| seen: set[int] = set() | |
| for t in token_list or []: | |
| t = int(t) | |
| if 0 <= t < vocab and t not in seen: | |
| seen.add(t) | |
| ids.append(t) | |
| ids = ids[:rows] | |
| self.slot_of_token = torch.full((vocab,), -1, dtype=torch.int32, device=dev) | |
| self.cache = torch.empty((max(len(ids), 1), w2.shape[0]), dtype=torch.bfloat16, device=dev) | |
| if ids: | |
| tok = torch.tensor(ids, dtype=torch.int64, device=dev) | |
| for s in range(0, len(ids), 256): | |
| t = tok[s: s + 256] | |
| markov_bias_rows(t, self.slot_of_token, self.cache, w1[t].contiguous(), w2, self.cache[s: s + 256]) | |
| self.slot_of_token[tok] = torch.arange(len(ids), dtype=torch.int32, device=dev) | |
| self.cached_rows = len(ids) | |
| def embed(self, token_ids: torch.Tensor) -> torch.Tensor: | |
| return self.w1[token_ids] | |
| def __call__(self, token_ids: torch.Tensor, markov_embed: torch.Tensor, out: torch.Tensor | None = None | |
| ) -> torch.Tensor: | |
| if out is None: | |
| out = torch.empty((markov_embed.shape[0], self.w2.shape[0]), dtype=torch.bfloat16, | |
| device=markov_embed.device) | |
| return markov_bias_rows(token_ids, self.slot_of_token, self.cache, markov_embed.contiguous(), self.w2, out) | |