family qwen2_5_vl_text
Qwen2's block, biased q, k and v, with multimodal rotary embeddings: three position streams (time, row, column) folded into one cos/sin before block 0, so an image token's position is its row and column in the image.
One block of the stack. Hover any part for its nnterp name; click to pin the card.
One block of the stack. Hover any part for its nnterp name; click to pin the card.
One block of the stack. Hover any part for its nnterp name; click to pin the card.
One block of the stack. Hover any part for its nnterp name; click to pin the card.
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.
[1, patches, vision_hidden_size], split per image by the processor's image_grid_thw. Each image's patches are in merge-block order (each 2 × 2 block the merger folds is consecutive), and on Qwen2.5-VL in window order inside the vision encoder.pos_embed, resampled to each image's grid, after patch_embed.vision.norm.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.
the vision encoder · Qwen ViT
What print(model) shows on Qwen/Qwen2.5-VL-3B-Instruct: the native modules, standard names and every standard value with its layout.
Qwen2_5_VLForConditionalGeneration(
(lm_head): Linear(in_features=2048, out_features=151936, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(151936, 2048)
(layers): ModuleList(
(0-35): 36 x Qwen2_5_VLDecoderLayer(
(self_attn): Qwen2_5_VLAttention(
(q_proj): Linear(in_features=2048, out_features=2048, bias=True)
(k_proj): Linear(in_features=2048, out_features=256, bias=True)
(v_proj): Linear(in_features=2048, out_features=256, bias=True)
(o_proj): Linear(in_features=2048, out_features=2048, 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): Qwen2MLP(
(gate_proj): Linear(in_features=2048, out_features=11008, bias=False)
(up_proj): Linear(in_features=2048, out_features=11008, bias=False)
(down_proj): Linear(in_features=11008, out_features=2048, 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): Qwen2_5_VLRMSNorm((2048,), eps=1e-06)
(post_attention_layernorm): Qwen2_5_VLRMSNorm((2048,), eps=1e-06)
(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
(layer_mid) -> Residual [batch seq hidden_size]: The residual stream after the attention add
(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): Qwen2_5_VLRMSNorm((2048,), eps=1e-06)
(vision): Qwen2_5_VisionTransformerPretrainedModel(
(patch_embed): Qwen2_5_VisionPatchEmbed(
(proj): Conv3d(3, 1280, kernel_size=(2, 14, 14), stride=(2, 14, 14), bias=False)
)
(rotary_pos_emb): Qwen2_5_VLVisionRotaryEmbedding()
(layers/blocks): ModuleList(
(0-31): 32 x Qwen2_5_VLVisionBlock(
(input_layernorm/norm1): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(post_attention_layernorm/norm2): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(self_attn/attn): Qwen2_5_VLVisionAttention(
(qkv): Linear(in_features=1280, out_features=3840, bias=True)
(o_proj/proj): Linear(in_features=1280, out_features=1280, bias=True)
(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_head_outputs) -> HeadOutputs [batch seq num_heads head_dim]: The per-head outputs before the output projection
(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_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
)
(mlp): Qwen2_5_VLMLP(
(gate_proj): Linear(in_features=1280, out_features=3420, bias=True)
(up_proj): Linear(in_features=1280, out_features=3420, bias=True)
(down_proj): Linear(in_features=3420, out_features=1280, bias=True)
(act_fn): SiLUActivation()
(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
)
)
(merger): Qwen2_5_VLPatchMerger(
(ln_q): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(mlp): Sequential(
(0): Linear(in_features=5120, out_features=5120, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=5120, out_features=2048, bias=True)
)
)
(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): Qwen2_5_VLPatchMerger(
(ln_q): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(mlp): Sequential(
(0): Linear(in_features=5120, out_features=5120, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=5120, out_features=2048, 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
)What print(model) shows on Qwen/Qwen2.5-VL-7B-Instruct: the native modules, standard names and every standard value with its layout.
Qwen2_5_VLForConditionalGeneration(
(lm_head): Linear(in_features=3584, out_features=152064, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(152064, 3584)
(layers): ModuleList(
(0-27): 28 x Qwen2_5_VLDecoderLayer(
(self_attn): Qwen2_5_VLAttention(
(q_proj): Linear(in_features=3584, out_features=3584, bias=True)
(k_proj): Linear(in_features=3584, out_features=512, bias=True)
(v_proj): Linear(in_features=3584, out_features=512, bias=True)
(o_proj): Linear(in_features=3584, out_features=3584, 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): Qwen2MLP(
(gate_proj): Linear(in_features=3584, out_features=18944, bias=False)
(up_proj): Linear(in_features=3584, out_features=18944, bias=False)
(down_proj): Linear(in_features=18944, out_features=3584, 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): Qwen2_5_VLRMSNorm((3584,), eps=1e-06)
(post_attention_layernorm): Qwen2_5_VLRMSNorm((3584,), eps=1e-06)
(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
(layer_mid) -> Residual [batch seq hidden_size]: The residual stream after the attention add
(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): Qwen2_5_VLRMSNorm((3584,), eps=1e-06)
(vision): Qwen2_5_VisionTransformerPretrainedModel(
(patch_embed): Qwen2_5_VisionPatchEmbed(
(proj): Conv3d(3, 1280, kernel_size=(2, 14, 14), stride=(2, 14, 14), bias=False)
)
(rotary_pos_emb): Qwen2_5_VLVisionRotaryEmbedding()
(layers/blocks): ModuleList(
(0-31): 32 x Qwen2_5_VLVisionBlock(
(input_layernorm/norm1): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(post_attention_layernorm/norm2): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(self_attn/attn): Qwen2_5_VLVisionAttention(
(qkv): Linear(in_features=1280, out_features=3840, bias=True)
(o_proj/proj): Linear(in_features=1280, out_features=1280, bias=True)
(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_head_outputs) -> HeadOutputs [batch seq num_heads head_dim]: The per-head outputs before the output projection
(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_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
)
(mlp): Qwen2_5_VLMLP(
(gate_proj): Linear(in_features=1280, out_features=3420, bias=True)
(up_proj): Linear(in_features=1280, out_features=3420, bias=True)
(down_proj): Linear(in_features=3420, out_features=1280, bias=True)
(act_fn): SiLUActivation()
(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
)
)
(merger): Qwen2_5_VLPatchMerger(
(ln_q): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(mlp): Sequential(
(0): Linear(in_features=5120, out_features=5120, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=5120, out_features=3584, bias=True)
)
)
(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): Qwen2_5_VLPatchMerger(
(ln_q): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(mlp): Sequential(
(0): Linear(in_features=5120, out_features=5120, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=5120, out_features=3584, 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
)What print(model) shows on Qwen/Qwen2.5-VL-32B-Instruct: the native modules, standard names and every standard value with its layout.
Qwen2_5_VLForConditionalGeneration(
(lm_head): Linear(in_features=5120, out_features=152064, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(152064, 5120, padding_idx=151643)
(layers): ModuleList(
(0-63): 64 x Qwen2_5_VLDecoderLayer(
(self_attn): Qwen2_5_VLAttention(
(q_proj): Linear(in_features=5120, out_features=5120, bias=True)
(k_proj): Linear(in_features=5120, out_features=1024, bias=True)
(v_proj): Linear(in_features=5120, out_features=1024, bias=True)
(o_proj): Linear(in_features=5120, out_features=5120, 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): Qwen2MLP(
(gate_proj): Linear(in_features=5120, out_features=27648, bias=False)
(up_proj): Linear(in_features=5120, out_features=27648, bias=False)
(down_proj): Linear(in_features=27648, out_features=5120, 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): Qwen2_5_VLRMSNorm((5120,), eps=1e-06)
(post_attention_layernorm): Qwen2_5_VLRMSNorm((5120,), eps=1e-06)
(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
(layer_mid) -> Residual [batch seq hidden_size]: The residual stream after the attention add
(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): Qwen2_5_VLRMSNorm((5120,), eps=1e-06)
(vision): Qwen2_5_VisionTransformerPretrainedModel(
(patch_embed): Qwen2_5_VisionPatchEmbed(
(proj): Conv3d(3, 1280, kernel_size=(2, 14, 14), stride=(2, 14, 14), bias=False)
)
(rotary_pos_emb): Qwen2_5_VLVisionRotaryEmbedding()
(layers/blocks): ModuleList(
(0-31): 32 x Qwen2_5_VLVisionBlock(
(input_layernorm/norm1): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(post_attention_layernorm/norm2): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(self_attn/attn): Qwen2_5_VLVisionAttention(
(qkv): Linear(in_features=1280, out_features=3840, bias=True)
(o_proj/proj): Linear(in_features=1280, out_features=1280, bias=True)
(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_head_outputs) -> HeadOutputs [batch seq num_heads head_dim]: The per-head outputs before the output projection
(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_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
)
(mlp): Qwen2_5_VLMLP(
(gate_proj): Linear(in_features=1280, out_features=3456, bias=True)
(up_proj): Linear(in_features=1280, out_features=3456, bias=True)
(down_proj): Linear(in_features=3456, out_features=1280, bias=True)
(act_fn): SiLUActivation()
(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
)
)
(merger): Qwen2_5_VLPatchMerger(
(ln_q): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(mlp): Sequential(
(0): Linear(in_features=5120, out_features=5120, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=5120, out_features=5120, bias=True)
)
)
(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): Qwen2_5_VLPatchMerger(
(ln_q): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(mlp): Sequential(
(0): Linear(in_features=5120, out_features=5120, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=5120, out_features=5120, 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
)What print(model) shows on Qwen/Qwen2.5-VL-72B-Instruct: the native modules, standard names and every standard value with its layout.
Qwen2_5_VLForConditionalGeneration(
(lm_head): Linear(in_features=8192, out_features=152064, bias=False)
(generator): Generator(
(streamer): Streamer()
)
(embed_tokens): Embedding(152064, 8192)
(layers): ModuleList(
(0-79): 80 x Qwen2_5_VLDecoderLayer(
(self_attn): Qwen2_5_VLAttention(
(q_proj): Linear(in_features=8192, out_features=8192, bias=True)
(k_proj): Linear(in_features=8192, out_features=1024, bias=True)
(v_proj): Linear(in_features=8192, out_features=1024, bias=True)
(o_proj): Linear(in_features=8192, out_features=8192, 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): Qwen2MLP(
(gate_proj): Linear(in_features=8192, out_features=29568, bias=False)
(up_proj): Linear(in_features=8192, out_features=29568, bias=False)
(down_proj): Linear(in_features=29568, out_features=8192, 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): Qwen2_5_VLRMSNorm((8192,), eps=1e-06)
(post_attention_layernorm): Qwen2_5_VLRMSNorm((8192,), eps=1e-06)
(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
(layer_mid) -> Residual [batch seq hidden_size]: The residual stream after the attention add
(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): Qwen2_5_VLRMSNorm((8192,), eps=1e-06)
(vision): Qwen2_5_VisionTransformerPretrainedModel(
(patch_embed): Qwen2_5_VisionPatchEmbed(
(proj): Conv3d(3, 1280, kernel_size=(2, 14, 14), stride=(2, 14, 14), bias=False)
)
(rotary_pos_emb): Qwen2_5_VLVisionRotaryEmbedding()
(layers/blocks): ModuleList(
(0-31): 32 x Qwen2_5_VLVisionBlock(
(input_layernorm/norm1): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(post_attention_layernorm/norm2): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(self_attn/attn): Qwen2_5_VLVisionAttention(
(qkv): Linear(in_features=1280, out_features=3840, bias=True)
(o_proj/proj): Linear(in_features=1280, out_features=1280, bias=True)
(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_head_outputs) -> HeadOutputs [batch seq num_heads head_dim]: The per-head outputs before the output projection
(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_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
)
(mlp): Qwen2_5_VLMLP(
(gate_proj): Linear(in_features=1280, out_features=3456, bias=True)
(up_proj): Linear(in_features=1280, out_features=3456, bias=True)
(down_proj): Linear(in_features=3456, out_features=1280, bias=True)
(act_fn): SiLUActivation()
(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
)
)
(merger): Qwen2_5_VLPatchMerger(
(ln_q): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(mlp): Sequential(
(0): Linear(in_features=5120, out_features=5120, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=5120, out_features=8192, bias=True)
)
)
(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): Qwen2_5_VLPatchMerger(
(ln_q): Qwen2_5_VLRMSNorm((1280,), eps=1e-06)
(mlp): Sequential(
(0): Linear(in_features=5120, out_features=5120, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=5120, out_features=8192, 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
)The text block is Qwen2's: a pre-norm attention whose q_proj, k_proj and v_proj add a bias
(o_proj has none), then a SwiGLU MLP with no biases, each behind an RMSNorm.
a = input_layernorm(x)
h = x + o_proj(attn(rope(q_proj(a)), rope(k_proj(a)), v_proj(a)))
out = h + mlp(post_attention_layernorm(h)) # SwiGLU, no biases
The block returns a tensor and adds both sublayers' outputs to the stream, so the identity is the plain sum:
with model.trace(prompt, images=[image]):
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()
torch.testing.assert_close(x + attn + mlp, out)
The wrapper passes the text model position_ids of [3, batch, seq]: a temporal, a height and a
width position per token. On text the three are equal and count up. Every token of an image
takes the image's start position as its temporal position; its height and width positions are
that start plus its row and its column in the image's grid of merged tokens. The text after an
image resumes one past the image's largest position, so an image h tokens high and w wide advances the positions by
max(h, w), not by h * w: after an image, a token's position is less than its index.
rotary = model.model.language_model.rotary_emb
with model.trace(prompt, images=[image]):
mask = model.vision.image_token_mask.save()
positions = rotary.inputs[0][1].save() # [3, batch, seq]: time, height, width
positions[:, 0, mask[0]] # the image tokens' three positions
rotary_emb folds the three into one cos/sin by mrope_section, [16, 24, 24] on every
checkpoint. Of each head's 64 rotary frequencies, the first 16 turn with the temporal position, the
next 24 with the height and the last 24 with the width. In a 128-wide head, dimensions 0 to 15 and
64 to 79 therefore carry time, 16 to 39 and 80 to 103 the row, and 40 to 63 and 104 to 127 the
column. The attention applies that pair with rotate_half before the attention interface, so attention_queries and
attention_keys are the rotated queries and keys, and on a prompt with no image the rotation is the
ordinary rotary one. rope_theta is 10⁶.
3B has 16 query heads over 2 key/value heads, 7B 28 over 4, 32B 40 over 8, 72B 64 over 8;
head_dim is 128 on all four. An edit to key/value head j on 3B reaches query heads 8j to
8j + 7. The score
scale is head_dim ** -0.5; there is no window and no softcap. On the text blocks the six attention
interior values need attn_implementation="eager". On the vision encoder's blocks
attention_scores and attention_probabilities are unavailable under every implementation.
The wrapper writes vision.image_features into the token embeddings at the image tokens before
block 0, so token_embeddings holds the <|image_pad|> embedding there and layers[0].input the
features: they agree at the text positions only. layers[0].input[vision.image_token_mask] ==
vision.image_features holds exactly. To ablate or patch the image as the text model receives it,
edit vision.image_features:
with model.trace(prompt, images=[image]):
model.vision.image_features[:] = 0
ablated = model.logits.save()
model.logits equals model.lm_head.output. On 3B the embedding and the unembedding are one
matrix (tie_word_embeddings), so an edit to embed_tokens.weight edits lm_head; 7B, 32B and 72B
have their own.
The tokenizer prepends no BOS (bos_token is None). Given no system message, the template
writes You are a helpful assistant., so a templated prompt opens with a system turn and
position 0 is <|im_start|>. The generation configs end on <|im_end|> (151645) or
<|endoftext|> (151643).
Every checkpoint here is Qwen2_5_VLForConditionalGeneration (model_type qwen2_5_vl) with a
text_config of model_type qwen2_5_vl_text. transformers registers no causal-LM class for it, so
every load is the wrapper with its processor, task="image-text-to-text": the text model at
model.language_model, the vision encoder at model.visual as model.vision. The text model's
names and values are the same whether or not a prompt carries an image.
The vision encoder runs on [patches, vision_hidden_size], the patches of every image in the invoke
concatenated. Its stream values (patch_embeddings, every block's layer_output,
attention_output and mlp_output, tower_output) are served [1, patches, vision_hidden_size], a view with a
leading images axis of 1, so in-place edits land; vision.layers[i].input and .output stay the
native [patches, vision_hidden_size], and the block identity holds across the two by broadcasting. The
processor's image_grid_thw ([t, h, w] per image, in patches; an image is two identical frames, so
t is 1) splits the row: image j has t * h * w patches.
inputs = model.processor(text=prompt, images=[red, wide], return_tensors="pt")
sizes = inputs["image_grid_thw"].prod(-1).tolist() # patches per image
with model.trace(prompt, images=[red, wide]):
patches = model.vision.layers[1].layer_output.save()
per_image = patches[0].split(sizes) # one [t*h*w, vision_hidden_size] each
Inside an image the patches are in merge-block order: the spatial_merge_size ×
spatial_merge_size (2 × 2) block of neighbours the merger folds into one image token is four
consecutive rows, blocks in raster order. Index 4 * b to 4 * b + 3 is block b, not a raster row.
The attention computes queries, keys and values for the whole row, then calls the attention
function once per image (once per window on Qwen2.5-VL's windowed blocks) and concatenates the
outputs. attention_queries, attention_keys and attention_values are served whole, before the
split, [1, heads, patches, head_dim], the queries and keys after the rotary embedding;
attention_head_outputs is the calls' outputs concatenated back, [1, patches, heads, head_dim]
(under any implementation but flash, which runs one call over cu_seqlens). attention_scores and
attention_probabilities are Unavailable under every implementation, eager included: "no one
tensor is the block's pattern". The split points are the attention's cu_seqlens argument,
self_attn.inputs[1]["cu_seqlens"], so a pattern per image is a softmax over each slice:
attn = model.vision.layers[1].self_attn
with model.trace(prompt, images=[red, wide]):
cu = attn.inputs[1]["cu_seqlens"].save() # read first: the module's input
q = attn.attention_queries.save()
k = attn.attention_keys.save()
patterns = []
for a, b in zip(cu[:-1].tolist(), cu[1:].tolist()):
scores = q[0, :, a:b] @ k[0, :, a:b].transpose(-1, -2) * model.vision.head_dim ** -0.5
patterns.append(scores.softmax(-1)) # [heads, patches_j, patches_j]
Each pattern times that image's values reproduces attention_head_outputs exactly (checked on
Qwen3.5's pinned tiny checkpoint).
model.projector is the vision encoder's own merger: it norms each patch, concatenates each 2 × 2
block into one 4 * vision_hidden_size vector and runs a two-layer MLP to the text model's width, so
image tokens per image are t * h * w / 4. It reads the last block's stream with no norm between
(projector.input == tower_output[0], the native [patches, vision_hidden_size]). Because the merger
runs inside the vision encoder's forward, vision.tower_output (the encoder's output) is reached after
it: read model.projector.input and .output before vision.tower_output in a trace.
image_sizemodel.vision reads its sizes off the vision config: vision_hidden_size is the encoder's width
(embed_dim on Qwen2-VL, whose config's hidden_size is the merger's output width),
num_heads, intermediate_size (embed_dim * mlp_ratio on Qwen2-VL), patch_size, and two of
its own, spatial_merge_size (2 on every line) and window_size (Qwen2.5-VL's window side in
pixels, 112; None on the others). image_size raises Unavailable: the processor cuts each
image into its own grid.
| line | block norms, merger norm | MLP | beyond the shared encoder |
|---|---|---|---|
| Qwen2-VL | LayerNorm | fc1, QuickGELU, fc2 |
none |
| Qwen2.5-VL | RMSNorm | SwiGLU, biased | windows of 112 pixels except on fullatt_block_indexes |
| Qwen3-VL, -MoE | LayerNorm | linear_fc1, GELU (tanh), linear_fc2 |
learned pos_embed; DeepStack taps |
| Qwen3.5, -MoE | LayerNorm | linear_fc1, GELU (tanh), linear_fc2 |
learned pos_embed |
On Qwen2.5-VL the encoder permutes the patches into windows at entry, so its blocks' values,
tower_output and projector.output are in window order, and it restores the merge-block order
after the merger: vision.image_features is in scatter order. On Qwen3-VL and Qwen3.5 vision.layers[0].input
is patch_embeddings plus the resampled pos_embed. On Qwen2-VL vision.layers[0].input is
patch_embeddings; on Qwen2.5-VL it is patch_embeddings permuted into window order; on both, positions
enter only through the rotary embedding.
model.projector is model.visual.merger, the vision encoder's last module: ln_q (an RMSNorm
over vision_hidden_size) on each patch, then each 2 × 2 block of consecutive patches concatenated into
one 4 * vision_hidden_size vector, and mlp: Linear, GELU, Linear to the text model's width
(out_hidden_size). On every checkpoint the vision encoder is 1280 wide, so the merger maps 5120 to
5120 and then to 2048 (3B), 3584 (7B), 5120 (32B) or 8192 (72B). A patch is 14 pixels, so an image
token covers 28 × 28 pixels, and an image of t * h * w patches (its image_grid_thw row) is
t * h * w / 4 image tokens: 256 for a 448 × 448 image.
with model.trace(prompt, images=[image]):
mask = model.vision.image_token_mask.save()
fed = model.projector.input.save() # [patches, vision_hidden_size]
features = model.vision.image_features.save()
first = model.layers[0].input.save()
fed.shape[0] // 4 == mask.sum() # True: one image token per 2 x 2 block
torch.equal(first[mask], features) # True
The vision encoder cuts each image into windows of 112 × 112 pixels, 8 × 8 patches (smaller at the
image's right and bottom edges). Its blocks attend inside a window, except the blocks in
vision_config.fullatt_block_indexes, which attend over the whole image: 7, 15, 23 and 31 of the 32
on every checkpoint. On a windowed block self_attn.inputs[1]["cu_seqlens"] holds the windows'
bounds; on the others, the images'.
To make each window's patches consecutive, the encoder permutes the patches, a merge block at a
time, after patch_embed. vision.patch_embeddings is in merge-block order; vision.layers[0].input,
every block's values, vision.tower_output, model.projector.input and model.projector.output are
in window order. The encoder restores the order after the merger, so vision.image_features is in
the image tokens' order, and projector.output holds the same rows, permuted. The permutation is
transformers' window index, one entry per merge block:
from transformers.vision_utils import get_vision_window_index
vc = model.config.vision_config
grid = model.processor(text=prompt, images=[image], return_tensors="pt")["image_grid_thw"]
window_index, _ = get_vision_window_index(
grid, spatial_merge_size=vc.spatial_merge_size,
window_size=vc.window_size, patch_size=vc.patch_size)
order = window_index.argsort()
with model.trace(prompt, images=[image]):
patches = model.vision.layers[1].layer_output.save() # window order
merged = model.projector.output.save() # window order
features = model.vision.image_features.save() # token order
torch.equal(merged[order], features) # True
in_order = patches[0].unflatten(0, (-1, 4))[order].flatten(0, 1)
An image of one window, 112 × 112 pixels or less, has the two orders the same.
The processor expands each <|image_pad|> (151655) in the prompt to the image's token count, between
<|vision_start|> and <|vision_end|>; vision.image_token_mask marks the pads only. The chat
template writes the three for an {"type": "image"} entry.
Qwen2.5-VL, text (Qwen2_5_VLTextModel, model_type qwen2_5_vl_text).
The language model inside Qwen2_5_VLForConditionalGeneration (model_type
qwen2_5_vl): Qwen2's block under multimodal rotary embeddings (M-RoPE),
folded into one cos/sin pair before any block runs and applied inside
the attention before the shared interface, so the base Attention holds, as on
qwen2_vl_text. Every checkpoint loads as the wrapper
(task="image-text-to-text"), whose text stack sits at model.language_model.
The wrapper's Qwen ViT model.visual is vision (a QwenVision: packed,
[1, patches, vision_hidden_size], and in window order: the tower permutes the
patches into attention windows at entry and restores the order after the
merger, so the blocks' values and projector.output are in window order while
vision.image_features, read at the tower's output, is in the scatter's).