use candle_core::DType;
use candle_core::Device;
use super::config::NomicBertConfig;
use crate::error::Result;
use crate::layers::rope::RotaryEmbedding;
pub fn dynamic_ntk_base(base: f64, factor: f64, max_trained: usize, seq: usize, dim: usize) -> f64 {
if seq <= max_trained {
return base;
}
let scaled = (factor * seq as f64 / max_trained as f64) - (factor - 1.0);
base * scaled.powf(dim as f64 / (dim as f64 - 2.0))
}
pub struct NomicRotary {
base: f64,
factor: Option<f64>,
max_trained: usize,
head_dim: usize,
dtype: DType,
device: Device,
cached: RotaryEmbedding,
}
impl NomicRotary {
pub fn new(config: &NomicBertConfig, dtype: DType, device: &Device) -> Result<Self> {
let head_dim = config.head_dim();
let max_trained = config.max_trained_positions;
let base = config.rotary_emb_base;
let cached = RotaryEmbedding::new(head_dim, max_trained, base, dtype, device)?;
Ok(Self {
base,
factor: config.scaling_factor(),
max_trained,
head_dim,
dtype,
device: device.clone(),
cached,
})
}
pub fn for_length(&self, seq: usize) -> Result<Table<'_>> {
if seq <= self.max_trained {
return Ok(Table::Cached(&self.cached));
}
let base = self.factor.map_or(self.base, |factor| {
dynamic_ntk_base(self.base, factor, self.max_trained, seq, self.head_dim)
});
Ok(Table::Fresh(RotaryEmbedding::new(
self.head_dim,
seq,
base,
self.dtype,
&self.device,
)?))
}
}
pub enum Table<'a> {
Cached(&'a RotaryEmbedding),
Fresh(RotaryEmbedding),
}
impl Table<'_> {
pub(super) fn as_rope(&self) -> &RotaryEmbedding {
match self {
Table::Cached(rope) => rope,
Table::Fresh(rope) => rope,
}
}
}
#[cfg(test)]
mod tests;