1#![allow(non_snake_case)]
11
12use crate::mamba3::single_ssd::ssd;
13use burn_stack::utils::fprim::F;
14use burn::backend::autodiff::{
15 Autodiff,
16 checkpoint::{base::Checkpointer, strategy::CheckpointStrategy},
17 grads::Gradients,
18 ops::{Backward, Ops, OpsKind},
19};
20use burn::backend::tensor::FloatTensor;
21use burn::backend::{Backend, BackendTypes};
22use ssd::serial_recalculated::{
23 Mamba3SingleSsdBackendExt,
24 combined_backward::{self, CombinedSingleSsdGrads},
25};
26
27impl<B: Backend + Mamba3SingleSsdBackendExt, C: CheckpointStrategy> Mamba3SingleSsdBackendExt
28 for Autodiff<B, C>
29{
30 fn single_ssd_serial_recalculated(
38 v_bnlmhp: FloatTensor<Self>,
39 da_bnlh: FloatTensor<Self>,
40 b_bnlmhr: FloatTensor<Self>,
41 c_bnlmhr: FloatTensor<Self>,
42 gamma_bnlh: FloatTensor<Self>,
43 scale_bnlh: FloatTensor<Self>,
44 initial_state_bhpr: FloatTensor<Self>,
45 siso_specialization: bool,
46 ) -> (FloatTensor<Self>, FloatTensor<Self>) {
47 #[derive(Debug)]
48 struct CombinedKernelsBackward;
49
50 #[derive(Clone, Debug)]
51 struct State<B: Backend> {
52 v_bnlmhp: <B as BackendTypes>::FloatTensorPrimitive,
53 da_bnlh: <B as BackendTypes>::FloatTensorPrimitive,
54 b_bnlmhr: <B as BackendTypes>::FloatTensorPrimitive,
55 c_bnlmhr: <B as BackendTypes>::FloatTensorPrimitive,
56 gamma_bnlh: <B as BackendTypes>::FloatTensorPrimitive,
57 scale_bnlh: <B as BackendTypes>::FloatTensorPrimitive,
58 initial_state_bhpr: <B as BackendTypes>::FloatTensorPrimitive,
59 siso_specialization: bool,
60 flat_len_y_BNLMHP: usize,
61 flat_len_final_state_BHPR: usize,
62 shape_v_bnlmhp: [usize; 6],
63 shape_da_bnlh: [usize; 4],
64 shape_b_bnlmhr: [usize; 6],
65 shape_c_bnlmhr: [usize; 6],
66 shape_gamma_bnlh: [usize; 4],
67 shape_scale_bnlh: [usize; 4],
68 shape_initial_state_bhpr: [usize; 4],
69 shape_y_bnlmhp: [usize; 6],
70 shape_final_state_bhpr: [usize; 4],
71 }
72
73 impl<B: Backend + Mamba3SingleSsdBackendExt> Backward<B, 7> for CombinedKernelsBackward {
74 type State = State<B>;
75
76 fn backward(
77 self,
78 ops: Ops<Self::State, 7>,
79 grads: &mut Gradients,
80 _checkpointer: &mut Checkpointer,
81 ) {
82 let [
83 node_v_bnlmhp,
84 node_da_bnlh,
85 node_b_bnlmhr,
86 node_c_bnlmhr,
87 node_gamma_bnlh,
88 node_scale_bnlh,
89 node_initial_state_bhpr,
90 ] = ops.parents;
91
92 let d_combined: <B as BackendTypes>::FloatTensorPrimitive =
93 grads.consume::<B>(&ops.node);
94
95 let State {
96 v_bnlmhp,
97 da_bnlh,
98 b_bnlmhr,
99 c_bnlmhr,
100 gamma_bnlh,
101 scale_bnlh,
102 initial_state_bhpr,
103 siso_specialization,
104 flat_len_y_BNLMHP,
105 flat_len_final_state_BHPR,
106 shape_v_bnlmhp,
107 shape_da_bnlh,
108 shape_b_bnlmhr,
109 shape_c_bnlmhr,
110 shape_gamma_bnlh,
111 shape_scale_bnlh,
112 shape_initial_state_bhpr,
113 shape_y_bnlmhp,
114 shape_final_state_bhpr,
115 } = ops.state;
116
117 let v_bnlmhp = F::<B, 6>::new(v_bnlmhp).reshape(shape_v_bnlmhp);
119 let da_bnlh = F::<B, 4>::new(da_bnlh).reshape(shape_da_bnlh);
120 let b_bnlmhr = F::<B, 6>::new(b_bnlmhr).reshape(shape_b_bnlmhr);
121 let c_bnlmhr = F::<B, 6>::new(c_bnlmhr).reshape(shape_c_bnlmhr);
122 let gamma_bnlh = F::<B, 4>::new(gamma_bnlh).reshape(shape_gamma_bnlh);
123 let scale_bnlh = F::<B, 4>::new(scale_bnlh).reshape(shape_scale_bnlh);
124 let initial_state_bhpr =
125 F::<B, 4>::new(initial_state_bhpr).reshape(shape_initial_state_bhpr);
126
127 let (d_y_bnlmhp, d_final_state_bhpr) =
128 burn_stack::utils::combined_grad::unflatten_pair::<B, 6, 4>(
129 d_combined,
130 flat_len_y_BNLMHP,
131 flat_len_final_state_BHPR,
132 shape_y_bnlmhp,
133 shape_final_state_bhpr,
134 );
135
136 let CombinedSingleSsdGrads {
137 d_v_bnlmhp,
138 d_da_bnlh,
139 d_b_bnlmhr,
140 d_c_bnlmhr,
141 d_gamma_bnlh,
142 d_scale_bnlh,
143 d_initial_state_bhpr,
144 } = combined_backward::combined_backward(
145 F::<B, 6>::new(d_y_bnlmhp),
146 F::<B, 4>::new(d_final_state_bhpr),
147 v_bnlmhp,
148 da_bnlh,
149 b_bnlmhr,
150 c_bnlmhr,
151 gamma_bnlh,
152 scale_bnlh,
153 initial_state_bhpr,
154 siso_specialization,
155 );
156
157 if let Some(n) = node_v_bnlmhp {
158 grads.register::<B>(n.id, d_v_bnlmhp.inner());
159 }
160 if let Some(n) = node_da_bnlh {
161 grads.register::<B>(n.id, d_da_bnlh.inner());
162 }
163 if let Some(n) = node_b_bnlmhr {
164 grads.register::<B>(n.id, d_b_bnlmhr.inner());
165 }
166 if let Some(n) = node_c_bnlmhr {
167 grads.register::<B>(n.id, d_c_bnlmhr.inner());
168 }
169 if let Some(n) = node_gamma_bnlh {
170 grads.register::<B>(n.id, d_gamma_bnlh.inner());
171 }
172 if let Some(n) = node_scale_bnlh {
173 grads.register::<B>(n.id, d_scale_bnlh.inner());
174 }
175 if let Some(n) = node_initial_state_bhpr {
176 grads.register::<B>(n.id, d_initial_state_bhpr.inner());
177 }
178 }
179 }
180
181 use burn::backend::TensorMetadata;
182 let [batch, nchunks, chunk_len, mimo_rank, nheads, per_head_dim] =
183 v_bnlmhp.primitive.shape().dims();
184 let [.., state_rank] = b_bnlmhr.primitive.shape().dims::<6>();
185
186 let flat_len_y_BNLMHP = batch * nchunks * chunk_len * mimo_rank * nheads * per_head_dim;
187 let flat_len_final_state_BHPR = batch * nheads * per_head_dim * state_rank;
188
189 let shape_v_bnlmhp: [usize; 6] =
190 [batch, nchunks, chunk_len, mimo_rank, nheads, per_head_dim];
191 let shape_da_bnlh: [usize; 4] = [batch, nchunks, chunk_len, nheads];
192 let shape_b_bnlmhr: [usize; 6] = [batch, nchunks, chunk_len, mimo_rank, nheads, state_rank];
193 let shape_c_bnlmhr: [usize; 6] = [batch, nchunks, chunk_len, mimo_rank, nheads, state_rank];
194 let shape_gamma_bnlh: [usize; 4] = [batch, nchunks, chunk_len, nheads];
195 let shape_scale_bnlh: [usize; 4] = [batch, nchunks, chunk_len, nheads];
196 let shape_initial_state_bhpr: [usize; 4] = [batch, nheads, per_head_dim, state_rank];
197 let shape_y_bnlmhp: [usize; 6] =
198 [batch, nchunks, chunk_len, mimo_rank, nheads, per_head_dim];
199 let shape_final_state_bhpr: [usize; 4] = [batch, nheads, per_head_dim, state_rank];
200
201 match CombinedKernelsBackward
202 .prepare::<C>([
203 v_bnlmhp.node.clone(),
204 da_bnlh.node.clone(),
205 b_bnlmhr.node.clone(),
206 c_bnlmhr.node.clone(),
207 gamma_bnlh.node.clone(),
208 scale_bnlh.node.clone(),
209 initial_state_bhpr.node.clone(),
210 ])
211 .compute_bound()
212 .stateful()
213 {
214 OpsKind::Tracked(prep) => {
215 let (prim_y_bnlmhp, prim_final_state_bhpr) = B::single_ssd_serial_recalculated(
216 v_bnlmhp.primitive.clone(),
217 da_bnlh.primitive.clone(),
218 b_bnlmhr.primitive.clone(),
219 c_bnlmhr.primitive.clone(),
220 gamma_bnlh.primitive.clone(),
221 scale_bnlh.primitive.clone(),
222 initial_state_bhpr.primitive.clone(),
223 siso_specialization,
224 );
225
226 let (prim_combined, _, _) = burn_stack::utils::combined_grad::flatten_pair::<B>(
227 prim_y_bnlmhp,
228 prim_final_state_bhpr,
229 );
230
231 let state = State {
232 v_bnlmhp: v_bnlmhp.primitive.clone(),
233 da_bnlh: da_bnlh.primitive.clone(),
234 b_bnlmhr: b_bnlmhr.primitive.clone(),
235 c_bnlmhr: c_bnlmhr.primitive.clone(),
236 gamma_bnlh: gamma_bnlh.primitive.clone(),
237 scale_bnlh: scale_bnlh.primitive.clone(),
238 initial_state_bhpr: initial_state_bhpr.primitive.clone(),
239 siso_specialization,
240 flat_len_y_BNLMHP,
241 flat_len_final_state_BHPR,
242 shape_v_bnlmhp,
243 shape_da_bnlh,
244 shape_b_bnlmhr,
245 shape_c_bnlmhr,
246 shape_gamma_bnlh,
247 shape_scale_bnlh,
248 shape_initial_state_bhpr,
249 shape_y_bnlmhp,
250 shape_final_state_bhpr,
251 };
252 let tracked_combined: FloatTensor<Autodiff<B, C>> =
253 prep.finish(state, prim_combined);
254
255 let (tracked_y_bnlmhp, tracked_final_state_bhpr) =
256 burn_stack::utils::combined_grad::autodiff_unflatten_pair::<B, C, 6, 4>(
257 tracked_combined,
258 flat_len_y_BNLMHP,
259 flat_len_final_state_BHPR,
260 shape_y_bnlmhp,
261 shape_final_state_bhpr,
262 );
263
264 (tracked_y_bnlmhp, tracked_final_state_bhpr)
265 }
266
267 OpsKind::UnTracked(prep) => {
268 let (prim_y_bnlmhp, prim_final_state_bhpr) = B::single_ssd_serial_recalculated(
269 v_bnlmhp.primitive,
270 da_bnlh.primitive,
271 b_bnlmhr.primitive,
272 c_bnlmhr.primitive,
273 gamma_bnlh.primitive,
274 scale_bnlh.primitive,
275 initial_state_bhpr.primitive,
276 siso_specialization,
277 );
278
279 let (prim_combined, _, _) = burn_stack::utils::combined_grad::flatten_pair::<B>(
280 prim_y_bnlmhp,
281 prim_final_state_bhpr,
282 );
283
284 let tracked_combined: FloatTensor<Autodiff<B, C>> = prep.finish(prim_combined);
285
286 let (tracked_y_bnlmhp, tracked_final_state_bhpr) =
287 burn_stack::utils::combined_grad::autodiff_unflatten_pair::<B, C, 6, 4>(
288 tracked_combined,
289 flat_len_y_BNLMHP,
290 flat_len_final_state_BHPR,
291 shape_y_bnlmhp,
292 shape_final_state_bhpr,
293 );
294
295 (tracked_y_bnlmhp, tracked_final_state_bhpr)
296 }
297 }
298 }
299}