Download engine/crates/model/src/gpu_model/forward.rs from respanai/span-02: direct link, hf CLI and curl.
- Browser
- Download file 8.3 kB
-
https://huggingface.co/respanai/span-02/resolve/main/engine/crates/model/src/gpu_model/forward.rs
- Command line
-
hf download hf://respanai/span-02/engine/crates/model/src/gpu_model/forward.rs
-
curl -L -o forward.rs https://huggingface.co/respanai/span-02/resolve/main/engine/crates/model/src/gpu_model/forward.rs
8.3 kB
| //! The decoder forward over one row batch (child module of `gpu_model`: sees the private fields): embedding + soft injection -> 30 layers -> final norm -> `hidden`. | |
| //! Per layer: fused norm + fp8 quant producers, FP8 MMA GEMV (<= 16 rows) / GEMM, mma attention, NVFP4 W4A4 block-scaled MMA MoE. In decode steps the dense | |
| //! MLP runs on a second stream, overlapping the router + MoE chain. | |
| use super::*; | |
| use dllm_kernels::attn as fattn; | |
| use dllm_kernels::linear as flin; | |
| use dllm_kernels::moe::MoeDecodeScratch; | |
| impl GpuModel { | |
| /// host-side prep of a prefill forward: attention tiles (consecutive rows sharing a block table) | |
| pub(super) fn prepare_tiles(&self, bt_off: &[i32], decode: bool) -> Result<()> { | |
| if decode { | |
| return Ok(()); | |
| } | |
| let ws = &self.ws; | |
| for (i, hd) in [256usize, 512].iter().enumerate() { | |
| let (r0, n) = fattn::make_tiles(bt_off, fattn::prefill_rows_per_tile(*hd)); | |
| ws.tile_row0[i].upload_slice(&r0)?; | |
| ws.tile_n[i].upload_slice(&n)?; | |
| ws.ntiles[i].store(r0.len(), Ordering::Relaxed); | |
| } | |
| Ok(()) | |
| } | |
| pub(super) fn forward_rows(&self, r: usize, decode: bool, splits: usize, m: DevMeta) -> Result<()> { | |
| let gpu = self.gpu.clone(); | |
| let be = &gpu.be; | |
| let cfg = &self.cfg; | |
| let (h, eps, dff) = (cfg.hidden_size, cfg.rms_eps, cfg.intermediate_size); | |
| let (k_top, im, ne) = (cfg.top_k_experts, cfg.moe_intermediate_size, cfg.num_experts); | |
| let ws = &self.ws; | |
| gpu.embed_gather_fp8(ws.x.ptr, self.embed_w.ptr, self.embed_s.ptr, m.tokens, r, h, self.embed_scale)?; | |
| let n_soft = self.soft_n.swap(0, Ordering::Relaxed); | |
| if n_soft > 0 { | |
| gpu.inject_soft(ws.x.ptr, self.soft_src.load(Ordering::Relaxed), self.soft_idx.ptr, self.soft_idx.at(self.opts.max_rows * 4), n_soft, h)?; | |
| } | |
| let small = r <= 16; | |
| let (aq, a_s) = (ws.aq.ptr, ws.a_s.ptr); | |
| flin::quant_rows(be, aq, a_s, ws.x.ptr, self.layers[0].in_ln.ptr, eps, r, h, true)?; | |
| let nl = self.layers.len(); | |
| for (i, l) in self.layers.iter().enumerate() { | |
| let sp = &l.spec; | |
| let moe = &l.moe; | |
| let fe = &moe.experts; | |
| let (nh, nkv, hd) = (cfg.num_heads, sp.n_kv_heads, sp.head_dim); | |
| let (nq, nk) = (nh * hd, nkv * hd); | |
| let nv = if l.v.is_some() { nk } else { 0 }; | |
| let hi = if sp.kind == LayerKind::Sliding { m.kv_hi_sl } else { m.kv_hi }; | |
| let window = if sp.kind == LayerKind::Sliding { sp.window.unwrap_or(0) } else { 0 }; | |
| let pm = self.kv_pmap(i); | |
| // ---- qkv | |
| if small { | |
| let ld = nq + nk + nv; | |
| let mut segs = vec![l.q.seg(), l.k.seg()]; | |
| if let Some(v) = &l.v { | |
| segs.push(v.seg()); | |
| } | |
| flin::gemv_pqd(be, ws.qkv.ptr, ld, aq, a_s, r, h, &segs, false, None)?; | |
| let vr = if l.v.is_some() { ws.qkv.at((nq + nk) * 2) } else { ws.qkv.at(nq * 2) }; | |
| fattn::qkv_prep_ld(&gpu, ws.q.ptr, self.kpool[i].ptr, self.vpool[i].ptr, ws.qkv.ptr, ws.qkv.at(nq * 2), vr, l.q_norm.ptr, l.k_norm.ptr, self.rope[l.rope].ptr, m.pos, m.slot, r, nh, nkv, hd, eps, ld, ld, ld, pm)?; | |
| } else { | |
| let (q, k) = (l.q.seg(), l.k.seg()); | |
| flin::gemm(be, ws.qraw.ptr, aq, a_s, q.w, q.s, r, nq, h)?; | |
| flin::gemm(be, ws.kraw.ptr, aq, a_s, k.w, k.s, r, nk, h)?; | |
| let vsrc = if let Some(v) = &l.v { | |
| let v = v.seg(); | |
| flin::gemm(be, ws.vraw.ptr, aq, a_s, v.w, v.s, r, nv, h)?; | |
| ws.vraw.ptr | |
| } else { | |
| ws.kraw.ptr | |
| }; | |
| fattn::qkv_prep(&gpu, ws.q.ptr, self.kpool[i].ptr, self.vpool[i].ptr, ws.qraw.ptr, ws.kraw.ptr, vsrc, l.q_norm.ptr, l.k_norm.ptr, self.rope[l.rope].ptr, m.pos, m.slot, r, nh, nkv, hd, eps, pm)?; | |
| } | |
| // ---- attention | |
| if decode { | |
| let sp_n = fattn::choose_splits(splits.max(1) * 1024, r, nkv, if r == 1 { 1 } else { 5 }); | |
| let (part, cnt) = if sp_n > 1 { (ws.part.ptr, ws.attn_cnt.ptr) } else { (0, 0) }; | |
| fattn::attn_decode(&gpu, ws.ao.ptr, part, ws.q.ptr, self.kpool[i].ptr, self.vpool[i].ptr, m.bt, m.bt_off, m.pos, hi, r, nh, nkv, hd, window, sp_n, cnt, pm)?; | |
| } else { | |
| let ti = if hd == 512 { 1 } else { 0 }; | |
| let nt = ws.ntiles[ti].load(Ordering::Relaxed); | |
| ensure!(nt > 0, "prefill needs the host tile table (call GpuModel::forward, not forward_dev, for prefill batches)"); | |
| fattn::attn_prefill(&gpu, ws.ao.ptr, ws.q.ptr, self.kpool[i].ptr, self.vpool[i].ptr, m.bt, m.bt_off, m.pos, hi, ws.tile_row0[ti].ptr, ws.tile_n[ti].ptr, nt, nh, nkv, hd, window, pm)?; | |
| } | |
| // ---- o_proj | |
| flin::quant_rows(be, aq, a_s, ws.ao.ptr, 0, eps, r, nq, false)?; | |
| let o = l.o.seg(); | |
| if small { | |
| flin::gemv_pqd(be, ws.o.ptr, h, aq, a_s, r, nq, &[o], false, None)?; | |
| } else { | |
| flin::gemm(be, ws.o.ptr, aq, a_s, o.w, o.s, r, h, nq)?; | |
| } | |
| // ---- sandwich + producers of the dense / expert / router inputs | |
| gpu.post_attn(ws.mid.ptr, ws.fq.ptr, ws.fs.ptr, ws.mxq.ptr, ws.mxs.ptr, ws.rn.ptr, ws.x.ptr, ws.o.ptr, l.post_attn_ln.ptr, l.pre_ff_ln.ptr, moe.pre_ff_ln2.ptr, moe.router_scale.ptr, fe.act_g, r, h, eps)?; | |
| // ---- dense MLP (own stream branch in decode: overlaps the router + MoE chain) | |
| if small { | |
| be.branch_fork()?; | |
| be.branch_use(true); | |
| } | |
| let (g, u, d) = (l.gate.seg(), l.up.seg(), l.down.seg()); | |
| if small { | |
| flin::gemv_pqd(be, ws.act.ptr, dff, ws.fq.ptr, ws.fs.ptr, r, h, &[g, u], true, None)?; | |
| flin::quant_rows(be, aq, a_s, ws.act.ptr, 0, eps, r, dff, false)?; | |
| flin::gemv_pqd(be, ws.m.ptr, h, aq, a_s, r, dff, &[d], false, None)?; | |
| } else { | |
| flin::gemm_glu(be, ws.act.ptr, ws.fq.ptr, ws.fs.ptr, g.w, g.s, u.w, u.s, r, dff, h)?; | |
| flin::quant_rows(be, aq, a_s, ws.act.ptr, 0, eps, r, dff, false)?; | |
| flin::gemm(be, ws.m.ptr, aq, a_s, d.w, d.s, r, h, dff)?; | |
| } | |
| if small { | |
| be.branch_use(false); | |
| } | |
| // ---- MoE | |
| let proj = moe.router_proj.ptr; | |
| if small { | |
| let s = MoeDecodeScratch { logits: ws.rlog.ptr, ids: ws.topk_ids.ptr, wts: ws.topk_w.ptr, ticket: ws.ticket.ptr, hq: ws.mhq.ptr, hs: ws.mhs.ptr, opair: ws.moe_o.ptr, grp: ws.grp.ptr }; | |
| gpu.moe_router_decode(&s, ws.rn.ptr, proj, moe.per_expert_scale.ptr, r, h)?; | |
| gpu.moe_glu_decode(fe, &s, ws.mxq.ptr, ws.mxs.ptr, r, h, im)?; | |
| gpu.moe_down_decode(fe, &s, r, h, im)?; | |
| } else { | |
| gpu.moe_router_logits_prefill(ws.rlog.ptr, ws.rn.ptr, proj, r, h)?; | |
| gpu.moe_topk_prefill(ws.topk_ids.ptr, ws.topk_w.ptr, ws.rlog.ptr, moe.per_expert_scale.ptr, r)?; | |
| gpu.moe_route(ws.counts.ptr, ws.offsets.ptr, ws.cursor.ptr, ws.pair_of_slot.ptr, ws.slot_of_pair.ptr, ws.topk_ids.ptr, r, k_top, ne)?; | |
| gpu.moe_glu_prefill(fe, ws.mhq.ptr, ws.mhs.ptr, ws.mxq.ptr, ws.mxs.ptr, ws.pair_of_slot.ptr, ws.offsets.ptr, ws.counts.ptr, r, h, im, ne)?; | |
| gpu.moe_down_prefill(fe, ws.moe_o.ptr, ws.mhq.ptr, ws.mhs.ptr, ws.pair_of_slot.ptr, ws.offsets.ptr, ws.counts.ptr, r, h, im, ne)?; | |
| } | |
| if small { | |
| be.branch_join()?; | |
| } | |
| // ---- combine + layer end (+ next layer's input norm / fp8 quant) | |
| let next = if i + 1 < nl { Some((self.layers[i + 1].in_ln.ptr, aq, a_s)) } else { None }; | |
| gpu.layer_final(ws.x.ptr, ws.m.ptr, ws.moe_o.ptr, ws.topk_w.ptr, ws.mid.ptr, l.post_ff_ln1.ptr, moe.post_ff_ln2.ptr, l.post_ff_ln.ptr, l.layer_scalar.ptr, r, h, eps, next)?; | |
| } | |
| gpu.rmsnorm(ws.hidden.ptr, ws.x.ptr, self.final_norm.ptr, r, h, eps)?; | |
| Ok(()) | |
| } | |
| } | |