use nuvec::{Array, Static};
#[derive(Debug, Clone, PartialEq, Static)]
#[non_exhaustive]
pub enum RopeScaling {
None,
Linear {
factor: f32,
},
Llama3(Llama3),
Yarn(Yarn),
LongRope(LongRope),
Proportional {
rotated_dims: i32,
factor: f32,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Static)]
pub struct Llama3 {
pub factor: f32,
pub low_freq_factor: f32,
pub high_freq_factor: f32,
pub original_max_position_embeddings: f32,
}
impl Default for Llama3 {
fn default() -> Self {
Self {
factor: 1.0,
low_freq_factor: 1.0,
high_freq_factor: 4.0,
original_max_position_embeddings: 8192.0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Static)]
pub struct Yarn {
pub factor: f32,
pub original_max_position_embeddings: f32,
pub beta_fast: f32,
pub beta_slow: f32,
pub mscale: f32,
pub mscale_all_dim: f32,
}
impl Default for Yarn {
fn default() -> Self {
Self {
factor: 1.0,
original_max_position_embeddings: 4096.0,
beta_fast: 32.0,
beta_slow: 1.0,
mscale: 1.0,
mscale_all_dim: 0.0,
}
}
}
#[derive(Debug, Clone, PartialEq, Static)]
pub struct LongRope {
pub long_factor: Vec<f32>,
pub max_position_embeddings: f32,
pub original_max_position_embeddings: f32,
pub long_mscale: Option<f32>,
}
impl Default for LongRope {
fn default() -> Self {
Self {
long_factor: vec![1.0],
max_position_embeddings: 131_072.0,
original_max_position_embeddings: 4096.0,
long_mscale: None,
}
}
}
fn powers(base: f32, upto: i32, dims: i32) -> Vec<f32> {
(0..upto)
.step_by(2)
.map(|i| base.powf(i as f32 / dims as f32))
.collect()
}
impl RopeScaling {
pub fn frequencies(&self, dims: i32, base: f32) -> Option<Array> {
let freqs: Vec<f32> = match self {
Self::None | Self::Linear { .. } => return None,
Self::Llama3(p) => {
let old = p.original_max_position_embeddings;
let (low_wavelen, high_wavelen) =
(old / p.low_freq_factor, old / p.high_freq_factor);
powers(base, dims, dims)
.into_iter()
.map(|freq| {
let wavelen = 2.0 * std::f32::consts::PI * freq;
let scaled = if wavelen > low_wavelen {
freq * p.factor
} else {
freq
};
if wavelen > high_wavelen && wavelen < low_wavelen {
let smooth = (old / wavelen - p.low_freq_factor)
/ (p.high_freq_factor - p.low_freq_factor);
scaled / ((1.0 - smooth) / p.factor + smooth)
} else {
scaled
}
})
.collect()
}
Self::Yarn(p) => {
let correction = |rotations: f32| {
(dims as f32
* (p.original_max_position_embeddings
/ (rotations * 2.0 * std::f32::consts::PI))
.ln())
/ (2.0 * base.ln())
};
let low = correction(p.beta_fast).floor().max(0.0);
let mut high = correction(p.beta_slow).ceil().min((dims - 1) as f32);
if low == high {
high += 0.001;
}
powers(base, dims, dims)
.into_iter()
.enumerate()
.map(|(i, extra)| {
let inter = p.factor * extra;
let ramp = ((i as f32 - low) / (high - low)).clamp(0.0, 1.0);
let mask = 1.0 - ramp;
(inter * extra) / (inter * mask + extra * (1.0 - mask))
})
.collect()
}
Self::LongRope(p) => {
let f = powers(base, dims, dims);
let factor = |i: usize| match p.long_factor.as_slice() {
[one] => *one,
all => all.get(i).copied().unwrap_or(1.0),
};
f.into_iter()
.enumerate()
.map(|(i, x)| factor(i) * x)
.collect()
}
Self::Proportional {
rotated_dims,
factor,
} => {
let mut f: Vec<f32> = powers(base, *rotated_dims, dims)
.into_iter()
.map(|x| factor * x)
.collect();
f.resize((dims / 2) as usize, f32::INFINITY);
f
}
};
Some(Array::from(freqs))
}
pub fn mscale(&self) -> f32 {
let yarn = |scale: f32, m: f32| {
if scale <= 1.0 {
1.0
} else {
0.1 * m * scale.ln() + 1.0
}
};
match self {
Self::Yarn(p) => yarn(p.factor, p.mscale) / yarn(p.factor, p.mscale_all_dim),
Self::LongRope(p) => {
let factor = p.max_position_embeddings / p.original_max_position_embeddings;
p.long_mscale.unwrap_or(if factor <= 1.0 {
1.0
} else {
(1.0 + factor.ln() / p.original_max_position_embeddings.ln()).sqrt()
})
}
_ => 1.0,
}
}
pub fn position_scale(&self) -> f32 {
match self {
Self::Linear { factor } => 1.0 / factor,
_ => 1.0,
}
}
}