use burn::prelude::*;
use crate::branches::{DeltaBranches, DeltaBranchesConfig};
use crate::delta::delta_update;
#[derive(Config, Debug)]
pub struct DeltaResidualConfig {
pub d_model: usize,
pub dv: usize,
pub d_hidden: usize,
#[config(default = "1e-8")]
pub eps: f32,
}
#[derive(Module, Debug)]
pub struct DeltaResidual<B: Backend> {
branches: DeltaBranches<B>,
eps: f32,
}
impl DeltaResidualConfig {
pub fn init<B: Backend>(&self, device: &B::Device) -> DeltaResidual<B> {
let branches_cfg = DeltaBranchesConfig::new(self.d_model, self.dv, self.d_hidden);
let branches_cfg = branches_cfg.with_eps(self.eps);
DeltaResidual {
branches: branches_cfg.init(device),
eps: self.eps,
}
}
}
impl<B: Backend> DeltaResidual<B> {
pub fn forward(&self, x: Tensor<B, 3>) -> Tensor<B, 3> {
let (k, beta, v) = self.branches.forward(&x);
delta_update(x, k, v, beta, self.eps)
}
pub fn forward_with_params(
&self,
x: Tensor<B, 3>,
) -> (Tensor<B, 3>, Tensor<B, 2>, Tensor<B, 2>, Tensor<B, 2>) {
let (k, beta, v) = self.branches.forward(&x);
let y = delta_update(x, k.clone(), v.clone(), beta.clone(), self.eps);
(y, k, beta, v)
}
}
#[derive(Module, Debug)]
pub struct DeltaResidualExternal<B: Backend> {
eps: f32,
_backend: core::marker::PhantomData<B>, }
impl<B: Backend> DeltaResidualExternal<B> {
pub fn new(eps: f32) -> Self {
Self {
eps,
_backend: core::marker::PhantomData,
}
}
pub fn forward(
&self,
x: Tensor<B, 3>,
k: Tensor<B, 2>,
v: Tensor<B, 2>,
beta: Tensor<B, 2>,
) -> Tensor<B, 3> {
delta_update(x, k, v, beta, self.eps)
}
}
#[cfg(test)]
mod tests {
use super::*;
pub type TestBackend = burn_ndarray::NdArray<f32>;
use burn::tensor::Distribution;
#[test]
fn test_delta_residual_shapes() {
let device = Default::default();
let cfg = DeltaResidualConfig::new(8, 4, 16);
let model = cfg.init::<TestBackend>(&device);
let x =
Tensor::<TestBackend, 3>::random([2, 8, 4], Distribution::Uniform(-1.0, 1.0), &device);
let (y, k, beta, v) = model.forward_with_params(x);
assert_eq!(y.dims(), [2, 8, 4]);
assert_eq!(k.dims(), [2, 8]);
assert_eq!(beta.dims(), [2, 1]);
assert_eq!(v.dims(), [2, 4]);
}
#[test]
fn test_delta_residual_external_shapes() {
let device = Default::default();
let block = DeltaResidualExternal::new(1e-8);
let x =
Tensor::<TestBackend, 3>::random([2, 8, 4], Distribution::Uniform(-1.0, 1.0), &device);
let k = Tensor::<TestBackend, 2>::random([2, 8], Distribution::Uniform(-1.0, 1.0), &device);
let v = Tensor::<TestBackend, 2>::random([2, 4], Distribution::Uniform(-1.0, 1.0), &device);
let beta =
Tensor::<TestBackend, 2>::random([2, 1], Distribution::Uniform(0.0, 2.0), &device);
let y = block.forward(x, k, v, beta);
assert_eq!(y.dims(), [2, 8, 4]);
}
}