1use crate::mamba1::prelude::*;
42use crate::modules::Silu;
43use crate::modules::sanity as san;
44use crate::modules::split_into;
45use burn::prelude::*;
46use burn::{
47 module::{Module, Param},
48 nn::conv::{Conv1d, Conv1dConfig},
49 nn::{Initializer, Linear, LinearConfig, PaddingConfig1d},
50};
51
52#[derive(Module, Debug)]
54pub struct Mamba1 {
55 pub in_proj: Linear,
58
59 pub conv1d: Conv1d,
62
63 pub x_proj: Linear,
66
67 pub dt_proj: Linear,
70
71 pub a_log: Param<Tensor<2>>,
73
74 pub d: Param<Tensor<1>>,
76
77 pub out_proj: Linear,
80}
81
82#[derive(Config, Debug)]
84pub struct Mamba1Config {
85 pub d_model: usize,
87
88 #[config(default = 16)]
91 pub state_rank: usize,
92
93 #[config(default = 4)]
95 pub conv_kernel: usize,
96
97 #[config(default = 2)]
99 pub expand: usize,
100
101 #[config(default = 1e-3)]
103 pub dt_min: f64,
104
105 #[config(default = 1e-1)]
107 pub dt_max: f64,
108
109 #[config(default = 1.)]
111 pub dt_scale: f64,
112
113 #[config(default = 1e-4)]
115 pub dt_init_floor: f64,
116
117 #[config(default = true)]
119 pub has_conv_bias: bool,
120
121 #[config(default = false)]
123 pub has_proj_bias: bool,
124
125 pub dt_rank: Option<usize>,
130
131 pub d_inner: Option<usize>,
135}
136
137impl Mamba1Config {
138 pub fn init(&self, device: &Device) -> Mamba1 {
140 let d_inner = self.d_inner();
141 assert_ne!(self.state_rank, 0);
142 assert!(self.d_model + self.state_rank > 0);
143 let dt_rank = self.dt_rank();
144
145 let uniform_init = |d_input: usize| {
147 let bound = 1.0 / (d_input as f64).sqrt();
148 Initializer::Uniform {
149 min: -bound,
150 max: bound,
151 }
152 };
153
154 let dt_proj = {
155 use burn::tensor::Distribution;
156 let weight: Tensor<2> = {
157 let dt_init_std = (dt_rank as f64).powf(-0.5) * self.dt_scale;
158 Tensor::random(
159 [dt_rank, d_inner],
160 Distribution::Uniform(-dt_init_std, dt_init_std),
161 device,
162 )
163 };
164 assert_eq!([dt_rank, d_inner], weight.dims());
165 let bias: Tensor<1> = {
166 let expm1 = |t: Tensor<1>| t.exp() - 1.;
170 let dt = Tensor::random([d_inner], Distribution::Uniform(0.0, 1.0), device)
171 * (f64::ln(self.dt_max) - f64::ln(self.dt_min))
172 + f64::ln(self.dt_min);
173 let dt = dt.exp().clamp_min(self.dt_init_floor);
174 dt.clone() + (-expm1(-dt)).log()
176 };
177 assert_eq!([d_inner], bias.dims());
178 Linear {
179 weight: Param::from_tensor(weight),
180 bias: Some(Param::from_tensor(bias)),
181 }
182 };
183
184 let a_log = {
185 let a_row: Tensor<1> =
186 Tensor::<1, Int>::arange(1..self.state_rank as i64 + 1, device).float();
187 assert_eq!([self.state_rank], a_row.dims());
188 let a_row = a_row.unsqueeze();
189 assert_eq!([1, self.state_rank], a_row.dims());
190 let a = a_row.repeat(&[d_inner, 1]);
191 assert_eq!([d_inner, self.state_rank], a.dims());
192 let a_log = a.log();
193 Param::from_tensor(a_log)
194 };
195
196 Mamba1 {
197 in_proj: LinearConfig::new(self.d_model, 2 * d_inner)
198 .with_bias(self.has_proj_bias)
199 .with_initializer(uniform_init(self.d_model))
201 .init(device),
202 conv1d: Conv1dConfig::new(d_inner, d_inner, self.conv_kernel)
203 .with_padding(PaddingConfig1d::Valid)
206 .with_groups(d_inner)
207 .with_bias(self.has_conv_bias)
208 .with_initializer(uniform_init(self.conv_kernel))
211 .init(device),
212 x_proj: LinearConfig::new(d_inner, dt_rank + 2 * self.state_rank)
213 .with_bias(false)
214 .with_initializer(uniform_init(d_inner))
216 .init(device),
217 dt_proj,
218 a_log,
219 d: Initializer::Ones.init([d_inner], device),
220 out_proj: LinearConfig::new(d_inner, self.d_model)
221 .with_bias(self.has_proj_bias)
222 .with_initializer(uniform_init(d_inner))
224 .init(device),
225 }
226 }
227 pub fn d_inner(&self) -> usize {
230 self.d_inner.unwrap_or(self.expand * self.d_model)
231 }
232 pub fn dt_rank(&self) -> usize {
235 self.dt_rank
236 .unwrap_or(self.d_model.div_ceil(self.state_rank))
237 }
238}
239
240impl Mamba1 {
241 pub fn forward(&self, x: Tensor<3>, cache: Option<Mamba1Cache>) -> (Tensor<3>, Mamba1Cache) {
252 let [batch, sequence, d_model] = x.dims();
253 let [d_inner] = self.d.dims();
254 let [_, _, conv_kernel] = self.conv1d.weight.dims();
255 let [_d_inner, state_rank] = self.a_log.dims();
256 let device = x.device();
257 assert!(sequence > 0, "sequence length must be at least 1");
258
259 let mut cache = cache.unwrap_or_else(|| Mamba1Cache {
261 conv_bik: Tensor::zeros([batch, d_inner, conv_kernel], &device),
262 ssm_bir: Tensor::zeros([batch, d_inner, state_rank], &device),
263 });
264 cache.sanity();
265
266 let [xs_bsi, res_bsi] = {
268 let xs_and_res = self.in_proj.forward(x);
269 assert_eq!([batch, sequence, 2 * d_inner], xs_and_res.dims());
270 split_into(xs_and_res, [d_inner, d_inner], 2)
271 };
272 assert_eq!([batch, sequence, d_inner], xs_bsi.dims());
273 assert_eq!([batch, sequence, d_inner], res_bsi.dims());
274
275 let xs_bsi = {
277 assert!(conv_kernel > 0);
278 let conv_in_bis = xs_bsi.permute([0, 2, 1]);
279 assert_eq!([batch, d_inner, sequence], conv_in_bis.dims());
280
281 let conv_in_padded = if conv_kernel >= 2 {
285 let tail = cache.conv_bik.clone().narrow(2, 1, conv_kernel - 1);
286 assert_eq!([batch, d_inner, conv_kernel - 1], tail.dims());
287 Tensor::cat(vec![tail, conv_in_bis], 2)
288 } else {
289 conv_in_bis
290 };
291 assert_eq!(
292 [batch, d_inner, (conv_kernel - 1) + sequence],
293 conv_in_padded.dims()
294 );
295
296 cache.conv_bik = conv_in_padded.clone().narrow(2, sequence - 1, conv_kernel);
299 assert_eq!([batch, d_inner, conv_kernel], cache.conv_bik.dims());
300
301 let xs = self.conv1d.forward(conv_in_padded);
302 assert_eq!([batch, d_inner, sequence], xs.dims());
303
304 let xs = xs.permute([0, 2, 1]);
306 assert_eq!([batch, sequence, d_inner], xs.dims());
307
308 let xs = Silu::new().forward(xs);
310 assert_eq!([batch, sequence, d_inner], xs.dims());
311
312 xs
313 };
314 assert_eq!([batch, sequence, d_inner], xs_bsi.dims());
315
316 let (scan_bsi, final_ssm) = self.ssm(xs_bsi, cache.ssm_bir.clone());
317 assert_eq!([batch, sequence, d_inner], scan_bsi.dims());
318 cache.ssm_bir = final_ssm;
319
320 let ys = scan_bsi * Silu::new().forward(res_bsi);
322 assert_eq!([batch, sequence, d_inner], ys.dims());
323
324 let y = self.out_proj.forward(ys);
325 assert_eq!([batch, sequence, d_model], y.dims());
326 san(&y);
327
328 (y, cache)
329 }
330
331 pub fn ssm(&self, u: Tensor<3>, init_ssm: Tensor<3>) -> (Tensor<3>, Tensor<3>) {
340 let [batch, sequence, d_inner] = u.dims();
341 let [_d_inner, state_rank] = self.a_log.dims();
342 let [dt_rank, _d_inner] = self.dt_proj.weight.dims();
343
344 let a = self.a_log.val().exp().neg();
349 assert_eq!([d_inner, state_rank], a.dims());
350
351 let x_dbl = self.x_proj.forward(u.clone());
352 assert_eq!([batch, sequence, dt_rank + 2 * state_rank], x_dbl.dims());
353
354 let [delta, b, c] = split_into(x_dbl, [dt_rank, state_rank, state_rank], 2);
358 assert_eq!([batch, sequence, dt_rank], delta.dims()); assert_eq!([batch, sequence, state_rank], b.dims());
360 assert_eq!([batch, sequence, state_rank], c.dims());
361
362 let delta = self.dt_proj.forward(delta);
365 assert_eq!([batch, sequence, d_inner], delta.dims());
366
367 let delta = burn::tensor::activation::softplus(delta, 1.);
368
369 let delta = delta.permute([1, 0, 2]);
370 assert_eq!([sequence, batch, d_inner], delta.dims());
371
372 let c = c.permute([1, 0, 2]);
373 assert_eq!([sequence, batch, state_rank], c.dims());
374
375 Self::selective_scan(delta, a, b, c, self.d.val(), u, init_ssm)
376 }
377
378 pub fn selective_scan(
396 delta: Tensor<3>,
397 a: Tensor<2>,
398 b: Tensor<3>,
399 c: Tensor<3>,
400 d: Tensor<1>,
401 u: Tensor<3>,
402 init_ssm: Tensor<3>,
403 ) -> (Tensor<3>, Tensor<3>) {
404 let [sequence, batch, d_inner] = delta.dims();
405 let [_d_inner, state_rank] = a.dims();
406 let outer_shape = [sequence, batch, d_inner, state_rank];
407
408 let (delta_a, delta_bu) = {
413 let delta = delta.unsqueeze_dim(3);
414 assert_eq!([sequence, batch, d_inner, 1], delta.dims());
415 let delta = delta.expand(outer_shape);
416 assert_eq!(outer_shape, delta.dims());
417
418 let a = a.unsqueeze_dims(&[0, 1]);
419 assert_eq!([1, 1, d_inner, state_rank], a.dims());
420 let a = a.expand(outer_shape);
421 assert_eq!(outer_shape, a.dims());
422 let delta_a = (delta.clone() * a).exp();
423 assert_eq!(outer_shape, delta_a.dims());
424
425 let b = b.permute([1, 0, 2]);
426 assert_eq!([sequence, batch, state_rank], b.dims());
427 let b = b.unsqueeze_dim(2);
428 assert_eq!([sequence, batch, 1, state_rank], b.dims());
429 let b = b.expand(outer_shape);
430 assert_eq!(outer_shape, b.dims());
431 let delta_b = delta * b;
432 assert_eq!(outer_shape, delta_b.dims());
433
434 let u = u.clone().permute([1, 0, 2]);
435 assert_eq!([sequence, batch, d_inner], u.dims());
436 let u = u.unsqueeze_dim(3);
437 assert_eq!([sequence, batch, d_inner, 1], u.dims());
438 let u = u.expand(outer_shape);
439 assert_eq!(outer_shape, u.dims());
440 let delta_bu = delta_b * u;
441 assert_eq!(outer_shape, delta_bu.dims());
442
443 (delta_a, delta_bu)
444 };
445 assert_eq!(outer_shape, delta_a.dims());
446 assert_eq!(outer_shape, delta_bu.dims());
447
448 let delta_a = delta_a.split(1, 0);
455 assert_eq!(delta_a.len(), sequence);
456
457 let delta_bu = delta_bu.split(1, 0);
458 assert_eq!(delta_bu.len(), sequence);
459
460 let c = c.unsqueeze_dim(3);
461 assert_eq!([sequence, batch, state_rank, 1], c.dims());
462 let c = c.split(1, 0);
463 assert_eq!(c.len(), sequence);
464
465 let inner_shape = [batch, d_inner, state_rank];
466 assert_eq!(inner_shape, init_ssm.dims());
467 let mut xs: Tensor<3> = init_ssm;
468 let mut ys = Vec::with_capacity(sequence); for ((delta_a, delta_bu), c) in delta_a
470 .into_iter()
471 .zip(delta_bu.into_iter())
472 .zip(c.into_iter())
473 {
474 let delta_a = delta_a.squeeze_dim(0);
475 assert_eq!(inner_shape, delta_a.dims());
476 let delta_bu = delta_bu.squeeze_dim(0);
477 assert_eq!(inner_shape, delta_bu.dims());
478 let c = c.squeeze_dim(0);
479 assert_eq!([batch, state_rank, 1], c.dims());
480
481 xs = (xs.clone() * delta_a) + delta_bu;
482 let y = xs.clone().matmul(c);
483 assert_eq!([batch, d_inner, 1], y.dims());
484 let y = y.squeeze_dim(2);
485 assert_eq!([batch, d_inner], y.dims());
486 ys.push(y);
487 }
488
489 let ys = Tensor::stack(ys, 1);
490 assert_eq!([batch, sequence, d_inner], ys.dims());
491
492 let d = d.unsqueeze_dims(&[0, 1]);
493 assert_eq!([1, 1, d_inner], d.dims());
494 let d = d.expand([batch, sequence, d_inner]);
495
496 let ys = ys + (d * u);
497 assert_eq!([batch, sequence, d_inner], ys.dims());
498
499 (ys, xs)
500 }
501}
502
503mod step {
504 use super::*;
505
506 impl Mamba1 {
507 pub fn step(&self, x: Tensor<2>, cache: Option<Mamba1Cache>) -> (Tensor<2>, Mamba1Cache) {
511 let [batch, d_model] = x.dims();
512 let [d_inner] = self.d.dims();
513 let [_, _, conv_kernel] = self.conv1d.weight.dims();
514 let [_d_inner, state_rank] = self.a_log.dims();
515 let device = x.device();
516
517 let mut cache = cache.unwrap_or_else(|| Mamba1Cache {
521 conv_bik: Tensor::zeros([batch, d_inner, conv_kernel], &device),
522 ssm_bir: Tensor::zeros([batch, d_inner, state_rank], &device),
523 });
524 cache.sanity();
525
526 let [xs_bi, res_bi] = {
528 let xs_and_res = self.in_proj.forward(x);
529 assert_eq!([batch, 2 * d_inner], xs_and_res.dims());
530 split_into(xs_and_res, [d_inner, d_inner], 1)
531 };
532 assert_eq!([batch, d_inner], xs_bi.dims());
533 assert_eq!([batch, d_inner], res_bi.dims());
534
535 cache.conv_bik = {
538 let t0 = cache.conv_bik.clone().narrow(2, 1, conv_kernel - 1);
539 assert_eq!([batch, d_inner, conv_kernel - 1], t0.dims());
540
541 let conv = Tensor::cat(vec![t0, xs_bi.unsqueeze_dim(2)], 2);
542 assert_eq!([batch, d_inner, conv_kernel], conv.dims());
543
544 conv
545 };
546 let xs_bi = {
547 let conv1d = self.conv1d.weight.val();
548 assert_eq!([d_inner, 1, conv_kernel], conv1d.dims());
550 let conv1d = conv1d.permute([1, 0, 2]);
551 assert_eq!([1, d_inner, conv_kernel], conv1d.dims());
552 let conv1d = conv1d.expand([batch, d_inner, conv_kernel]);
553 assert_eq!([batch, d_inner, conv_kernel], conv1d.dims());
554
555 let xs = cache.conv_bik.clone() * conv1d;
556 let xs = xs.sum_dim(2);
557 assert_eq!([batch, d_inner, 1], xs.dims());
558 let xs = xs.squeeze_dim(2);
559 assert_eq!([batch, d_inner], xs.dims());
560
561 let conv1d_bias = self.conv1d.bias.as_ref().unwrap().val();
563 assert_eq!([d_inner], conv1d_bias.dims());
565 let conv1d_bias = conv1d_bias.unsqueeze();
566 assert_eq!([1, d_inner], conv1d_bias.dims());
567 let xs = xs + conv1d_bias;
568
569 let xs = Silu::new().forward(xs);
571 assert_eq!([batch, d_inner], xs.dims());
572
573 xs
574 };
575 assert_eq!([batch, d_inner], xs_bi.dims());
576
577 let (scan_bi, cache) = self.ssm_step(xs_bi, cache);
578 assert_eq!([batch, d_inner], scan_bi.dims());
579
580 let ys = scan_bi * Silu::new().forward(res_bi);
582 assert_eq!([batch, d_inner], ys.dims());
583
584 let y = self.out_proj.forward(ys);
585 assert_eq!([batch, d_model], y.dims());
586
587 (y, cache)
588 }
589
590 pub fn ssm_step(&self, u: Tensor<2>, cache: Mamba1Cache) -> (Tensor<2>, Mamba1Cache) {
598 let [batch, d_inner, state_rank] = cache.ssm_bir.dims();
599 let [dt_rank, _d_inner] = self.dt_proj.weight.dims();
600
601 let a = self.a_log.val().exp().neg();
606 assert_eq!([d_inner, state_rank], a.dims());
607
608 let x_dbl = self.x_proj.forward(u.clone());
609 assert_eq!([batch, dt_rank + 2 * state_rank], x_dbl.dims());
610
611 let [delta, b, c] = split_into(x_dbl, [dt_rank, state_rank, state_rank], 1);
615 assert_eq!([batch, dt_rank], delta.dims()); assert_eq!([batch, state_rank], b.dims());
617 assert_eq!([batch, state_rank], c.dims());
618
619 let delta = self.dt_proj.forward(delta);
622 assert_eq!([batch, d_inner], delta.dims());
623 let delta = burn::tensor::activation::softplus(delta, 1.);
624
625 Self::selective_scan_step(delta, a, b, c, self.d.val(), u, cache)
626 }
627
628 pub fn selective_scan_step(
644 delta: Tensor<2>,
645 a: Tensor<2>,
646 b: Tensor<2>,
647 c: Tensor<2>,
648 d: Tensor<1>,
649 u: Tensor<2>,
650 mut cache: Mamba1Cache,
651 ) -> (Tensor<2>, Mamba1Cache) {
652 let [batch, d_inner, state_rank] = cache.ssm_bir.dims();
653 let outer_shape = [batch, d_inner, state_rank];
654
655 let (delta_a, delta_bu) = {
660 let delta = delta.unsqueeze_dim(2);
661 assert_eq!([batch, d_inner, 1], delta.dims());
662 let delta = delta.expand(outer_shape);
663 assert_eq!(outer_shape, delta.dims());
664
665 let a = a.unsqueeze();
666 assert_eq!([1, d_inner, state_rank], a.dims());
667 let a = a.expand(outer_shape);
668 assert_eq!(outer_shape, a.dims());
669 let delta_a = (delta.clone() * a).exp();
670 assert_eq!(outer_shape, delta_a.dims());
671
672 let b = b.unsqueeze_dim(1);
673 assert_eq!([batch, 1, state_rank], b.dims());
674 let b = b.expand(outer_shape);
675 assert_eq!(outer_shape, b.dims());
676 let delta_b = delta * b;
677 assert_eq!(outer_shape, delta_b.dims());
678
679 let u = u.clone().unsqueeze_dim(2);
680 assert_eq!([batch, d_inner, 1], u.dims());
681 let u = u.expand(outer_shape);
682 assert_eq!(outer_shape, u.dims());
683 let delta_bu = delta_b * u;
684 assert_eq!(outer_shape, delta_bu.dims());
685
686 (delta_a, delta_bu)
687 };
688 assert_eq!(outer_shape, delta_a.dims());
689 assert_eq!(outer_shape, delta_bu.dims());
690
691 cache.ssm_bir = (cache.ssm_bir.clone() * delta_a) + delta_bu;
692
693 let c = c.unsqueeze_dim(2);
694 assert_eq!([batch, state_rank, 1], c.dims());
695
696 let y = cache.ssm_bir.clone().matmul(c);
697 assert_eq!([batch, d_inner, 1], y.dims());
698 let y = y.squeeze_dim(2);
699 assert_eq!([batch, d_inner], y.dims());
700
701 let d = d.unsqueeze();
702 assert_eq!([1, d_inner], d.dims());
703 let d = d.expand([batch, d_inner]);
704 assert_eq!([batch, d_inner], d.dims());
705
706 let y = y + (d * u);
707 assert_eq!([batch, d_inner], y.dims());
708
709 (y, cache)
710 }
711 }
712}
713
714#[cfg(all(test, feature = "_dev-test"))]
719mod tests;