LLaVA-OneVision:单图、多图、视频合一 本节摘要:在 LLaVA-OneVision(Li 等人,2024 年 8 月)之前,开源 VLM 世界有各自独立的谱系:LLaVA-1.5 做单图,Mantis 与 VILA 做多图,Video-LLaVA 与 Video-LLaMA 做视频。每个赢了自己的基准,却在其余场景翻车。LLaVA-OneVision 主张:一套课程能训练一个模型统治全部三种场景,且涌现的任务迁移效应(单图技能外溢到视频,多图推理外溢到单图)胜过专家之和。配方简单到具有欺骗性:一个跨场景保持恒定的视觉 token 预算,加上一条从单图走向 OneVision(多图)再到视频的显式课程。本节读透预算、课程与涌现行为。
本节摘要:在 LLaVA-OneVision(Li 等人,2024 年 8 月)之前,开源 VLM 世界有各自独立的谱系:LLaVA-1.5 做单图,Mantis 与 VILA 做多图,Video-LLaVA 与 Video-LLaMA 做视频。每个赢了自己的基准,却在其余场景翻车。LLaVA-OneVision 主张:一套课程能训练一个模型统治全部三种场景,且涌现的任务迁移效应(单图技能外溢到视频,多图推理外溢到单图)胜过专家之和。配方简单到具有欺骗性:一个跨场景保持恒定的视觉 token 预算,加上一条从单图走向 OneVision(多图)再到视频的显式课程。本节读透预算、课程与涌现行为。
阅读完本节,你应当能够:
图像、多图、视频对模型的压力各不相同。
如果你训分开的模型,只能挑一个预算。如果训一个模型,你需要预算在各场景间合理伸缩,又不撑爆上下文。
OneVision 之前,默认答案是「训一个场景,无视其余」。Video-LLaVA 用额外训练阶段把视频回填到图像模型;LLaVA-NeXT 用切图加多图支持。没有一个干净地同时处理三者。
LLaVA-OneVision 选定每样本约 3000~4000 token 的统一视觉 token 预算,按场景不同地分配:
分配让总 token 数大致恒定。LLM 永远不会看到撑爆上下文的 batch。编码器按场景产出不同几何,但 LLM 消费同一预算。
LLaVA-OneVision 分三阶段训练:
关键:课程顺序重要。先训视频或先训多图,即便数据相同,图像表现也比先训单图差。论文显式消融了这一点。
单图训练建立感知基座。patch token 携带细粒度视觉特征,LLM 学会把它们与文本整合。多图与视频引入结构性挑战(哪张是哪张、什么先发生),没有强感知基座很难学。
如果你从头一起训所有场景,模型会欠拟合感知(每 batch 单图数据有限)又过拟合结构(多图/视频数据多)。结果是个会遵循跨图推理模式但视觉浅薄的模型。
课程顺序让你从阶段 SI 拿到感知强度,再从阶段 OV 拿到组合/时间推理,两者都不丢。
LLaVA-OneVision 论文报告三种涌现能力:
这些都不是训出来的任务,而是从课程的结构组合里涌现的。
token 预算要求池化。OneVision 在二维 patch 网格上做双线性插值:24×24 = 576 patch 变 12×12 = 144(2 倍因子)或 8×8 = 64(3 倍因子)。池化在 patch 网格空间而非 token 空间做,以保留局部性。
每场景的池化因子本身就是超参。少池化 = 多 token = 更丰富表示;多池化 = 少 token = 容下更多帧/图。
2025 年的后续(LLaVA-OneVision-1.5,arXiv 2509.23661)在训练数据、模型权重、代码上「完全开源」,在部分基准上追平闭源差距,让配方民主化。同课程、更多数据、更强基础 LLM,架构不变。
Qwen2.5-VL(第 09 节)做了不同选择:用 M-RoPE 与动态 FPS,而非固定池化。它的预算随输入伸缩——1 分钟视频比 5 秒视频用更多 token。LLaVA-OneVision 固定预算、伸缩池化。两者都成立,用可配置性换可预测性。
code/main.py 是一个 OneVision 式 VLM 的课程与预算规划器。给定每样本 token 预算与目标场景配比(比如 40% 单图、30% 多图、30% 视频),它:
def allocate_budget(total_budget, scenario_mix): plans = {} # 单图: 高分辨率, AnyRes + 激进池化 plans["single"] = {"anyres": 9, "pool": 4, "frames": 1} # 多图: 中分辨率, 不切图 plans["multi"] = {"anyres": 1, "pool": 1, "images": total_budget // 729} # 视频: 低分辨率, 激进池化 plans["video"] = {"anyres": 1, "pool": 9, "frames": total_budget // 81} for s, p in plans.items(): p["tokens"] = compute_tokens(p) assert p["tokens"] <= total_budget # 不撑爆预算 return plans
def bilinear_pool_2d(patches, grid_h, grid_w, factor): # patches 形状 (grid_h*grid_w, D), factor=2 即每维缩 2 倍 out_h, out_w = grid_h // factor, grid_w // factor out = zeros((out_h*out_w, D)) for i in range(out_h): for j in range(out_w): block = patches_2d[i*factor:(i+1)*factor, j*factor:(j+1)*factor] out[i*out_w+j] = block.mean(axis=(0,1)) # 2x2 块均值 ≈ 双线性 return out
💡 关键洞察:池化在 patch 网格空间而非 token 空间做,是为了保留二维局部性——相邻 patch 的均值仍有空间意义,而一维 token 序列上的池化会打乱邻接关系。
def curriculum(): stage_SI = train(single_image_data, lr=2e-5) # 感知基座 stage_OV = train(mix(single, multi, video), # 从 SI 继续, 不重置 init_from=stage_SI, lr=1e-5) stage_TT = train(task_mix, init_from=stage_OV, # 任务专属微调 lr=5e-6) # 注意: 顺序不能反 — 视频优先会损害图像表现
llava-onevision-qwen2 系列是事实标准。工程取舍:要单模型统治三场景用 LLaVA-OneVision;要预算随输入动态伸缩用 Qwen2.5-VL;只做视频或只做多图可用专门模型;做产品部署用 OneVision-1.5 全开源版。
本节产出 outputs/skill-onevision-budget-planner.md。给定目标任务分布与每样本预算,它输出 AnyRes 因子、每帧池化、视频帧数、课程阶段权重。每当你训练或微调统一场景 VLM 时都用它。
产品配比:你的产品是 80% 单图、10% 多图(24 张)、10% 视频(816 帧)。设计 token 预算,把省下的预算放哪?
第四种涌现:读 LLaVA-OneVision 第 4.3 节(涌现能力),提出一个课程很可能解锁、但论文未报告的第四种涌现技能。
换课程顺序:把课程顺序换成「多图优先 → 单图 → 视频」,预测哪些基准会退步、为什么。
8 帧泛化:论文报告视频基准只在每样本 8 帧上训练。这能泛化到推理时的 30 秒视频吗?什么先崩——token 预算还是时间推理?
池化验证:24×24 patch 双线性池化到 12×12 是每维 4 倍缩减。用标准库 Python 实现池化,验证每个 2×2 块的均值与双线性输出一致。
下一节,我们将进入 Qwen-VL 家族——它用 M-RoPE 与动态 FPS 走另一条路,把分辨率与帧率都交给输入决定,是国产开源 VLM 的代表路线。