family falcon_mamba
Mamba's block, one norm and a selective-scan mixer, with no attention and no MLP; inside the mixer, weightless RMS norms sit on B, C and the low-rank step input before the scan.
One block of the stack. Hover any part for its nnterp name; click to pin the card.
identity layers[i].input + linear_attn.attention_output == layer_output
⚠︎ marks a value this checkpoint has only under some load: hover it for the condition.
What print(model) shows on tiiuae/falcon-mamba-7b: the native modules, standard names and every standard value with its layout.
FalconMambaForCausalLM(
(lm_head): Linear(in_features=4096, out_features=65024, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(65024, 4096)
(layers): ModuleList(
(0-63): 64 x FalconMambaBlock(
(input_layernorm/norm): FalconMambaRMSNorm((4096,), eps=1e-05)
(linear_attn/mixer): FalconMambaMixer(
(conv1d): Conv1d(8192, 8192, kernel_size=(4,), stride=(1,), padding=(3,), groups=8192)
(act): SiLUActivation()
(in_proj): Linear(in_features=4096, out_features=16384, bias=False)
(x_proj): Linear(in_features=8192, out_features=288, bias=False)
(dt_proj): Linear(in_features=256, out_features=8192, bias=True)
(out_proj): Linear(in_features=8192, out_features=4096, bias=False)
(dt_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-06)
(b_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-06)
(c_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-06)
(attention_queries) -> ScanQK [batch seq groups state_dim]: C, the vector each token reads the state with
(attention_keys) -> ScanQK [batch seq groups state_dim]: B, the vector each token writes into the state with
(attention_values) -> ScanValues [batch seq channels]: x, the input the scan writes into the state
(betas) -> ScanSteps [batch seq channels]: The step size dt = softplus(dt + dt_bias), per token and channel; derived, read-only
(decays) -> ScanDecays [batch seq channels state_dim]: The per-token log decay dt * A of the state; derived, read-only
(state_input) -> ScanState | None [batch channels state_dim]: The state entering the layer on a decode step (a copy of the cache's buffer), None on a prompt
(attention_head_outputs) -> ScanValues [batch seq channels]: y = C.h + D.x, the scan's read of the state before the gate and out_proj
(state_output) -> ScanState [batch channels state_dim]: The state leaving the layer
(state) -> ScanState [batch channels state_dim]: The state after one token of the prompt; iterate it with tracer.iter; needs route_kernels(family, 'torch')
(states) -> ScanStates [batch seq channels state_dim]: The state after every token of this call; needs route_kernels(family, 'torch')
(attention_output) -> Residual [batch seq hidden_size]: What the mixer adds to the residual stream
)
(layer_mid): Unavailable: a state-space block: one sublayer, the mixer, so there is no stream between sublayers and no MLP
(layer_input) -> Residual [batch seq hidden_size]: The residual stream entering the block
(attention_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the attention
(mlp_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the MLP
(mlp_input) -> Residual [batch seq hidden_size]: What the MLP is called with
(layer_output) -> Residual [batch seq hidden_size]: The residual stream leaving the block, a tensor even when the block returns a tuple
)
)
(norm): FalconMambaRMSNorm((4096,), eps=1e-05)
(logits) -> Logits [batch seq vocab_size]: The logits the model returns, after anything it does past lm_head (a softcap, a scale)
(token_embeddings) -> Residual [batch seq hidden_size]: The embedding module's output; layers[0].input is what enters the first block
(final_norm_output) -> Residual [batch seq hidden_size]: The residual stream after the final norm, what lm_head reads
(lm_head_output) -> Logits [batch seq vocab_size]: The head's logits before anything the model does past lm_head (a softcap, a scale)
(next_token_probs) -> NextTokenProbs [batch vocab_size]: The next-token distribution at the last position; derived, read-only
(input_ids) -> Tokens [batch seq]: The token ids the model was called with
(attention_mask) -> Tokens [batch seq]: The attention mask the model was called with; zeros are padding
(input_size): [batch, seq] of the current call; read-only
)What print(model) shows on tiiuae/falcon-mamba-7b-instruct: the native modules, standard names and every standard value with its layout.
FalconMambaForCausalLM(
(lm_head): Linear(in_features=4096, out_features=65024, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(65024, 4096)
(layers): ModuleList(
(0-63): 64 x FalconMambaBlock(
(input_layernorm/norm): FalconMambaRMSNorm((4096,), eps=1e-05)
(linear_attn/mixer): FalconMambaMixer(
(conv1d): Conv1d(8192, 8192, kernel_size=(4,), stride=(1,), padding=(3,), groups=8192)
(act): SiLUActivation()
(in_proj): Linear(in_features=4096, out_features=16384, bias=False)
(x_proj): Linear(in_features=8192, out_features=288, bias=False)
(dt_proj): Linear(in_features=256, out_features=8192, bias=True)
(out_proj): Linear(in_features=8192, out_features=4096, bias=False)
(dt_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-06)
(b_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-06)
(c_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-06)
(attention_queries) -> ScanQK [batch seq groups state_dim]: C, the vector each token reads the state with
(attention_keys) -> ScanQK [batch seq groups state_dim]: B, the vector each token writes into the state with
(attention_values) -> ScanValues [batch seq channels]: x, the input the scan writes into the state
(betas) -> ScanSteps [batch seq channels]: The step size dt = softplus(dt + dt_bias), per token and channel; derived, read-only
(decays) -> ScanDecays [batch seq channels state_dim]: The per-token log decay dt * A of the state; derived, read-only
(state_input) -> ScanState | None [batch channels state_dim]: The state entering the layer on a decode step (a copy of the cache's buffer), None on a prompt
(attention_head_outputs) -> ScanValues [batch seq channels]: y = C.h + D.x, the scan's read of the state before the gate and out_proj
(state_output) -> ScanState [batch channels state_dim]: The state leaving the layer
(state) -> ScanState [batch channels state_dim]: The state after one token of the prompt; iterate it with tracer.iter; needs route_kernels(family, 'torch')
(states) -> ScanStates [batch seq channels state_dim]: The state after every token of this call; needs route_kernels(family, 'torch')
(attention_output) -> Residual [batch seq hidden_size]: What the mixer adds to the residual stream
)
(layer_mid): Unavailable: a state-space block: one sublayer, the mixer, so there is no stream between sublayers and no MLP
(layer_input) -> Residual [batch seq hidden_size]: The residual stream entering the block
(attention_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the attention
(mlp_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the MLP
(mlp_input) -> Residual [batch seq hidden_size]: What the MLP is called with
(layer_output) -> Residual [batch seq hidden_size]: The residual stream leaving the block, a tensor even when the block returns a tuple
)
)
(norm): FalconMambaRMSNorm((4096,), eps=1e-05)
(logits) -> Logits [batch seq vocab_size]: The logits the model returns, after anything it does past lm_head (a softcap, a scale)
(token_embeddings) -> Residual [batch seq hidden_size]: The embedding module's output; layers[0].input is what enters the first block
(final_norm_output) -> Residual [batch seq hidden_size]: The residual stream after the final norm, what lm_head reads
(lm_head_output) -> Logits [batch seq vocab_size]: The head's logits before anything the model does past lm_head (a softcap, a scale)
(next_token_probs) -> NextTokenProbs [batch vocab_size]: The next-token distribution at the last position; derived, read-only
(input_ids) -> Tokens [batch seq]: The token ids the model was called with
(attention_mask) -> Tokens [batch seq]: The attention mask the model was called with; zeros are padding
(input_size): [batch, seq] of the current call; read-only
)What print(model) shows on tiiuae/falcon-mamba-7b-pre-decay: the native modules, standard names and every standard value with its layout.
FalconMambaForCausalLM(
(lm_head): Linear(in_features=4096, out_features=65024, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(65024, 4096)
(layers): ModuleList(
(0-63): 64 x FalconMambaBlock(
(input_layernorm/norm): FalconMambaRMSNorm((4096,), eps=1e-05)
(linear_attn/mixer): FalconMambaMixer(
(conv1d): Conv1d(8192, 8192, kernel_size=(4,), stride=(1,), padding=(3,), groups=8192)
(act): SiLUActivation()
(in_proj): Linear(in_features=4096, out_features=16384, bias=False)
(x_proj): Linear(in_features=8192, out_features=288, bias=False)
(dt_proj): Linear(in_features=256, out_features=8192, bias=True)
(out_proj): Linear(in_features=8192, out_features=4096, bias=False)
(dt_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-06)
(b_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-06)
(c_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-06)
(attention_queries) -> ScanQK [batch seq groups state_dim]: C, the vector each token reads the state with
(attention_keys) -> ScanQK [batch seq groups state_dim]: B, the vector each token writes into the state with
(attention_values) -> ScanValues [batch seq channels]: x, the input the scan writes into the state
(betas) -> ScanSteps [batch seq channels]: The step size dt = softplus(dt + dt_bias), per token and channel; derived, read-only
(decays) -> ScanDecays [batch seq channels state_dim]: The per-token log decay dt * A of the state; derived, read-only
(state_input) -> ScanState | None [batch channels state_dim]: The state entering the layer on a decode step (a copy of the cache's buffer), None on a prompt
(attention_head_outputs) -> ScanValues [batch seq channels]: y = C.h + D.x, the scan's read of the state before the gate and out_proj
(state_output) -> ScanState [batch channels state_dim]: The state leaving the layer
(state) -> ScanState [batch channels state_dim]: The state after one token of the prompt; iterate it with tracer.iter; needs route_kernels(family, 'torch')
(states) -> ScanStates [batch seq channels state_dim]: The state after every token of this call; needs route_kernels(family, 'torch')
(attention_output) -> Residual [batch seq hidden_size]: What the mixer adds to the residual stream
)
(layer_mid): Unavailable: a state-space block: one sublayer, the mixer, so there is no stream between sublayers and no MLP
(layer_input) -> Residual [batch seq hidden_size]: The residual stream entering the block
(attention_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the attention
(mlp_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the MLP
(mlp_input) -> Residual [batch seq hidden_size]: What the MLP is called with
(layer_output) -> Residual [batch seq hidden_size]: The residual stream leaving the block, a tensor even when the block returns a tuple
)
)
(norm): FalconMambaRMSNorm((4096,), eps=1e-05)
(logits) -> Logits [batch seq vocab_size]: The logits the model returns, after anything it does past lm_head (a softcap, a scale)
(token_embeddings) -> Residual [batch seq hidden_size]: The embedding module's output; layers[0].input is what enters the first block
(final_norm_output) -> Residual [batch seq hidden_size]: The residual stream after the final norm, what lm_head reads
(lm_head_output) -> Logits [batch seq vocab_size]: The head's logits before anything the model does past lm_head (a softcap, a scale)
(next_token_probs) -> NextTokenProbs [batch vocab_size]: The next-token distribution at the last position; derived, read-only
(input_ids) -> Tokens [batch seq]: The token ids the model was called with
(attention_mask) -> Tokens [batch seq]: The attention mask the model was called with; zeros are padding
(input_size): [batch, seq] of the current call; read-only
)What print(model) shows on tiiuae/Falcon3-Mamba-7B-Base: the native modules, standard names and every standard value with its layout.
FalconMambaForCausalLM(
(lm_head): Linear(in_features=4096, out_features=65024, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(65024, 4096)
(layers): ModuleList(
(0-63): 64 x FalconMambaBlock(
(input_layernorm/norm): FalconMambaRMSNorm((4096,), eps=1e-05)
(linear_attn/mixer): FalconMambaMixer(
(conv1d): Conv1d(8192, 8192, kernel_size=(4,), stride=(1,), padding=(3,), groups=8192)
(act): SiLUActivation()
(in_proj): Linear(in_features=4096, out_features=16384, bias=False)
(x_proj): Linear(in_features=8192, out_features=288, bias=False)
(dt_proj): Linear(in_features=256, out_features=8192, bias=True)
(out_proj): Linear(in_features=8192, out_features=4096, bias=False)
(dt_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-05)
(b_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-05)
(c_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-05)
(attention_queries) -> ScanQK [batch seq groups state_dim]: C, the vector each token reads the state with
(attention_keys) -> ScanQK [batch seq groups state_dim]: B, the vector each token writes into the state with
(attention_values) -> ScanValues [batch seq channels]: x, the input the scan writes into the state
(betas) -> ScanSteps [batch seq channels]: The step size dt = softplus(dt + dt_bias), per token and channel; derived, read-only
(decays) -> ScanDecays [batch seq channels state_dim]: The per-token log decay dt * A of the state; derived, read-only
(state_input) -> ScanState | None [batch channels state_dim]: The state entering the layer on a decode step (a copy of the cache's buffer), None on a prompt
(attention_head_outputs) -> ScanValues [batch seq channels]: y = C.h + D.x, the scan's read of the state before the gate and out_proj
(state_output) -> ScanState [batch channels state_dim]: The state leaving the layer
(state) -> ScanState [batch channels state_dim]: The state after one token of the prompt; iterate it with tracer.iter; needs route_kernels(family, 'torch')
(states) -> ScanStates [batch seq channels state_dim]: The state after every token of this call; needs route_kernels(family, 'torch')
(attention_output) -> Residual [batch seq hidden_size]: What the mixer adds to the residual stream
)
(layer_mid): Unavailable: a state-space block: one sublayer, the mixer, so there is no stream between sublayers and no MLP
(layer_input) -> Residual [batch seq hidden_size]: The residual stream entering the block
(attention_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the attention
(mlp_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the MLP
(mlp_input) -> Residual [batch seq hidden_size]: What the MLP is called with
(layer_output) -> Residual [batch seq hidden_size]: The residual stream leaving the block, a tensor even when the block returns a tuple
)
)
(norm): FalconMambaRMSNorm((4096,), eps=1e-05)
(logits) -> Logits [batch seq vocab_size]: The logits the model returns, after anything it does past lm_head (a softcap, a scale)
(token_embeddings) -> Residual [batch seq hidden_size]: The embedding module's output; layers[0].input is what enters the first block
(final_norm_output) -> Residual [batch seq hidden_size]: The residual stream after the final norm, what lm_head reads
(lm_head_output) -> Logits [batch seq vocab_size]: The head's logits before anything the model does past lm_head (a softcap, a scale)
(next_token_probs) -> NextTokenProbs [batch vocab_size]: The next-token distribution at the last position; derived, read-only
(input_ids) -> Tokens [batch seq]: The token ids the model was called with
(attention_mask) -> Tokens [batch seq]: The attention mask the model was called with; zeros are padding
(input_size): [batch, seq] of the current call; read-only
)What print(model) shows on tiiuae/Falcon3-Mamba-7B-Instruct: the native modules, standard names and every standard value with its layout.
FalconMambaForCausalLM(
(lm_head): Linear(in_features=4096, out_features=65024, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(65024, 4096)
(layers): ModuleList(
(0-63): 64 x FalconMambaBlock(
(input_layernorm/norm): FalconMambaRMSNorm((4096,), eps=1e-05)
(linear_attn/mixer): FalconMambaMixer(
(conv1d): Conv1d(8192, 8192, kernel_size=(4,), stride=(1,), padding=(3,), groups=8192)
(act): SiLUActivation()
(in_proj): Linear(in_features=4096, out_features=16384, bias=False)
(x_proj): Linear(in_features=8192, out_features=288, bias=False)
(dt_proj): Linear(in_features=256, out_features=8192, bias=True)
(out_proj): Linear(in_features=8192, out_features=4096, bias=False)
(dt_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-05)
(b_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-05)
(c_layernorm): FalconMambaWeightlessRMSNorm(eps=1e-05)
(attention_queries) -> ScanQK [batch seq groups state_dim]: C, the vector each token reads the state with
(attention_keys) -> ScanQK [batch seq groups state_dim]: B, the vector each token writes into the state with
(attention_values) -> ScanValues [batch seq channels]: x, the input the scan writes into the state
(betas) -> ScanSteps [batch seq channels]: The step size dt = softplus(dt + dt_bias), per token and channel; derived, read-only
(decays) -> ScanDecays [batch seq channels state_dim]: The per-token log decay dt * A of the state; derived, read-only
(state_input) -> ScanState | None [batch channels state_dim]: The state entering the layer on a decode step (a copy of the cache's buffer), None on a prompt
(attention_head_outputs) -> ScanValues [batch seq channels]: y = C.h + D.x, the scan's read of the state before the gate and out_proj
(state_output) -> ScanState [batch channels state_dim]: The state leaving the layer
(state) -> ScanState [batch channels state_dim]: The state after one token of the prompt; iterate it with tracer.iter; needs route_kernels(family, 'torch')
(states) -> ScanStates [batch seq channels state_dim]: The state after every token of this call; needs route_kernels(family, 'torch')
(attention_output) -> Residual [batch seq hidden_size]: What the mixer adds to the residual stream
)
(layer_mid): Unavailable: a state-space block: one sublayer, the mixer, so there is no stream between sublayers and no MLP
(layer_input) -> Residual [batch seq hidden_size]: The residual stream entering the block
(attention_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the attention
(mlp_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the MLP
(mlp_input) -> Residual [batch seq hidden_size]: What the MLP is called with
(layer_output) -> Residual [batch seq hidden_size]: The residual stream leaving the block, a tensor even when the block returns a tuple
)
)
(norm): FalconMambaRMSNorm((4096,), eps=1e-05)
(logits) -> Logits [batch seq vocab_size]: The logits the model returns, after anything it does past lm_head (a softcap, a scale)
(token_embeddings) -> Residual [batch seq hidden_size]: The embedding module's output; layers[0].input is what enters the first block
(final_norm_output) -> Residual [batch seq hidden_size]: The residual stream after the final norm, what lm_head reads
(lm_head_output) -> Logits [batch seq vocab_size]: The head's logits before anything the model does past lm_head (a softcap, a scale)
(next_token_probs) -> NextTokenProbs [batch vocab_size]: The next-token distribution at the last position; derived, read-only
(input_ids) -> Tokens [batch seq]: The token ids the model was called with
(attention_mask) -> Tokens [batch seq]: The attention mask the model was called with; zeros are padding
(input_size): [batch, seq] of the current call; read-only
)out = x + mixer(norm(x)) # added in float32
mixer(h): u, z = in_proj(h)
u = silu(conv1d(u)) # attention_values
dt, B, C = x_proj(u)
dt, B, C = rms(dt), rms(B), rms(C) # weightless
y = scan(u, dt_proj(dt), A, B, C) + D * u
return out_proj(y * silu(z)) # attention_output
The tree, the block and the values are Mamba's (the mamba page): the block's norm is
input_layernorm (native norm), the mixer is linear_attn, and model.norm is the final
norm_f. What is this family's own sits inside the mixer: dt_layernorm, b_layernorm and
c_layernorm, RMS norms with no gain (their weight is a buffer of ones the torch path never
reads), with mixer_rms_eps (1e-6 on falcon-mamba-7b, 1e-5 on Falcon3-Mamba).
x_proj maps attention_values (the convolved x) to a low-rank step, B and C; the three
norms apply to those three outputs, and the scan reads what they return.
attention_keys and attention_queries are the normed B and C: each token's vector of
state_size (16) entries has a root-mean-square of one.betas is softplus(dt_proj(rms(dt))), dt_proj's bias included: the norm sits on the low-rank step
(time_step_rank, 256) before dt_proj, so betas itself carries no fixed scale, and
decays is betas * A as on Mamba.B and C are in x_proj's output, columns time_step_rank: of it. Read it in a
trace of its own. The kernel's values first look up which kernel the call runs, at the top of the
mixer's forward, before x_proj runs, and are then read at the kernel call, after it, so a trace
that reads x_proj.output and a kernel value fails with OutOfOrderError in either order.mix = model.layers[1].linear_attn
with model.trace(prompt):
raw = mix.x_proj.output.save() # [batch, seq, rank + 2 * state_size]
with model.trace(prompt):
B = mix.attention_keys.save() # [batch, seq, 1, state_size]
r, n = model.config.time_step_rank, model.config.state_size
b = raw[..., r:r + n].float()
normed = b * torch.rsqrt(b.pow(2).mean(-1, keepdim=True) + model.config.mixer_rms_eps)
torch.testing.assert_close(normed.to(B.dtype), B[:, :, 0])
A write to attention_keys or attention_queries replaces the normed vector the scan reads,
so a written vector need not have unit scale; a write to x_proj.output passes through the
norms first.
attention_output is out_proj's output and all the block adds:
layers[i].input + attention_output == layer_output, exactly, in float32.
with model.trace(prompt):
x = model.layers[1].input.save()
attn = model.layers[1].linear_attn.attention_output.save()
out = model.layers[1].layer_output.save()
torch.testing.assert_close(x + attn.float(), out)
With mamba_ssm installed every trace on CPU fails inside the scan kernel
(RuntimeError: Expected u.is_cuda() to be true), and on GPU every linear_attn value but
attention_output reports the kernel in support(). Routing binds the scan and the decode
step to transformers' torch functions in Falcon-Mamba's own modeling module; after it
support() reports every value, state and states included.
import nnterp
from nnterp import StandardizedTransformer, route_kernels
route_kernels(nnterp.families.falcon_mamba, "torch")
model = StandardizedTransformer("tiiuae/falcon-mamba-7b")
On falcon-mamba-7b the mixer is 8192 channels wide, each with a state of 16:
attention_values, betas and attention_head_outputs are [batch, seq, 8192],
attention_keys and attention_queries [batch, seq, 1, 16], decays and states
[batch, seq, 8192, 16]. config.expand reads 16 on the falcon-mamba-7b checkpoints and 2 on Falcon3-Mamba;
the mixer's width is intermediate_size, 8192 on both. The scan is Mamba's, so the hidden
attention on the mamba page rebuilds attention_head_outputs here unchanged, with the normed
B and C.
state_output is [batch, 8192, 16] and equals states[:, -1]. On a decode step read
state_output before attention_head_outputs: the step updates the state before it reads it.
heads, leaving = [], []
with model.generate(prompt, max_new_tokens=3, do_sample=False) as tracer:
for step in tracer.iter[:3]:
if step == 0:
heads.append(mix.attention_head_outputs.save())
leaving.append(mix.state_output.save())
else:
leaving.append(mix.state_output.save())
heads.append(mix.attention_head_outputs.save())
lm_head has its own weight. project_on_vocab casts the normed stream to the head's dtype
and the logits to float32, as the model does, so at the last block's layer_output it equals
logits. token_embeddings equals layers[0].input.
falcon-mamba-7b and its -instruct and -pre-decay checkpoints, and Falcon3-Mamba-7B
-Base and -Instruct, all 64 blocks of width 4096. They tokenize with Falcon's 65024-token
BPE and prepend nothing. The tokenizer's end-of-text token is <|endoftext|> (id 11), and it sets no
padding token; the -pre-decay and Falcon3-Mamba configs set eos_token_id to 0.
Falcon-Mamba (FalconMambaForCausalLM): Mamba-1 with normed scan inputs.
Mamba's tree and block: backbone.{embeddings, layers[i].{norm, mixer}, norm_f} plus lm_head, a pre-norm and a selective-scan mixer per block,
no attention and no MLP (see nnterp.families.mamba). What differs is inside
the mixer: weightless RMS norms (dt_layernorm, b_layernorm,
c_layernorm) on the step-size projection, B and C before the
scan. The values are read at the kernel call, after those norms, so
attention_keys and attention_queries are the normed B and C
the scan uses, and the base holds. The kernels are the same functions under
the same names, in Falcon-Mamba's own modeling module:
nnterp.route_kernels(model.family, "torch") routes them.