#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ScanMode {
Sequential,
Parallel,
#[default]
Auto,
}
impl ScanMode {
pub const PARALLEL_SCAN_THRESHOLD: usize = 256;
pub fn use_parallel(self, seq_len: usize, d_state: usize) -> bool {
if d_state > 64 {
return true;
}
match self {
Self::Sequential => false,
Self::Parallel => true,
Self::Auto => seq_len > Self::PARALLEL_SCAN_THRESHOLD,
}
}
pub fn resolve(self, seq_len: usize) -> Self {
match self {
Self::Auto => {
if seq_len <= Self::PARALLEL_SCAN_THRESHOLD {
Self::Sequential
} else {
Self::Parallel
}
}
other => other,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct MambaConfig {
pub d_model: usize,
pub d_state: usize,
pub d_conv: usize,
pub expand: usize,
pub n_layers: usize,
pub scan_mode: ScanMode,
pub rms_norm_eps: f32,
}
impl MambaConfig {
pub fn d_inner(&self) -> usize {
self.expand * self.d_model
}
pub fn dt_rank(&self) -> usize {
self.d_model.div_ceil(16)
}
pub fn xdbl_dim(&self) -> usize {
self.dt_rank() + 2 * self.d_state
}
}
impl MambaConfig {
pub fn validate(&self) -> Result<(), String> {
if self.d_model == 0 {
return Err("d_model must be > 0".into());
}
if self.d_state == 0 {
return Err("d_state must be > 0".into());
}
if self.d_conv == 0 {
return Err("d_conv must be > 0".into());
}
if self.expand == 0 {
return Err("expand must be > 0".into());
}
if self.n_layers == 0 {
return Err("n_layers must be > 0".into());
}
if self.d_model > (1 << 20) {
return Err(format!("d_model ({}) must be <= 2^20", self.d_model));
}
if self.n_layers > 4096 {
return Err(format!("n_layers ({}) must be <= 4096", self.n_layers));
}
let d_inner = self
.expand
.checked_mul(self.d_model)
.ok_or("expand * d_model overflows usize")?;
if d_inner > 65535 {
return Err(format!(
"d_inner ({d_inner}) must be <= 65535 (CUDA grid.y limit for the parallel scan)"
));
}
if self.d_state > 256 {
return Err(format!(
"d_state ({}) must be <= 256 (CUDA parallel scan MAX_DSTATE limit)",
self.d_state
));
}
if self.d_conv > 8 {
return Err(format!(
"d_conv ({}) must be <= 8 (CUDA kernel limit)",
self.d_conv
));
}
if !self.d_inner().is_multiple_of(4) {
return Err(format!(
"d_inner ({}) must be divisible by 4 (d_model={} * expand={})",
self.d_inner(),
self.d_model,
self.expand
));
}
Ok(())
}
}
impl Default for MambaConfig {
fn default() -> Self {
Self {
d_model: 128,
d_state: 16,
d_conv: 4,
expand: 2,
n_layers: 3,
scan_mode: ScanMode::Auto,
rms_norm_eps: crate::ops::fast_math::RMS_NORM_EPS,
}
}
}