metrale_model_layers/layers/moe/
forward_atomic_c4.rs1use super::*;
10
11impl MoeLayer {
12 pub fn forward_atomic_c4_decode(
26 &self,
27 input: DevicePtr,
28 num_tokens: usize,
29 ctx: &ForwardContext,
30 stream: u64,
31 ) -> Result<()> {
32 anyhow::ensure!(
33 self.router_logits_n as usize == ctx.config.num_experts,
34 "zero-expert MoE routing is not wired on this dispatch variant yet (forward_atomic_c4)"
35 );
36 self.refuse_lean_layout("MoeLayer::forward_atomic_c4_decode")?;
37
38 self.reject_decode_lora(ctx, "forward_atomic_c4_decode")?;
41 let has_shared = self.weights.shared_expert.gate_proj.weight.0 != 0
42 && self.weights.shared_expert.up_proj.weight.0 != 0
43 && self.weights.shared_expert.down_proj.weight.0 != 0;
44 let nvfp4_supported = num_tokens == 4
45 && self.moe_decode_atomic_c4_silu_down_accum_k.0 != 0
46 && self.moe_decode_atomic_c4_finalize_k.0 != 0
47 && self.bf16_gate_weight_ptrs.is_none()
48 && !self.has_mixed_bf16_shared_expert()
49 && self.fp8_gate_weight_ptrs.is_none()
50 && !self.use_t_layout_for_decode()
51 && self.pre_expert_norm.is_none()
52 && has_shared;
53 if !nvfp4_supported {
54 return self.forward_batched(input, num_tokens, ctx, stream);
55 }
56
57 let h = ctx.config.hidden_size as u32;
58 let inter = ctx.config.moe_intermediate_size as u32;
59 let num_experts = ctx.config.num_experts as u32;
60 let top_k = ctx.config.num_experts_per_tok as u32;
61 let n = num_tokens as u32;
62
63 let router_in = self.router_input(input, n, h, ctx, stream)?;
64 let gate_logits = ctx.buffers.gate_logits();
65 if let Some(ref nvfp4) = self.gate_nvfp4 {
66 ops::w4a16_gemm(
67 ctx.gpu,
68 self.w4a16_gemm,
69 router_in,
70 nvfp4,
71 gate_logits,
72 n,
73 num_experts,
74 h,
75 stream,
76 )?;
77 } else {
78 ops::dense_gemm(
79 ctx.gpu,
80 self.dense_gemm,
81 router_in,
82 &self.weights.gate,
83 gate_logits,
84 n,
85 num_experts,
86 h,
87 stream,
88 )?;
89 }
90
91 let scratch = ctx.buffers.scratch();
92 let topk_bytes = num_tokens * top_k as usize * 4;
93 let indices_dev = scratch;
94 let weights_dev = scratch.offset(topk_bytes);
95 let accum_off = (topk_bytes * 2 + 255) & !255;
96 let accum_bytes = num_tokens * h as usize * 4;
97 anyhow::ensure!(
98 ctx.buffers.scratch_bytes() >= accum_off + accum_bytes,
99 "scratch too small for METRALE_MOE_ATOMIC_C4_DECODE: need {} bytes, have {}",
100 accum_off + accum_bytes,
101 ctx.buffers.scratch_bytes()
102 );
103 let routed_accum = scratch.offset(accum_off);
104
105 if let Some(bias) = self.correction_bias_dev {
106 ops::moe_topk_sigmoid_batched(
107 ctx.gpu,
108 self.moe_topk_sigmoid_batched_k,
109 gate_logits,
110 bias,
111 indices_dev,
112 weights_dev,
113 num_experts,
114 top_k,
115 ctx.config.norm_topk_prob,
116 ctx.config.routed_scaling_factor as f32,
117 n,
118 stream,
119 )?;
120 } else {
121 ops::moe_topk_softmax_batched(
122 ctx.gpu,
123 self.moe_topk_batched,
124 gate_logits,
125 indices_dev,
126 weights_dev,
127 num_experts,
128 top_k,
129 ctx.config.norm_topk_prob,
130 n,
131 stream,
132 )?;
133 }
134
135 let expert_gate_out = ctx.buffers.expert_gate_out();
136 let expert_up_out = ctx.buffers.expert_up_out();
137 let shared_gate_scratch = ctx.buffers.logits();
138 let shared_up_scratch = ctx.buffers.ssm_qkvz();
139 let shared_down_out = ctx.buffers.attn_output();
140 let output = ctx.buffers.moe_output();
141
142 ops::moe_expert_gate_up_shared_prefill(
143 ctx.gpu,
144 self.moe_expert_gate_up_shared_token_major,
145 input,
146 self.gate_ptrs.packed_ptrs,
147 self.gate_ptrs.scale_ptrs,
148 self.gate_ptrs.scale2_vals,
149 expert_gate_out,
150 self.up_ptrs.packed_ptrs,
151 self.up_ptrs.scale_ptrs,
152 self.up_ptrs.scale2_vals,
153 expert_up_out,
154 indices_dev,
155 &self.weights.shared_expert.gate_proj,
156 shared_gate_scratch,
157 &self.weights.shared_expert.up_proj,
158 shared_up_scratch,
159 inter,
160 h,
161 top_k,
162 n,
163 stream,
164 )?;
165
166 ctx.gpu.memset_async(routed_accum, 0, accum_bytes, stream)?;
167 ops::moe_decode_atomic_c4_silu_down_accum(
168 ctx.gpu,
169 self.moe_decode_atomic_c4_silu_down_accum_k,
170 expert_gate_out,
171 expert_up_out,
172 self.down_ptrs.packed_ptrs,
173 self.down_ptrs.scale_ptrs,
174 self.down_ptrs.scale2_vals,
175 indices_dev,
176 weights_dev,
177 routed_accum,
178 shared_gate_scratch,
179 shared_up_scratch,
180 &self.weights.shared_expert.down_proj,
181 shared_down_out,
182 h,
183 inter,
184 top_k,
185 n,
186 stream,
187 )?;
188
189 let is_ep = ctx.comm.is_some() && ctx.config.ep_world_size > 1;
190 ops::moe_decode_atomic_c4_finalize(
191 ctx.gpu,
192 self.moe_decode_atomic_c4_finalize_k,
193 output,
194 routed_accum,
195 shared_down_out,
196 input,
197 self.weights.shared_expert_gate.weight,
198 h,
199 n,
200 !is_ep,
201 stream,
202 )?;
203
204 if let Some(comm) = ctx.comm
205 && ctx.config.ep_world_size > 1
206 {
207 if ctx.graph_capture {
208 comm.all_reduce(output.0, num_tokens * h as usize * 2)?;
209 } else {
210 comm.all_reduce_async(output.0, num_tokens * h as usize * 2, stream)?;
211 }
212 ops::moe_batched_blend(
213 ctx.gpu,
214 self.moe_batched_blend,
215 output,
216 shared_down_out,
217 input,
218 self.weights.shared_expert_gate.weight,
219 h,
220 n,
221 stream,
222 )?;
223 }
224
225 Ok(())
226 }
227}