use candle_core::DType;
use candle_core::Device;
use candle_core::Tensor;
use serde::Deserialize;
use serde::Serialize;
use crate::error::Result;
fn power_of_two_slopes(n: usize) -> Vec<f64> {
let ratio = 2f64.powf(-8.0 / n as f64);
(0..n).map(|i| ratio.powi(i as i32 + 1)).collect()
}
pub fn head_slopes(n: usize) -> Vec<f64> {
if n.is_power_of_two() {
return power_of_two_slopes(n);
}
let c = n.next_power_of_two() / 2;
let mut slopes = power_of_two_slopes(c);
slopes.extend(
power_of_two_slopes(2 * c)
.into_iter()
.step_by(2)
.take(n - c),
);
slopes
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum AlibiSlopeVariant {
Canonical,
HalvedInterpolatedTail,
}
pub struct AlibiBias {
slopes: Vec<f64>,
}
impl AlibiBias {
pub fn new(num_heads: usize, variant: AlibiSlopeVariant) -> Self {
let mut slopes = head_slopes(num_heads);
if variant == AlibiSlopeVariant::HalvedInterpolatedTail && !num_heads.is_power_of_two() {
let tail_start = num_heads.next_power_of_two() / 2;
for slope in &mut slopes[tail_start..] {
*slope /= 2.0;
}
}
Self { slopes }
}
pub fn forward(&self, seq: usize, device: &Device) -> Result<Tensor> {
let positions = Tensor::arange(0u32, seq as u32, device)?.to_dtype(DType::F32)?;
let distance = positions
.reshape((seq, 1))?
.broadcast_sub(&positions.reshape((1, seq))?)?
.abs()?;
let negated: Vec<f32> = self.slopes.iter().map(|s| -(*s as f32)).collect();
let slopes = Tensor::from_vec(negated, (self.slopes.len(), 1, 1), device)?;
Ok(
distance
.broadcast_mul(&slopes)?
.unsqueeze(0)?
.contiguous()?,
)
}
}
#[cfg(test)]
mod tests;