"""Single-launch W4A16 decode kernel for the Kimi-Linear motif. The CUDA grid is cooperative and persistent. All projection, attention, recurrent-state, routing, and expert phases execute inside that one grid; grid barriers connect phases without returning to Python. Quantized weights are unpacked and dequantized in registers and are never materialized. """ from __future__ import annotations import os from dataclasses import dataclass, field import torch import torch.nn as nn EPS = 1.0e-6 GROUP_SIZE = 128 @dataclass(frozen=True) class Config: hidden: int = 2304 kda_heads: int = 32 kda_head_dim: int = 128 short_conv: int = 4 mla_heads: int = 32 kv_lora: int = 512 qk_nope: int = 128 qk_rope: int = 64 v_head: int = 128 rope_theta: float = 10000.0 n_experts: int = 64 n_active: int = 8 n_shared: int = 1 moe_inter: int = 1024 routed_scaling: float = 2.446 group: int = 128 pattern: tuple = ("K", "K", "K", "M") dtype: torch.dtype = field(default=torch.bfloat16) def build_config(shape: dict) -> Config: return Config(n_experts=int(shape.get("n_experts", 64))) class QuantLinear(nn.Module): def __init__(self, in_f: int, out_f: int, group: int = GROUP_SIZE): super().__init__() self.in_f, self.out_f, self.group = in_f, out_f, group self.register_buffer("w_q", torch.zeros(in_f // 2, out_f, dtype=torch.uint8)) self.register_buffer("scales", torch.zeros(in_f // group, out_f, dtype=torch.bfloat16)) self.register_buffer("zeros", torch.zeros(in_f // group, out_f, dtype=torch.bfloat16)) class QuantExperts(nn.Module): def __init__(self, n: int, in_f: int, out_f: int, group: int = GROUP_SIZE): super().__init__() self.n, self.in_f, self.out_f, self.group = n, in_f, out_f, group self.register_buffer("w_q", torch.zeros(n, in_f // 2, out_f, dtype=torch.uint8)) self.register_buffer("scales", torch.zeros(n, in_f // group, out_f, dtype=torch.bfloat16)) self.register_buffer("zeros", torch.zeros(n, in_f // group, out_f, dtype=torch.bfloat16)) class KDA(nn.Module): def __init__(self, cfg): super().__init__() d, c, h = cfg.hidden, cfg.kda_heads * cfg.kda_head_dim, cfg.kda_heads self.q_proj = QuantLinear(d, c, cfg.group) self.k_proj = QuantLinear(d, c, cfg.group) self.v_proj = QuantLinear(d, c, cfg.group) self.g_proj = QuantLinear(d, c, cfg.group) self.beta_proj = nn.Linear(d, h, bias=False, dtype=cfg.dtype) self.conv_w = nn.Parameter(torch.empty(3, c, cfg.short_conv, dtype=cfg.dtype)) self.o_proj = QuantLinear(c, d, cfg.group) class MLA(nn.Module): def __init__(self, cfg): super().__init__() d, h = cfg.hidden, cfg.mla_heads self.q_proj = QuantLinear(d, h * (cfg.qk_nope + cfg.qk_rope), cfg.group) self.kv_a = QuantLinear(d, cfg.kv_lora + cfg.qk_rope, cfg.group) self.kv_b = QuantLinear(cfg.kv_lora, h * (cfg.qk_nope + cfg.v_head), cfg.group) self.o_proj = QuantLinear(h * cfg.v_head, d, cfg.group) class MoE(nn.Module): def __init__(self, cfg): super().__init__() d, m, e = cfg.hidden, cfg.moe_inter, cfg.n_experts self.router = nn.Linear(d, e, bias=False, dtype=cfg.dtype) self.gate = QuantExperts(e, d, m, cfg.group) self.up = QuantExperts(e, d, m, cfg.group) self.down = QuantExperts(e, m, d, cfg.group) self.s_gate = QuantExperts(cfg.n_shared, d, m, cfg.group) self.s_up = QuantExperts(cfg.n_shared, d, m, cfg.group) self.s_down = QuantExperts(cfg.n_shared, m, d, cfg.group) class Block(nn.Module): def __init__(self, cfg, kind: str): super().__init__() self.kind = kind self.attn_norm = nn.Parameter(torch.ones(cfg.hidden, dtype=cfg.dtype)) self.moe_norm = nn.Parameter(torch.ones(cfg.hidden, dtype=cfg.dtype)) self.attn = KDA(cfg) if kind == "K" else MLA(cfg) self.moe = MoE(cfg) _CPP = r""" #include void kimi_launch(std::vector, torch::Tensor, torch::Tensor, std::vector, torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor, torch::Tensor, int64_t, bool); PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { m.def("launch", &kimi_launch); } """ _CUDA = r""" #include #include #include #include #include #include #include namespace cg = cooperative_groups; using B = __nv_bfloat16; constexpr int D = 2304; constexpr int H = 32; constexpr int DK = 128; constexpr int C = 4096; constexpr int M = 1024; constexpr int ACTIVE = 8; constexpr int SLOTS = 9; constexpr int E = 64; constexpr int KV = 512; constexpr int QR = 64; constexpr int QN = 128; constexpr int QDIM = 192; constexpr int THREADS = 256; struct QW { const unsigned char* q; const B* s; const B* z; }; struct EW { const unsigned char* q; const B* s; const B* z; }; struct MoEW { const B* router; EW gate, up, down, sg, su, sd; }; struct KL { const B* an; QW q, k, v, g; const B* beta; const B* conv; QW o; const B* mn; MoEW moe; }; struct ML { const B* an; QW q, kva, kvb, o; const B* mn; MoEW moe; }; struct KS { float* S; B* cq; B* ck; B* cv; }; struct P { KL kl[3]; ML ml; KS ks[3]; const B* hidden; B* output; const B* cin; const B* kin; B* cout; B* kout; float* work; int L; int copy_cache; int nb; }; __device__ __forceinline__ float lb(const B* p) { return __bfloat162float(*p); } __device__ __forceinline__ void sb(B* p, float x) { *p = __float2bfloat16_rn(x); } __device__ __forceinline__ float br(float x) { return __bfloat162float(__float2bfloat16_rn(x)); } __device__ __forceinline__ float silu(float x) { return x / (1.0f + __expf(-x)); } __device__ __forceinline__ float iq(unsigned char b, int hi) { return float(hi ? (b >> 4) : (b & 15)); } __device__ __forceinline__ void split_info(int N, int Kpairs, int nb, int bid, int &n, int &sid, int &ns, int &lo, int &hi) { int tiles = (N + THREADS - 1) / THREADS; int tile = bid % tiles; sid = bid / tiles; ns = (nb - 1 - tile) / tiles + 1; n = tile * THREADS + threadIdx.x; lo = (Kpairs * sid) / ns; hi = (Kpairs * (sid + 1)) / ns; } __device__ void gemv_part(QW w, const float* x, int K, int N, float* part, int nb) { int n, sid, ns, lo, hi; split_info(N, K / 2, nb, blockIdx.x, n, sid, ns, lo, hi); float acc = 0.0f; if (n < N) { int g0 = lo >> 6, g1 = (hi + 63) >> 6; for (int g = g0; g < g1; ++g) { int a = max(lo, g << 6), b = min(hi, (g + 1) << 6); float s = lb(w.s + g * N + n), z = lb(w.z + g * N + n); float qa = 0.0f, sx = 0.0f; for (int p = a; p < b; ++p) { unsigned char q = w.q[p * N + n]; float x0=x[2*p],x1=x[2*p+1]; qa=fmaf(x0,iq(q,0),qa);qa=fmaf(x1,iq(q,1),qa);sx+=x0+x1; } acc=fmaf(qa-z*sx,s,acc); } } part[blockIdx.x * THREADS + threadIdx.x] = acc; } __device__ void gemv_reduce(float* part, float* out, int N, int nb, bool round_out) { int tiles = (N + THREADS - 1) / THREADS; int tile = blockIdx.x % tiles, sid = blockIdx.x / tiles; int n = tile * THREADS + threadIdx.x; if (sid == 0 && n < N) { int ns = (nb - 1 - tile) / tiles + 1; float v = 0.0f; for (int s = 0; s < ns; ++s) v += part[(s * tiles + tile) * THREADS + threadIdx.x]; out[n] = round_out ? br(v) : v; } } __device__ void qkvg_part(const KL &l, const float* x, float* p0, float* p1, float* p2, float* p3, int nb) { int n, sid, ns, lo, hi; split_info(C, D / 2, nb, blockIdx.x, n, sid, ns, lo, hi); float aq=0, ak=0, av=0, ag=0; if (n < C) { for (int gg = lo >> 6; gg < (hi + 63) >> 6; ++gg) { int a=max(lo,gg<<6), b=min(hi,(gg+1)<<6); float sq=lb(l.q.s+gg*C+n), zq=lb(l.q.z+gg*C+n); float sk=lb(l.k.s+gg*C+n), zk=lb(l.k.z+gg*C+n); float sv=lb(l.v.s+gg*C+n), zv=lb(l.v.z+gg*C+n); float sg=lb(l.g.s+gg*C+n), zg=lb(l.g.z+gg*C+n); float tq=0,tk=0,tv=0,tg=0,sx=0; for (int p=a; p>=1){if(threadIdx.xbest){best=logits[e];bi=e;} } idx[s]=bi; rw[s]=best; } float mx=rw[0]; for(int s=1;s>6;gg<(hi+63)>>6;++gg){ int a=max(lo,gg<<6),b=min(hi,(gg+1)<<6); float sg=lb(wg.s+ep+gg*M+col),zg=lb(wg.z+ep+gg*M+col); float su=lb(wu.s+ep+gg*M+col),zu=lb(wu.z+ep+gg*M+col); float tg=0,tu=0,sx=0; for(int p=a;p>6;gg<(hi+63)>>6;++gg){ int a=max(lo,gg<<6),b=min(hi,(gg+1)<<6); for(int slot=0;slot>6;gg<(hi+63)>>6;++gg){int a=max(lo,gg<<6),b=min(hi,(gg+1)<<6); float s=lb(w.s+gg*N+nn),z=lb(w.z+gg*N+nn); float tq=0,sx=0;for(int p=a;p>5,lane=threadIdx.x&31,gw=blockIdx.x*8+warp,total=nb*8; for(int n=gw;n>=1)a+=__shfl_down_sync(0xffffffff,a,off); if(lane==0)qa[r*H+h]=a; } } __device__ void mla_scores(const float* qa,const float* q,const B* c,const B* kr,float* scores,int T,int nb){ int warp=threadIdx.x>>5,h=threadIdx.x&31,gw=blockIdx.x*8+warp,total=nb*8; for(int t=gw;t>=1){if(threadIdx.x>=1){if(threadIdx.x>6;gg<(hi+63)>>6;++gg){int a=max(lo,gg<<6),b=min(hi,(gg+1)<<6);float s=lb(l.kvb.s+gg*NW+col),z=lb(l.kvb.z+gg*NW+col); float tq=0,sx=0;for(int p=a;p(t.data_ptr());} static const B* cbp(torch::Tensor &t){return reinterpret_cast(t.data_ptr());} static QW qw(std::vector&w,int&i){QW a{w[i].data_ptr(),cbp(w[i+1]),cbp(w[i+2])};i+=3;return a;} static EW ew(std::vector&w,int&i){EW a{w[i].data_ptr(),cbp(w[i+1]),cbp(w[i+2])};i+=3;return a;} static MoEW mw(std::vector&w,int&i){MoEW m{};m.router=cbp(w[i++]);m.gate=ew(w,i);m.up=ew(w,i);m.down=ew(w,i);m.sg=ew(w,i);m.su=ew(w,i);m.sd=ew(w,i);return m;} void kimi_launch(std::vector w,torch::Tensor hidden,torch::Tensor output, std::vector st,torch::Tensor cin,torch::Tensor kin, torch::Tensor cout,torch::Tensor kout,torch::Tensor work,int64_t L,bool copy){ P p{};int i=0; for(int z=0;z<3;++z){KL &l=p.kl[z];l.an=cbp(w[i++]);l.mn=cbp(w[i++]);l.q=qw(w,i);l.k=qw(w,i);l.v=qw(w,i);l.g=qw(w,i); l.beta=cbp(w[i++]);l.conv=cbp(w[i++]);l.o=qw(w,i);l.moe=mw(w,i);} ML &l=p.ml;l.an=cbp(w[i++]);l.mn=cbp(w[i++]);l.q=qw(w,i);l.kva=qw(w,i);l.kvb=qw(w,i);l.o=qw(w,i);l.moe=mw(w,i); for(int z=0,s=0;z<3;++z){p.ks[z].S=st[s++].data_ptr();p.ks[z].cq=bp(st[s++]);p.ks[z].ck=bp(st[s++]);p.ks[z].cv=bp(st[s++]);} p.hidden=cbp(hidden);p.output=bp(output);p.cin=cbp(cin);p.kin=cbp(kin);p.cout=bp(cout);p.kout=bp(kout);p.work=work.data_ptr();p.L=int(L);p.copy_cache=copy; static int grid=0;if(!grid){int dev,active;cudaGetDevice(&dev);cudaDeviceProp prop;cudaGetDeviceProperties(&prop,dev); cudaOccupancyMaxActiveBlocksPerMultiprocessor(&active,kimi_kernel,THREADS,0);grid=active*prop.multiProcessorCount;} p.nb=grid;void* args[]={&p};cudaError_t e=cudaLaunchCooperativeKernel((void*)kimi_kernel,grid,THREADS,args,0,at::cuda::getCurrentCUDAStream()); TORCH_CHECK(e==cudaSuccess,"cooperative Kimi kernel launch failed: ",cudaGetErrorString(e)); } """ _extension = None def _get_extension(): global _extension if _extension is None: # The runner's nvcc shim is outside CUDA_HOME; point the standard PyTorch # extension builder at the installed toolkit before importing it. os.environ.setdefault("CUDA_HOME", "/usr/local/cuda") from torch.utils.cpp_extension import load_inline _extension = load_inline( name="kimi_linear_single_kernel_v7", cpp_sources=_CPP, cuda_sources=_CUDA, extra_cflags=["-O3"], extra_cuda_cflags=["-O3", "--use_fast_math"], verbose=False, ) return _extension class Model(nn.Module): def __init__(self, cfg): super().__init__() self.cfg = cfg self.blocks = nn.ModuleList(Block(cfg, k) for k in cfg.pattern) self._weight_args = None self._workspace = None @staticmethod def _add_q(dst, q): dst.extend((q.w_q, q.scales, q.zeros)) @staticmethod def _add_e(dst, q): dst.extend((q.w_q, q.scales, q.zeros)) def _weights(self): if self._weight_args is not None: return self._weight_args out = [] for b in self.blocks: out.extend((b.attn_norm, b.moe_norm)) if b.kind == "K": for q in (b.attn.q_proj, b.attn.k_proj, b.attn.v_proj, b.attn.g_proj): self._add_q(out, q) out.extend((b.attn.beta_proj.weight, b.attn.conv_w)) self._add_q(out, b.attn.o_proj) else: for q in (b.attn.q_proj, b.attn.kv_a, b.attn.kv_b, b.attn.o_proj): self._add_q(out, q) out.append(b.moe.router.weight) for q in (b.moe.gate, b.moe.up, b.moe.down, b.moe.s_gate, b.moe.s_up, b.moe.s_down): self._add_e(out, q) self._weight_args = out return out @staticmethod def _extended(cache, rows, width): need = rows * width * cache.element_size() available = cache.untyped_storage().nbytes() - cache.storage_offset() * cache.element_size() if available >= need: return cache.as_strided((rows, width), (width, 1)), False capacity = max(rows + 63, ((rows + 63) // 64) * 64) buf = torch.empty((capacity, width), dtype=cache.dtype, device=cache.device) return buf[:rows], True def step(self, hidden, state): mla_state = state[3] old_c, old_k = mla_state["c_kv"], mla_state["k_rope"] length = old_c.shape[0] new_c, copy_c = self._extended(old_c, length + 1, 512) new_k, copy_k = self._extended(old_k, length + 1, 64) copy_cache = copy_c or copy_k # Both reference-created cache tensors have exact-sized storage; after # the first step both views have spare storage and advance together. if copy_c != copy_k: new_c = torch.empty((length + 64, 512), dtype=old_c.dtype, device=old_c.device)[: length + 1] new_k = torch.empty((length + 64, 64), dtype=old_k.dtype, device=old_k.device)[: length + 1] copy_cache = True needed = 4 * 256 * 256 + 70000 + 2 * (length + 1) * 32 if self._workspace is None or self._workspace.numel() < needed: self._workspace = torch.empty(needed + 4096, dtype=torch.float32, device=hidden.device) output = torch.empty_like(hidden) st_args = [] for s in state[:3]: st_args.extend((s["S"], s["cq"], s["ck"], s["cv"])) _get_extension().launch( self._weights(), hidden, output, st_args, old_c, old_k, new_c, new_k, self._workspace, length, copy_cache, ) mla_state["c_kv"] = new_c mla_state["k_rope"] = new_k return output, state