Cheat sheets

Open VLM Families: LLaVA, Qwen-VL, InternVL

LLaVA, LLaVA-OneVision, Qwen-VL and InternVL3 side by side: connector, resolution, video, tokens and training.

  • Concepts and terms
  • Tasks and commands
  • Annotated code
  • Diagrams
  • Comparisons
  • Defaults and numbers
  • Troubleshooting
  • Questions and tips

Source

Families side by side#

FactorLLaVA-NeXTLLaVA-OneVisionQwen-VL familyInternVL3
Vision to LLM2-layer MLP, GELUSame MLP projectorQwen2-VL: 2-layer MLP on merged patchesNative, no align stage
RecipePost-hoc on a text LLMPost-hoc on a text LLMPost-hoc on a text LLMNative multimodal pretrain
High resolutionAnyRes: 336 tiles plus thumbnailAnyRes-9 or AnyRes-4, 384 tilesQwen2-VL: any H and W divisible by 28ViR picks low, medium or high
VideoPer-frame concat32 frames, 81 tokens eachDynamic FPS, <time> tokens5% video-text in pretrain
Visual tokens576 base, 2880 AnyRes3000-4000 per sample, fixedScales with input256, 576 or 2048+ via ViR
TrainingAlign, then instructStages SI, OV, TTQwen3-VL: stages stress OCR, grounding, agentsOne pretrain stage, then instruct
Swap the LLMRetrain the projectorRetrain the projectorRetrain the adapterNot possible later

From Lesson 12.05, Lesson 12.08, Lesson 12.09, Lesson 12.10, 12.10 code/main.py

LLaVA forward pass#

patches576 tokensfull sequenceclientImage336x336modelCLIP ViT-L/14 @ 336576 patches, dim 1024process2-layer MLP1024 → 4096 → 4096, GELUclientPromptsystem + <image> + userprocessReplace <image>576 projected tokensmodelLLMVicuna-13B, laterLlama-3.1-8Bpatches576 tokensfull sequenceclientImage336x336modelCLIP ViT-L/14 @ 336576 patches, dim 1024process2-layer MLP1024 → 4096 → 4096,GELUclientPromptsystem + <image> + userprocessReplace <image>576 projected tokensmodelLLMVicuna-13B, laterLlama-3.1-8B

From Lesson 12.05

Training recipes#

StepLLaVAOneVisionInternVL3
FirstTrain MLP only, 558k captionsSI: single image, AnyResNative pretrain
SecondMLP + LLM, 158k GPT-4 turnsOV: 0.5 / 0.3 / 0.2 mixInstruction tuning
ThirdNoneTT: target task mixNone
FrozenViT and LLM in stage 1No weight resetNo freezing stage
DataLAION-CC-SBU, LLaVA-InstructLLaVA-NeXT data plus own40/35/20/5 text, interleaved, caption, video

From Lesson 12.05, Lesson 12.08, 12.08 code/main.py, Lesson 12.10

Defaults in the lessons#

SettingDefaultNote
anyres_cost tile, thumb336576 tokens per tile at patch 14
square_cost side336Fixed 576 tokens per image
LLaVA prompt image_tokens576Replaces the image placeholder
MRoPEConfig base10000.0RoPE frequency base per band
Qwen2-VL video sampling1-2 FPSAccepts any frame count
OneVision planner budget4096Visual tokens per sample
Dynamic-FPS demo budget3276881 tokens per frame after 3x pool
dvd_throughput llm_tokens128Output tokens per request

From 12.05 code/main.py, 12.06 code/main.py, 12.08 code/main.py, Lesson 12.09, 12.09 code/main.py, 12.10 code/main.py

Troubleshooting#

SymptomCauseFix
Squished text, lost chart labelsSquare resize to 336Native aspect ratio with a max-pixels cap
Large image fills the contextAnyRes 4x4 is about 9800 tokensNative pack or M-RoPE, no tile overhead
Patches attend across imagesNo block-diagonal maskMask from cumulative offsets, or use the cu_seqlens path
Weak image skills after trainingVideo-first or multi-image-first orderTrain SI, then OV, then TT
GSM8K drops 5-10 pointsPost-hoc alignment debtNative pretrain with a 40% text floor
Long video runs out of frequency rangeFixed position scaleMRoPE-v2 scaling with max input size

From Lesson 12.06, Lesson 12.08, Lesson 12.09, Lesson 12.10

Qwen-VL lineage#

