1use crate::quantized_nn::RmsNorm;
18use candle::quantized::gguf_file;
19use candle::quantized::QTensor;
20use candle::D;
21use candle::{DType, Device, IndexOp, Result, Tensor};
22use candle_nn::{Embedding, Module};
23
24pub const MAX_SEQ_LEN: usize = 131072; pub const DEFAULT_SLIDING_WINDOW_TYPE: usize = 6;
26pub const DEFAULT_ROPE_FREQUENCY: f32 = 1_000_000.;
27pub const DEFAULT_ROPE_FREQUENCY_SLIDING: f32 = 10_000.;
28pub const DEFAULT_ROPE_FREQUENCY_SCALE_FACTOR: f32 = 1.;
29
30#[derive(Debug, Clone)]
31struct QMatMul {
32 inner: candle::quantized::QMatMul,
33 span: tracing::Span,
34}
35
36impl QMatMul {
37 fn from_qtensor(qtensor: QTensor) -> Result<Self> {
38 let inner = candle::quantized::QMatMul::from_qtensor(qtensor)?;
39 let span = tracing::span!(tracing::Level::TRACE, "qmatmul");
40 Ok(Self { inner, span })
41 }
42
43 fn forward(&self, xs: &Tensor) -> Result<Tensor> {
44 let _enter = self.span.enter();
45 self.inner.forward(xs)
46 }
47}
48
49#[derive(Debug, Clone)]
50struct Mlp {
51 feed_forward_gate: QMatMul, feed_forward_up: QMatMul, feed_forward_down: QMatMul, }
55
56impl Module for Mlp {
57 fn forward(&self, xs: &Tensor) -> Result<Tensor> {
58 let gate = self.feed_forward_gate.forward(xs)?;
59 let up = self.feed_forward_up.forward(xs)?;
60 let silu = candle_nn::ops::silu(&gate)?;
61 let gated = (silu * up)?;
62 self.feed_forward_down.forward(&gated)
63 }
64}
65
66#[derive(Debug, Clone)]
67struct RotaryEmbedding {
68 sin: Tensor,
69 cos: Tensor,
70}
71
72impl RotaryEmbedding {
73 fn new(head_dim: usize, rope_frequency: f32, device: &Device) -> Result<Self> {
74 let theta: Vec<_> = (0..head_dim)
75 .step_by(2)
76 .map(|i| 1f32 / rope_frequency.powf(i as f32 / head_dim as f32))
77 .collect();
78 let theta = Tensor::new(theta.as_slice(), device)?;
79 let idx_theta = Tensor::arange(0, MAX_SEQ_LEN as u32, device)?
80 .to_dtype(DType::F32)?
81 .reshape((MAX_SEQ_LEN, 1))?
82 .matmul(&theta.reshape((1, theta.elem_count()))?)?;
83 let cos = idx_theta.cos()?;
84 let sin = idx_theta.sin()?;
85 Ok(Self { sin, cos })
86 }
87
88 fn apply_rotary_emb_qkv(
89 &self,
90 q: &Tensor,
91 k: &Tensor,
92 index_pos: usize,
93 ) -> Result<(Tensor, Tensor)> {
94 let (_b_sz, _h, seq_len, _n_embd) = q.dims4()?;
95 let cos = self.cos.narrow(0, index_pos, seq_len)?;
96 let sin = self.sin.narrow(0, index_pos, seq_len)?;
97 let q_embed = candle_nn::rotary_emb::rope(&q.contiguous()?, &cos, &sin)?;
98 let k_embed = candle_nn::rotary_emb::rope(&k.contiguous()?, &cos, &sin)?;
99 Ok((q_embed, k_embed))
100 }
101}
102
103#[derive(Debug, Clone)]
104struct LayerWeights {
105 attention_wq: QMatMul,
107 attention_wk: QMatMul,
108 attention_wv: QMatMul,
109 attention_wo: QMatMul,
110
111 attention_q_norm: RmsNorm,
113 attention_k_norm: RmsNorm,
114
115 attention_norm: RmsNorm, post_attention_norm: RmsNorm, ffn_norm: RmsNorm, post_ffn_norm: RmsNorm, mlp: Mlp,
123
124 n_head: usize, n_kv_head: usize, head_dim: usize, q_dim: usize, sliding_window_size: Option<usize>,
131
132 rotary_embedding: RotaryEmbedding,
133 neg_inf: Tensor,
134
135 kv_cache: Option<(Tensor, Tensor)>,
137
138 span_attn: tracing::Span,
140 span_mlp: tracing::Span,
141}
142
143impl LayerWeights {
144 fn mask(
145 &self,
146 b_sz: usize,
147 seq_len: usize,
148 index_pos: usize,
149 dtype: DType,
150 device: &Device,
151 ) -> Result<Tensor> {
152 let mask: Vec<_> = if let Some(sliding_window_size) = self.sliding_window_size {
153 (0..seq_len)
154 .flat_map(|i| {
155 (0..seq_len).map(move |j| {
156 if i < j || j + sliding_window_size < i {
157 0u32
158 } else {
159 1u32
160 }
161 })
162 })
163 .collect()
164 } else {
165 (0..seq_len)
166 .flat_map(|i| (0..seq_len).map(move |j| if i < j { 0u32 } else { 1u32 }))
167 .collect()
168 };
169 let mask = Tensor::from_slice(&mask, (seq_len, seq_len), device)?;
170 let mask = if index_pos > 0 {
171 let mask0 = Tensor::zeros((seq_len, index_pos), DType::F32, device)?;
172 Tensor::cat(&[&mask0, &mask], D::Minus1)?
173 } else {
174 mask
175 };
176 mask.expand((b_sz, 1, seq_len, seq_len + index_pos))?
177 .to_dtype(dtype)
178 }
179
180 fn forward_attn(
181 &mut self,
182 x: &Tensor,
183 mask: Option<&Tensor>,
184 index_pos: usize,
185 ) -> Result<Tensor> {
186 let _enter = self.span_attn.enter();
187 let (b_sz, seq_len, _) = x.dims3()?;
188
189 let q = self.attention_wq.forward(x)?;
190 let k = self.attention_wk.forward(x)?;
191 let v = self.attention_wv.forward(x)?;
192
193 let q = q
194 .reshape((b_sz, seq_len, self.n_head, self.head_dim))?
195 .transpose(1, 2)?;
196 let k = k
197 .reshape((b_sz, seq_len, self.n_kv_head, self.head_dim))?
198 .transpose(1, 2)?;
199 let v = v
200 .reshape((b_sz, seq_len, self.n_kv_head, self.head_dim))?
201 .transpose(1, 2)?;
202
203 let q = self.attention_q_norm.forward(&q.contiguous()?)?;
204 let k = self.attention_k_norm.forward(&k.contiguous()?)?;
205
206 let (q, k) = self
207 .rotary_embedding
208 .apply_rotary_emb_qkv(&q, &k, index_pos)?;
209
210 let (k, v) = match &self.kv_cache {
211 None => (k, v),
212 Some((k_cache, v_cache)) => {
213 if index_pos == 0 {
214 (k, v)
215 } else {
216 let k = Tensor::cat(&[k_cache, &k], 2)?; let v = Tensor::cat(&[v_cache, &v], 2)?;
218 (k, v)
219 }
220 }
221 };
222 self.kv_cache = Some((k.clone(), v.clone())); let k = crate::utils::repeat_kv(k, self.n_head / self.n_kv_head)?;
226 let v = crate::utils::repeat_kv(v, self.n_head / self.n_kv_head)?;
227
228 let scale = 1.0 / (self.head_dim as f64).sqrt();
230 let mut attn_weights = (q.matmul(&k.transpose(2, 3)?)? * scale)?;
231
232 if let Some(mask) = mask {
233 let mask = mask.broadcast_as(attn_weights.shape())?;
234 let neg_inf = self.neg_inf.broadcast_as(attn_weights.dims())?;
235 attn_weights = mask.eq(0u32)?.where_cond(&neg_inf, &attn_weights)?;
236 }
237
238 let attn_weights = candle_nn::ops::softmax_last_dim(&attn_weights)?;
239 let attn_output = attn_weights.matmul(&v)?;
240
241 let attn_output = attn_output
242 .transpose(1, 2)?
243 .reshape((b_sz, seq_len, self.q_dim))?;
244
245 self.attention_wo.forward(&attn_output)
246 }
247}
248
249#[derive(Debug, Clone)]
250pub struct ModelWeights {
251 tok_embeddings: Embedding,
252 embedding_length: usize,
253 layers: Vec<LayerWeights>,
254 norm: RmsNorm,
255 output: QMatMul,
256 span: tracing::Span,
257 span_output: tracing::Span,
258}
259
260impl ModelWeights {
261 pub fn from_gguf<R: std::io::Seek + std::io::Read>(
262 ct: gguf_file::Content,
263 reader: &mut R,
264 device: &Device,
265 ) -> Result<Self> {
266 let prefix = ["gemma3", "gemma2", "gemma", "gemma-embedding"]
269 .iter()
270 .find(|p| {
271 ct.metadata
272 .contains_key(&format!("{}.attention.head_count", p))
273 })
274 .copied()
275 .unwrap_or("gemma3");
276
277 let md_get = |s: &str| {
278 let key = format!("{prefix}.{s}");
279 match ct.metadata.get(&key) {
280 None => candle::bail!("cannot find {key} in metadata"),
281 Some(v) => Ok(v),
282 }
283 };
284
285 let head_count = md_get("attention.head_count")?.to_u32()? as usize;
286 let head_count_kv = md_get("attention.head_count_kv")?.to_u32()? as usize;
287 let block_count = md_get("block_count")?.to_u32()? as usize;
288 let embedding_length = md_get("embedding_length")?.to_u32()? as usize;
289 let key_length = md_get("attention.key_length")?.to_u32()? as usize;
290 let _value_length = md_get("attention.value_length")?.to_u32()? as usize;
291 let rms_norm_eps = md_get("attention.layer_norm_rms_epsilon")?.to_f32()? as f64;
292 let sliding_window_size = md_get("attention.sliding_window")?.to_u32()? as usize;
293
294 let sliding_window_type = md_get("attention.sliding_window_type")
295 .and_then(|m| Ok(m.to_u32()? as usize))
296 .unwrap_or(DEFAULT_SLIDING_WINDOW_TYPE);
297
298 let rope_freq_base = md_get("rope.freq_base")
299 .and_then(|m| m.to_f32())
300 .unwrap_or(DEFAULT_ROPE_FREQUENCY);
301
302 let rope_freq_base_sliding = md_get("rope.local_freq_base")
303 .and_then(|m| m.to_f32())
304 .unwrap_or(DEFAULT_ROPE_FREQUENCY_SLIDING);
305
306 let _rope_freq_scaling_factor = md_get("rope.scaling.factor")
308 .and_then(|m| m.to_f32())
309 .unwrap_or(DEFAULT_ROPE_FREQUENCY_SCALE_FACTOR);
310
311 let q_dim = head_count * key_length;
314
315 let neg_inf = Tensor::new(f32::NEG_INFINITY, device)?;
316
317 let tok_embeddings = ct.tensor(reader, "token_embd.weight", device)?;
319 let tok_embeddings = tok_embeddings.dequantize(device)?;
320 let norm = RmsNorm::from_qtensor(
321 ct.tensor(reader, "output_norm.weight", device)?,
322 rms_norm_eps,
323 )?;
324 let output = match ct.tensor(reader, "output.weight", device) {
325 Ok(tensor) => tensor,
326 Err(_) => ct.tensor(reader, "token_embd.weight", device)?, };
328
329 let mut layers = Vec::with_capacity(block_count);
330 for layer_idx in 0..block_count {
331 let prefix = format!("blk.{layer_idx}");
332
333 let attention_wq = ct.tensor(reader, &format!("{prefix}.attn_q.weight"), device)?;
334 let attention_wk = ct.tensor(reader, &format!("{prefix}.attn_k.weight"), device)?;
335 let attention_wv = ct.tensor(reader, &format!("{prefix}.attn_v.weight"), device)?;
336 let attention_wo =
337 ct.tensor(reader, &format!("{prefix}.attn_output.weight"), device)?;
338
339 let attention_q_norm = RmsNorm::from_qtensor(
340 ct.tensor(reader, &format!("{prefix}.attn_q_norm.weight"), device)?,
341 rms_norm_eps,
342 )?;
343
344 let attention_k_norm = RmsNorm::from_qtensor(
345 ct.tensor(reader, &format!("{prefix}.attn_k_norm.weight"), device)?,
346 rms_norm_eps,
347 )?;
348
349 let attention_norm = RmsNorm::from_qtensor(
350 ct.tensor(reader, &format!("{prefix}.attn_norm.weight"), device)?,
351 rms_norm_eps,
352 )?;
353
354 let post_attention_norm = RmsNorm::from_qtensor(
355 ct.tensor(
356 reader,
357 &format!("{prefix}.post_attention_norm.weight"),
358 device,
359 )?,
360 rms_norm_eps,
361 )?;
362
363 let ffn_norm = RmsNorm::from_qtensor(
364 ct.tensor(reader, &format!("{prefix}.ffn_norm.weight"), device)?,
365 rms_norm_eps,
366 )?;
367
368 let post_ffn_norm = RmsNorm::from_qtensor(
369 ct.tensor(reader, &format!("{prefix}.post_ffw_norm.weight"), device)?,
370 rms_norm_eps,
371 )?;
372
373 let feed_forward_gate =
374 ct.tensor(reader, &format!("{prefix}.ffn_gate.weight"), device)?;
375 let feed_forward_up = ct.tensor(reader, &format!("{prefix}.ffn_up.weight"), device)?;
376 let feed_forward_down =
377 ct.tensor(reader, &format!("{prefix}.ffn_down.weight"), device)?;
378
379 let mlp = Mlp {
380 feed_forward_gate: QMatMul::from_qtensor(feed_forward_gate)?,
381 feed_forward_up: QMatMul::from_qtensor(feed_forward_up)?,
382 feed_forward_down: QMatMul::from_qtensor(feed_forward_down)?,
383 };
384
385 let is_sliding = (layer_idx + 1) % sliding_window_type > 0;
387 let sliding_window_size = is_sliding.then_some(sliding_window_size);
388 let layer_rope_frequency = if is_sliding {
389 rope_freq_base_sliding
390 } else {
391 rope_freq_base
392 };
393
394 let rotary_embedding = RotaryEmbedding::new(key_length, layer_rope_frequency, device)?;
395
396 let span_attn = tracing::span!(tracing::Level::TRACE, "attn");
398 let span_mlp = tracing::span!(tracing::Level::TRACE, "attn-mlp");
399
400 layers.push(LayerWeights {
401 attention_wq: QMatMul::from_qtensor(attention_wq)?,
402 attention_wk: QMatMul::from_qtensor(attention_wk)?,
403 attention_wv: QMatMul::from_qtensor(attention_wv)?,
404 attention_wo: QMatMul::from_qtensor(attention_wo)?,
405 attention_q_norm,
406 attention_k_norm,
407 attention_norm,
408 post_attention_norm,
409 ffn_norm,
410 post_ffn_norm,
411 mlp,
412 n_head: head_count,
413 n_kv_head: head_count_kv,
414 head_dim: key_length,
415 q_dim,
416 sliding_window_size,
417 rotary_embedding,
418 neg_inf: neg_inf.clone(),
419 kv_cache: None,
420 span_attn,
421 span_mlp,
422 })
423 }
424
425 let span = tracing::span!(tracing::Level::TRACE, "model");
426 let span_output = tracing::span!(tracing::Level::TRACE, "output");
427
428 Ok(Self {
429 tok_embeddings: Embedding::new(tok_embeddings, embedding_length),
430 embedding_length,
431 layers,
432 norm,
433 output: QMatMul::from_qtensor(output)?,
434 span,
435 span_output,
436 })
437 }
438
439 pub fn forward(&mut self, x: &Tensor, index_pos: usize) -> Result<Tensor> {
440 let (b_sz, seq_len) = x.dims2()?;
441 let _enter = self.span.enter();
442
443 let mut layer_in = self.tok_embeddings.forward(x)?;
444 layer_in = (layer_in * (self.embedding_length as f64).sqrt())?;
445
446 for layer in self.layers.iter_mut() {
447 let attention_mask = if seq_len == 1 {
448 None
449 } else {
450 Some(layer.mask(b_sz, seq_len, index_pos, x.dtype(), x.device())?)
451 };
452
453 let residual = &layer_in;
455 let x = layer.attention_norm.forward(&layer_in)?;
456 let x = layer.forward_attn(&x, attention_mask.as_ref(), index_pos)?;
457 let x = layer.post_attention_norm.forward(&x)?;
458 let x = (x + residual)?;
459
460 let _enter = layer.span_mlp.enter();
462 let residual = &x;
463 let x = layer.ffn_norm.forward(&x)?;
464 let x = layer.mlp.forward(&x)?;
465 let x = layer.post_ffn_norm.forward(&x)?;
466 let x = (x + residual)?;
467 drop(_enter);
468
469 layer_in = x;
470 }
471
472 let _enter = self.span_output.enter();
473
474 let x = layer_in.i((.., seq_len - 1, ..))?;
475 let x = self.norm.forward(&x)?;
476 let output = self.output.forward(&x)?;
477
478 Ok(output)
479 }
480}