metrale_model_layers/layers/qwen3_attention/
helpers.rs1use anyhow::Result;
12use metrale_gpu_runtime::gpu::{DevicePtr, GpuBackend};
13
14use super::types::{HcWeights, HeadGateActivation, MlaWeights, Qwen3AttentionLayer};
15use crate::layers::FfnComponent;
16use crate::layers::ops;
17use crate::weight_map::{DenseWeight, QuantizedWeight};
18
19fn yarn_get_mscale(scale: f32, mscale: f32) -> f32 {
22 if scale <= 1.0 {
23 1.0
24 } else {
25 0.1 * mscale * scale.ln() + 1.0
26 }
27}
28
29pub fn yarn_rope_mscale(config: &metrale_config::ModelConfig) -> f32 {
34 let factor = config.yarn_factor;
35 if factor <= 1.0 {
36 return 1.0;
37 }
38 let num = yarn_get_mscale(factor, config.yarn_mscale);
39 let den = yarn_get_mscale(factor, config.yarn_mscale_all_dim);
40 num / den
41}
42
43impl Qwen3AttentionLayer {
44 pub fn set_mla_weights(&mut self, mla: MlaWeights) {
47 self.mla = Some(mla);
48 }
49
50 pub fn set_hc_weights(&mut self, hc: HcWeights) {
54 self.hc = Some(hc);
55 }
56
57 pub fn set_qsa(&mut self, qsa: crate::layers::qsa::QsaIndexer) {
58 self.qsa = Some(qsa);
59 }
60
61 pub fn set_dimension_overrides(
64 &mut self,
65 head_dim: usize,
66 num_q_heads: usize,
67 num_kv_heads: usize,
68 ) {
69 self.head_dim_override = Some(head_dim);
70 self.num_q_heads_override = Some(num_q_heads);
71 self.num_kv_heads_override = Some(num_kv_heads);
72 }
73
74 pub fn set_sliding_window(&mut self, window: Option<u32>) {
77 self.sliding_window = window;
78 }
79
80 pub fn set_head_gate_weight(&mut self, w: DenseWeight, activation: HeadGateActivation) {
83 self.head_gate_weight = Some(w);
84 self.head_gate_activation = activation;
85 }
86
87 pub(crate) fn rotates_qk(&self) -> bool {
90 self.position_encoding == metrale_config::AttnPositionEncoding::Rope
91 }
92
93 pub fn set_yarn_rope(&mut self, inv_freq: DevicePtr, attention_factor: f32) {
94 assert!(
95 self.rotates_qk(),
96 "YaRN RoPE on a layer without positional encoding"
97 );
98 self.yarn_inv_freq = inv_freq;
99 self.yarn_attention_factor = attention_factor;
100 }
101
102 pub fn set_rope_overrides(&mut self, theta: f32, rotary_dim: u32) {
103 assert!(
104 self.rotates_qk(),
105 "RoPE overrides on a layer without positional encoding"
106 );
107 self.rope_theta_override = Some(theta);
108 self.rotary_dim_override = Some(rotary_dim);
109 }
110
111 pub fn set_rope_proportional(&mut self, enable: bool) {
116 assert!(
117 !enable || self.rotates_qk(),
118 "proportional RoPE on a layer without positional encoding"
119 );
120 self.rope_proportional = enable;
121 }
122
123 pub fn set_attn_scale_override(&mut self, scale: f32) {
126 self.attn_scale_override = Some(scale);
127 }
128
129 #[allow(clippy::too_many_arguments)]
133 pub(super) fn nvfp4_decode_gemv(
134 &self,
135 gpu: &dyn GpuBackend,
136 use_sw: bool,
137 input: DevicePtr,
138 weight: &QuantizedWeight,
139 output: DevicePtr,
140 n: u32,
141 k: u32,
142 stream: u64,
143 ) -> Result<()> {
144 if ops::w4a4_proj::fixed_nvfp4_proj(
146 gpu,
147 metrale_config::ProjFamily::Attn,
148 weight,
149 input,
150 output,
151 1,
152 n,
153 k,
154 stream,
155 )? {
156 return Ok(());
157 }
158 ops::w4a16_decode_gemv(
159 gpu,
160 self.w4a16_gemv_k,
161 self.w4a16_gemv_sw_k,
162 use_sw,
163 input,
164 weight,
165 output,
166 n,
167 k,
168 stream,
169 )
170 }
171
172 pub(super) fn fixed_nvfp4_qkv_serves(&self, rows: usize) -> bool {
176 let nvfp4 = |w: &Option<crate::weight_map::QuantWeight>| {
177 w.as_ref().and_then(|w| w.as_nvfp4()).is_some()
178 };
179 self.mla.is_none()
180 && self.lora.is_none()
181 && nvfp4(&self.q_weight)
182 && nvfp4(&self.k_weight)
183 && nvfp4(&self.v_weight)
184 && crate::layers::fixed_act(metrale_config::ProjFamily::Attn, rows)
185 == Some(metrale_config::ActQuantFormat::Nvfp4)
186 }
187
188 pub fn set_k_eq_v(&mut self, v_norm_weight: DenseWeight) {
192 self.k_eq_v = true;
193 self.v_norm_weight = Some(v_norm_weight);
194 }
195
196 pub fn set_v_norm(&mut self, v_norm_weight: DenseWeight) {
200 self.v_norm_weight = Some(v_norm_weight);
201 }
202
203 pub fn set_o_dense_bf16(&mut self, o_dense: DenseWeight) {
209 self.o_dense_bf16 = Some(o_dense);
210 }
211
212 pub fn set_post_sublayer_norms(
213 &mut self,
214 post_attn_out: DenseWeight,
215 post_ffn_out: DenseWeight,
216 ) {
217 self.post_attn_out_norm = Some(post_attn_out);
218 self.post_ffn_out_norm = Some(post_ffn_out);
219 }
220
221 pub fn set_layer_scalar(&mut self, scalar: f32) {
222 self.layer_scalar = Some(scalar);
223 }
224
225 pub fn set_moe_ffn(
229 &mut self,
230 ffn: FfnComponent,
231 pre_norm: DenseWeight,
232 post_norm: DenseWeight,
233 post_dense_norm: DenseWeight,
234 ) {
235 self.moe_ffn = Some(ffn);
236 self.pre_moe_norm = Some(pre_norm);
237 self.post_moe_out_norm = Some(post_norm);
238 self.post_dense_ffn_norm = Some(post_dense_norm);
239 }
240
241 pub fn set_shortcut_moe(
247 &mut self,
248 moe: FfnComponent,
249 carry: metrale_gpu_runtime::gpu::DevicePtr,
250 carry_tokens: usize,
251 ) {
252 self.moe_ffn = Some(moe);
253 self.shortcut_carry_out = Some((carry, carry_tokens));
254 }
255
256 pub fn set_shortcut_carry_in(
260 &mut self,
261 carry: metrale_gpu_runtime::gpu::DevicePtr,
262 carry_tokens: usize,
263 ) {
264 self.shortcut_carry_in = Some((carry, carry_tokens));
265 }
266
267 pub(crate) fn apply_layer_scalar(
270 &self,
271 gpu: &dyn metrale_gpu_runtime::gpu::GpuBackend,
272 hidden: metrale_gpu_runtime::gpu::DevicePtr,
273 hidden_size: usize,
274 scalar: f32,
275 stream: u64,
276 ) -> anyhow::Result<()> {
277 use metrale_gpu_runtime::kernel_args::KernelLaunch;
278 let scale_k = gpu.kernel("embed_scale", "bf16_scale_inplace")?;
279 let n = hidden_size as u32;
280 KernelLaunch::new(gpu, scale_k)
281 .grid([n.div_ceil(256), 1, 1])
282 .block([256, 1, 1])
283 .arg_ptr(hidden)
284 .arg_u32(n)
285 .arg_f32(scalar)
286 .launch(stream)
287 }
288
289 pub(crate) fn effective_attn_scale(&self, head_dim: u32) -> f32 {
290 self.attn_scale_override
291 .unwrap_or_else(|| 1.0f32 / (head_dim as f32).sqrt())
292 }
293}
294
295pub(in crate::layers::qwen3_attention) fn qsa_seq_state<'a>(
299 qsa: &crate::layers::qsa::QsaIndexer,
300 state: &'a mut dyn crate::layer::LayerState,
301 gpu: &dyn metrale_gpu_runtime::gpu::GpuBackend,
302) -> anyhow::Result<&'a mut crate::layers::qsa::QsaSeqState> {
303 let attn = state
304 .as_any_mut()
305 .downcast_mut::<crate::layer::AttnLayerState>()
306 .ok_or_else(|| anyhow::anyhow!("QSA host layer state is not AttnLayerState"))?;
307 if attn.qsa.is_none() {
308 attn.qsa = Some(qsa.new_seq_state(gpu)?);
309 }
310 Ok(attn.qsa.as_mut().expect("just created"))
311}
312
313#[cfg(test)]
314mod yarn_mscale_tests {
315 use super::yarn_rope_mscale;
316 use metrale_config::ModelConfig;
317
318 #[test]
321 fn ds4f_forced_config_yields_mscale_one() {
322 let mut c = ModelConfig::qwen3_next_80b_nvfp4();
323 c.yarn_factor = 16.0;
324 c.yarn_mscale = 0.0;
325 c.yarn_mscale_all_dim = 0.0;
326 assert_eq!(yarn_rope_mscale(&c), 1.0);
327 }
328
329 #[test]
332 fn generic_yarn_default_unchanged_1277() {
333 let mut c = ModelConfig::qwen3_next_80b_nvfp4();
334 c.yarn_factor = 16.0;
335 c.yarn_mscale = 1.0;
336 c.yarn_mscale_all_dim = 0.0;
337 let m = yarn_rope_mscale(&c);
338 assert!((m - 1.2772589).abs() < 1e-5, "expected ~1.2772589, got {m}");
339 }
340
341 #[test]
343 fn yarn_disabled_factor_one_is_mscale_one() {
344 let mut c = ModelConfig::qwen3_next_80b_nvfp4();
345 c.yarn_factor = 1.0;
346 c.yarn_mscale = 1.0;
347 c.yarn_mscale_all_dim = 0.0;
348 assert_eq!(yarn_rope_mscale(&c), 1.0);
349 }
350}