Module 26 · Part VII · Beyond Text

Vision-Language Models

Connectors, High-Resolution Tiling, 2D Positions, and Training on Images and Text Together

By the end you can build the input sequence of a VLM and train it correctly.

Builds onModule 25·
Check yourself ▸

Before you start, can you already…

  • ☐turn an image into tokens, and explain how image and text encoders are aligned. (Module 25)

If any is shaky, the linked module teaches it.

Open in Colab
3 Hours·Elective·Specialized·0/4

Many real inputs are images: photos, scanned documents, charts, screenshots, video frames. A vision-language model (VLM) takes images and text together and answers in text. The idea throughout: once an image is a list of vectors of the right width, a transformer treats it like any other sequence. This module connects a ViT (section 25.2) to a language model (26.1), handles large images without running out of tokens (26.2 and 26.3), and trains the combination (26.4).

26.1 Connecting Vision to LanguageRun this section

A VLM usually joins a separately trained vision encoder, often a CLIP or SigLIP ViT (section 25.3) whose vectors already relate to words, and a decoder-only language model such as LLaMA, Gemma or Qwen. The encoder's vectors have their own width dvisd_{\text{vis}} (not attention's value width ); the language model expects vectors of width dtextd_{\text{text}} that look like its token embeddings. A small trained connector converts one into the other.

Architecture Flowchart
Diagram: Vision encoder (e.g. SigLIP or CLIP ViT); Image vectors H_v, N x d_vis; Connector (small trained network); Image tokens H_v', M x d_text; Decoder-only language model; Text tokens from the user's prompt

In words. The vision encoder turns the image into NN vectors; the connector turns them into MM vectors the language model reads like token embeddings, alongside the text prompt.

Three Kinds of Connector

1. Linear or 2-Layer MLP Projection (LLaVA Style)

The simplest connector maps each image vector on its own. LLaVA (Liu et al., 2023) used a single matrix; LLaVA-1.5 uses a 2-layer MLP with GELU:

Hv′=GELU⁡(HvW1+b1)W2+b2H_v' = \operatorname{GELU}(H_v W_1 + \mathbf{b}_1) W_2 + \mathbf{b}_2

With and W2∈Rdmid×dtextW_2 \in \mathbb{R}^{d_{\text{mid}} \times d_{\text{text}}}, each row changes width but the row count stays: M=NM = N. It is simple and keeps every detail, but every patch takes a token position: 196196 to 576576 per image for common encoders.

2. Perceiver Resampler / Q-Former (Flamingo & BLIP-2)

This connector outputs a fixed number of tokens however many patches go in. MM learned queries q∈RM×d\mathbf{q} \in \mathbb{R}^{M \times d} (M=64M = 64 in Flamingo) cross-attend (section 8.1) to the image vectors, which supply the keys and values:

Hv′=CrossAttention⁡(q,Hv,Hv)H_v' = \operatorname{CrossAttention}(\mathbf{q}, H_v, H_v)

Each query gives one output, so hundreds of patches become MM tokens. Real resamplers stack several such layers with feed-forward networks.

3. Spatial Patch Merging / Pixel Unshuffle

A middle option: concatenate each 2×22 \times 2 block of neighboring patch vectors into width 4dvis4 d_{\text{vis}} and map that to dtextd_{\text{text}}. The count drops 75%75\% (), and the grid keeps its shape, coarser: 24×2424 \times 24 becomes 12×1212 \times 12.

Figure 26.1
What each connector costs in language-model tokens

The vision encoder produces a grid of patch vectors. Each connector turns them into a different number of tokens for the language model.

Bars are drawn against a 4,096-token context window.
Predict, then try

With a 32 × 32 patch grid, predict which connectors still fit comfortably in a 4,096-token context alongside a long prompt.

In words. For a chosen patch grid, each connector's token count as a bar against a four-thousand-token context, with what each keeps or loses.

26.2 High Resolution: AnyRes TilingRun this section