1Qwen-VL (2023)448 res, grounding boxes as text, Q-Former with256 queries.2Qwen2-VL (2024)M-RoPE, native dynamic resolution, MLPprojector.3Qwen2.5-VL (2025)dynamic FPS, absolute time tokens, windowattention in the ViT.4Qwen2.5-VL agentsJSON tool calls. ScreenSpot goes from 55% to84%.5Qwen3-VL (2025)Qwen3 base, thinking mode, more OCR data. ViTand M-RoPE stay.

From Lesson 12.09, 12.09 code/main.py

Use each family when#

  • LLaVA you need a cheap, reproducible recipe. Stage 2 takes ~20 hours on 8xA100.
  • LLaVA-OneVision one model serves single image, multi-image and video at a predictable cost.
  • Qwen2.5-VL video with timestamps, GUI agents with JSON output, min_pixels and max_pixels caps.
  • InternVL3 text skills must not regress and you can pay for native pretraining.
  • Post-hoc recipe you want to swap in a new LLM later. It stays cheaper for most projects.
  • AnyRes tiling the encoder is frozen at 336x336, but you need detail.

From Lesson 12.05, Lesson 12.06, 12.06 code/main.py, Lesson 12.08, Lesson 12.09, Lesson 12.10

Toy code by lesson#

TaskCode
Project ViT patchesMLPProjector(PATCH_DIM, HIDDEN_DIM, LLM_DIM)
Build a LLaVA promptbuild_llava_prompt(system, user, 576)
Pack a mixed batchpack_batch(images, patch)
Dense block-diagonal maskbuild_dense_mask(pack)
AnyRes token costanyres_cost(img, tile=336, thumb=336)
Square-resize costsquare_cost(img, side=336, patch=14)
OneVision video planplan_video(budget)
ViR average tokensvir_sim(tiers)

From 12.05 code/main.py, 12.06 code/main.py, 12.08 code/main.py, 12.10 code/main.py

M-RoPE, dynamic FPS, tool calls#

cfg = MRoPEConfig(hidden=48, temporal_dim=16, height_dim=16, width_dim=16)
mrope_angles(cfg, 0, 5, 7)image patch: t=0, h=row, w=col
mrope_angles(cfg, 3, 5, 7)video frame t=3
mrope_rotate(cfg, vec, 3, 5, 7) # rotates each band by its axis
plan = VideoPlan(duration_s=600.0, tokens_per_frame=81,
budget=32768, motion="low")
plan.fps()first candidate <= fps_max
plan.frame_times()one timestamp per frame
plan.total_tokens()frames times tokens_per_frame
parse_tool_call(raw)json.loads, then slice { to }

From 12.09 code/main.py

Token math#

LLaVA base
576 tokens per image. At 2048 context, 1472 tokens stay for text.
AnyRes 2x2
4 * 576 + 576 = 2880 visual tokens.
AnyRes 4x4
a 1344x1344 image gives 9216 + 576, about 9800 tokens.
Qwen2-VL native
1120x672 gives 40x24 merged patches, 960 tokens.
OneVision image
AnyRes-9 with 2x2 pool, 9 * 182 + 182 = 1820 tokens.
OneVision video
32 frames with 3x3 pool, 32 * 81 = 2592 tokens.
Dynamic FPS cap
fps_{max} = B / (T \cdot \text{tokens per frame})
Qwen2.5-VL video
60 s at 4 FPS with 81 tokens per frame is 19440 tokens.

From Lesson 12.05, Lesson 12.06, Lesson 12.08, Lesson 12.09

Abbreviations#

M-RoPE
Multimodal RoPE. Time, height and width bands in the hidden dim.
V2PE
variable visual position encoding. Learned band split per modality.
NaFlex
SigLIP 2 native-flex mode. One checkpoint serves 256, 729 or 1024 tokens.
ViR
Visual Resolution Router. Picks the minimum resolution before encoding.
DvD
Decoupled Vision-Language deployment. Encoder and LLM on separate GPUs.
SI, OV, TT
OneVision stages. Single-image, OneVision mix, task transfer.

From Lesson 12.06, Lesson 12.08, Lesson 12.09, Lesson 12.10

Questions#

Why did MLP beat Q-Former?
LM loss only and easy LLM swap. Contexts grew to 32k-128k+, so 576 tokens became cheap.
OneVision or Qwen2.5-VL budget?
OneVision fixes the budget and scales the pooling. Qwen2.5-VL budget scales with input.
Why does M-RoPE need no position table?
Each token rotates by its (t, h, w) position. Images use t = 0.
Why not always pretrain native?
Compute is like a text LLM. Interleaved data is rare. The LLM cannot change later.
What does DvD give?
For an 8B LLM with a 400M encoder, about 2x per-node throughput.

From Lesson 12.05, Lesson 12.08, Lesson 12.09, Lesson 12.10