1use crate::mamba2::prelude::*;
45use crate::modules::{StateMoments, sanity as san, segsum};
46use burn::prelude::*;
47
48impl Mamba2SsdInput {
49 pub fn detached(&self) -> Self {
52 Self {
53 x_bnlhp: self.x_bnlhp.clone().detach(),
54 dt_bnlh: self.dt_bnlh.clone().detach(),
55 a_decay_h: self.a_decay_h.clone().detach(),
56 b_bnlhr: self.b_bnlhr.clone().detach(),
57 c_bnlhr: self.c_bnlhr.clone().detach(),
58 d_h: self.d_h.clone().detach(),
59 initial_state_bhpr: self.initial_state_bhpr.clone().detach(),
60 init_state_hpr: self.init_state_hpr.clone().map(Tensor::detach),
61 }
62 }
63
64 pub fn state_moments(&self, valid_len: usize) -> StateMoments {
71 let [batch, nchunks, chunk_len, nheads, per_head_dim] = self.x_bnlhp.dims();
72 let [.., state_rank] = self.b_bnlhr.dims();
73 let device = &self.x_bnlhp.device();
74 assert!(
75 (1..=nchunks * chunk_len).contains(&valid_len),
76 "valid_len must be within the (padded) sequence"
77 );
78
79 let delta_b_bnlhr = self.dt_bnlh.clone().unsqueeze_dim(4) * self.b_bnlhr.clone();
82 let a_bnlh = self.dt_bnlh.clone()
83 * self
84 .a_decay_h
85 .clone()
86 .unsqueeze_dims::<4>(&[0, 1, 2])
87 .expand([batch, nchunks, chunk_len, nheads]);
88 let a_bhnl = a_bnlh.permute([0, 3, 1, 2]);
89 let a_cumsum_bhnl = a_bhnl.clone().cumsum(3);
90 san(&a_cumsum_bhnl);
91
92 let state_in_bnhpr = {
94 let a_cumsum_last_bhn1 = a_cumsum_bhnl.clone().slice(s![.., .., .., -1]);
96 let decay_state_bhnl = (a_cumsum_last_bhn1.clone() - a_cumsum_bhnl.clone()).exp();
97 let decay_state_bnlh1 = decay_state_bhnl.permute([0, 2, 3, 1]).unsqueeze_dim(4);
98 let decayed_x_bnhpl = (decay_state_bnlh1 * self.x_bnlhp.clone())
99 .permute([0, 1, 3, 4, 2]);
100 let state_bnhpr = decayed_x_bnhpl
101 .matmul(delta_b_bnlhr.clone().permute([0, 1, 3, 2, 4]));
102
103 let initial_state_b1hpr = self.initial_state_bhpr.clone().unsqueeze_dim(1);
105 let initial_state_b1hpr = if let Some(init_hpr) = &self.init_state_hpr {
106 let init_b1hpr = init_hpr.clone().unsqueeze_dim::<4>(0).expand([
107 batch,
108 1,
109 nheads,
110 per_head_dim,
111 state_rank,
112 ]);
113 initial_state_b1hpr + init_b1hpr
114 } else {
115 initial_state_b1hpr
116 };
117 let state_bNhpr = Tensor::cat(vec![initial_state_b1hpr, state_bnhpr], 1);
118 let a_chunk_pad_bhN = Tensor::cat(
119 vec![
120 Tensor::<3>::zeros(Shape::new([batch, nheads, 1]), device),
121 a_cumsum_last_bhn1.squeeze_dim::<3>(3),
122 ],
123 2,
124 );
125 let decay_chunk_bhNN = segsum::<3, 4>(a_chunk_pad_bhN).exp();
126 let flat_state_dim = per_head_dim * state_rank;
127 let state_bhNf = state_bNhpr
128 .permute([0, 2, 1, 3, 4])
129 .reshape([batch, nheads, 1 + nchunks, flat_state_dim]);
130 let new_state_bhNf = decay_chunk_bhNN.matmul(state_bhNf);
131 let new_state_bhNpr =
132 new_state_bhNf.reshape([batch, nheads, 1 + nchunks, per_head_dim, state_rank]);
133 new_state_bhNpr
135 .slice(s![.., .., 0..nchunks, .., ..])
136 .permute([0, 2, 1, 3, 4]) };
138 san(&state_in_bnhpr);
139
140 let mask_11nl = Tensor::<1, Int>::arange(0..(nchunks * chunk_len) as i64, device)
142 .lower_elem(valid_len as i64)
143 .float()
144 .reshape([1, 1, nchunks, chunk_len]);
145
146 let d_bhnl = a_cumsum_bhnl.exp() * mask_11nl.clone();
148 let l_bhnll = segsum::<4, 5>(a_bhnl).exp() * mask_11nl.unsqueeze_dim::<5>(4);
149 san(&d_bhnl);
150 san(&l_bhnll);
151
152 let sd1_bhn = d_bhnl.clone().sum_dim(3).squeeze_dim::<3>(3); let sd2_bhn = d_bhnl
155 .clone()
156 .powf_scalar(2.0)
157 .sum_dim(3)
158 .squeeze_dim::<3>(3); let w_bhnl = d_bhnl
161 .unsqueeze_dim::<5>(3)
162 .matmul(l_bhnll.clone())
163 .squeeze_dim::<4>(3);
164 let u_bhnl = l_bhnll.clone().sum_dim(3).squeeze_dim::<4>(3);
166 let k_bhnll = l_bhnll.clone().permute([0, 1, 2, 4, 3]).matmul(l_bhnll);
168
169 let x_bnhpl = self.x_bnlhp.clone().permute([0, 1, 3, 4, 2]);
171 let bbar_bnhlr = delta_b_bnlhr.permute([0, 1, 3, 2, 4]);
172 let state_in_bnhrp = state_in_bnhpr.clone().permute([0, 1, 2, 4, 3]);
173
174 let gram_x_bnhll = x_bnhpl.clone().permute([0, 1, 2, 4, 3]).matmul(x_bnhpl.clone());
176 let kg_bnhll = k_bhnll.permute([0, 2, 1, 3, 4]) * gram_x_bnhll;
177 let term_input_bnhrr = bbar_bnhlr
178 .clone()
179 .permute([0, 1, 2, 4, 3])
180 .matmul(kg_bnhll)
181 .matmul(bbar_bnhlr.clone());
182
183 let w_bnhl1 = w_bhnl.permute([0, 2, 1, 3]).unsqueeze_dim::<5>(4);
185 let p_bnhpr = x_bnhpl.clone().matmul(w_bnhl1 * bbar_bnhlr.clone());
186 let cross_bnhrr = state_in_bnhrp.clone().matmul(p_bnhpr);
187 let term_cross_bnhrr = cross_bnhrr.clone() + cross_bnhrr.permute([0, 1, 2, 4, 3]);
188
189 let sd2_bnh11 = sd2_bhn.permute([0, 2, 1]).unsqueeze_dims::<5>(&[3, 4]);
191 let term_carry_bnhrr = sd2_bnh11 * state_in_bnhrp.matmul(state_in_bnhpr.clone());
192
193 let m2_bhrr = (term_carry_bnhrr + term_cross_bnhrr + term_input_bnhrr)
194 .sum_dim(1)
195 .squeeze_dim::<4>(1);
196 san(&m2_bhrr);
197
198 let sd1_bnh11 = sd1_bhn.permute([0, 2, 1]).unsqueeze_dims::<5>(&[3, 4]);
200 let u_bnhl1 = u_bhnl.permute([0, 2, 1, 3]).unsqueeze_dim::<5>(4);
201 let sum_h_bnhpr = sd1_bnh11 * state_in_bnhpr + x_bnhpl.matmul(u_bnhl1 * bbar_bnhlr);
202 let m1_bhr = sum_h_bnhpr
203 .sum_dim(1)
204 .sum_dim(3)
205 .reshape([batch, nheads, state_rank]);
206 san(&m1_bhr);
207
208 StateMoments {
209 m2_bhrr,
210 m1_bhr,
211 count: valid_len * per_head_dim,
212 }
213 }
214}
215
216#[cfg(all(test, feature = "_dev-test"))]
217mod tests;