Safe By Design AI

LlavaNextForConditionalGeneration

LlavaNextForConditionalGeneration at 40 layers and hidden size 2048. 4 published checkpoints share this shape.

Implementing it

How to read this sheet: method.

No forward was recorded for this shape; the block is read from the published configuration and from LlavaNextForConditionalGeneration at transformers v4.57.1 (modelling, processor).

From granite-vision-3.3-2b

Also covers granite-vision-3.3-2b-chart2csv-preview.

# The image path: anyres tiles, four tower depths, one projector,
# then packing, then one scatter into the embedding.
tiles = [base_tile] + anyres_grid(image)  # 384x384 tiles; the grid is the
                                          #   `image_grid_pinpoints` entry
                                          #   that best fits the image
hs = vision_tower(tiles).hidden_states
f  = concat(hs[-24], hs[-20], hs[-12], hs[-1])   # [729, 4*1152] a tile
                                          # `vision_feature_layer`: four
                                          #   depths side by side. 729 =
                                          #   (384 // 14)^2, all kept
                                          #   (`vision_feature_select_strategy:
                                          #   full`: SigLIP has no CLS row)
r  = linear_2(gelu(linear_1(f)))          # multi_modal_projector:
                                          #   4608 -> 2048 -> 2048, with biases
grid = weave(r[1:], grid_shape)           # one raster, row-major across the
                                          #   whole grid, not tile after tile
grid = unpad(grid, image_size)            # crop the letterbox padding
grid = append_to_each_raster_row(grid, image_newline)   # learned [2048]
rows = concat(r[0], flatten(grid))        # the base tile's 729 rows first

#   The SigLIP tower, as published:
#     layers                     27   `num_hidden_layers`
#     width                    1152   `hidden_size`
#     heads                      16   `num_attention_heads`
#     ffn width                4304   `intermediate_size`
#     patch / image          14 / 384 `patch_size`, `image_size`
#     activation  gelu_pytorch_tanh   `hidden_act`
#     norm eps                1e-06   `layer_norm_eps`

ids = tokenize(prompt)                    # the processor has already expanded
                                          #   each <image> to len(rows) copies
x   = embed[ids]
x[ids == 49155] = rows                    # masked scatter over the
                                          #   placeholders (`image_token_index`)

x = x * 12                                # <- embedding_multiplier
for i in 0 .. 39:
    h = rmsnorm(x, layers[i].input_layernorm, eps=1e-05)
    q = h @ layers[i].self_attn.q_proj.T       # [T, 32*64]
    k = h @ layers[i].self_attn.k_proj.T       # [T, 8*64]
    v = h @ layers[i].self_attn.v_proj.T       # [T, 8*64]
    q, k = rope(q, k, theta=300000)
    k, v = repeat_kv(k, v, 4)            # 32 query heads share 8 key/value heads
    a = softmax(q @ k.T * 0.015625, mask=causal) @ v      # <- attention_multiplier
    a = a @ layers[i].self_attn.o_proj.T
    x = x + a * 0.22        # <- residual_multiplier

    h = rmsnorm(x, layers[i].post_attention_layernorm)
    g = silu(h @ layers[i].mlp.gate_proj.T)           # [T, 8192]
    u =       h @ layers[i].mlp.up_proj.T
    y = (g * u) @ layers[i].mlp.down_proj.T
    x = x + y * 0.22

x = rmsnorm(x, model.norm)
logits = (x @ embed.T) / 8        # tied to the input embedding; <- logits_scaling

Differs from the block above

The same arithmetic with these values changed. Everything not listed is as above.

checkpointtower hidden_act, layer_norm_epsprojector activation and biasimage_grid_pinpointscontext
granite-vision-3.2-2bnot published; SiglipVisionConfig defaults are gelu_pytorch_tanh, 1e-06not published; LlavaNextConfig defaults are gelu, with biasgranite-vision-3.3-2b's 26 grids plus [384, 384]131,072
granite-vision-3.1-2b-previewnot published; defaults as abovenot published; defaults as abovethe same 26 as granite-vision-3.3-2b16,384

Notes

head_dim is not published; 2048 / 32 = 64 is used.

Output head: the configuration says tied, the checkpoint ships a separate one. granite-vision-3.3-2b-chart2csv-preview sets tie_word_embeddings: true, which is what the block follows, but its checkpoint also ships a separate language_model.lm_head.weight [49156, 2048], which LlavaNext renames to lm_head on load (L540). A standard transformers load reads that tensor and then, because the configuration asks for tying, replaces it with the input embedding (modeling_utils.py L2994, L5065), so the logits it computes are the ones written here. The published headers carry shapes, not values, so whether the shipped head equals embed is not known; if it does not, a loader that uses the shipped lm_head.weight computes different logits (findings §10).

The decoder's four multipliers are placed as in modeling_granite.py at transformers v4.57.1: embedding, attention scale, residual, logits.

The image path, line by line, at transformers v4.57.1. The four tower depths are concatenated on the feature axis (L404-L408), which is why linear_1 reads 4 × 1,152 = 4,608 (L204-L207). The projector runs before packing (L413). Packing weaves the grid tiles into one raster, unpads it, appends image_newline to every raster row and puts the base tile first (L306-L339); image_newline is a learned parameter of the model (L263). The rows then replace the placeholder embeddings by masked_scatter (L505).

The row count is fixed by the processor, before the tower runs. It expands each <image> into base rows + unpadded rows + one newline per raster row (processing_llava_next.py L166-L169, L186-L226). So the count is not a multiple of 729, and a port that concatenates tiles in order gets neither the count nor the arrangement right.

Tower defaults, where a configuration omits them: SiglipVisionConfig L176-L177; projector defaults: LlavaNextConfig L93, L99.

The decoder half is 40 layers at width 2,048; the projector's output width has to match it.

Geometry

layers40
hidden size2,048
attention heads32, 8 key/value
feed-forward width8,192
vocabulary49,156
trained context16,384 tokens (granite-vision-3.1-2b-preview); 131,072 tokens (granite-vision-3.2-2b, granite-vision-3.3-2b, granite-vision-3.3-2b-chart2csv-preview)
largest checkpoint3B

Weight structure

The tensors one element of the repeating stack holds, by the names the published checkpoint uses.

repeating stackdepthwhat one element holds
vision_tower.vision_model.encoder.layers.#27layer_norm1.bias, layer_norm1.weight, layer_norm2.bias, layer_norm2.weight, mlp.fc1.bias, mlp.fc1.weight, mlp.fc2.bias, mlp.fc2.weight, self_attn.k_proj.bias, self_attn.k_proj.weight, self_attn.out_proj.bias, self_attn.out_proj.weight, self_attn.q_proj.bias, self_attn.q_proj.weight, self_attn.v_proj.bias, self_attn.v_proj.weight

How this was checked

Status and evidence grade in the assessment (see what the grades mean):

Parts of the author's unpublished implementation that exist for this shape:

Checkpoints with this architecture

modelparameterscontext
granite-vision-3.1-2b-preview3B16,384
granite-vision-3.2-2b3B131,072
granite-vision-3.3-2b3B131,072
granite-vision-3.3-2b-chart2csv-preview3B131,072