metrale_model_arch/nemotron_mamba2/
trait_impl.rs1use anyhow::Result;
12use metrale_cache::kv_cache::PagedKvCache;
13use metrale_gpu_runtime::gpu::{DevicePtr, GpuBackend};
14
15use super::NemotronMamba2Layer;
16use metrale_model_layers::layer::{ForwardContext, LayerState, SsmLayerState, TransformerLayer};
17use metrale_model_layers::layer::{
18 LayerAuxState, LayerCapabilities, LayerGraphHooks, LayerSplitPrefill, LayerWeightSetup,
19 LayerWriteOnAccept,
20};
21use metrale_model_layers::layers::ops;
22
23impl TransformerLayer for NemotronMamba2Layer {
24 fn decode(
25 &self,
26 hidden: DevicePtr,
27 residual: DevicePtr,
28 state: &mut dyn LayerState,
29 _kv_cache: &mut metrale_cache::kv_cache::PagedKvCache,
30 _seq_len: usize,
31 _block_table: &mut Vec<u32>,
32 _disk_block_ids: &mut Vec<u32>,
33 _disk_last_offloaded_per_layer: &mut Vec<u32>,
34 ctx: &ForwardContext,
35 stream: u64,
36 ) -> Result<()> {
37 let h = ctx.config.hidden_size;
38 let eps = ctx.config.rms_norm_eps as f32;
39
40 let ssm_state = state
41 .as_any_mut()
42 .downcast_mut::<SsmLayerState>()
43 .ok_or_else(|| anyhow::anyhow!("Expected SsmLayerState"))?;
44
45 let normed = ctx.buffers.norm_output();
46 ops::rms_norm_residual(
47 ctx.gpu,
48 self.rms_norm_residual_k,
49 hidden,
50 &self.input_norm,
51 normed,
52 residual,
53 1,
54 h as u32,
55 eps,
56 stream,
57 )?;
58
59 let proj = ctx.buffers.ssm_qkvz();
60 if let Some(ref w) = self.in_proj_bf16 {
63 ops::dense_gemv(
65 ctx.gpu,
66 self.dense_gemv_bf16_k,
67 normed,
68 w,
69 proj,
70 self.in_proj_size as u32,
71 h as u32,
72 stream,
73 )?;
74 } else if let Some(ref fp8w) = self.in_proj_fp8 {
75 ops::w8a16_gemv(
76 ctx.gpu,
77 self.w8a16_gemv_k,
78 normed,
79 fp8w.weight,
80 fp8w.row_scale,
81 proj,
82 self.in_proj_size as u32,
83 h as u32,
84 stream,
85 )?;
86 } else {
87 ops::w4a16_decode_gemv(
88 ctx.gpu,
89 self.w4a16_gemv_k,
90 self.w4a16_gemv_sw_k,
91 ctx.levers.gemv_sw,
92 normed,
93 &self.ssm.in_proj,
94 proj,
95 self.in_proj_size as u32,
96 h as u32,
97 stream,
98 )?;
99 }
100
101 let z_ptr = proj;
102 let xbc_ptr = proj.offset(self.d_inner * 2);
103 let dt_ptr = proj.offset((self.d_inner + self.d_xbc) * 2);
104
105 let xbc_out = ctx.buffers.ssm_deinterleaved();
106 self.conv1d_update_biased(
107 ctx.gpu,
108 ssm_state.conv_state,
109 xbc_ptr,
110 xbc_out,
111 self.d_xbc as u32,
112 self.d_conv as u32,
113 1,
114 stream,
115 )?;
116
117 let x_ptr = xbc_out;
118 let gs = self.n_groups * self.state_size;
119 let b_ptr = xbc_out.offset(self.d_inner * 2);
120 let c_ptr = xbc_out.offset((self.d_inner + gs) * 2);
121
122 let y_ptr = ctx.buffers.attn_output();
123 self.ssm_decode(
124 ctx.gpu,
125 ssm_state.h_state,
126 x_ptr,
127 b_ptr,
128 c_ptr,
129 dt_ptr,
130 y_ptr,
131 1,
132 stream,
133 )?;
134
135 let gated_out = ctx.buffers.norm_output();
136 let group_size = (self.d_inner / self.n_groups) as u32;
137 ops::gated_rms_norm(
138 ctx.gpu,
139 self.gated_rms_norm_k,
140 y_ptr,
141 z_ptr,
142 &self.ssm.ssm_norm,
143 gated_out,
144 1,
145 self.d_inner as u32,
146 self.in_proj_size as u32,
147 eps,
148 group_size,
149 stream,
150 )?;
151
152 let out = ctx.buffers.qkv_output();
153 if let Some(ref w) = self.out_proj_bf16 {
154 ops::dense_gemv(
155 ctx.gpu,
156 self.dense_gemv_bf16_k,
157 gated_out,
158 w,
159 out,
160 h as u32,
161 self.d_inner as u32,
162 stream,
163 )?;
164 } else if let Some(ref fp8w) = self.out_proj_fp8 {
165 ops::w8a16_gemv(
166 ctx.gpu,
167 self.w8a16_gemv_k,
168 gated_out,
169 fp8w.weight,
170 fp8w.row_scale,
171 out,
172 h as u32,
173 self.d_inner as u32,
174 stream,
175 )?;
176 } else {
177 ops::w4a16_decode_gemv(
178 ctx.gpu,
179 self.w4a16_gemv_k,
180 self.w4a16_gemv_sw_k,
181 ctx.levers.gemv_sw,
182 gated_out,
183 &self.ssm.out_proj,
184 out,
185 h as u32,
186 self.d_inner as u32,
187 stream,
188 )?;
189 }
190
191 ops::residual_add(ctx.gpu, self.residual_add_k, hidden, out, h as u32, stream)?;
194
195 Ok(())
196 }
197
198 fn prefill(
199 &self,
200 hidden: DevicePtr,
201 residual: DevicePtr,
202 num_tokens: usize,
203 state: &mut dyn LayerState,
204 _kv_cache: &mut PagedKvCache,
205 _seq_len_start: usize,
206 _block_table: &mut Vec<u32>,
207 _disk_block_ids: &mut Vec<u32>,
208 _disk_last_offloaded_per_layer: &mut Vec<u32>,
209 _kv_write_start: usize,
210 ctx: &ForwardContext,
211 stream: u64,
212 ) -> Result<()> {
213 self.prefill_ssm(hidden, residual, num_tokens, state, ctx, stream)
214 }
215
216 fn alloc_state(&self, gpu: &dyn GpuBackend) -> Result<Box<dyn LayerState>> {
217 let h_state = gpu.alloc(self.h_state_bytes)?;
218 gpu.memset(h_state, 0, self.h_state_bytes)?;
219 let conv_state = gpu.alloc(self.conv_state_bytes)?;
220 gpu.memset(conv_state, 0, self.conv_state_bytes)?;
221 Ok(Box::new(SsmLayerState {
222 h_state,
223 conv_state,
224 h_state_checkpoint: None,
225 conv_state_checkpoint: None,
226 h_state_intermediates: Vec::new(),
227 conv_state_intermediates: Vec::new(),
228 h_is_f16: false,
229 h_prefill_stage: None,
230 ple: None,
231 }))
232 }
233}
234
235impl LayerCapabilities for NemotronMamba2Layer {}
236impl LayerWeightSetup for NemotronMamba2Layer {}
237impl LayerWriteOnAccept for NemotronMamba2Layer {}
238impl LayerGraphHooks for NemotronMamba2Layer {}
239impl LayerAuxState for NemotronMamba2Layer {}
240impl LayerSplitPrefill for NemotronMamba2Layer {}
241impl metrale_model_layers::circuit_exec::CircuitBindings for NemotronMamba2Layer {}