Documents, screenshots and diagrams need high resolution. A 2048×20482048 \times 2048 image in 16×1616 \times 16 patches gives 16,38416{,}384 tokens, more than the whole 4,096-token context early VLMs such as LLaVA-1.5 were built on, and the ViT was trained at a fixed size such as 336×336336 \times 336. LLaVA-NeXT and InternVL use tiling (LLaVA-NeXT's AnyRes): encode a grid of tiles matching the image's shape at the ViT's own size, plus a shrunken copy of the whole image.

Architecture Flowchart
Diagram: High-resolution image, 1008 wide x 672 tall; Shrink the whole image to 336 x 336 (one overview tile); Cut into 2 rows x 3 columns of 336 x 336 tiles; Encode the overview with the ViT; Encode each of the 6 tiles with the same ViT; Join all image tokens in order, with a separator token at the end of each row; Feed the joined image tokens to the language model

In words. The shrunken overview tile gives the layout; the full-size tiles give the detail. All their tokens are joined in order, with separators at the end of each grid row.

Seven tiles cost seven times a single tile's tokens, which is why tiling is often combined with patch merging.

Figure 26.2
Tiling a large image to the encoder’s size

The image is covered by a grid of 336 × 336 tiles chosen to match its shape, and a shrunken copy of the whole image is encoded too.

576 tokens per tile, as for a ViT with 14 × 14 patches on 336 × 336 inputs. The grid choice is a simplified version of LLaVA-NeXT’s.
Predict, then try

A wide 1008 × 336 image and a square 672 × 672 image hold the same number of pixels. Before trying them, predict which tile grid each gets and how many image tokens each costs at 576 tokens per tile, plus one overview tile.

In words. For an image size and tile size, the tile grid that best matches the image's shape, drawn with the overview tile beside it, and the tile and token counts with and without two-by-two patch merging.

26.3 2D RoPE for Image Patches

Numbered row by row, vertically touching patches end up a whole row apart: 1414 positions in a 1414-wide grid. 2D RoPE gives each patch its row and column directly: for a patch at row yy, column xx, rotate the first half of the query (section 15.1) by yy and the second half by xx:

q(y,x)=[RΘy,y q[:d/2],RΘx,x q[d/2:]]\mathbf{q}_{(y, x)} = \left[R_{\Theta_y, y} \, \mathbf{q}_{[:d/2]}, \quad R_{\Theta_x, x} \, \mathbf{q}_{[d/2:]}\right]

Keys are rotated the same way, so in each half only the difference survives: scores depend on how many rows and columns apart two patches are. That directly signals neighbors, helping layout tasks such as reading tables or locating objects. Qwen2-VL's vision encoder uses it to read images at their own size instead of fixed tiles.

26.4 Training on Images and Text TogetherRun this section

Merging Image and Text Into One Sequence

How "User: What is this? <image>\nAssistant: It's a red fox." becomes one sequence:

  1. Find the image marker, a special token with its own ID (say 32000).
  2. Turn each part into vectors. The T1T_1 text tokens before it are looked up in , giving Xprefix∈RT1×d\mathbf{X}_{\text{prefix}} \in \mathbb{R}^{T_1 \times d}; the image goes through the ViT and connector, giving Hv′∈RNpatches×d\mathbf{H}_v' \in \mathbb{R}^{N_{\text{patches}} \times d} (say 576 vectors, or the resampler's output count); the T2T_2 tokens after give Xsuffix∈RT2×d\mathbf{X}_{\text{suffix}} \in \mathbb{R}^{T_2 \times d}.
  3. Stack them in order, the image vectors replacing the marker:
    Xunified=[Xprefix; Hv′; Xsuffix]∈R(T1+Npatches+T2)×d\mathbf{X}_{\text{unified}} = \left[\mathbf{X}_{\text{prefix}}; \, \mathbf{H}_v'; \, \mathbf{X}_{\text{suffix}}\right] \in \mathbb{R}^{(T_1 + N_{\text{patches}} + T_2) \times d}
    With T1=8T_1 = 8, 576576 image vectors and T2=10T_2 = 10, the language model sees 594594 positions and runs ordinary self-attention over all of them, image and text alike.

Which Tokens Count Toward the Loss

Visual instruction tuning fine-tunes on image-question-answer examples with section 20.1's masked loss: only the assistant's answer tokens count.

L(θ)=−∑t=1Tmtlog⁡Pθ(wt∣Xunified,w<t)\mathcal{L}(\theta) = -\sum_{t=1}^T m_t \log P_\theta(w_t \mid \mathbf{X}_{\text{unified}}, w_{<t})

The mask is

mt={1,if token t is an assistant response token0,if token t is a user prompt, system prompt, or visual patchm_t = \begin{cases} 1, & \text{if token } t \text{ is an assistant response token} \\ 0, & \text{if token } t \text{ is a user prompt, system prompt, or visual patch} \end{cases}

Masked positions are still read as context. In PyTorch, set their labels to -100, the default ignore_index that F.cross_entropy skips (it also averages rather than sums, which only rescales the loss):

python
# prompt and image positions stay in the input as context; -100 drops them from the loss
labels[prompt_mask] = -100
loss = F.cross_entropy(logits.view(-1, vocab_size), labels.view(-1), ignore_index=-100)

prompt_mask is true at every system-prompt, user-prompt and image position. Without it, the model would be trained to predict the question and to "predict" image positions, which are not vocabulary tokens at all.

Browser lab

Building a training example for a vision-language model

Assemble section 26.4’s example: 8 prompt tokens, 576 image positions and 10 tokens after them, with next-token labels set to −100 everywhere except where the target is an assistant-answer token. The counts should be 594 positions, the 7 answer tokens scored, and every prompt and image label masked.

Tokens are written as strings for readability; a real pipeline works with ids and replaces the single image marker with the connector’s 576 output vectors.

Figure 26.4
Which positions the loss counts

One training example as a strip of positions, each segment drawn to scale. With the mask on, every position labelled −100 is skipped by the loss.

All positions are still read as context by the model; the mask only removes them from the loss.
Predict, then try

The sequence is a system prompt, a user question, 576 image positions and a short answer. Before switching the mask on, predict roughly what share of positions contribute to the loss.

In words. One training sequence as a strip of segments sized by length: system prompt, user text, image positions and answer. Switching the mask on greys out every position labelled minus 100, leaving only the answer, and the readout gives the scored share.

Exercises

Apply

An AnyRes image uses a 2 × 3 grid of tiles plus one overview tile, each encoded to 576 tokens. How many image tokens is that, and how many after 2 × 2 patch merging?

Apply

A 24 × 24 grid of patch vectors goes through 2 × 2 patch merging. How many tokens come out, and what width is each merged vector before its projection, if dvis=1024d_{\text{vis}} = 1024?

Check

Why does a Perceiver resampler output the same number of tokens for every image, whatever its resolution?

Extend

With 2D RoPE, why does the attention score between two patches depend only on how many rows and columns apart they are?

Core Academic References

  • Liu et al. (2023): Visual Instruction Tuning (LLaVA). NeurIPS 2023. arXiv:2304.08485
  • Liu et al. (2024): Improved Baselines with Visual Instruction Tuning (LLaVA-1.5). CVPR 2024. arXiv:2310.03744
  • Liu et al. (2024): LLaVA-NeXT: Improved reasoning, OCR, and world knowledge. Project blog post, January 2024.
  • Alayrac et al. (2022): Flamingo: a Visual Language Model for Few-Shot Learning. NeurIPS 2022. arXiv:2204.14198
  • Li et al. (2023): BLIP-2: Bootstrapping Language-Image Pre-training with Frozen Image Encoders and Large Language Models. ICML 2023. arXiv:2301.12597
  • Chen et al. (2024): InternVL: Scaling up Vision Foundation Models and Aligning for Generic Visual-Linguistic Tasks. CVPR 2024. arXiv:2312.14238
  • Bai et al. (2023): Qwen-VL: A Versatile Vision-Language Model for Understanding, Localization, Text Reading, and Beyond. arXiv:2308.12966
  • Wang et al. (2024): Qwen2-VL: Enhancing Vision-Language Model's Perception of the World at Any Resolution. arXiv:2409.12191