spark_model/layers/qwen3_attention/
helpers.rs1use anyhow::Result;
7use spark_runtime::gpu::{DevicePtr, GpuBackend};
8
9use super::types::{HcWeights, HeadGateActivation, MlaWeights, Qwen3AttentionLayer};
10use crate::layers::FfnComponent;
11use crate::layers::ops;
12use crate::weight_map::{DenseWeight, QuantizedWeight};
13
14fn yarn_get_mscale(scale: f32, mscale: f32) -> f32 {
18 if scale <= 1.0 {
19 1.0
20 } else {
21 0.1 * mscale * scale.ln() + 1.0
22 }
23}
24
25pub(crate) fn yarn_rope_mscale(config: &atlas_core::config::ModelConfig) -> f32 {
29 let factor = config.yarn_factor;
30 if factor <= 1.0 {
31 return 1.0;
32 }
33 let num = yarn_get_mscale(factor, config.yarn_mscale);
34 let den = yarn_get_mscale(factor, config.yarn_mscale_all_dim);
35 num / den
36}
37
38impl Qwen3AttentionLayer {
39 pub fn set_mla_weights(&mut self, mla: MlaWeights) {
42 self.mla = Some(mla);
43 }
44
45 pub fn set_hc_weights(&mut self, hc: HcWeights) {
49 self.hc = Some(hc);
50 }
51
52 pub fn set_qsa(&mut self, qsa: crate::layers::qsa::QsaIndexer) {
54 self.qsa = Some(qsa);
55 }
56
57 pub fn set_dimension_overrides(
61 &mut self,
62 head_dim: usize,
63 num_q_heads: usize,
64 num_kv_heads: usize,
65 ) {
66 self.head_dim_override = Some(head_dim);
67 self.num_q_heads_override = Some(num_q_heads);
68 self.num_kv_heads_override = Some(num_kv_heads);
69 }
70
71 pub fn set_sliding_window(&mut self, window: Option<u32>) {
75 self.sliding_window = window;
76 }
77
78 pub(crate) fn set_head_gate_weight(&mut self, w: DenseWeight, activation: HeadGateActivation) {
81 self.head_gate_weight = Some(w);
82 self.head_gate_activation = activation;
83 }
84
85 pub(crate) fn set_yarn_rope(&mut self, inv_freq: DevicePtr, attention_factor: f32) {
86 self.yarn_inv_freq = inv_freq;
87 self.yarn_attention_factor = attention_factor;
88 }
89
90 pub fn set_rope_overrides(&mut self, theta: f32, rotary_dim: u32) {
93 self.rope_theta_override = Some(theta);
94 self.rotary_dim_override = Some(rotary_dim);
95 }
96
97 pub fn set_rope_proportional(&mut self, enable: bool) {
101 self.rope_proportional = enable;
102 }
103
104 pub fn set_attn_scale_override(&mut self, scale: f32) {
107 self.attn_scale_override = Some(scale);
108 }
109
110 #[allow(clippy::too_many_arguments)]
113 pub(super) fn nvfp4_decode_gemv(
114 &self,
115 gpu: &dyn GpuBackend,
116 use_sw: bool,
117 input: DevicePtr,
118 weight: &QuantizedWeight,
119 output: DevicePtr,
120 n: u32,
121 k: u32,
122 stream: u64,
123 ) -> Result<()> {
124 ops::w4a16_decode_gemv(
125 gpu,
126 self.w4a16_gemv_k,
127 self.w4a16_gemv_sw_k,
128 use_sw,
129 input,
130 weight,
131 output,
132 n,
133 k,
134 stream,
135 )
136 }
137
138 pub fn set_k_eq_v(&mut self, v_norm_weight: DenseWeight) {
146 self.k_eq_v = true;
147 self.v_norm_weight = Some(v_norm_weight);
148 }
149
150 pub fn set_v_norm(&mut self, v_norm_weight: DenseWeight) {
156 self.v_norm_weight = Some(v_norm_weight);
157 }
158
159 pub fn set_o_dense_bf16(&mut self, o_dense: DenseWeight) {
165 self.o_dense_bf16 = Some(o_dense);
166 }
167
168 pub fn set_post_sublayer_norms(
170 &mut self,
171 post_attn_out: DenseWeight,
172 post_ffn_out: DenseWeight,
173 ) {
174 self.post_attn_out_norm = Some(post_attn_out);
175 self.post_ffn_out_norm = Some(post_ffn_out);
176 }
177
178 pub fn set_layer_scalar(&mut self, scalar: f32) {
181 self.layer_scalar = Some(scalar);
182 }
183
184 pub fn set_moe_ffn(
187 &mut self,
188 ffn: FfnComponent,
189 pre_norm: DenseWeight,
190 post_norm: DenseWeight,
191 post_dense_norm: DenseWeight,
192 ) {
193 self.moe_ffn = Some(ffn);
194 self.pre_moe_norm = Some(pre_norm);
195 self.post_moe_out_norm = Some(post_norm);
196 self.post_dense_ffn_norm = Some(post_dense_norm);
197 }
198
199 pub fn set_shortcut_moe(
205 &mut self,
206 moe: FfnComponent,
207 carry: spark_runtime::gpu::DevicePtr,
208 carry_tokens: usize,
209 ) {
210 self.moe_ffn = Some(moe);
211 self.shortcut_carry_out = Some((carry, carry_tokens));
212 }
213
214 pub fn set_shortcut_carry_in(
217 &mut self,
218 carry: spark_runtime::gpu::DevicePtr,
219 carry_tokens: usize,
220 ) {
221 self.shortcut_carry_in = Some((carry, carry_tokens));
222 }
223
224 pub(crate) fn apply_layer_scalar(
227 &self,
228 gpu: &dyn spark_runtime::gpu::GpuBackend,
229 hidden: spark_runtime::gpu::DevicePtr,
230 hidden_size: usize,
231 scalar: f32,
232 stream: u64,
233 ) -> anyhow::Result<()> {
234 use spark_runtime::kernel_args::KernelLaunch;
235 let scale_k = gpu.kernel("embed_scale", "bf16_scale_inplace")?;
236 let n = hidden_size as u32;
237 KernelLaunch::new(gpu, scale_k)
238 .grid([n.div_ceil(256), 1, 1])
239 .block([256, 1, 1])
240 .arg_ptr(hidden)
241 .arg_u32(n)
242 .arg_f32(scalar)
243 .launch(stream)
244 }
245
246 pub(crate) fn effective_attn_scale(&self, head_dim: u32) -> f32 {
249 self.attn_scale_override
250 .unwrap_or_else(|| 1.0f32 / (head_dim as f32).sqrt())
251 }
252}
253
254pub(in crate::layers::qwen3_attention) fn qsa_seq_state<'a>(
257 qsa: &crate::layers::qsa::QsaIndexer,
258 state: &'a mut dyn crate::layer::LayerState,
259 gpu: &dyn spark_runtime::gpu::GpuBackend,
260) -> anyhow::Result<&'a mut crate::layers::qsa::QsaSeqState> {
261 let attn = state
262 .as_any_mut()
263 .downcast_mut::<crate::layer::AttnLayerState>()
264 .ok_or_else(|| anyhow::anyhow!("QSA host layer state is not AttnLayerState"))?;
265 if attn.qsa.is_none() {
266 attn.qsa = Some(qsa.new_seq_state(gpu)?);
267 }
268 Ok(attn.qsa.as_mut().expect("just created"))
269}
270
271#[cfg(test)]
272mod yarn_mscale_tests {
273 use super::yarn_rope_mscale;
274 use atlas_core::config::ModelConfig;
275
276 #[test]
281 fn ds4f_forced_config_yields_mscale_one() {
282 let mut c = ModelConfig::qwen3_next_80b_nvfp4();
283 c.yarn_factor = 16.0;
284 c.yarn_mscale = 0.0;
285 c.yarn_mscale_all_dim = 0.0;
286 assert_eq!(yarn_rope_mscale(&c), 1.0);
287 }
288
289 #[test]
295 fn generic_yarn_default_unchanged_1277() {
296 let mut c = ModelConfig::qwen3_next_80b_nvfp4();
297 c.yarn_factor = 16.0;
298 c.yarn_mscale = 1.0;
299 c.yarn_mscale_all_dim = 0.0;
300 let m = yarn_rope_mscale(&c);
301 assert!((m - 1.2772589).abs() < 1e-5, "expected ~1.2772589, got {m}");
302 }
303
304 #[test]
306 fn yarn_disabled_factor_one_is_mscale_one() {
307 let mut c = ModelConfig::qwen3_next_80b_nvfp4();
308 c.yarn_factor = 1.0;
309 c.yarn_mscale = 1.0;
310 c.yarn_mscale_all_dim = 0.0;
311 assert_eq!(yarn_rope_mscale(&c), 1.0);
312 }
313}