1use burn::prelude::*;
14
15use crate::branches::{DeltaBranches, DeltaBranchesConfig};
16use crate::delta::delta_update;
17
18#[derive(Config, Debug)]
20pub struct DeltaResidualConfig {
21 pub d_model: usize,
23 pub dv: usize,
25 pub d_hidden: usize,
27 #[config(default = "1e-8")]
29 pub eps: f32,
30}
31
32#[derive(Module, Debug)]
37pub struct DeltaResidual<B: Backend> {
38 branches: DeltaBranches<B>,
39 eps: f32,
40}
41
42impl DeltaResidualConfig {
43 pub fn init<B: Backend>(&self, device: &B::Device) -> DeltaResidual<B> {
44 let branches_cfg = DeltaBranchesConfig::new(self.d_model, self.dv, self.d_hidden);
45 let branches_cfg = branches_cfg.with_eps(self.eps);
46
47 DeltaResidual {
48 branches: branches_cfg.init(device),
49 eps: self.eps,
50 }
51 }
52}
53
54impl<B: Backend> DeltaResidual<B> {
55 pub fn forward(&self, x: Tensor<B, 3>) -> Tensor<B, 3> {
61 let (k, beta, v) = self.branches.forward(&x);
62 delta_update(x, k, v, beta, self.eps)
63 }
64
65 pub fn forward_with_params(
67 &self,
68 x: Tensor<B, 3>,
69 ) -> (Tensor<B, 3>, Tensor<B, 2>, Tensor<B, 2>, Tensor<B, 2>) {
70 let (k, beta, v) = self.branches.forward(&x);
71 let y = delta_update(x, k.clone(), v.clone(), beta.clone(), self.eps);
72 (y, k, beta, v)
73 }
74}
75
76#[derive(Module, Debug)]
78pub struct DeltaResidualExternal<B: Backend> {
79 eps: f32,
80 _backend: core::marker::PhantomData<B>, }
82
83impl<B: Backend> DeltaResidualExternal<B> {
84 pub fn new(eps: f32) -> Self {
85 Self {
86 eps,
87 _backend: core::marker::PhantomData,
88 }
89 }
90
91 pub fn forward(
99 &self,
100 x: Tensor<B, 3>,
101 k: Tensor<B, 2>,
102 v: Tensor<B, 2>,
103 beta: Tensor<B, 2>,
104 ) -> Tensor<B, 3> {
105 delta_update(x, k, v, beta, self.eps)
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 pub type TestBackend = burn_ndarray::NdArray<f32>;
114 use burn::tensor::Distribution;
115
116 #[test]
117 fn test_delta_residual_shapes() {
118 let device = Default::default();
119
120 let cfg = DeltaResidualConfig::new(8, 4, 16);
121 let model = cfg.init::<TestBackend>(&device);
122
123 let x =
124 Tensor::<TestBackend, 3>::random([2, 8, 4], Distribution::Uniform(-1.0, 1.0), &device);
125
126 let (y, k, beta, v) = model.forward_with_params(x);
127 assert_eq!(y.dims(), [2, 8, 4]);
128 assert_eq!(k.dims(), [2, 8]);
129 assert_eq!(beta.dims(), [2, 1]);
130 assert_eq!(v.dims(), [2, 4]);
131 }
132
133 #[test]
134 fn test_delta_residual_external_shapes() {
135 let device = Default::default();
136
137 let block = DeltaResidualExternal::new(1e-8);
138
139 let x =
140 Tensor::<TestBackend, 3>::random([2, 8, 4], Distribution::Uniform(-1.0, 1.0), &device);
141 let k = Tensor::<TestBackend, 2>::random([2, 8], Distribution::Uniform(-1.0, 1.0), &device);
142 let v = Tensor::<TestBackend, 2>::random([2, 4], Distribution::Uniform(-1.0, 1.0), &device);
143 let beta =
144 Tensor::<TestBackend, 2>::random([2, 1], Distribution::Uniform(0.0, 2.0), &device);
145
146 let y = block.forward(x, k, v, beta);
147 assert_eq!(y.dims(), [2, 8, 4]);
148 }
149}