1use burn::prelude::*;
5use burn_stack::modules::{Block, BlockConfig, CacheStack};
6
7
8#[derive(Debug, Clone)]
15pub enum MambaCaches {
16 #[cfg(feature = "mamba1")]
18 Mamba1(crate::mamba1::prelude::Mamba1Caches),
19 #[cfg(feature = "mamba2")]
21 Mamba2(crate::mamba2::prelude::Mamba2Caches),
22 #[cfg(feature = "mamba3")]
24 Mamba3(crate::mamba3::prelude::Mamba3Caches),
25}
26
27#[cfg(feature = "mamba2")]
32mod impl_mamba2 {
33 use super::*;
34 use crate::mamba2::prelude::{
35 Mamba2, Mamba2Cache, Mamba2CacheConfig, Mamba2Caches, Mamba2CachesConfig, Mamba2Config,
36 Mamba2SsdPath,
37 };
38
39 impl CacheStack for Mamba2Caches {
40 type Cache = Mamba2Cache;
41 fn slot_count(&self) -> usize {
42 self.caches.len()
43 }
44 fn into_slots(self) -> Vec<Option<Mamba2Cache>> {
45 self.caches.into_iter().map(Some).collect()
46 }
47 fn from_slots(slots: Vec<Option<Mamba2Cache>>) -> Self {
48 Self {
49 caches: slots.into_iter().map(Option::unwrap).collect(),
50 }
51 }
52 fn cache_to_inner(c: Mamba2Cache) -> Mamba2Cache {
53 Mamba2Cache {
54 conv_bvk: c.conv_bvk.inner(),
55 ssm_bhpr: c.ssm_bhpr.inner(),
56 }
57 }
58 fn cache_from_inner(c: Mamba2Cache) -> Mamba2Cache {
59 Mamba2Cache {
60 conv_bvk: Tensor::from_inner(c.conv_bvk),
61 ssm_bhpr: Tensor::from_inner(c.ssm_bhpr),
62 }
63 }
64 }
65
66 impl Block for Mamba2 {
67 type Cache = Mamba2Cache;
68 type Caches = Mamba2Caches;
69 type Options = Mamba2SsdPath;
70
71 fn block_forward(
72 &self,
73 x: Tensor<3>,
74 cache: Option<Mamba2Cache>,
75 options: Mamba2SsdPath,
76 ) -> (Tensor<3>, Mamba2Cache) {
77 self.forward(x, cache, options)
78 }
79 fn block_step(&self, x: Tensor<2>, cache: Option<Mamba2Cache>) -> (Tensor<2>, Mamba2Cache) {
80 self.step(x, cache)
81 }
82 fn zero_caches_3d(&self, x: &Tensor<3>, n_virtual: usize) -> Mamba2Caches {
83 let [batch, _seq, _d] = x.dims();
84 self.make_zero(batch, n_virtual, &x.device())
85 }
86 fn zero_caches_2d(&self, x: &Tensor<2>, n_virtual: usize) -> Mamba2Caches {
87 let [batch, _d] = x.dims();
88 self.make_zero(batch, n_virtual, &x.device())
89 }
90 }
91
92 impl Mamba2 {
93 fn make_zero(&self, batch: usize, n_virtual: usize, device: &Device) -> Mamba2Caches {
94 let [conv_dim, _, conv_kernel] = self.conv1d.weight.dims();
95 Mamba2CachesConfig::new(
96 n_virtual,
97 Mamba2CacheConfig {
98 batch,
99 state_rank: self.state_rank,
100 conv_kernel,
101 conv_dim,
102 per_head_dim: self.per_head_dim(),
103 nheads: self.nheads(),
104 },
105 )
106 .init(device)
107 }
108 }
109
110 impl BlockConfig for Mamba2Config {
111 type Block = Mamba2;
112 fn d_model(&self) -> usize {
113 self.d_model
114 }
115 fn init_block(&self, device: &Device) -> Mamba2 {
116 self.init(device)
117 }
118 #[cfg(feature = "optim")]
119 fn muon_projections(&self) -> Vec<burn_stack::optim::ProjSpec> {
120 self.muon_projections()
121 }
122 }
123}
124
125#[cfg(feature = "mamba3")]
126mod impl_mamba3 {
127 use super::*;
128 use crate::mamba3::double_ssd::prelude::Mamba3DoubleSsdCache;
129 use crate::mamba3::prelude::{Mamba3, Mamba3Cache, Mamba3Caches, Mamba3Config, Mamba3SsdPath};
130 use crate::mamba3::single_ssd::prelude::{
131 Mamba3SingleSsdCache, Mamba3SingleSsdCacheConfig, Mamba3SingleSsdCaches,
132 Mamba3SingleSsdCachesConfig,
133 };
134
135 fn zero_single_ssd_caches(
139 mamba_block: &Mamba3,
140 batch: usize,
141 n_virtual: usize,
142 device: &Device,
143 ) -> Mamba3SingleSsdCaches {
144 Mamba3SingleSsdCachesConfig::new(
145 n_virtual,
146 Mamba3SingleSsdCacheConfig {
147 batch,
148 state_rank: mamba_block.state_rank,
149 num_rope_angles: mamba_block.num_rope_angles,
150 per_head_dim: mamba_block.per_head_dim(),
151 nheads: mamba_block.nheads(),
152 mimo_rank: mamba_block.mimo_rank,
153 rotation: mamba_block.rotation,
154 num_quat_blocks: mamba_block.num_quat_blocks,
155 },
156 )
157 .init(device)
158 }
159
160 impl CacheStack for Mamba3Caches {
161 type Cache = Mamba3Cache;
162 fn slot_count(&self) -> usize {
163 self.caches_len()
164 }
165 fn into_slots(self) -> Vec<Option<Mamba3Cache>> {
166 self.into_options()
167 }
168 fn from_slots(slots: Vec<Option<Mamba3Cache>>) -> Self {
169 Self::from_options(slots)
170 }
171 fn cache_to_inner(c: Mamba3Cache) -> Mamba3Cache {
172 use crate::mamba3::prelude::RotationState;
173 fn rot(r: RotationState) -> RotationState {
174 match r {
175 RotationState::Real(u) => RotationState::Real(u),
176 RotationState::Angle(t) => RotationState::Angle(t.inner()),
177 RotationState::Quaternion(t) => RotationState::Quaternion(t.inner()),
178 RotationState::Rotor(t) => RotationState::Rotor(t.inner()),
179 }
180 }
181 match c {
182 Mamba3Cache::DoubleSsd(c) => Mamba3Cache::DoubleSsd(Mamba3DoubleSsdCache {
183 ssm_bhpr: c.ssm_bhpr.inner(),
184 k_state_bmhr: c.k_state_bmhr.inner(),
185 v_state_bhp: c.v_state_bhp.inner(),
186 rotation: rot(c.rotation),
187 }),
188 Mamba3Cache::SingleSsd(c) => Mamba3Cache::SingleSsd(Mamba3SingleSsdCache {
189 ssm_bhpr: c.ssm_bhpr.inner(),
190 k_state_bmhr: c.k_state_bmhr.inner(),
191 v_state_bhp: c.v_state_bhp.inner(),
192 rotation: rot(c.rotation),
193 }),
194 }
195 }
196 fn cache_from_inner(c: Mamba3Cache) -> Mamba3Cache {
197 use crate::mamba3::prelude::RotationState;
198 fn rot(r: RotationState) -> RotationState {
199 match r {
200 RotationState::Real(u) => RotationState::Real(u),
201 RotationState::Angle(t) => RotationState::Angle(Tensor::from_inner(t)),
202 RotationState::Quaternion(t) => {
203 RotationState::Quaternion(Tensor::from_inner(t))
204 }
205 RotationState::Rotor(t) => RotationState::Rotor(Tensor::from_inner(t)),
206 }
207 }
208 match c {
209 Mamba3Cache::DoubleSsd(c) => Mamba3Cache::DoubleSsd(Mamba3DoubleSsdCache {
210 ssm_bhpr: Tensor::from_inner(c.ssm_bhpr),
211 k_state_bmhr: Tensor::from_inner(c.k_state_bmhr),
212 v_state_bhp: Tensor::from_inner(c.v_state_bhp),
213 rotation: rot(c.rotation),
214 }),
215 Mamba3Cache::SingleSsd(c) => Mamba3Cache::SingleSsd(Mamba3SingleSsdCache {
216 ssm_bhpr: Tensor::from_inner(c.ssm_bhpr),
217 k_state_bmhr: Tensor::from_inner(c.k_state_bmhr),
218 v_state_bhp: Tensor::from_inner(c.v_state_bhp),
219 rotation: rot(c.rotation),
220 }),
221 }
222 }
223 }
224
225 impl Block for Mamba3 {
226 type Cache = Mamba3Cache;
227 type Caches = Mamba3Caches;
228 type Options = Mamba3SsdPath;
229
230 fn block_forward(
231 &self,
232 x: Tensor<3>,
233 cache: Option<Mamba3Cache>,
234 options: Mamba3SsdPath,
235 ) -> (Tensor<3>, Mamba3Cache) {
236 self.forward(x, cache, options)
237 }
238 fn block_step(&self, x: Tensor<2>, cache: Option<Mamba3Cache>) -> (Tensor<2>, Mamba3Cache) {
239 self.step(x, cache)
240 }
241 fn block_step_infinite(&self, x: Tensor<2>) -> Tensor<2> {
242 self.step_infinite(x)
243 }
244 fn zero_caches_3d(&self, x: &Tensor<3>, n_virtual: usize) -> Mamba3Caches {
245 let [batch, _seq, _d] = x.dims();
246 zero_single_ssd_caches(self, batch, n_virtual, &x.device()).into()
247 }
248 fn zero_caches_2d(&self, x: &Tensor<2>, n_virtual: usize) -> Mamba3Caches {
249 let [batch, _d] = x.dims();
250 zero_single_ssd_caches(self, batch, n_virtual, &x.device()).into()
251 }
252 }
253
254 impl BlockConfig for Mamba3Config {
255 type Block = Mamba3;
256 fn d_model(&self) -> usize {
257 self.d_model
258 }
259 fn init_block(&self, device: &Device) -> Mamba3 {
260 self.init(device)
261 }
262 #[cfg(feature = "optim")]
263 fn muon_projections(&self) -> Vec<burn_stack::optim::ProjSpec> {
264 self.muon_projections()
265 }
266 }
267}
268
269#[cfg(feature = "mamba1")]
270mod impl_mamba1 {
271 use super::*;
272 use crate::mamba1::prelude::{
273 Mamba1, Mamba1Cache, Mamba1CacheConfig, Mamba1Caches, Mamba1CachesConfig, Mamba1Config,
274 };
275
276 impl CacheStack for Mamba1Caches {
277 type Cache = Mamba1Cache;
278 fn slot_count(&self) -> usize {
279 self.caches.len()
280 }
281 fn into_slots(self) -> Vec<Option<Mamba1Cache>> {
282 self.caches.into_iter().map(Some).collect()
283 }
284 fn from_slots(slots: Vec<Option<Mamba1Cache>>) -> Self {
285 Self {
286 caches: slots.into_iter().map(Option::unwrap).collect(),
287 }
288 }
289 fn cache_to_inner(c: Mamba1Cache) -> Mamba1Cache {
290 Mamba1Cache {
291 conv_bik: c.conv_bik.inner(),
292 ssm_bir: c.ssm_bir.inner(),
293 }
294 }
295 fn cache_from_inner(c: Mamba1Cache) -> Mamba1Cache {
296 Mamba1Cache {
297 conv_bik: Tensor::from_inner(c.conv_bik),
298 ssm_bir: Tensor::from_inner(c.ssm_bir),
299 }
300 }
301 }
302
303 impl Block for Mamba1 {
304 type Cache = Mamba1Cache;
305 type Caches = Mamba1Caches;
306 type Options = ();
308
309 fn block_forward(
310 &self,
311 x: Tensor<3>,
312 cache: Option<Mamba1Cache>,
313 _options: (),
314 ) -> (Tensor<3>, Mamba1Cache) {
315 self.forward(x, cache)
316 }
317 fn block_step(&self, x: Tensor<2>, cache: Option<Mamba1Cache>) -> (Tensor<2>, Mamba1Cache) {
318 self.step(x, cache)
319 }
320 fn zero_caches_3d(&self, x: &Tensor<3>, n_virtual: usize) -> Mamba1Caches {
321 let [batch, _seq, _d] = x.dims();
322 self.make_zero(batch, n_virtual, &x.device())
323 }
324 fn zero_caches_2d(&self, x: &Tensor<2>, n_virtual: usize) -> Mamba1Caches {
325 let [batch, _d] = x.dims();
326 self.make_zero(batch, n_virtual, &x.device())
327 }
328 }
329
330 impl Mamba1 {
331 fn cache_config(&self, batch: usize) -> Mamba1CacheConfig {
332 let [d_inner, state_rank] = self.a_log.dims();
333 let [_, _, conv_kernel] = self.conv1d.weight.dims();
334 Mamba1CacheConfig::new(batch, d_inner)
335 .with_state_rank(state_rank)
336 .with_conv_kernel(conv_kernel)
337 }
338 fn make_zero(&self, batch: usize, n_virtual: usize, device: &Device) -> Mamba1Caches {
339 Mamba1CachesConfig::new(n_virtual, self.cache_config(batch)).init(device)
340 }
341 }
342
343 impl BlockConfig for Mamba1Config {
344 type Block = Mamba1;
345 fn d_model(&self) -> usize {
346 self.d_model
347 }
348 fn init_block(&self, device: &Device) -> Mamba1 {
349 self.init(device)
350 }
351 #[cfg(feature = "optim")]
352 fn muon_projections(&self) -> Vec<burn_stack::optim::ProjSpec> {
353 self.muon_projections()
354 }
355 }
356}