pub struct NemotronMamba2Layer { /* private fields */ }Implementations§
Source§impl NemotronMamba2Layer
impl NemotronMamba2Layer
pub fn new( input_norm: DenseWeight, ssm: NemotronSsmWeights, config: &ModelConfig, gpu: &dyn GpuBackend, layer_idx: usize, ) -> Result<Self>
Sourcepub fn set_fp8_weights(
&mut self,
in_proj: Option<Fp8Weight>,
out_proj: Option<Fp8Weight>,
prefill: bool,
) -> Result<()>
pub fn set_fp8_weights( &mut self, in_proj: Option<Fp8Weight>, out_proj: Option<Fp8Weight>, prefill: bool, ) -> Result<()>
Set native FP8 weights to skip double-quantization (FP8→BF16→NVFP4).
When set, decode uses w8a16_gemv and prefill uses w8a16_gemm /
w8a16_gemm_pipelined instead of the NVFP4/W4A4 arms.
Inputs MUST be tagged WeightQuantFormat::Fp8BlockScaled: every w8a16
kernel indexes block_scale[n/128 * k_blocks + k/128], so a per-row [N]
scale — or the checkpoint’s raw 4-byte scalar weight_scale — reads far
past the end of its allocation (illegal address, not wrong numbers). The
kernel-handle checks are the same contract: once the FP8 weights are
installed the NVFP4 fallbacks are NULL, so a missing kernel must fail
here at load, not deref NULL on the first token.
prefill selects whether the prefill GEMMs may use these weights. When
false (ATLAS_NEMOTRON_NATIVE_FP8_SSM=decode) only w8a16_gemv reads
them and prefill stays on the legacy NVFP4 / pre-dequantized copies,
which the loader still builds in that mode.
Sourcepub fn ssm_weights(&self) -> &NemotronSsmWeights
pub fn ssm_weights(&self) -> &NemotronSsmWeights
Access SSM weights (needed by weight loader for transpose).
Sourcepub fn set_prefill_weights(
&mut self,
in_proj_t: Option<QuantizedWeight>,
out_proj_t: Option<QuantizedWeight>,
)
pub fn set_prefill_weights( &mut self, in_proj_t: Option<QuantizedWeight>, out_proj_t: Option<QuantizedWeight>, )
Set transposed NVFP4 weights for fast prefill GEMM (FP8 MMA, N128, cp.async). Switches prefill from w4a16_gemm (M64,N64,K16 BF16) to w4a16_gemm_t (M64,N128,K32 FP8 MMA) — est. 3-4x TTFT improvement for SSM layers.
Sourcepub fn set_bf16_weights(&mut self, in_proj: DenseWeight, out_proj: DenseWeight)
pub fn set_bf16_weights(&mut self, in_proj: DenseWeight, out_proj: DenseWeight)
Set pre-dequantized FP8 E4M3 copies of in_proj/out_proj for prefill.
w4a16_gemm_t_m128 dequantizes its NVFP4 B tile from FP4 to FP8 in
shared memory on every K step, and that work is redone by every M-block:
the cost is NK(M/M_TILE), so a 1k-token prefill pays for it 8x over.
Measured on Puzzle: ablating just that dequant ALU cut a 1k prefill from
557 ms to 424 ms. Converting the weights once at load time removes it
entirely and lets prefill use fp8_gemm_t, which has no dequant phase.
Install the checkpoint’s own BF16 projections, bypassing the NVFP4
requant entirely. Only valid when BOTH projections are BF16 in the
checkpoint and the dense kernels resolved; the caller checks that.
Sourcepub fn bf16_native_ready(&self) -> bool
pub fn bf16_native_ready(&self) -> bool
Whether this layer can run natively BF16 (weights installed AND both dense kernels present).
pub fn set_fp8_prefill_weights( &mut self, in_proj: DevicePtr, out_proj: DevicePtr, )
Trait Implementations§
Source§impl TransformerLayer for NemotronMamba2Layer
impl TransformerLayer for NemotronMamba2Layer
Source§fn decode(
&self,
hidden: DevicePtr,
residual: DevicePtr,
state: &mut dyn LayerState,
_kv_cache: &mut PagedKvCache,
_seq_len: usize,
_block_table: &mut Vec<u32>,
_disk_block_ids: &mut Vec<u32>,
_disk_last_offloaded_per_layer: &mut Vec<u32>,
ctx: &ForwardContext<'_>,
stream: u64,
) -> Result<()>
fn decode( &self, hidden: DevicePtr, residual: DevicePtr, state: &mut dyn LayerState, _kv_cache: &mut PagedKvCache, _seq_len: usize, _block_table: &mut Vec<u32>, _disk_block_ids: &mut Vec<u32>, _disk_last_offloaded_per_layer: &mut Vec<u32>, ctx: &ForwardContext<'_>, stream: u64, ) -> Result<()>
hidden in-place. Read morefn prefill( &self, hidden: DevicePtr, residual: DevicePtr, num_tokens: usize, state: &mut dyn LayerState, _kv_cache: &mut PagedKvCache, _seq_len_start: usize, _block_table: &mut Vec<u32>, _disk_block_ids: &mut Vec<u32>, _disk_last_offloaded_per_layer: &mut Vec<u32>, _kv_write_start: usize, ctx: &ForwardContext<'_>, stream: u64, ) -> Result<()>
Source§fn alloc_state(&self, gpu: &dyn GpuBackend) -> Result<Box<dyn LayerState>>
fn alloc_state(&self, gpu: &dyn GpuBackend) -> Result<Box<dyn LayerState>>
Source§fn uses_local_mla_prefill(&self) -> bool
fn uses_local_mla_prefill(&self) -> bool
Source§fn as_any_mut(&mut self) -> Option<&mut dyn Any>
fn as_any_mut(&mut self) -> Option<&mut dyn Any>
&mut dyn Any downcast hook for post-construction weight overlays (e.g.
the LoRA install walk). Default None; overlay-capable layers override.Source§fn fp8_calibration_frozen(&self) -> Option<bool>
fn fp8_calibration_frozen(&self) -> Option<bool>
None = this layer runs no online calibration (non-attention layer,
static checkpoint scales, or a non-FP8 KV dtype). The scheduler’s
graph-suppression gate keys off this rather than a token count: the
scale freezes on the FIRST observe, so waiting calibration_tokens
tokens would run ~256+ eager steps for a calibration that finished
immediately.Source§fn decode_prestage(
&self,
_token: u32,
_state: &mut dyn LayerState,
_gpu: &dyn GpuBackend,
_stream: u64,
) -> Result<()>
fn decode_prestage( &self, _token: u32, _state: &mut dyn LayerState, _gpu: &dyn GpuBackend, _stream: u64, ) -> Result<()>
token_ids upload —
so the captured graph contains only kernels over stable device
buffers. Layers with no host-side decode work keep the no-op default.Source§fn decode_prestage_rearm(&self, _state: &mut dyn LayerState)
fn decode_prestage_rearm(&self, _state: &mut dyn LayerState)
decode_prestage).Source§fn decode_graph_unsupported(&self) -> bool
fn decode_graph_unsupported(&self) -> bool
Source§fn decode_multi_seq_unsupported(&self) -> bool
fn decode_multi_seq_unsupported(&self) -> bool
decode_multi_seq’s shared-ForwardContext loop would alias
per-sequence state across rows rather than merely run slowly. Read moreSource§fn decode_verify_multi_unsupported(&self) -> bool
fn decode_verify_multi_unsupported(&self) -> bool
decode_verify_multi). Consumed by
can_batch_verify_dispatch; a true layer falls back to the
per-sequence verify loop, which is the sealed single-sequence path. Read moreSource§fn snapshot_aux(
&self,
_state: &dyn LayerState,
_gpu: &dyn GpuBackend,
_stream: u64,
) -> Result<Option<Vec<u8>>>
fn snapshot_aux( &self, _state: &dyn LayerState, _gpu: &dyn GpuBackend, _stream: u64, ) -> Result<Option<Vec<u8>>>
copy_d2h_on_stream).
Default: the layer carries no aux sequence state.Source§fn has_aux_state(&self) -> bool
fn has_aux_state(&self) -> bool
Source§fn restore_aux(
&self,
_state: &mut dyn LayerState,
_blob: &[u8],
_gpu: &dyn GpuBackend,
_stream: u64,
) -> Result<()>
fn restore_aux( &self, _state: &mut dyn LayerState, _blob: &[u8], _gpu: &dyn GpuBackend, _stream: u64, ) -> Result<()>
Self::snapshot_aux on a
prefix-cache hit, BEFORE the resumed prefill runs.Source§fn graph_stale_on_new_sequence(&self) -> bool
fn graph_stale_on_new_sequence(&self) -> bool
Source§fn sync_replayed_step(
&self,
_state: &mut dyn LayerState,
_seq_len: usize,
_k: usize,
) -> Result<()>
fn sync_replayed_step( &self, _state: &mut dyn LayerState, _seq_len: usize, _k: usize, ) -> Result<()>
seq_len is the
sequence length BEFORE this step’s k rows. Read moreSource§fn check_replay_room(
&self,
_state: &dyn LayerState,
_seq_len: usize,
_k: usize,
) -> Result<()>
fn check_replay_room( &self, _state: &dyn LayerState, _seq_len: usize, _k: usize, ) -> Result<()>
Source§fn prefill_phase1(
&self,
hidden: DevicePtr,
residual: DevicePtr,
num_tokens: usize,
state: &mut dyn LayerState,
kv_cache: &mut PagedKvCache,
seq_len_start: usize,
block_table: &mut Vec<u32>,
disk_block_ids: &mut Vec<u32>,
disk_last_offloaded_per_layer: &mut Vec<u32>,
kv_write_start: usize,
gdn_bufs: &GdnPrefillBuffers,
token_offset: usize,
ctx: &ForwardContext<'_>,
stream: u64,
) -> Result<()>
fn prefill_phase1( &self, hidden: DevicePtr, residual: DevicePtr, num_tokens: usize, state: &mut dyn LayerState, kv_cache: &mut PagedKvCache, seq_len_start: usize, block_table: &mut Vec<u32>, disk_block_ids: &mut Vec<u32>, disk_last_offloaded_per_layer: &mut Vec<u32>, kv_write_start: usize, gdn_bufs: &GdnPrefillBuffers, token_offset: usize, ctx: &ForwardContext<'_>, stream: u64, ) -> Result<()>
Source§fn prefill_phase1_proj_batched(
&self,
hidden_stacked: DevicePtr,
residual_stacked: DevicePtr,
total_tokens: usize,
gdn_bufs: &GdnPrefillBuffers,
ctx: &ForwardContext<'_>,
stream: u64,
) -> Result<()>
fn prefill_phase1_proj_batched( &self, hidden_stacked: DevicePtr, residual_stacked: DevicePtr, total_tokens: usize, gdn_bufs: &GdnPrefillBuffers, ctx: &ForwardContext<'_>, stream: u64, ) -> Result<()>
prefill_phase1_conv1d_one per request then prefill_phase1_l2_batched.Source§fn prefill_phase1_conv1d_one(
&self,
state: &mut dyn LayerState,
token_offset: usize,
len: usize,
gdn_bufs: &GdnPrefillBuffers,
ctx: &ForwardContext<'_>,
stream: u64,
) -> Result<()>
fn prefill_phase1_conv1d_one( &self, state: &mut dyn LayerState, token_offset: usize, len: usize, gdn_bufs: &GdnPrefillBuffers, ctx: &ForwardContext<'_>, stream: u64, ) -> Result<()>
Source§fn prefill_phase1_l2_batched(
&self,
total_tokens: usize,
gdn_bufs: &GdnPrefillBuffers,
ctx: &ForwardContext<'_>,
stream: u64,
) -> Result<()>
fn prefill_phase1_l2_batched( &self, total_tokens: usize, gdn_bufs: &GdnPrefillBuffers, ctx: &ForwardContext<'_>, stream: u64, ) -> Result<()>
Source§fn prefill_gdn_full(
&self,
_state: &mut dyn LayerState,
_gdn_bufs: &GdnPrefillBuffers,
_ctx: &ForwardContext<'_>,
_stream: u64,
) -> Result<()>
fn prefill_gdn_full( &self, _state: &mut dyn LayerState, _gdn_bufs: &GdnPrefillBuffers, _ctx: &ForwardContext<'_>, _stream: u64, ) -> Result<()>
Source§fn prefill_inner_batched_q12(
&self,
_hidden_stacked: DevicePtr,
_residual_stacked: DevicePtr,
_num_tokens: usize,
_kv_cache: &mut PagedKvCache,
_seq_len_start: usize,
_batched_meta: &BatchedAttnMetadata,
_ctx: &ForwardContext<'_>,
_stream: u64,
) -> Result<()>
fn prefill_inner_batched_q12( &self, _hidden_stacked: DevicePtr, _residual_stacked: DevicePtr, _num_tokens: usize, _kv_cache: &mut PagedKvCache, _seq_len_start: usize, _batched_meta: &BatchedAttnMetadata, _ctx: &ForwardContext<'_>, _stream: u64, ) -> Result<()>
Source§fn prefill_gdn_full_batched(
&self,
_h_state_ptrs: DevicePtr,
_gdn_bufs: &GdnPrefillBuffers,
_batch_size: u32,
_chunk_len: u32,
_ctx: &ForwardContext<'_>,
_stream: u64,
) -> Result<()>
fn prefill_gdn_full_batched( &self, _h_state_ptrs: DevicePtr, _gdn_bufs: &GdnPrefillBuffers, _batch_size: u32, _chunk_len: u32, _ctx: &ForwardContext<'_>, _stream: u64, ) -> Result<()>
Source§fn prefill_gdn_full_batched_fla_varlen(
&self,
_h_state_ptrs: DevicePtr,
_gdn_bufs: &GdnPrefillBuffers,
_batch_size: u32,
_cu_seqlens: DevicePtr,
_max_num_chunks: u32,
_total_nt: usize,
_max_seqlen: u32,
_ctx: &ForwardContext<'_>,
_stream: u64,
) -> Result<bool>
fn prefill_gdn_full_batched_fla_varlen( &self, _h_state_ptrs: DevicePtr, _gdn_bufs: &GdnPrefillBuffers, _batch_size: u32, _cu_seqlens: DevicePtr, _max_num_chunks: u32, _total_nt: usize, _max_seqlen: u32, _ctx: &ForwardContext<'_>, _stream: u64, ) -> Result<bool>
cu_seqlens in
ONE gdn_prefill_fla(batch=N, is_varlen) call (replaces the non-uniform
per-request loop → fills chunk_delta_h’s 32→32N CTAs). Returns Ok(true)
if it ran, Ok(false) if not eligible (caller falls back to the loop).
Default (non-SSM layers, or FLA disabled): Ok(false).Source§fn prefill_phase3(
&self,
_hidden: DevicePtr,
_residual: DevicePtr,
_num_tokens: usize,
_gdn_bufs: &GdnPrefillBuffers,
_token_offset: usize,
_ctx: &ForwardContext<'_>,
_stream: u64,
) -> Result<()>
fn prefill_phase3( &self, _hidden: DevicePtr, _residual: DevicePtr, _num_tokens: usize, _gdn_bufs: &GdnPrefillBuffers, _token_offset: usize, _ctx: &ForwardContext<'_>, _stream: u64, ) -> Result<()>
Source§fn is_ssm_layer(&self) -> bool
fn is_ssm_layer(&self) -> bool
Source§fn transpose_moe_for_prefill(
&mut self,
_gpu: &dyn GpuBackend,
_config: &ModelConfig,
) -> Result<()>
fn transpose_moe_for_prefill( &mut self, _gpu: &dyn GpuBackend, _config: &ModelConfig, ) -> Result<()>
factory::build
after LM-head NVFP4 quantization has freed BF16 headroom, so
memory-tight EP configurations (e.g. MiniMax M2.7-NVFP4 EP=2) can
fit the transpose that layer-0 preflight would otherwise reject. Read moreSource§fn transpose_moe_gate_up_for_prefill(
&mut self,
_gpu: &dyn GpuBackend,
_config: &ModelConfig,
) -> Result<()>
fn transpose_moe_gate_up_for_prefill( &mut self, _gpu: &dyn GpuBackend, _config: &ModelConfig, ) -> Result<()>
transpose_moe_for_prefill but only transposes the gate+up
projections (skips the down projection), reducing the transpose cost
from 3× to 2× per expert. Used as a memory-tight fallback by the
MiniMax loader when full transpose doesn’t fit.Source§fn set_moe_down_transpose_scratch(
&mut self,
_scratch_packed: DevicePtr,
_scratch_scale: DevicePtr,
_packed_ptrs_t: DevicePtr,
_scale_ptrs_t: DevicePtr,
)
fn set_moe_down_transpose_scratch( &mut self, _scratch_packed: DevicePtr, _scratch_scale: DevicePtr, _packed_ptrs_t: DevicePtr, _scale_ptrs_t: DevicePtr, )
down_proj transpose scratch into this
layer’s MoE block. Used as a memory-tight alternative to the
persistent down transpose: factory allocates one shared scratch,
every MoE layer reuses it layer-by-layer during sequential
prefill. No-op for non-MoE layers and MoE layers that already
have a persistent transposed down.Source§fn transpose_moe_for_prefill_unified(
&mut self,
_gpu: &dyn GpuBackend,
_config: &ModelConfig,
) -> Result<()>
fn transpose_moe_for_prefill_unified( &mut self, _gpu: &dyn GpuBackend, _config: &ModelConfig, ) -> Result<()>
MoeLayer::use_t_layout_for_decode() must
gate dispatch to the _t decode kernels. Default no-op.Source§fn transpose_moe_for_prefill_hybrid(
&mut self,
_gpu: &dyn GpuBackend,
_config: &ModelConfig,
) -> Result<()>
fn transpose_moe_for_prefill_hybrid( &mut self, _gpu: &dyn GpuBackend, _config: &ModelConfig, ) -> Result<()>
Source§fn decode_batched(
&self,
hidden: DevicePtr,
residual: DevicePtr,
num_tokens: usize,
state: &mut dyn LayerState,
kv_cache: &mut PagedKvCache,
seq_len: usize,
block_table: &mut Vec<u32>,
disk_block_ids: &mut Vec<u32>,
disk_last_offloaded_per_layer: &mut Vec<u32>,
ctx: &ForwardContext<'_>,
stream: u64,
) -> Result<()>
fn decode_batched( &self, hidden: DevicePtr, residual: DevicePtr, num_tokens: usize, state: &mut dyn LayerState, kv_cache: &mut PagedKvCache, seq_len: usize, block_table: &mut Vec<u32>, disk_block_ids: &mut Vec<u32>, disk_last_offloaded_per_layer: &mut Vec<u32>, ctx: &ForwardContext<'_>, stream: u64, ) -> Result<()>
Source§fn decode_multi_seq<'a, 'b: 'a>(
&self,
hidden: DevicePtr,
residual: DevicePtr,
num_seqs: usize,
states: &'a mut [&'b mut (dyn LayerState + 'static)],
kv_cache: &mut PagedKvCache,
seq_lens: &[usize],
block_tables: &[Vec<u32>],
ctx: &ForwardContext<'_>,
stream: u64,
) -> Result<()>
fn decode_multi_seq<'a, 'b: 'a>( &self, hidden: DevicePtr, residual: DevicePtr, num_seqs: usize, states: &'a mut [&'b mut (dyn LayerState + 'static)], kv_cache: &mut PagedKvCache, seq_lens: &[usize], block_tables: &[Vec<u32>], ctx: &ForwardContext<'_>, stream: u64, ) -> Result<()>
Source§fn decode_verify_multi<'a, 'b: 'a>(
&self,
_hidden: DevicePtr,
_residual: DevicePtr,
_n_seqs: usize,
_ks: &[usize],
_states: &'a mut [&'b mut (dyn LayerState + 'static)],
_kv_cache: &mut PagedKvCache,
_wy_tables: DevicePtr,
_ctx: &ForwardContext<'_>,
_stream: u64,
) -> Result<()>
fn decode_verify_multi<'a, 'b: 'a>( &self, _hidden: DevicePtr, _residual: DevicePtr, _n_seqs: usize, _ks: &[usize], _states: &'a mut [&'b mut (dyn LayerState + 'static)], _kv_cache: &mut PagedKvCache, _wy_tables: DevicePtr, _ctx: &ForwardContext<'_>, _stream: u64, ) -> Result<()>
n_seqs sequences × k tokens through this layer
in ONE weight sweep (rows seq-major, r = i*k + j, contiguous in
hidden/residual). Projections/FFN batch across all n_seqs*k rows;
the stateful recurrence (conv/GDN) runs per-sequence against
states[i] with row-offset buffer bases — per-sequence math is
byte-identical to the single-sequence decode_batched K-token body. Read moreSource§fn release_state(
&self,
_state: &mut dyn LayerState,
_gpu: &dyn GpuBackend,
) -> Result<()>
fn release_state( &self, _state: &mut dyn LayerState, _gpu: &dyn GpuBackend, ) -> Result<()>
alloc_state produced, plus anything
the layer attached to it lazily afterwards. Read more