--- id: vlm-model-families title: Open VLM Families: LLaVA, Qwen-VL, InternVL code: OV subtitle: LLaVA, LLaVA-OneVision, Qwen-VL and InternVL3 side by side: connector, resolution, video, tokens and training. hue: 265 sources: phases/12-multimodal-ai/05-llava-visual-instruction-tuning, phases/12-multimodal-ai/06-any-resolution-patch-n-pack, phases/12-multimodal-ai/08-llava-onevision-single-multi-video, phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps, phases/12-multimodal-ai/10-internvl3-native-multimodal source_hash: 854d13f0d4ee45ed --- ## Families side by side type: comparison span: 2 from: phases/12-multimodal-ai/05-llava-visual-instruction-tuning/docs/en.md, phases/12-multimodal-ai/08-llava-onevision-single-multi-video/docs/en.md, phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps/docs/en.md, phases/12-multimodal-ai/10-internvl3-native-multimodal/docs/en.md, phases/12-multimodal-ai/10-internvl3-native-multimodal/code/main.py | Factor | LLaVA-NeXT | LLaVA-OneVision | Qwen-VL family | InternVL3 | |---|---|---|---|---| | Vision to LLM | 2-layer MLP, GELU | Same MLP projector | Qwen2-VL: 2-layer MLP on merged patches | Native, no align stage | | Recipe | Post-hoc on a text LLM | Post-hoc on a text LLM | Post-hoc on a text LLM | Native multimodal pretrain | | High resolution | AnyRes: 336 tiles plus thumbnail | AnyRes-9 or AnyRes-4, 384 tiles | Qwen2-VL: any H and W divisible by 28 | ViR picks low, medium or high | | Video | Per-frame concat | 32 frames, 196 tokens each | Dynamic FPS, absolute-time M-RoPE | 5% video-text in pretrain | | Visual tokens | 576 base, 2880 AnyRes | 6000-9000 per sample, balanced | Scales with input | 256, 576 or 2048+ via ViR | | Training | Align, then instruct | Stages SI, OV, TT | Qwen3-VL: stages stress OCR, grounding, agents | One pretrain stage, then instruct | | Swap the LLM | Retrain the projector | Retrain the projector | Retrain the adapter | Not possible later | ## LLaVA forward pass type: architecture from: phases/12-multimodal-ai/05-llava-visual-instruction-tuning/docs/en.md ```arch node | img | 1,1 | Image | 336x336 | client node | vit | 2,1 | CLIP ViT-L/14 @ 336 | 576 patches, dim 1024 | model node | mlp | 3,1 | 2-layer MLP | 1024 → 4096 → 4096, GELU | process node | prompt | 1,2 | Prompt | system + + user | client node | splice | 2,2 | Replace | 576 projected tokens | process node | llm | 3,2 | LLM | Vicuna-13B, later Llama-3.1-8B | model edge | img | vit | edge | vit | mlp | patches edge | mlp | splice | 576 tokens edge | prompt | splice | edge | splice | llm | full sequence ``` ## Qwen-VL lineage type: flow from: phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps/docs/en.md, phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps/code/main.py 1. **Qwen-VL (2023)**: 448 res, grounding boxes as text, Q-Former with 256 queries. 2. **Qwen2-VL (2024)**: M-RoPE, native dynamic resolution, MLP projector. 3. **Qwen2.5-VL (2025)**: dynamic FPS, absolute-time M-RoPE, window attention in the ViT. 4. **Qwen2.5-VL agents**: JSON tool calls. ScreenSpot goes from 55% to 84%. 5. **Qwen3-VL (2025)**: Qwen3 base, thinking mode, more OCR data. ViT and M-RoPE stay. ## Use each family when type: tips from: phases/12-multimodal-ai/05-llava-visual-instruction-tuning/docs/en.md, phases/12-multimodal-ai/06-any-resolution-patch-n-pack/docs/en.md, phases/12-multimodal-ai/06-any-resolution-patch-n-pack/code/main.py, phases/12-multimodal-ai/08-llava-onevision-single-multi-video/docs/en.md, phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps/docs/en.md, phases/12-multimodal-ai/10-internvl3-native-multimodal/docs/en.md - **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. ## Toy code by lesson type: task-table from: phases/12-multimodal-ai/05-llava-visual-instruction-tuning/code/main.py, phases/12-multimodal-ai/06-any-resolution-patch-n-pack/code/main.py, phases/12-multimodal-ai/08-llava-onevision-single-multi-video/code/main.py, phases/12-multimodal-ai/10-internvl3-native-multimodal/code/main.py | Task | Code | |---|---| | Project ViT patches | `MLPProjector(PATCH_DIM, HIDDEN_DIM, LLM_DIM)` | | Build a LLaVA prompt | `build_llava_prompt(system, user, 576)` | | Pack a mixed batch | `pack_batch(images, patch)` | | Dense block-diagonal mask | `build_dense_mask(pack)` | | AnyRes token cost | `anyres_cost(img, tile=336, thumb=336)` | | Square-resize cost | `square_cost(img, side=336, patch=14)` | | OneVision video plan | `plan_video(budget)` | | ViR average tokens | `vir_sim(tiers)` | ## M-RoPE, dynamic FPS, tool calls type: annotated-code lang: python from: phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps/code/main.py ```python 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 } ``` ## Token math type: concepts from: phases/12-multimodal-ai/05-llava-visual-instruction-tuning/docs/en.md, phases/12-multimodal-ai/06-any-resolution-patch-n-pack/docs/en.md, phases/12-multimodal-ai/08-llava-onevision-single-multi-video/docs/en.md, phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps/docs/en.md - **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 2x2 pool, 32 * 196 = 6272 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. ## Training recipes type: comparison from: phases/12-multimodal-ai/05-llava-visual-instruction-tuning/docs/en.md, phases/12-multimodal-ai/08-llava-onevision-single-multi-video/docs/en.md, phases/12-multimodal-ai/08-llava-onevision-single-multi-video/code/main.py, phases/12-multimodal-ai/10-internvl3-native-multimodal/docs/en.md | Step | LLaVA | OneVision | InternVL3 | |---|---|---|---| | First | Train MLP only, 558k captions | SI: single image, AnyRes | Native pretrain | | Second | MLP + LLM, 158k GPT-4 turns | OV: 0.5 / 0.3 / 0.2 mix | Instruction tuning | | Third | None | TT: target task mix | None | | Frozen | ViT and LLM in stage 1 | No weight reset | No freezing stage | | Data | LAION-CC-SBU, LLaVA-Instruct | LLaVA-NeXT data plus own | 40/35/20/5 text, interleaved, caption, video | ## Defaults in the lessons type: defaults from: phases/12-multimodal-ai/05-llava-visual-instruction-tuning/code/main.py, phases/12-multimodal-ai/06-any-resolution-patch-n-pack/code/main.py, phases/12-multimodal-ai/08-llava-onevision-single-multi-video/code/main.py, phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps/docs/en.md, phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps/code/main.py, phases/12-multimodal-ai/10-internvl3-native-multimodal/code/main.py | Setting | Default | Note | |---|---|---| | `anyres_cost` tile, thumb | 336 | 576 tokens per tile at patch 14 | | `square_cost` side | 336 | Fixed 576 tokens per image | | LLaVA prompt image_tokens | 576 | Replaces the image placeholder | | `MRoPEConfig` base | 10000.0 | RoPE frequency base per band | | Qwen2-VL video sampling | 1-2 FPS | Accepts any frame count | | OneVision toy planner budget | 4096 | Visual tokens per sample in the lesson code | | Dynamic-FPS demo budget | 32768 | 81 tokens per frame after 3x pool | | `dvd_throughput` llm_tokens | 128 | Output tokens per request | ## Troubleshooting type: troubleshooting from: phases/12-multimodal-ai/06-any-resolution-patch-n-pack/docs/en.md, phases/12-multimodal-ai/08-llava-onevision-single-multi-video/docs/en.md, phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps/docs/en.md, phases/12-multimodal-ai/10-internvl3-native-multimodal/docs/en.md | Symptom | Cause | Fix | |---|---|---| | Squished text, lost chart labels | Square resize to 336 | Native aspect ratio with a max-pixels cap | | Large image fills the context | AnyRes 4x4 is about 9800 tokens | Native pack or M-RoPE, no tile overhead | | Patches attend across images | No block-diagonal mask | Mask from cumulative offsets, or use the `cu_seqlens` path | | Weak image skills after training | Video-first or multi-image-first order | Train SI, then OV, then TT | | GSM8K drops 5-10 points | Post-hoc alignment debt | Native pretrain with a 40% text floor | | Long video runs out of frequency range | Fixed position scale | MRoPE-v2 scaling with max input size | ## Abbreviations type: glossary from: phases/12-multimodal-ai/06-any-resolution-patch-n-pack/docs/en.md, phases/12-multimodal-ai/08-llava-onevision-single-multi-video/docs/en.md, phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps/docs/en.md, phases/12-multimodal-ai/10-internvl3-native-multimodal/docs/en.md - **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. ## Questions type: qa from: phases/12-multimodal-ai/05-llava-visual-instruction-tuning/docs/en.md, phases/12-multimodal-ai/08-llava-onevision-single-multi-video/docs/en.md, phases/12-multimodal-ai/09-qwen-vl-family-dynamic-fps/docs/en.md, phases/12-multimodal-ai/10-internvl3-native-multimodal/docs/en.md - **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.