family cohere2
Command R's parallel block on one bias-free LayerNorm, with three sliding-window blocks to each full one; only the sliding blocks apply rotary, and the logits are the head's output times logit_scale.
One block of the stack. Hover any part for its nnterp name; click to pin the card. The slider picks a block; this family's blocks differ by layer_types.
One block of the stack. Hover any part for its nnterp name; click to pin the card. The slider picks a block; this family's blocks differ by layer_types.
identity layers[i].input + self_attn.attention_output + mlp.mlp_output == layer_output
The image's path into the text model, then one block of the vision encoder. Hover any part for its nnterp name; click to pin the card.
post_layernorm, a LayerNorm over every patch after the last block, is vision.norm; vision.tower_output is its output.identity vision.layers[i].input + self_attn.attention_output + mlp.mlp_output == layer_output
⚠︎ marks a value this checkpoint has only under some load: hover it for the condition.
⚠︎ marks a value this checkpoint has only under some load: hover it for the condition.
the vision encoder · SigLIP
What print(model) shows on mlx-community/c4ai-command-r7b-12-2024-bf16: the native modules, standard names and every standard value with its layout.
Cohere2ForCausalLM(
(lm_head): Linear(in_features=4096, out_features=256000, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(256000, 4096, padding_idx=0)
(layers): ModuleList(
(0-31): 32 x Cohere2DecoderLayer(
(self_attn): Cohere2Attention(
(q_proj): Linear(in_features=4096, out_features=4096, bias=False)
(k_proj): Linear(in_features=4096, out_features=1024, bias=False)
(v_proj): Linear(in_features=4096, out_features=1024, bias=False)
(o_proj): Linear(in_features=4096, out_features=4096, bias=False)
(attention_queries) -> Queries [batch num_heads seq qk_head_dim]: The queries entering attention
(attention_keys) -> Keys [batch num_kv_heads seq qk_head_dim]: The keys entering attention
(attention_values) -> Values [batch num_kv_heads seq head_dim]: The values entering attention
(attention_scores) -> Pattern [batch num_heads query key]: The attention scores entering the softmax, masked
(attention_premix) -> HeadOutputs [batch seq num_heads head_dim]: Every head's output side by side, as the output projection takes it
(attention_output) -> Residual [batch seq hidden_size]: What the attention adds to the residual stream
(attention_probabilities) -> Pattern [batch num_heads query key]: The attention pattern the values are mixed with
(attention_head_outputs) -> HeadOutputs [batch seq num_heads head_dim]: The per-head outputs before the output projection
)
(mlp): Cohere2MLP(
(gate_proj): Linear(in_features=4096, out_features=14336, bias=False)
(up_proj): Linear(in_features=4096, out_features=14336, bias=False)
(down_proj): Linear(in_features=14336, out_features=4096, bias=False)
(act_fn): SiLUActivation()
(mlp_activation) -> Neurons [batch seq intermediate_size]: The activation function's output
(mlp_neurons) -> Neurons [batch seq intermediate_size]: What the down projection receives: act(gate)·up on a gated MLP, the activation itself otherwise
(mlp_output) -> Residual [batch seq hidden_size]: What the MLP adds to the residual stream
)
(input_layernorm): Cohere2LayerNorm()
(layer_mid): Unavailable: a parallel block: the attention and the MLP read the same input, so there is no stream between them
(mlp_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the MLP: the one norm feeds both sublayers
(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_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): Cohere2LayerNorm()
(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 unsloth/c4ai-command-a-03-2025: the native modules, standard names and every standard value with its layout.
Cohere2ForCausalLM(
(lm_head): Linear(in_features=12288, out_features=256000, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(256000, 12288, padding_idx=0)
(layers): ModuleList(
(0-63): 64 x Cohere2DecoderLayer(
(self_attn): Cohere2Attention(
(q_proj): Linear(in_features=12288, out_features=12288, bias=False)
(k_proj): Linear(in_features=12288, out_features=1024, bias=False)
(v_proj): Linear(in_features=12288, out_features=1024, bias=False)
(o_proj): Linear(in_features=12288, out_features=12288, bias=False)
(attention_queries) -> Queries [batch num_heads seq qk_head_dim]: The queries entering attention
(attention_keys) -> Keys [batch num_kv_heads seq qk_head_dim]: The keys entering attention
(attention_values) -> Values [batch num_kv_heads seq head_dim]: The values entering attention
(attention_scores) -> Pattern [batch num_heads query key]: The attention scores entering the softmax, masked
(attention_premix) -> HeadOutputs [batch seq num_heads head_dim]: Every head's output side by side, as the output projection takes it
(attention_output) -> Residual [batch seq hidden_size]: What the attention adds to the residual stream
(attention_probabilities) -> Pattern [batch num_heads query key]: The attention pattern the values are mixed with
(attention_head_outputs) -> HeadOutputs [batch seq num_heads head_dim]: The per-head outputs before the output projection
)
(mlp): Cohere2MLP(
(gate_proj): Linear(in_features=12288, out_features=36864, bias=False)
(up_proj): Linear(in_features=12288, out_features=36864, bias=False)
(down_proj): Linear(in_features=36864, out_features=12288, bias=False)
(act_fn): SiLUActivation()
(mlp_activation) -> Neurons [batch seq intermediate_size]: The activation function's output
(mlp_neurons) -> Neurons [batch seq intermediate_size]: What the down projection receives: act(gate)·up on a gated MLP, the activation itself otherwise
(mlp_output) -> Residual [batch seq hidden_size]: What the MLP adds to the residual stream
)
(input_layernorm): Cohere2LayerNorm()
(layer_mid): Unavailable: a parallel block: the attention and the MLP read the same input, so there is no stream between them
(mlp_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the MLP: the one norm feeds both sublayers
(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_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): Cohere2LayerNorm()
(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 unsloth/aya-vision-8b: the native modules, standard names and every standard value with its layout.
AyaVisionForConditionalGeneration(
(lm_head): Linear(in_features=4096, out_features=256000, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(256000, 4096, padding_idx=0)
(layers): ModuleList(
(0-31): 32 x Cohere2DecoderLayer(
(self_attn): Cohere2Attention(
(q_proj): Linear(in_features=4096, out_features=4096, bias=False)
(k_proj): Linear(in_features=4096, out_features=1024, bias=False)
(v_proj): Linear(in_features=4096, out_features=1024, bias=False)
(o_proj): Linear(in_features=4096, out_features=4096, bias=False)
(attention_queries) -> Queries [batch num_heads seq qk_head_dim]: The queries entering attention
(attention_keys) -> Keys [batch num_kv_heads seq qk_head_dim]: The keys entering attention
(attention_values) -> Values [batch num_kv_heads seq head_dim]: The values entering attention
(attention_scores) -> Pattern [batch num_heads query key]: The attention scores entering the softmax, masked
(attention_premix) -> HeadOutputs [batch seq num_heads head_dim]: Every head's output side by side, as the output projection takes it
(attention_output) -> Residual [batch seq hidden_size]: What the attention adds to the residual stream
(attention_probabilities) -> Pattern [batch num_heads query key]: The attention pattern the values are mixed with
(attention_head_outputs) -> HeadOutputs [batch seq num_heads head_dim]: The per-head outputs before the output projection
)
(mlp): Cohere2MLP(
(gate_proj): Linear(in_features=4096, out_features=14336, bias=False)
(up_proj): Linear(in_features=4096, out_features=14336, bias=False)
(down_proj): Linear(in_features=14336, out_features=4096, bias=False)
(act_fn): SiLUActivation()
(mlp_activation) -> Neurons [batch seq intermediate_size]: The activation function's output
(mlp_neurons) -> Neurons [batch seq intermediate_size]: What the down projection receives: act(gate)·up on a gated MLP, the activation itself otherwise
(mlp_output) -> Residual [batch seq hidden_size]: What the MLP adds to the residual stream
)
(input_layernorm): Cohere2LayerNorm()
(layer_mid): Unavailable: a parallel block: the attention and the MLP read the same input, so there is no stream between them
(mlp_norm_output) -> Residual [batch seq hidden_size]: The normed stream entering the MLP: the one norm feeds both sublayers
(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_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): Cohere2LayerNorm()
(vision): SiglipVisionModel(
(embeddings): SiglipVisionEmbeddings(
(patch_embedding): Conv2d(3, 1152, kernel_size=(14, 14), stride=(14, 14), padding=valid)
(position_embedding): Embedding(676, 1152)
)
(norm/post_layernorm): LayerNorm((1152,), eps=1e-06, elementwise_affine=True, bias=True)
(patch_embed): Conv2d(3, 1152, kernel_size=(14, 14), stride=(14, 14), padding=valid)
(layers): ModuleList(
(0-26): 27 x SiglipEncoderLayer(
(input_layernorm/layer_norm1): LayerNorm((1152,), eps=1e-06, elementwise_affine=True, bias=True)
(self_attn): SiglipAttention(
(k_proj): Linear(in_features=1152, out_features=1152, bias=True)
(v_proj): Linear(in_features=1152, out_features=1152, bias=True)
(q_proj): Linear(in_features=1152, out_features=1152, bias=True)
(o_proj/out_proj): Linear(in_features=1152, out_features=1152, bias=True)
(attention_output) -> Patches [images patches vision_hidden_size]: What the attention adds to the tower's stream
(attention_premix) -> HeadOutputs [batch seq num_heads head_dim]: Every head's output side by side, as the output projection takes it
(attention_queries) -> Queries [batch num_heads seq qk_head_dim]: The queries entering attention
(attention_keys) -> Keys [batch num_kv_heads seq qk_head_dim]: The keys entering attention
(attention_values) -> Values [batch num_kv_heads seq head_dim]: The values entering attention
(attention_scores) -> Pattern [batch num_heads query key]: The attention scores entering the softmax, masked
(attention_probabilities) -> Pattern [batch num_heads query key]: The attention pattern the values are mixed with
(attention_head_outputs) -> HeadOutputs [batch seq num_heads head_dim]: The per-head outputs before the output projection
)
(post_attention_layernorm/layer_norm2): LayerNorm((1152,), eps=1e-06, elementwise_affine=True, bias=True)
(mlp): SiglipMLP(
(act_fn/activation_fn): GELUTanh()
(fc1): Linear(in_features=1152, out_features=4304, bias=True)
(down_proj/fc2): Linear(in_features=4304, out_features=1152, bias=True)
(mlp_output) -> Patches [images patches vision_hidden_size]: What the MLP adds to the tower's stream
(mlp_activation) -> Neurons [batch seq intermediate_size]: The activation function's output
(mlp_neurons) -> Neurons [batch seq intermediate_size]: What the down projection receives
)
(layer_input) -> Patches [images patches vision_hidden_size]: The tower's stream entering the block
(attention_norm_output) -> Patches [images patches vision_hidden_size]: The normed stream entering the attention
(layer_mid) -> Patches [images patches vision_hidden_size]: The tower's stream after the attention add
(mlp_norm_output) -> Patches [images patches vision_hidden_size]: The normed stream entering the MLP
(mlp_input) -> Patches [images patches vision_hidden_size]: What the MLP is called with
(layer_output) -> Patches [images patches vision_hidden_size]: The tower's stream leaving the block
)
)
(image_token_mask) -> ImageTokenMask [batch seq]: Which positions hold image tokens: input_ids == the config's image_token_id; read-only
(patch_embeddings) -> Patches [images patches vision_hidden_size]: The patch embedding's output, one row per patch
(tower_output) -> Patches [images patches vision_hidden_size]: The last block's stream after the tower's final norm, before any pooling or adapter
(image_features) -> ImageFeatures [image_tokens hidden_size]: The image features the text model receives at the image tokens, flat over them
)
(projector): AyaVisionMultiModalProjector(
(layernorm): LayerNorm((4608,), eps=1e-06, elementwise_affine=True, bias=True)
(linear_1): Linear(in_features=4608, out_features=28672, bias=True)
(act): SiLUActivation()
(linear_2): Linear(in_features=14336, out_features=4096, bias=True)
)
(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
)h = input_layernorm(x)
out = x + self_attn(h) + mlp(h)
The block is Command R's: input_layernorm is its only norm, a LayerNorm with a weight and no
bias, computed in float32. Its one output tensor is passed to the attention and then to the MLP,
so self_attn.input and mlp.input are the same tensor: an in-place edit of self_attn.input
also changes what the MLP reads, and assigning input_layernorm.output changes what both read.
attention_output is o_proj's output and mlp_output is down_proj's. The block computes
residual + attn + mlp, so that sum reproduces layer_output bit for bit; summed in another
order it differs by rounding. Zeroing attention_output leaves that block's mlp.input unchanged.
with model.trace(prompt):
x = model.layers[1].input.save()
attn = model.layers[1].self_attn.attention_output.save()
mlp = model.layers[1].mlp.mlp_output.save()
out = model.layers[1].layer_output.save()
assert torch.equal(x + attn + mlp, out) # the block's own order
config.layer_types is full_attention on every fourth block (3, 7, ..., 31 of Command R7B's 32 blocks)
and sliding_attention elsewhere. A sliding block attends over a window of 4096 tokens; on a
prompt no longer than the window both masks are the same causal mask. To tell the kinds apart outside a trace, read
model.layers[i].self_attn._module.sliding_window: the window on a sliding block, None on a full one.
Only the sliding blocks apply the rotary. A full block has no position encoding: its
attention_queries and attention_keys are q_proj's and k_proj's outputs split into heads,
and only the causal mask orders the tokens there. On a sliding block they are read after the
rotary, which turns adjacent pairs of dimensions (2i with 2i + 1) at base 50,000.
full = model.config.layer_types.index("full_attention")
with model.trace(prompt):
k_proj = model.layers[full].self_attn.k_proj.output.save()
with model.trace(prompt):
keys = model.layers[full].self_attn.attention_keys.save()
heads = k_proj.view(*k_proj.shape[:2], -1, model.head_dim).transpose(1, 2)
assert torch.equal(heads, keys) # no rotary on a full block
Command R7B has 32 query heads and 8 key/value heads, Command A 96 and 8, so an edit to a key or
value head reaches 4 or 12 query heads; attention_keys and attention_values are served before
repeat_kv. The query scale is head_dim ** -0.5 (128). Both kinds of block make the same
attention-interface call, so every interior value resolves on every block, under
attn_implementation="eager" (the values marked ⚠). There are no query or key norms.
logit_scalelm_head is the embedding matrix (tie_word_embeddings), and the model multiplies its output by
config.logit_scale, 0.25 on Command R7B and Command A. logits is the scaled tensor and
lm_head.output the unscaled one. The family imports Command R's project_on_vocab (the final
norm, lm_head, the scale), so a logit lens on the last block equals logits exactly.
with model.trace(prompt):
resid = model.layers[-1].layer_output.save()
raw = model.lm_head.output.save()
logits = model.logits.save()
assert torch.equal(logits, raw * model.config.logit_scale)
assert torch.equal(model.project_on_vocab(resid), logits)
aya_vision and cohere2_vision checkpoints load with task="image-text-to-text". nnterp picks this
family from config.text_config and binds embed_tokens, layers and norm under
model.language_model, with lm_head at the root. The vision encoder is SigLIP at
model.vision_tower. The image features replace the image tokens' embeddings after
embed_tokens, so at those positions token_embeddings is the placeholder token's embedding and
layers[0].input holds the projected image features; at text positions the two are equal. embed_tokens runs before
the vision encoder, so read token_embeddings before any vision value in a trace.
No class token: vision.patch_embeddings, every block's layer_output and vision.tower_output have
the same length, (image_size // patch_size) ** 2 patches per image or tile, in raster order. Row r,
column c of the grid is index r * (image_size // patch_size) + c on every value of the vision encoder.
vision.normpost_layernorm norms every patch after the last block, so
vision.tower_output == vision.norm(vision.layers[-1].layer_output). Each wrapper's notes say whether its
projector reads tower_output or a block's layer_output before the norm.
vision.normvision_feature_layer is -1 and vision_feature_select_strategy is "full": the projector
receives the vision encoder's last hidden state, vision.layers[-1].layer_output, every patch kept.
post_layernorm (vision.norm) runs after it and vision.tower_output is computed and discarded:
on the pinned tiny wrapper zeroing tower_output leaves vision.image_features bit-identical, and
zeroing the last block's layer_output changes them.
with model.trace(prompt, images=[image]):
mask = model.vision.image_token_mask.save()
last = model.vision.layers[-1].layer_output.save()
fed = model.projector.input.save()
features = model.vision.image_features.save()
first = model.layers[0].input.save()
torch.equal(fed, last) # True: block -1, before vision.norm
torch.equal(first[mask], features) # True: the scatter
downsample_factor is 2: the projector lays a tile's patches out as their grid and stacks each
2 × 2 neighborhood into one vector four times as wide, so a tile's (image_size // patch_size) ** 2
patches become a quarter as many image tokens. linear_1 maps that vector to
alignment_intermediate_size, its two halves are combined as a SwiGLU (silu(gate) * x), and
linear_2 maps the result to the text model's hidden_size. model.projector.output keeps the
grid, [tiles, rows, columns, hidden_size]; vision.image_features is it flattened over the tiles
and the grid, and those are the rows the scatter writes.
On Aya Vision the shuffled vector is normed first: model.projector.layernorm, a LayerNorm with a
bias over the 4 × vision_hidden_size channels, precedes linear_1.
Aya Vision 8B's vision encoder takes 364-pixel tiles in 14-pixel patches, 26 × 26 = 676 patches, and the shuffle makes 13 × 13 = 169 image tokens per tile.
The processor cuts an image into up to max_patches (12) tiles of image_size pixels, each a row
of the vision encoder's batch, and adds a thumbnail of the whole image as a last tile when there is
more than one. On the pinned tiny wrapper a square image is one tile and a 2 : 1 image three (two
tiles and the thumbnail); each tile gives 16 image tokens there (8 × 8 patches, shuffled to 4 × 4).
The tile markers the prompt carries around each run of image tokens are text tokens:
vision.image_token_mask marks only the image tokens.
Cohere 2 (Cohere2ForCausalLM, Command-R7B / Command-A).
Cohere's tree and parallel block (x + attn + mlp from one LayerNorm), with
sliding-window and full attention layers interleaved (config.layer_types).
Only the sliding layers apply the rotary; the full layers use no position
encoding. Both kinds make the same attention_interface call, so every
interior value resolves on every block, and on a full layer
attention_queries / attention_keys are the unrotated projections.
The model multiplies the head's output by config.logit_scale, as Cohere's
does, so the family takes Cohere's project_on_vocab.
Aya Vision and Cohere2-Vision put a SigLIP tower at model.vision_tower, which is
vision (its post_layernorm over the patches is vision.norm), and a
pixel-shuffling projector model.multi_modal_projector, which is projector;
vision.image_features is read at the scatter (ImageScatter). Aya Vision's
projector reads the last block's layer_output before vision.norm
(vision_feature_layer -1, strategy "full") and norms after its pixel shuffle;
Cohere2-Vision's reads vision.tower_output and has no norm. Aya Vision 32B's text
config is cohere, so it loads through that family, which binds no tower.