2026-05-09 12:18:16 +08:00
|
|
|
use anyhow::Result;
|
2025-09-22 16:38:12 +08:00
|
|
|
use candle_core::{D, DType, Device, IndexOp, Tensor};
|
|
|
|
|
use candle_transformers::models::deepseek2::SplitOp;
|
|
|
|
|
|
2025-12-03 17:21:01 +08:00
|
|
|
use crate::utils::tensor_utils::{index_select_2d, split_tensor};
|
|
|
|
|
|
2025-09-22 16:38:12 +08:00
|
|
|
pub fn compute_default_rope_parameters(dim: usize, base: f32) -> Vec<f32> {
|
|
|
|
|
let inv_freq: Vec<f32> = (0..dim)
|
|
|
|
|
.step_by(2)
|
|
|
|
|
.map(|i| 1.0_f32 / base.powf(i as f32 / dim as f32))
|
|
|
|
|
.collect();
|
|
|
|
|
inv_freq
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn rotate_half(x: &Tensor) -> Result<Tensor> {
|
|
|
|
|
let half_dim = x.dim(D::Minus1)? / 2;
|
|
|
|
|
let x1 = x.narrow(D::Minus1, 0, half_dim)?;
|
|
|
|
|
let x2 = x.narrow(D::Minus1, half_dim, half_dim)?;
|
|
|
|
|
let x2 = x2.affine(-1.0, 0.0)?;
|
|
|
|
|
let rotate_x = Tensor::cat(&[&x2, &x1], D::Minus1)?.contiguous()?;
|
|
|
|
|
Ok(rotate_x)
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-09 12:18:16 +08:00
|
|
|
pub fn rotate_half_interleave(x: &Tensor) -> Result<Tensor> {
|
|
|
|
|
let x_rank = x.rank();
|
|
|
|
|
let x_dim = x.dims();
|
|
|
|
|
let half_dim = x_dim[x_rank - 1] / 2;
|
|
|
|
|
let mut x_reshape = x_dim[0..x_rank - 1].to_vec();
|
|
|
|
|
x_reshape.push(half_dim);
|
|
|
|
|
x_reshape.push(2);
|
|
|
|
|
let x = x.reshape(x_reshape)?;
|
|
|
|
|
let even = x.narrow(D::Minus1, 0, 1)?;
|
|
|
|
|
let odd = x.narrow(D::Minus1, 1, 1)?.affine(-1.0, 0.0)?;
|
|
|
|
|
let rotate_x = Tensor::cat(&[&odd, &even], D::Minus1)?
|
|
|
|
|
.reshape(x_dim)?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
Ok(rotate_x)
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-22 16:38:12 +08:00
|
|
|
pub fn apply_multimodel_rotary_pos_emb(
|
|
|
|
|
q: &Tensor,
|
|
|
|
|
k: &Tensor,
|
|
|
|
|
cos: &Tensor,
|
|
|
|
|
sin: &Tensor,
|
|
|
|
|
mrope_section: Vec<usize>,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
|
|
|
|
let mrope_section = mrope_section.repeat(2);
|
|
|
|
|
let cos_select: Vec<Tensor> = cos
|
|
|
|
|
.split(&mrope_section, D::Minus1)?
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.map(|(i, m)| m.i(i % 3).unwrap())
|
|
|
|
|
.collect();
|
|
|
|
|
let cos = Tensor::cat(&cos_select, D::Minus1)?
|
|
|
|
|
.unsqueeze(1)?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
let sin_select: Vec<Tensor> = sin
|
|
|
|
|
.split(&mrope_section, D::Minus1)?
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.map(|(i, m)| m.i(i % 3).unwrap())
|
|
|
|
|
.collect();
|
|
|
|
|
let sin = Tensor::cat(&sin_select, D::Minus1)?
|
|
|
|
|
.unsqueeze(1)?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
let q_embed = q
|
|
|
|
|
.broadcast_mul(&cos)?
|
2025-10-15 21:03:49 +08:00
|
|
|
.add(&rotate_half(q)?.broadcast_mul(&sin)?)?;
|
2025-09-22 16:38:12 +08:00
|
|
|
let k_embed = k
|
|
|
|
|
.broadcast_mul(&cos)?
|
2025-10-15 21:03:49 +08:00
|
|
|
.add(&rotate_half(k)?.broadcast_mul(&sin)?)?;
|
2025-09-22 16:38:12 +08:00
|
|
|
Ok((q_embed, k_embed))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn apply_rotary_pos_emb_vision(
|
|
|
|
|
q: &Tensor,
|
|
|
|
|
k: &Tensor,
|
|
|
|
|
cos: &Tensor,
|
|
|
|
|
sin: &Tensor,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
|
|
|
|
// q, k -> (seq_len, num_heads, head_dim)
|
|
|
|
|
// cos, sin -> (seq_len, head_dim) -> (seq_len, 1, head_dim)
|
|
|
|
|
let cos = cos.unsqueeze(D::Minus2)?;
|
|
|
|
|
let sin = sin.unsqueeze(D::Minus2)?;
|
2025-10-26 21:39:23 +08:00
|
|
|
let cos = cos.to_dtype(q.dtype())?;
|
|
|
|
|
let sin = sin.to_dtype(q.dtype())?;
|
2025-09-22 16:38:12 +08:00
|
|
|
let q_embed = q
|
|
|
|
|
.broadcast_mul(&cos)?
|
|
|
|
|
.add(&rotate_half(q)?.broadcast_mul(&sin)?)?;
|
|
|
|
|
let k_embed = k
|
|
|
|
|
.broadcast_mul(&cos)?
|
|
|
|
|
.add(&rotate_half(k)?.broadcast_mul(&sin)?)?;
|
|
|
|
|
Ok((q_embed, k_embed))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn apply_rotary_pos_emb(
|
|
|
|
|
q: &Tensor,
|
|
|
|
|
k: &Tensor,
|
|
|
|
|
cos: &Tensor,
|
|
|
|
|
sin: &Tensor,
|
2025-10-03 22:25:58 +08:00
|
|
|
tof32: bool,
|
2025-09-22 16:38:12 +08:00
|
|
|
) -> Result<(Tensor, Tensor)> {
|
2025-10-03 22:25:58 +08:00
|
|
|
// sin/cos: to (bs, 1, seq_len, head_dim)
|
2025-09-22 16:38:12 +08:00
|
|
|
// q/k: (bs, n_head, seq_len, head_dim)
|
2025-10-03 22:25:58 +08:00
|
|
|
let mut cos = cos.clone();
|
|
|
|
|
let mut sin = sin.clone();
|
|
|
|
|
if cos.rank() == 2 {
|
|
|
|
|
// (seq_len, head_dim) -> (1, 1, seq_len, head_dim)
|
|
|
|
|
cos = cos.unsqueeze(0)?.unsqueeze(0)?;
|
|
|
|
|
sin = sin.unsqueeze(0)?.unsqueeze(0)?;
|
|
|
|
|
}
|
|
|
|
|
if cos.rank() == 3 {
|
|
|
|
|
// (bs, seq_len, head_dim) -> (bs, 1, seq_len, head_dim)
|
|
|
|
|
cos = cos.unsqueeze(1)?;
|
|
|
|
|
sin = sin.unsqueeze(1)?;
|
|
|
|
|
}
|
|
|
|
|
let orig_dtype = q.dtype();
|
2025-10-15 21:03:49 +08:00
|
|
|
let q = if tof32 { &q.to_dtype(DType::F32)? } else { q };
|
|
|
|
|
let k = if tof32 { &k.to_dtype(DType::F32)? } else { k };
|
2025-10-03 22:25:58 +08:00
|
|
|
let cos = cos.to_dtype(q.dtype())?;
|
|
|
|
|
let sin = sin.to_dtype(q.dtype())?;
|
|
|
|
|
|
2025-09-22 16:38:12 +08:00
|
|
|
let q_embed = q
|
|
|
|
|
.broadcast_mul(&cos)?
|
2025-10-15 21:03:49 +08:00
|
|
|
.add(&rotate_half(q)?.broadcast_mul(&sin)?)?
|
|
|
|
|
.to_dtype(orig_dtype)?;
|
2025-09-22 16:38:12 +08:00
|
|
|
let k_embed = k
|
|
|
|
|
.broadcast_mul(&cos)?
|
2025-10-15 21:03:49 +08:00
|
|
|
.add(&rotate_half(k)?.broadcast_mul(&sin)?)?
|
|
|
|
|
.to_dtype(orig_dtype)?;
|
2025-09-22 16:38:12 +08:00
|
|
|
Ok((q_embed, k_embed))
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-09 12:18:16 +08:00
|
|
|
pub fn apply_rotary_pos_emb_interleave(
|
|
|
|
|
q: &Tensor,
|
|
|
|
|
k: &Tensor,
|
|
|
|
|
cos: &Tensor,
|
|
|
|
|
sin: &Tensor,
|
|
|
|
|
tof32: bool,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
|
|
|
|
// sin/cos: to (bs, 1, seq_len, head_dim)
|
|
|
|
|
// q/k: (bs, n_head, seq_len, head_dim)
|
|
|
|
|
let mut cos = cos.clone();
|
|
|
|
|
let mut sin = sin.clone();
|
|
|
|
|
if cos.rank() == 2 {
|
|
|
|
|
// (seq_len, head_dim) -> (1, 1, seq_len, head_dim)
|
|
|
|
|
cos = cos.unsqueeze(0)?.unsqueeze(0)?;
|
|
|
|
|
sin = sin.unsqueeze(0)?.unsqueeze(0)?;
|
|
|
|
|
}
|
|
|
|
|
if cos.rank() == 3 {
|
|
|
|
|
// (bs, seq_len, head_dim) -> (bs, 1, seq_len, head_dim)
|
|
|
|
|
cos = cos.unsqueeze(1)?;
|
|
|
|
|
sin = sin.unsqueeze(1)?;
|
|
|
|
|
}
|
|
|
|
|
let orig_dtype = q.dtype();
|
|
|
|
|
let q = if tof32 { &q.to_dtype(DType::F32)? } else { q };
|
|
|
|
|
let k = if tof32 { &k.to_dtype(DType::F32)? } else { k };
|
|
|
|
|
let cos = cos.to_dtype(q.dtype())?;
|
|
|
|
|
let sin = sin.to_dtype(q.dtype())?;
|
|
|
|
|
|
|
|
|
|
let q_embed = q
|
|
|
|
|
.broadcast_mul(&cos)?
|
|
|
|
|
.add(&rotate_half_interleave(q)?.broadcast_mul(&sin)?)?
|
|
|
|
|
.to_dtype(orig_dtype)?;
|
|
|
|
|
let k_embed = k
|
|
|
|
|
.broadcast_mul(&cos)?
|
|
|
|
|
.add(&rotate_half_interleave(k)?.broadcast_mul(&sin)?)?
|
|
|
|
|
.to_dtype(orig_dtype)?;
|
|
|
|
|
Ok((q_embed, k_embed))
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-07 21:46:01 +08:00
|
|
|
pub fn glm_asr_apply_rotary_pos_emb(
|
|
|
|
|
q: &Tensor,
|
|
|
|
|
k: &Tensor,
|
|
|
|
|
cos: &Tensor,
|
|
|
|
|
sin: &Tensor,
|
|
|
|
|
tof32: bool,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
|
|
|
|
// sin/cos: to (bs, 1, seq_len, head_dim/2)
|
|
|
|
|
// q/k: (bs, n_head, seq_len, head_dim)
|
|
|
|
|
let mut cos = cos.clone();
|
|
|
|
|
let mut sin = sin.clone();
|
|
|
|
|
if cos.rank() == 2 {
|
|
|
|
|
// (seq_len, head_dim/2) -> (1, 1, seq_len, head_dim/2)
|
|
|
|
|
cos = cos.unsqueeze(0)?.unsqueeze(0)?;
|
|
|
|
|
sin = sin.unsqueeze(0)?.unsqueeze(0)?;
|
|
|
|
|
}
|
|
|
|
|
if cos.rank() == 3 {
|
|
|
|
|
// (bs, seq_len, head_dim/2) -> (bs, 1, seq_len, head_dim/2)
|
|
|
|
|
cos = cos.unsqueeze(1)?;
|
|
|
|
|
sin = sin.unsqueeze(1)?;
|
|
|
|
|
}
|
|
|
|
|
let orig_dtype = q.dtype();
|
|
|
|
|
let q = if tof32 { &q.to_dtype(DType::F32)? } else { q };
|
|
|
|
|
let k = if tof32 { &k.to_dtype(DType::F32)? } else { k };
|
|
|
|
|
let cos = cos.to_dtype(q.dtype())?;
|
|
|
|
|
let sin = sin.to_dtype(q.dtype())?;
|
|
|
|
|
let rotary_dim = cos.dim(D::Minus1)?;
|
2026-03-05 21:57:03 +08:00
|
|
|
let q_dim = q.dim(D::Minus1)?;
|
2026-01-07 21:46:01 +08:00
|
|
|
let q_rot = q.narrow(D::Minus1, 0, rotary_dim)?;
|
2026-03-05 21:57:03 +08:00
|
|
|
let q_pass = q.narrow(D::Minus1, rotary_dim, q_dim - rotary_dim)?;
|
2026-01-07 21:46:01 +08:00
|
|
|
let k_rot = k.narrow(D::Minus1, 0, rotary_dim)?;
|
2026-03-05 21:57:03 +08:00
|
|
|
let k_pass = k.narrow(D::Minus1, rotary_dim, q_dim - rotary_dim)?;
|
2026-01-07 21:46:01 +08:00
|
|
|
|
|
|
|
|
let q_embed = q_rot
|
|
|
|
|
.broadcast_mul(&cos)?
|
|
|
|
|
.add(&rotate_half(&q_rot)?.broadcast_mul(&sin)?)?;
|
|
|
|
|
let k_embed = k_rot
|
|
|
|
|
.broadcast_mul(&cos)?
|
|
|
|
|
.add(&rotate_half(&k_rot)?.broadcast_mul(&sin)?)?;
|
|
|
|
|
let q_embed = Tensor::cat(&[q_embed, q_pass], D::Minus1)?.to_dtype(orig_dtype)?;
|
|
|
|
|
let k_embed = Tensor::cat(&[k_embed, k_pass], D::Minus1)?.to_dtype(orig_dtype)?;
|
|
|
|
|
Ok((q_embed, k_embed))
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-05 23:49:49 -05:00
|
|
|
/// Interleaved rotation used by GLM-OCR text decoder.
|
|
|
|
|
///
|
|
|
|
|
/// Python `rotate_half_llm`:
|
|
|
|
|
/// x1 = x[..., 0::2] # even indices
|
|
|
|
|
/// x2 = x[..., 1::2] # odd indices
|
|
|
|
|
/// return stack((-x2, x1), dim=-1).flatten(-2)
|
|
|
|
|
/// # e.g. [q0,q1,q2,q3] → [-q1, q0, -q3, q2]
|
|
|
|
|
///
|
|
|
|
|
/// Each adjacent pair (x_{2i}, x_{2i+1}) is rotated to (-x_{2i+1}, x_{2i}).
|
|
|
|
|
/// This is the correct counterpart to `repeat_interleave(2)` style cos/sin.
|
|
|
|
|
fn rotate_half_llm(x: &Tensor) -> Result<Tensor> {
|
|
|
|
|
let last_dim = x.dim(D::Minus1)?;
|
|
|
|
|
let half = last_dim / 2;
|
|
|
|
|
// Reshape (..., D) → (..., D/2, 2) so each row is one adjacent pair
|
|
|
|
|
let mut pair_shape = x.dims().to_vec();
|
|
|
|
|
let rank = pair_shape.len();
|
|
|
|
|
pair_shape[rank - 1] = half;
|
|
|
|
|
pair_shape.push(2);
|
|
|
|
|
let x_pairs = x.reshape(pair_shape)?; // (..., half, 2)
|
|
|
|
|
// col 0 = even elements [x0, x2, ...], col 1 = odd elements [x1, x3, ...]
|
|
|
|
|
let x_even = x_pairs.narrow(D::Minus1, 0, 1)?; // (..., half, 1)
|
2026-03-07 18:08:06 +08:00
|
|
|
let x_odd = x_pairs.narrow(D::Minus1, 1, 1)?; // (..., half, 1)
|
2026-03-05 23:49:49 -05:00
|
|
|
let neg_x_odd = x_odd.affine(-1.0, 0.0)?;
|
|
|
|
|
// Concatenate [-x_odd, x_even] → [[-x1,x0], [-x3,x2], ...]
|
|
|
|
|
let result_pairs = Tensor::cat(&[&neg_x_odd, &x_even], D::Minus1)?; // (..., half, 2)
|
|
|
|
|
// Flatten last two dims back to D: [-x1, x0, -x3, x2, ...]
|
|
|
|
|
Ok(result_pairs.reshape(x.dims().to_vec())?)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn glm_ocr_apply_rotary_pos_emb(
|
|
|
|
|
q: &Tensor,
|
|
|
|
|
k: &Tensor,
|
|
|
|
|
cos: &Tensor,
|
|
|
|
|
sin: &Tensor,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
|
|
|
|
// GLM-OCR applies rotary to only the first rotary_dim of head_dim
|
|
|
|
|
// cos/sin: (bs, seq_len, head_dim) - already doubled via cat(freqs, freqs)
|
|
|
|
|
// q/k: (bs, n_head, seq_len, head_dim)
|
|
|
|
|
// Python: unsqueeze_dim=1
|
|
|
|
|
// - rank 2 (seq_len, head_dim) -> unsqueeze(1) -> (seq_len, 1, head_dim)
|
|
|
|
|
// - rank 3 (bs, seq_len, head_dim) -> unsqueeze(1) -> (bs, 1, seq_len, head_dim)
|
|
|
|
|
let mut cos = cos.clone();
|
|
|
|
|
let mut sin = sin.clone();
|
|
|
|
|
|
|
|
|
|
cos = cos.unsqueeze(1)?; // (seq_len, head_dim) -> (seq_len, 1, head_dim)
|
|
|
|
|
sin = sin.unsqueeze(1)?;
|
|
|
|
|
|
|
|
|
|
// Python: cos = cos[..., :cos.shape[-1]//2].repeat_interleave(2, dim=-1)
|
|
|
|
|
// Take first half and interleave each element
|
|
|
|
|
let full_dim = cos.dim(D::Minus1)?;
|
|
|
|
|
let half_dim = full_dim / 2;
|
|
|
|
|
let cos_half = cos.narrow(D::Minus1, 0, half_dim)?;
|
|
|
|
|
let sin_half = sin.narrow(D::Minus1, 0, half_dim)?;
|
|
|
|
|
// repeat_interleave(2, dim=-1): [a,b,c] -> [a,a,b,b,c,c]
|
|
|
|
|
let cos_interleaved = cos_half
|
|
|
|
|
.unsqueeze(D::Minus1)?
|
|
|
|
|
.broadcast_mul(&Tensor::ones(
|
|
|
|
|
&[1, 1, 1, 1, 2],
|
|
|
|
|
cos_half.dtype(),
|
|
|
|
|
cos_half.device(),
|
|
|
|
|
)?)?
|
|
|
|
|
.reshape(cos.shape())?;
|
|
|
|
|
let sin_interleaved = sin_half
|
|
|
|
|
.unsqueeze(D::Minus1)?
|
|
|
|
|
.broadcast_mul(&Tensor::ones(
|
|
|
|
|
&[1, 1, 1, 1, 2],
|
|
|
|
|
sin_half.dtype(),
|
|
|
|
|
sin_half.device(),
|
|
|
|
|
)?)?
|
|
|
|
|
.reshape(sin.shape())?;
|
|
|
|
|
|
|
|
|
|
let cos = cos_interleaved.to_dtype(q.dtype())?;
|
|
|
|
|
let sin = sin_interleaved.to_dtype(q.dtype())?;
|
|
|
|
|
|
|
|
|
|
let rotary_dim = cos.dim(D::Minus1)?;
|
|
|
|
|
// Split q/k into rotary and pass-through portions
|
|
|
|
|
let q_rot = q.narrow(D::Minus1, 0, rotary_dim)?;
|
|
|
|
|
let q_pass = q.narrow(D::Minus1, rotary_dim, q.dim(D::Minus1)? - rotary_dim)?;
|
|
|
|
|
let k_rot = k.narrow(D::Minus1, 0, rotary_dim)?;
|
|
|
|
|
let k_pass = k.narrow(D::Minus1, rotary_dim, k.dim(D::Minus1)? - rotary_dim)?;
|
|
|
|
|
|
|
|
|
|
// Apply rotary: q_rot * cos + rotate_half_llm(q_rot) * sin
|
|
|
|
|
// Must use interleaved rotate_half_llm (not split-half rotate_half) because
|
|
|
|
|
// cos/sin use repeat_interleave(2) format: [c0,c0,c1,c1,...].
|
|
|
|
|
// rotate_half_llm rotates adjacent pairs (q_{2i},q_{2i+1}) → (-q_{2i+1}, q_{2i}),
|
|
|
|
|
// which is the correct counterpart for this cos/sin format.
|
|
|
|
|
let q_embed = q_rot
|
|
|
|
|
.broadcast_mul(&cos)?
|
|
|
|
|
.add(&rotate_half_llm(&q_rot)?.broadcast_mul(&sin)?)?;
|
|
|
|
|
let k_embed = k_rot
|
|
|
|
|
.broadcast_mul(&cos)?
|
|
|
|
|
.add(&rotate_half_llm(&k_rot)?.broadcast_mul(&sin)?)?;
|
|
|
|
|
|
|
|
|
|
// Concatenate rotary and pass-through portions
|
|
|
|
|
let q_embed = Tensor::cat(&[&q_embed, &q_pass], D::Minus1)?;
|
|
|
|
|
let k_embed = Tensor::cat(&[&k_embed, &k_pass], D::Minus1)?;
|
|
|
|
|
Ok((q_embed, k_embed))
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-30 22:04:23 +08:00
|
|
|
pub fn apply_rotary_pos_emb_roformer(
|
|
|
|
|
q: &Tensor,
|
|
|
|
|
k: &Tensor,
|
|
|
|
|
cos: &Tensor,
|
|
|
|
|
sin: &Tensor,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
2026-05-09 12:18:16 +08:00
|
|
|
let ori_dtype = q.dtype();
|
|
|
|
|
let (bs, n_head, seq_len, dim) = q.dims4()?;
|
|
|
|
|
let half_dim = dim / 2;
|
|
|
|
|
let rotr = cos
|
|
|
|
|
.narrow(D::Minus1, 0, half_dim)?
|
|
|
|
|
.to_dtype(candle_core::DType::F32)?;
|
|
|
|
|
let roti = sin
|
|
|
|
|
.narrow(D::Minus1, 0, half_dim)?
|
|
|
|
|
.to_dtype(candle_core::DType::F32)?;
|
|
|
|
|
let q = q
|
|
|
|
|
.reshape((bs, n_head, seq_len, half_dim, 2))?
|
|
|
|
|
.to_dtype(candle_core::DType::F32)?;
|
|
|
|
|
let qr = q.narrow(D::Minus1, 0, 1)?.squeeze(D::Minus1)?;
|
|
|
|
|
let qi = q.narrow(D::Minus1, 1, 1)?.squeeze(D::Minus1)?;
|
|
|
|
|
|
|
|
|
|
let k = k
|
|
|
|
|
.reshape((bs, n_head, seq_len, half_dim, 2))?
|
|
|
|
|
.to_dtype(candle_core::DType::F32)?;
|
|
|
|
|
let kr = k.narrow(D::Minus1, 0, 1)?.squeeze(D::Minus1)?;
|
|
|
|
|
let ki = k.narrow(D::Minus1, 1, 1)?.squeeze(D::Minus1)?;
|
|
|
|
|
|
|
|
|
|
let qor = qr.broadcast_mul(&rotr)?.sub(&qi.broadcast_mul(&roti)?)?;
|
|
|
|
|
let qoi = qr.broadcast_mul(&roti)?.add(&qi.broadcast_mul(&rotr)?)?;
|
|
|
|
|
|
|
|
|
|
let kor = kr.broadcast_mul(&rotr)?.sub(&ki.broadcast_mul(&roti)?)?;
|
|
|
|
|
let koi = kr.broadcast_mul(&roti)?.add(&ki.broadcast_mul(&rotr)?)?;
|
|
|
|
|
|
|
|
|
|
let q = Tensor::stack(&[qor, qoi], D::Minus1)?
|
|
|
|
|
.reshape((bs, n_head, seq_len, dim))?
|
|
|
|
|
.to_dtype(ori_dtype)?;
|
|
|
|
|
let k = Tensor::stack(&[kor, koi], D::Minus1)?
|
|
|
|
|
.reshape((bs, n_head, seq_len, dim))?
|
|
|
|
|
.to_dtype(ori_dtype)?;
|
|
|
|
|
Ok((q, k))
|
2026-01-30 22:04:23 +08:00
|
|
|
}
|
|
|
|
|
|
2025-09-22 16:38:12 +08:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct Qwen2_5VLTextRotaryEmbedding {
|
|
|
|
|
inv_freq: Vec<f32>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Qwen2_5VLTextRotaryEmbedding {
|
|
|
|
|
pub fn new(dim: usize, theta_base: f32) -> Self {
|
|
|
|
|
let inv_freq = compute_default_rope_parameters(dim, theta_base);
|
|
|
|
|
Self { inv_freq }
|
|
|
|
|
}
|
|
|
|
|
pub fn forward(
|
|
|
|
|
&self,
|
|
|
|
|
position_ids: &Tensor,
|
|
|
|
|
dtype: DType,
|
|
|
|
|
mrope_section: Vec<usize>,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
|
|
|
|
// position_ids shape: (3, bs, position) -> (3, bs, 1, position)
|
|
|
|
|
let position_ids_expanded = position_ids
|
|
|
|
|
.unsqueeze(D::Minus2)?
|
|
|
|
|
.to_dtype(DType::F32)?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
// inv_freq Vec<f32> -> Tensor(1, 1, head_dim / 2, 1) -> (3, bs, head_dim / 2, 1)
|
|
|
|
|
let inv_freq_expanded = Tensor::from_vec(
|
|
|
|
|
self.inv_freq.clone(),
|
|
|
|
|
(1, 1, self.inv_freq.len(), 1),
|
|
|
|
|
position_ids.device(),
|
|
|
|
|
)?
|
|
|
|
|
.broadcast_as((3, position_ids.dim(1)?, self.inv_freq.len(), 1))?
|
|
|
|
|
.to_dtype(DType::F32)?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
|
|
|
|
|
// (3, bs, head_dim / 2, 1) matmul (3, bs, 1, position)
|
|
|
|
|
// -> (3, bs, head_dim / 2, seq_len) -> (3, bs, seq_len, head_dim / 2)
|
|
|
|
|
let freqs = inv_freq_expanded
|
|
|
|
|
.matmul(&position_ids_expanded)?
|
|
|
|
|
.transpose(2, 3)?;
|
|
|
|
|
// let freqs = position_ids_expanded.matmul(&inv_freq_expanded)?;
|
|
|
|
|
// (3, bs, seq_len, head_dim / 2) -> (3, bs, seq_len, head_dim)
|
|
|
|
|
let emb = Tensor::cat(&[&freqs, &freqs], D::Minus1)?.contiguous()?;
|
|
|
|
|
let cos = emb.cos()?;
|
|
|
|
|
let sin = emb.sin()?;
|
|
|
|
|
let mrope_section = mrope_section.repeat(2);
|
|
|
|
|
let cos_select: Vec<Tensor> = cos
|
|
|
|
|
.split(&mrope_section, D::Minus1)?
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.map(|(i, m)| m.i(i % 3).unwrap())
|
|
|
|
|
.collect();
|
|
|
|
|
// (bs, seq_len, head_dim) -> (bs, 1, seq_len, head_dim)
|
|
|
|
|
let cos = Tensor::cat(&cos_select, D::Minus1)?
|
|
|
|
|
.unsqueeze(1)?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
let sin_select: Vec<Tensor> = sin
|
|
|
|
|
.split(&mrope_section, D::Minus1)?
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.map(|(i, m)| m.i(i % 3).unwrap())
|
|
|
|
|
.collect();
|
|
|
|
|
// (bs, seq_len, head_dim) -> (bs, 1, seq_len, head_dim)
|
|
|
|
|
let sin = Tensor::cat(&sin_select, D::Minus1)?
|
|
|
|
|
.unsqueeze(1)?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
Ok((cos.to_dtype(dtype)?, sin.to_dtype(dtype)?))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct Qwen2_5VisionRotaryEmbedding {
|
|
|
|
|
inv_freq: Vec<f32>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Qwen2_5VisionRotaryEmbedding {
|
|
|
|
|
pub fn new(dim: usize, theta_base: Option<f32>) -> Self {
|
2025-10-15 21:03:49 +08:00
|
|
|
let theta_base = theta_base.unwrap_or(10000.0_f32);
|
2025-09-22 16:38:12 +08:00
|
|
|
let inv_freq = compute_default_rope_parameters(dim, theta_base);
|
|
|
|
|
Self { inv_freq }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn forward(&self, seqlen: usize, device: &Device) -> Result<Tensor> {
|
|
|
|
|
let seq = Tensor::arange(0.0_f32, seqlen as f32, device)?.reshape((seqlen, 1))?;
|
|
|
|
|
let inv_freq = Tensor::from_vec(self.inv_freq.clone(), (1, self.inv_freq.len()), device)?;
|
|
|
|
|
let freqs = seq.matmul(&inv_freq)?;
|
|
|
|
|
Ok(freqs)
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-26 21:39:23 +08:00
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct Qwen3VLTextRotaryEmbedding {
|
|
|
|
|
inv_freq: Vec<f32>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Qwen3VLTextRotaryEmbedding {
|
|
|
|
|
pub fn new(dim: usize, theta_base: f32) -> Self {
|
|
|
|
|
let inv_freq = compute_default_rope_parameters(dim, theta_base);
|
|
|
|
|
Self { inv_freq }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn apply_interleaved_mrope(
|
|
|
|
|
&self,
|
|
|
|
|
freqs: &Tensor,
|
|
|
|
|
mrope_section: Vec<usize>,
|
|
|
|
|
) -> Result<Tensor> {
|
|
|
|
|
let mut freqs_t = freqs.i(0)?.contiguous()?; //(3, bs, seq_len, head_dim //2) -> (bs, seq_len, head_dim //2)
|
|
|
|
|
|
2025-10-26 23:19:11 +08:00
|
|
|
// for dim in 1..3 {
|
|
|
|
|
for (dim, section) in mrope_section.iter().enumerate().skip(1) {
|
|
|
|
|
// let length = mrope_section[dim] * 3;
|
|
|
|
|
let length = section * 3;
|
2025-10-26 21:39:23 +08:00
|
|
|
let idx = Tensor::arange_step(dim as u32, length as u32, 3, freqs.device())?;
|
|
|
|
|
let src = freqs.i(dim)?.contiguous()?; // (bs, seq_len, head_dim //2)
|
|
|
|
|
let src = src.index_select(&idx, D::Minus1)?.contiguous()?;
|
|
|
|
|
let idx = idx
|
|
|
|
|
.unsqueeze(0)?
|
|
|
|
|
.unsqueeze(0)?
|
|
|
|
|
.broadcast_as(src.shape())?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
freqs_t = freqs_t.scatter(&idx, &src, D::Minus1)?;
|
|
|
|
|
}
|
|
|
|
|
Ok(freqs_t)
|
|
|
|
|
}
|
2026-02-05 00:43:49 +08:00
|
|
|
|
|
|
|
|
pub fn apply_interleaved_mrope_asr(
|
|
|
|
|
&self,
|
|
|
|
|
freqs: &Tensor,
|
|
|
|
|
mrope_section: Vec<usize>,
|
|
|
|
|
) -> Result<Tensor> {
|
|
|
|
|
let mut freqs_t = freqs.i(0)?.contiguous()?; //(3, bs, seq_len, head_dim //2) -> (bs, seq_len, head_dim //2)
|
|
|
|
|
|
|
|
|
|
// for dim in 1..3 {
|
|
|
|
|
for (dim, offset) in (1..3).enumerate() {
|
2026-02-14 15:52:30 +08:00
|
|
|
let dim = dim + 1;
|
2026-02-05 00:43:49 +08:00
|
|
|
let length = mrope_section[dim];
|
|
|
|
|
let idx = Tensor::arange_step(offset as u32, length as u32, 3, freqs.device())?;
|
|
|
|
|
let src = freqs.i(dim)?.contiguous()?; // (bs, seq_len, head_dim //2)
|
|
|
|
|
let src = src.index_select(&idx, D::Minus1)?.contiguous()?;
|
|
|
|
|
let idx = idx
|
|
|
|
|
.unsqueeze(0)?
|
|
|
|
|
.unsqueeze(0)?
|
|
|
|
|
.broadcast_as(src.shape())?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
freqs_t = freqs_t.scatter(&idx, &src, D::Minus1)?;
|
|
|
|
|
}
|
|
|
|
|
Ok(freqs_t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn forward_asr(
|
|
|
|
|
&self,
|
|
|
|
|
position_ids: &Tensor,
|
|
|
|
|
dtype: DType,
|
|
|
|
|
mrope_section: Vec<usize>,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
|
|
|
|
// position_ids shape: (3, bs, position) -> (3, bs, 1, position)
|
|
|
|
|
let position_ids = if position_ids.rank() == 2 {
|
|
|
|
|
let (bs, len) = position_ids.dims2()?;
|
|
|
|
|
position_ids.unsqueeze(0)?.expand((3, bs, len))?
|
|
|
|
|
} else {
|
|
|
|
|
position_ids.clone()
|
|
|
|
|
};
|
|
|
|
|
let position_ids_expanded = position_ids
|
|
|
|
|
.unsqueeze(D::Minus2)?
|
|
|
|
|
.to_dtype(DType::F32)?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
// inv_freq Vec<f32> -> Tensor(1, 1, head_dim / 2, 1) -> (3, bs, head_dim / 2, 1)
|
|
|
|
|
let inv_freq_expanded = Tensor::from_vec(
|
|
|
|
|
self.inv_freq.clone(),
|
|
|
|
|
(1, 1, self.inv_freq.len(), 1),
|
|
|
|
|
position_ids.device(),
|
|
|
|
|
)?
|
|
|
|
|
.broadcast_as((3, position_ids.dim(1)?, self.inv_freq.len(), 1))?
|
|
|
|
|
.to_dtype(DType::F32)?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
|
|
|
|
|
// (3, bs, head_dim / 2, 1) matmul (3, bs, 1, position)
|
|
|
|
|
// -> (3, bs, head_dim / 2, seq_len) -> (3, bs, seq_len, head_dim / 2)
|
|
|
|
|
let freqs = inv_freq_expanded
|
|
|
|
|
.matmul(&position_ids_expanded)?
|
|
|
|
|
.transpose(2, 3)?;
|
|
|
|
|
let freqs = self.apply_interleaved_mrope_asr(&freqs, mrope_section)?;
|
|
|
|
|
let emb = Tensor::cat(&[&freqs, &freqs], D::Minus1)?.contiguous()?;
|
|
|
|
|
let cos = emb.cos()?;
|
|
|
|
|
let sin = emb.sin()?;
|
|
|
|
|
Ok((cos.to_dtype(dtype)?, sin.to_dtype(dtype)?))
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-26 21:39:23 +08:00
|
|
|
pub fn forward(
|
|
|
|
|
&self,
|
|
|
|
|
position_ids: &Tensor,
|
|
|
|
|
dtype: DType,
|
|
|
|
|
mrope_section: Vec<usize>,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
|
|
|
|
// position_ids shape: (3, bs, position) -> (3, bs, 1, position)
|
|
|
|
|
let position_ids = if position_ids.rank() == 2 {
|
|
|
|
|
let (bs, len) = position_ids.dims2()?;
|
|
|
|
|
position_ids.unsqueeze(0)?.expand((3, bs, len))?
|
|
|
|
|
} else {
|
|
|
|
|
position_ids.clone()
|
|
|
|
|
};
|
|
|
|
|
let position_ids_expanded = position_ids
|
|
|
|
|
.unsqueeze(D::Minus2)?
|
|
|
|
|
.to_dtype(DType::F32)?
|
2026-03-17 15:39:34 +08:00
|
|
|
// .to_dtype(dtype)?
|
2025-10-26 21:39:23 +08:00
|
|
|
.contiguous()?;
|
|
|
|
|
// inv_freq Vec<f32> -> Tensor(1, 1, head_dim / 2, 1) -> (3, bs, head_dim / 2, 1)
|
|
|
|
|
let inv_freq_expanded = Tensor::from_vec(
|
|
|
|
|
self.inv_freq.clone(),
|
|
|
|
|
(1, 1, self.inv_freq.len(), 1),
|
|
|
|
|
position_ids.device(),
|
|
|
|
|
)?
|
|
|
|
|
.broadcast_as((3, position_ids.dim(1)?, self.inv_freq.len(), 1))?
|
|
|
|
|
.to_dtype(DType::F32)?
|
2026-03-17 15:39:34 +08:00
|
|
|
// .to_dtype(dtype)?
|
2025-10-26 21:39:23 +08:00
|
|
|
.contiguous()?;
|
|
|
|
|
|
|
|
|
|
// (3, bs, head_dim / 2, 1) matmul (3, bs, 1, position)
|
|
|
|
|
// -> (3, bs, head_dim / 2, seq_len) -> (3, bs, seq_len, head_dim / 2)
|
|
|
|
|
let freqs = inv_freq_expanded
|
|
|
|
|
.matmul(&position_ids_expanded)?
|
|
|
|
|
.transpose(2, 3)?;
|
|
|
|
|
let freqs = self.apply_interleaved_mrope(&freqs, mrope_section)?;
|
|
|
|
|
let emb = Tensor::cat(&[&freqs, &freqs], D::Minus1)?.contiguous()?;
|
|
|
|
|
let cos = emb.cos()?;
|
|
|
|
|
let sin = emb.sin()?;
|
|
|
|
|
Ok((cos.to_dtype(dtype)?, sin.to_dtype(dtype)?))
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-11-22 23:27:14 +08:00
|
|
|
|
|
|
|
|
pub struct RoPE {
|
|
|
|
|
inv_freq: Tensor, // (1, dim / 2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl RoPE {
|
|
|
|
|
pub fn new(dim: usize, theta_base: f32, device: &Device) -> Result<Self> {
|
|
|
|
|
let inv_freq = compute_default_rope_parameters(dim, theta_base);
|
|
|
|
|
let inv_freq = Tensor::from_slice(&inv_freq, (1, inv_freq.len()), device)?;
|
|
|
|
|
Ok(Self { inv_freq })
|
|
|
|
|
}
|
|
|
|
|
pub fn forward(
|
|
|
|
|
&self,
|
|
|
|
|
seqlen_offset: usize,
|
|
|
|
|
seq_len: usize,
|
|
|
|
|
device: &Device,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
|
|
|
|
let positions = Tensor::arange(
|
|
|
|
|
seqlen_offset as f32,
|
|
|
|
|
(seqlen_offset + seq_len) as f32,
|
2026-03-18 19:15:21 +08:00
|
|
|
self.inv_freq.device(),
|
2025-11-22 23:27:14 +08:00
|
|
|
)?
|
|
|
|
|
.reshape((seq_len, 1))?; // (seq_len, 1)
|
|
|
|
|
let freqs = positions.matmul(&self.inv_freq)?; // (seq_len, dim / 2)
|
2026-03-18 19:15:21 +08:00
|
|
|
let emb = Tensor::cat(&[&freqs, &freqs], D::Minus1)?
|
|
|
|
|
.contiguous()?
|
|
|
|
|
.to_device(device)?; // (seq_len, dim)
|
2025-11-22 23:27:14 +08:00
|
|
|
let cos = emb.cos()?;
|
|
|
|
|
let sin = emb.sin()?;
|
|
|
|
|
Ok((cos, sin))
|
|
|
|
|
}
|
2026-05-09 12:18:16 +08:00
|
|
|
pub fn forward_repeat_interleave(
|
|
|
|
|
&self,
|
|
|
|
|
seqlen_offset: usize,
|
|
|
|
|
seq_len: usize,
|
|
|
|
|
device: &Device,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
|
|
|
|
let positions = Tensor::arange(
|
|
|
|
|
seqlen_offset as f32,
|
|
|
|
|
(seqlen_offset + seq_len) as f32,
|
|
|
|
|
self.inv_freq.device(),
|
|
|
|
|
)?
|
|
|
|
|
.reshape((seq_len, 1))?; // (seq_len, 1)
|
|
|
|
|
let freqs = positions.matmul(&self.inv_freq)?; // (seq_len, dim / 2)
|
|
|
|
|
let cos = freqs
|
|
|
|
|
.cos()?
|
|
|
|
|
.unsqueeze(D::Minus1)?
|
|
|
|
|
.repeat((1, 1, 2))?
|
|
|
|
|
.flatten_from(D::Minus2)?
|
|
|
|
|
.contiguous()?
|
|
|
|
|
.to_device(device)?;
|
|
|
|
|
let sin = freqs
|
|
|
|
|
.sin()?
|
|
|
|
|
.unsqueeze(D::Minus1)?
|
|
|
|
|
.repeat((1, 1, 2))?
|
|
|
|
|
.flatten_from(D::Minus2)?
|
|
|
|
|
.contiguous()?
|
|
|
|
|
.to_device(device)?;
|
|
|
|
|
Ok((cos, sin))
|
|
|
|
|
}
|
2025-11-22 23:27:14 +08:00
|
|
|
}
|
2025-12-03 17:21:01 +08:00
|
|
|
|
|
|
|
|
pub fn get_xd_cos_sin(
|
|
|
|
|
cos: &Tensor,
|
|
|
|
|
sin: &Tensor,
|
|
|
|
|
position_ids: &Tensor,
|
|
|
|
|
xdrope_section: Vec<usize>,
|
|
|
|
|
) -> Result<(Tensor, Tensor)> {
|
|
|
|
|
let x_dim = xdrope_section.len();
|
|
|
|
|
// position_ids: (bs, 4, seq_len)
|
|
|
|
|
let mut cos_vec = vec![];
|
|
|
|
|
let mut sin_vec = vec![];
|
|
|
|
|
let bs = position_ids.dim(0)?;
|
|
|
|
|
for i in 0..bs {
|
|
|
|
|
let pos_i = position_ids.i(i)?;
|
|
|
|
|
let cos_i = index_select_2d(cos, &pos_i)?;
|
|
|
|
|
let sin_i = index_select_2d(sin, &pos_i)?;
|
|
|
|
|
cos_vec.push(cos_i);
|
|
|
|
|
sin_vec.push(sin_i);
|
|
|
|
|
}
|
|
|
|
|
// (bs, 4, seq_len, dim) -> (bs, seq_len, 4, dim)
|
|
|
|
|
let cos = Tensor::stack(&cos_vec, 0)?
|
|
|
|
|
.permute((0, 2, 1, 3))?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
let sin = Tensor::stack(&sin_vec, 0)?
|
|
|
|
|
.permute((0, 2, 1, 3))?
|
|
|
|
|
.contiguous()?;
|
|
|
|
|
let xdrope_section: Vec<usize> = xdrope_section.iter().map(|&i| i * 2).collect();
|
|
|
|
|
let cos_select: Vec<Tensor> = split_tensor(&cos, &xdrope_section, D::Minus1)?
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.map(|(i, m)| m.i((.., .., i % x_dim)).unwrap())
|
|
|
|
|
.collect();
|
|
|
|
|
let sin_select: Vec<Tensor> = split_tensor(&sin, &xdrope_section, D::Minus1)?
|
|
|
|
|
.iter()
|
|
|
|
|
.enumerate()
|
|
|
|
|
.map(|(i, m)| m.i((.., .., i % x_dim)).unwrap())
|
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
|
|
let cos = Tensor::cat(&cos_select, D::Minus1)?;
|
|
|
|
|
let sin = Tensor::cat(&sin_select, D::Minus1)?;
|
|
|
|
|
Ok((cos, sin))
|
|
|
|
|
}
|