mojolearn.mamba#
Mamba-1, Mamba-2 and Mamba-3 blocks in float32.
The block and state classes are also exported from mojolearn. Each block takes
caller-supplied weights and provides forward(x, state=None), step(x, state),
allocate_state(...) and backward(x, grad_output). The recurrent state is
explicit and owned by the caller, so prefill, continuation and token-by-token decode
give the same bits. Forward runs under numeric_mode ‘identical’ (the default) or
‘fast’. backward returns the gradients of a zero-state prefill with respect to
x and every constructor weight (11 arrays for Mamba-1, 10 each for Mamba-2 and
Mamba-3), recomputing the forward internally; gradients through a carried state or a
decode step are not available. Inputs are read through the buffer protocol, so PyTorch
and NumPy are not required.
Mamba1DecodeSession (from Mamba1Block.decode_session) keeps a Mamba-1 block and
its state resident on the device for fast decoding.
Examples
With float32 weights, x and dy of the right shapes:
from mojolearn.mamba import Mamba2Block
block = Mamba2Block(weights, numeric_mode="identical")
y = block.forward(x)
gradients = block.backward(x, dy)
state = block.allocate_state(batch_size=x.shape[0])
y0 = block.step(x[:, :1], state)
Classes
|
One Mamba-1 block: RMSNorm, selective-scan mixer and residual. |
|
Token-by-token decoding on one |
|
Recurrent state of a |
|
One Mamba-2 (SSD) block: RMSNorm, mixer and residual. |
|
Recurrent state of a |
|
One Mamba-3 (SISO) block: RMSNorm, mixer and residual. |
|
Recurrent state of a |
- class mojolearn.mamba.Mamba1Block(weights)[source]#
Bases:
_MambaBaseOne Mamba-1 block: RMSNorm, selective-scan mixer and residual.
Matches Hugging Face’s
MambaBlock.forward. Takes (B, L, d_model) float32 and returns (B, L, d_model) float32, with the recurrent state explicit and caller-owned (Mamba1State).Constructor keyword
numeric_modeselects ‘identical’ (the default) or ‘fast’. Inputs, weights and state must be float32: bfloat16, float16 and float64 are refused by name rather than converted, and non-finite values are refused by name. Arrays are read through the buffer protocol, so NumPy is not required; arrays the block allocates aremojolearn.Array, zero-copy undernumpy.asarray. There is no initializer: weights are passed in, so a cross-check can give both sides the same values. Projection weights may also be packed withmojolearn.lowbit; they are expanded exactly to float32 (seeweight_format).Fixed by the block: d_state 16, d_conv 4, expand 2, dt_rank
ceil(d_model / 16), convolution bias on, projection bias off, SiLU activation.- Parameters:
weights (dict of str to float32 buffer) – Weights under the reference parameter names, with d_inner = 2 * d_model and dt_rank = ceil(d_model / 16):
norm.weight(d_model,)in_proj.weight(2 * d_inner, d_model)conv1d.weight(d_inner, 1, 4) or (d_inner, 4)conv1d.bias(d_inner,)x_proj.weight(dt_rank + 32, d_inner)dt_proj.weight(d_inner, dt_rank)dt_proj.bias(d_inner,)A_log(d_inner, 16)D(d_inner,)out_proj.weight(d_model, d_inner)
- Variables:
Examples
>>> import numpy as np, mojolearn >>> block = mojolearn.Mamba1Block(weights) # dict of float32 arrays, as above >>> x = np.random.default_rng(0).random((2, 16, block.d_model), dtype=np.float32) >>> y = block.forward(x) >>> state = block.allocate_state(2) >>> y = block.forward(x, state) >>> y_next = block.step(x[:, -1], state)
- allocate_state(batch_size)[source]#
Return a zero
Mamba1Stateforbatch_sizesequences.- Parameters:
batch_size (int) – Number of sequences B.
- Returns:
Mamba1State
- forward(x, state=None, *, lengths=None)[source]#
Run the block over a sequence.
- Parameters:
x (float32 buffer, shape (B, L, d_model)) – Input activations: a NumPy array,
array.array('f'),mojolearn.Arrayor any float32 buffer. Other dtypes raiseTypeError.state (Mamba1State or None, default None) – None runs a self-contained prefill from a zero state and discards the final state. Pass a state from
allocate_stateto carry it: it is read at entry and updated in place, so a laterforwardorstepcontinues the sequence exactly as if the whole sequence had run in one call.lengths (sequence of int or None, default None) – Makes the batch ragged: B integers in [1, L]. Row i is real at positions [0, lengths[i]) and padding after. Each real position’s output equals the row run alone at its own length, and every padding position’s output is exactly +0.0. Not allowed together with
state.
- Returns:
y (mojolearn.Array, shape (B, L, d_model)) – Block output, residual included.
numpy.asarray(y)is zero-copy.
- backward(x, grad_output)[source]#
Gradients of a zero-state prefill (a vector-Jacobian product).
Recomputes the forward with the current weights on every call; no earlier forward or cached state is used or changed. Runs under
numeric_mode‘identical’ or ‘fast’; other modes raiseNotImplementedError. Gradients with respect to a carried state, decode backward and final-state cotangents are not available.- Parameters:
x (float32 buffer, shape (B, L, d_model)) – Forward input.
grad_output (float32 buffer, shape (B, L, d_model)) – Gradient of the loss with respect to the block output. Must be finite.
- Returns:
grads (dict of str to mojolearn.Array) –
'x'plus one entry per constructor weight, under the same names.
- step(x, state)[source]#
Run one decode token.
The same computation as
forwardat L = 1 with the state carried, so decoding token by token gives the same bits as prefilling the whole sequence.- Parameters:
x (float32 buffer, shape (B, 1, d_model) or (B, d_model)) – One token per row.
state (Mamba1State) – Required; updated in place.
- Returns:
y (mojolearn.Array, shape (B, 1, d_model))
- decode_session(state)[source]#
Open a
Mamba1DecodeSessionfor fast token-by-token decoding.On a GPU the session keeps the weights and the state on the device across steps; its
stepgives the same bytes asMamba1Block.step. The session copies the weights and the state when it opens:until
close()orsync_state(), the state’s arrays are stale, andforward/stepon this block refuse that state by name;weight edits after opening are not seen; close and open a new session;
edits to the state arrays are not seen until
load_state().
- Parameters:
state (Mamba1State) – State to decode from.
- Returns:
Mamba1DecodeSession
- class mojolearn.mamba.Mamba1DecodeSession(block, state)[source]#
Bases:
objectToken-by-token decoding on one
Mamba1Blockand oneMamba1State.Made by
Mamba1Block.decode_session(state). Every output is byte for byte whatMamba1Block.stepgives on the same block and state. On a GPU the weights, the state and the decode buffers stay on the device across steps; on a CPU-only install the session holds its own copies and steps on the host. A session is not thread-safe. Use it as a context manager to close it automatically.- Variables:
state (Mamba1State) – The state this session decodes from.
is_open (bool) – Whether the session is open.
Examples
>>> with block.decode_session(state) as session: ... for x_t in tokens: ... y_t = session.step(x_t)
- property state#
The
Mamba1Statethis session decodes from.
- property is_open#
Whether the session is open.
- step(x)[source]#
Decode one token per row.
- Parameters:
x (float32 buffer, shape (B, 1, d_model) or (B, d_model)) – B must equal the session’s batch size.
- Returns:
y (mojolearn.Array, shape (B, 1, d_model))
- sync_state()[source]#
Copy the session’s current state into the
Mamba1Statearrays and return the state.
- class mojolearn.mamba.Mamba1State(conv_window, h, *, profile_id=1, absolute_position=0, affine_boundary=None, affine_a=None, affine_b=None)[source]#
Bases:
objectRecurrent state of a
Mamba1Block, owned by the caller.Make one with
Mamba1Block.allocate_state; it is all zeros before the first token.forwardandstepupdate the arrays in place. The arrays aremojolearn.Arraywhenallocate_statemade them, or any writable float32 buffer (a NumPy array included) you supply; their bytes can be saved and restored exactly.- Variables:
conv_window (float32 buffer, shape (B, d_inner, 4)) – The last four inputs to the convolution, oldest first.
h (float32 buffer, shape (B, d_inner, 16)) – SSM state.
- class mojolearn.mamba.Mamba2Block(weights, *, dt_limit=(0.0, inf))[source]#
Bases:
_MambaBaseOne Mamba-2 (SSD) block: RMSNorm, mixer and residual.
Matches Hugging Face’s
Mamba2Block.forward(the non-memory-efficient mixer). Takes (B, L, d_model) float32 and returns (B, L, d_model) float32, with the recurrent state explicit and caller-owned (Mamba2State).Constructor keyword
numeric_modeselects ‘identical’ (the default) or ‘fast’. Inputs, weights and state must be float32: bfloat16, float16 and float64 are refused by name rather than converted, and non-finite values are refused by name. Arrays are read through the buffer protocol, so NumPy is not required; arrays the block allocates aremojolearn.Array, zero-copy undernumpy.asarray. There is no initializer: weights are passed in, so a cross-check can give both sides the same values. Projection weights may also be packed withmojolearn.lowbit; they are expanded exactly to float32 (seeweight_format).d_modelmust be a multiple of 32. Fixed by the block: d_state 128, head dimension 64, one group, chunk size 256, expand 2, RMSNorm on with the gate applied before the norm. Decoding resumes the open chunk, sostepand aforwardwith a carried state continue a prefill bit for bit.After every call,
h_last_holds the SSM state after the final padded chunk. This is a reporting value, not the resumption state; feeding it back asinitial_statesmatches resumption only on a chunk boundary.- Parameters:
weights (dict of str to float32 buffer) – With d_inner = 2 * d_model, H = d_inner / 64 heads and CD = d_inner + 256:
block_norm.weight(d_model,), the block normin_proj.weight(2 * d_inner + 256 + H, d_model), column order z | xBC | dtconv1d.weight(CD, 1, 4) or (CD, 4)conv1d.bias(CD,)dt_bias(H,)A_log(H,), one value per headD(H,)norm.weight(d_inner,), the gated normout_proj.weight(d_model, d_inner)
dt_limit (tuple of float, default (0.0, inf)) – Clamp
(lo, hi)applied to dt.
- Variables:
Examples
>>> block = mojolearn.Mamba2Block(weights, numeric_mode="identical") >>> y = block.forward(x) >>> grads = block.backward(x, dy) >>> state = block.allocate_state(batch_size=x.shape[0]) >>> y0 = block.step(x[:, :1], state)
- allocate_state(batch_size)[source]#
Return a zero
Mamba2Stateforbatch_sizesequences.Set its
hnonzero before the first call to supplyinitial_states.- Parameters:
batch_size (int) – Number of sequences B.
- Returns:
Mamba2State
- forward(x, state=None, *, lengths=None)[source]#
Run the block over a sequence.
- Parameters:
x (float32 buffer, shape (B, L, d_model)) – Input activations: a NumPy array,
array.array('f'),mojolearn.Arrayor any float32 buffer. Other dtypes raiseTypeError.state (Mamba2State or None, default None) – None runs a self-contained prefill from a zero state and discards the final state. Pass a state from
allocate_stateto carry it: it is read at entry and updated in place, so a laterforwardorstepcontinues the sequence exactly as if the whole sequence had run in one call.lengths (sequence of int or None, default None) – Makes the batch ragged: B integers in [1, L]. Row i is real at positions [0, lengths[i]) and padding after. Each real position’s output equals the row run alone at its own length, and every padding position’s output is exactly +0.0. Not allowed together with
state.
- Returns:
y (mojolearn.Array, shape (B, L, d_model)) – Block output, residual included.
numpy.asarray(y)is zero-copy.
- backward(x, grad_output)[source]#
Gradients of a zero-state prefill (a vector-Jacobian product).
Recomputes the forward with the current weights on every call; no earlier forward or cached state is used or changed. Runs under
numeric_mode‘identical’ or ‘fast’; other modes raiseNotImplementedError. Gradients with respect to a carried state, decode backward and final-state cotangents are not available.- Parameters:
x (float32 buffer, shape (B, L, d_model)) – Forward input.
grad_output (float32 buffer, shape (B, L, d_model)) – Gradient of the loss with respect to the block output. Must be finite.
- Returns:
grads (dict of str to mojolearn.Array) –
'x'plus one entry per constructor weight, under the same names.
- step(x, state)[source]#
Run one decode token.
The same computation as
forwardat L = 1 with the state carried, so decoding token by token gives the same bits as prefilling the whole sequence.- Parameters:
x (float32 buffer, shape (B, 1, d_model) or (B, d_model)) – One token per row.
state (Mamba2State) – Required; updated in place.
- Returns:
y (mojolearn.Array, shape (B, 1, d_model))
- class mojolearn.mamba.Mamba2State(conv_window, h, buffer_xbc, buffer_dtraw, buffered_tokens=0)[source]#
Bases:
objectRecurrent state of a
Mamba2Block, owned by the caller.With H = d_model / 32 heads and CD = 2 * d_model + 256 convolution channels. Make one with
Mamba2Block.allocate_state; it is all zeros (andbuffered_tokens == 0) before the first token.forwardandstepupdate it in place. Settinghnonzero on a fresh state supplies the reference’sinitial_states.- Variables:
conv_window (float32 buffer, shape (B, CD, 4)) – The last four pre-convolution xBC inputs, oldest first.
h (float32 buffer, shape (B, H, 64, 128)) – SSM state as of the last completed 256-token chunk.
buffer_xbc (float32 buffer, shape (B, 256, CD)) – Post-convolution, post-SiLU xBC rows of the open chunk.
buffer_dtraw (float32 buffer, shape (B, 256, H)) – Raw dt rows of the open chunk.
buffered_tokens (int) – Number of valid rows in the open-chunk buffers, in [0, 256). Decoding resumes the open chunk from these rows.
- class mojolearn.mamba.Mamba3Block(weights)[source]#
Bases:
_MambaBaseOne Mamba-3 (SISO) block: RMSNorm, mixer and residual.
Matches mamba_ssm’s
Mamba3.forward(SISO) inside the non-fused block. Takes (B, L, d_model) float32 and returns (B, L, d_model) float32, with the recurrent state explicit and caller-owned (Mamba3State).Compared with
Mamba2Block: no convolution (v is the raw x split), no dt clamp (so nodt_limit), A depends on the token and head with a floor clamp, the gate is applied inside the core (no gated output norm), and B and C have their own RMSNorms with per-head biases added after the norm.Constructor keyword
numeric_modeselects ‘identical’ (the default) or ‘fast’. Inputs, weights and state must be float32: bfloat16, float16 and float64 are refused by name rather than converted, and non-finite values are refused by name. Arrays are read through the buffer protocol, so NumPy is not required; arrays the block allocates aremojolearn.Array, zero-copy undernumpy.asarray. There is no initializer: weights are passed in, so a cross-check can give both sides the same values. Projection weights may also be packed withmojolearn.lowbit; they are expanded exactly to float32 (seeweight_format).d_modelmust be a multiple of 32. Fixed by the block: d_state 128, head dimension 64, one group, rope fraction 0.5 (32 angles), A floor 1e-4, chunk size 64, expand 2. MIMO, output-projection norm, fused pre-gate options, more than one group and variable-length batches are not available. Decoding resumes the working chunk, sostepand aforwardwith a carried state continue a prefill bit for bit.After every call,
h_last_,k_last_,v_last_andtheta_last_hold reporting values, not the resumption state.- Parameters:
weights (dict of str to float32 buffer) – With d_inner = 2 * d_model, H = d_inner / 64 heads, N = 128 and d_in_proj = 2 * d_inner + 256 + 3 * H + 32:
block_norm.weight(d_model,), the block normin_proj.weight(d_in_proj, d_model), column order z | x | B | C | dd_dt | dd_A | trap | angledt_bias(H,)B_norm.weight(N,), RMSNorm with eps 1e-5C_norm.weight(N,)B_bias(H, N)C_bias(H, N)D(H,)out_proj.weight(d_model, d_inner)
- Variables:
Examples
>>> block = mojolearn.Mamba3Block(weights) >>> y = block.forward(x) >>> state = block.allocate_state(x.shape[0]) >>> y = block.forward(x, state) >>> y_next = block.step(x[:, -1], state)
- allocate_state(batch_size)[source]#
Return a zero
Mamba3Stateforbatch_sizesequences.For a reference
Input_Statescontinuation, callMamba3State.set_input_stateson the fresh state.- Parameters:
batch_size (int) – Number of sequences B.
- Returns:
Mamba3State
- session_info()[source]#
Counters of the prefill session as a dict, or None before the first call.
Reports weight uploads, re-copies and reuses, backward stage reuses, forward recomputes and the number of stages held.
- forward(x, state=None, *, lengths=None)[source]#
Run the block over a sequence.
- Parameters:
x (float32 buffer, shape (B, L, d_model)) – Input activations: a NumPy array,
array.array('f'),mojolearn.Arrayor any float32 buffer. Other dtypes raiseTypeError.state (Mamba3State or None, default None) – None runs a self-contained prefill from a zero state and discards the final state. Pass a state from
allocate_stateto carry it: it is read at entry and updated in place, so a laterforwardorstepcontinues the sequence exactly as if the whole sequence had run in one call.lengths (sequence of int or None, default None) – Makes the batch ragged: B integers in [1, L]. Row i is real at positions [0, lengths[i]) and padding after. Each real position’s output equals the row run alone at its own length, and every padding position’s output is exactly +0.0. Not allowed together with
state.
- Returns:
y (mojolearn.Array, shape (B, L, d_model)) – Block output, residual included.
numpy.asarray(y)is zero-copy.
- backward(x, grad_output)[source]#
Gradients of a zero-state prefill (a vector-Jacobian product).
Recomputes the forward with the current weights on every call; no earlier forward or cached state is used or changed. Runs under
numeric_mode‘identical’ or ‘fast’; other modes raiseNotImplementedError. Gradients with respect to a carried state, decode backward and final-state cotangents are not available.- Parameters:
x (float32 buffer, shape (B, L, d_model)) – Forward input.
grad_output (float32 buffer, shape (B, L, d_model)) – Gradient of the loss with respect to the block output. Must be finite.
- Returns:
grads (dict of str to mojolearn.Array) –
'x'plus one entry per constructor weight, under the same names.
- step(x, state)[source]#
Run one decode token.
The same computation as
forwardat L = 1 with the state carried, so decoding token by token gives the same bits as prefilling the whole sequence.- Parameters:
x (float32 buffer, shape (B, 1, d_model) or (B, d_model)) – One token per row.
state (Mamba3State) – Required; updated in place.
- Returns:
y (mojolearn.Array, shape (B, 1, d_model))
- class mojolearn.mamba.Mamba3State(theta, h, buffer_qrot, buffer_krot, buffer_v, buffer_dt, buffer_sig, buffer_adt, pending_k, pending_v, buffered_tokens=0, pending=False)[source]#
Bases:
objectRecurrent state of a
Mamba3Block, owned by the caller.With H = d_model / 32 heads, N = 128 (QK head dimension), P = 64 (V head dimension), R = 32 rotary angles and Q = 64 (the Mamba-3 chunk size). Make one with
Mamba3Block.allocate_state; it is all zeros (buffered_tokens == 0,pending == False) before the first token.forwardandstepupdate it in place.- Variables:
theta (float32 buffer, shape (B, H, R)) – Rotary angles, each in [0, 2*pi).
h (float32 buffer, shape (B, H, P, N)) – SSM state entering the last working chunk.
buffer_krot (buffer_qrot,) – Rotated, unscaled q and k rows of the working chunk.
buffer_v (float32 buffer, shape (B, Q, H, P)) – Raw v rows.
buffer_adt (buffer_dt, buffer_sig,) – dt, sigmoid(trap) and A*dt rows.
pending_k (float32 buffer, shape (B, H, N)) – Input-state k, used only when
pending.pending_v (float32 buffer, shape (B, H, P)) – Input-state v, used only when
pending.buffered_tokens (int) – Valid buffer rows, in [0, Q]. After the first call it is always in [1, Q].
pending (bool) – True when
set_input_statessupplied the state; consumed by the next call.
- set_input_states(theta, h, k, v)[source]#
Start from a reference
Input_Statescontinuation.Copies the given values into
theta,h,pending_kandpending_vand marks them pending for the next call. The state must be fresh (no tokens yet); that is checked at the next call. Arrays must already be float32 with the shapes above; nothing is converted.- Parameters:
theta (float32 buffer, shape (B, H, R))
h (float32 buffer, shape (B, H, P, N))
k (float32 buffer, shape (B, H, N))
v (float32 buffer, shape (B, H, P))