资讯详情

资讯详情

没有ViT的多模态模型:直接Patch Embedding接LLM的可行性与实践指南

多模态大模型聊到架构选型绕不开一个老熟脸ViT。几乎每个 MLLM 的 backbone 图里都躺着一位 ViT 编码器前接像素后接 LLM。时间长了大家也就默认了这套流程。但总有人会问一个非常“省事”的问题既然输入侧已经做了 patch embedding图像已经被切成 token 了那为什么还要过一整个 ViT能不能直接把 patch embedding 送给大模型这问题我最早是在内部做轻量级多模态方案评审时被问到的当时我还觉得是异想天开直到自己动手复现了几版才发现这个方向背后藏着 MLLM 架构设计里一个很少被摆上台面讨论的问题视觉分支到底需要在语言模型之前承担多少建模工作。这篇文章就把我踩过的坑、做过的对比实验和最终结论一次性说清楚。先说结论直接 patch embedding 接 LLM这条路在特定约束下能跑通但它不是简单地“砍掉一个模块”而是要把视觉侧的职责逐项拆解、逐项补偿。没有想清楚这几点就动手大概率会得到一个训练不稳、方位感知稀烂、细节全糊的四不像模型。1. “不要ViT”这句话翻译过来到底是在问什么要讨论能不能去掉 ViT先得把 ViT 在多模态架构里到底干了什么拆清楚。ViT 拿到一张图之后实际做了三件事第一件事patch embedding。把图像按固定大小切成小块每个块展平后做一次线性投影得到一组向量序列。这一步负责的是“图像到 token 的初加工”本质上是把像素空间压缩成高维特征空间的几个点。第二件事位置编码。给每个 patch 的 embedding 注入空间位置信息让模型知道哪个 token 来自图片的哪个区域。这一步解决的是“序列顺序和空间结构”的问题因为 Transformer 本身没有位置感。第三件事多层 Transformer encoder 的特征提取与交互。这是 ViT 最重的部分也是争论的核心。patch token 进入 ViT 后会经历若干层 self-attention 和 FFN在不同尺度上反复融合局部和全局信息最终产出一组语义更丰富、抽象程度更高的视觉特征。所以“不要 ViT直接 patch embedding”这个说法准确翻译是保留第一件事和位置编码去掉第三件事也就是视觉侧只做 token 化不做 Transformer 级的特征提取直接把原始 patch embedding 序列交给 LLM。这个想法初看是反直觉的因为它相当激进。但仔细想想它成立的前提其实很诱人LLM 本身就是一个巨大的 Transformer注意力机制天生就能建模任意 token 之间的关系。既然视觉 token 已经进了 LLM为什么不能由 LLM 自己来完成视觉 token 之间的交互、组合和语义抽象换句话说你在问的是能不能把视觉特征提取这件事从“视觉专用 Transformer”手里移交给你即将推理的“通用 Transformer”这个问题的吸引人之处不只是结构简化。从工程上看ViT 通常也有几百 M 甚至上 G 的参数量推理时它占用的显存和时间是实打实的开销。从研发流程上看少一个组件就少一套视觉预训练、少一组对齐模块、少一堆超参调试。从学术理想上看这种“极简 token 化 大语言模型统一处理”的思路也更符合人们对 scaling law 的直觉——既然模型更大更强为什么视觉侧不能更“笨”一点但问题在于“理论上可以成立”和“工程上真的能用”之间隔着很多细节。直接 patch embedding 会遇到三堵非常具体的墙我下一节逐一说。2. 直接把 patch embedding 交给 LLM会撞上三堵墙2.1 第一堵墙局部语义建模完全缺失图像和语言在 token 层面的性质有本质区别。语言里的 token词、子词本身就是一个完整或准完整的语义单元比如“猫”“跑步”“但是”这些词单独拿出来都带有明确语义。而图像 patch 不是这样的。一个 16×16 的 patch里面可能只有一条边缘、一小块纹理、物体的一角它的语义必须结合周围 patch 才能确定。ViT 之所以要用多层 Transformer encoder一个非常重要的原因是它的早期层承担了类似 CNN 低层卷积核的工作把相邻 patch 的边缘和纹理组合成有意义的局部 pattern再把局部 pattern 组合成稍大的语义块。也就是说ViT 在进入高层语义建模之前先把“局部特征整合”这件脏活累活干完了。当你把 ViT 去掉直接送 patch embedding 进 LLMLLM 的第一层 self-attention 就必须同时做两件事既要补做低层特征组合边缘变纹理、纹理变局部形状又要完成高层语义推理物体识别、跨区域关系建模。不是说 attention 做不到而是这样做会把 LLM 的建模负担成倍增加而且还会污染它本身擅长的语言推理能力。我在实验里发现一个非常明显的现象去掉 ViT 之后模型对细粒度类别的区分能力下降比如能说出“一只狗”但很难区分“哈士奇”和“阿拉斯加”。原因就是局部纹理细节没有被有效地组合成判别性特征LLM 拿到的每个 token 都太“原始”了。2.2 第二堵墙序列长度呈指数级拖累计算视觉 token 的数量由图像分辨率 / patch size决定这个数字在直接 patch embedding 方案里会成为一个非常头疼的问题。举个例子224×224 的输入图patch size 16×16得到的 token 数是(224/16)² 196个。这个数量级 LLM 还能勉强接受。但如果输入换成 448×448同样的 patch sizetoken 数直接变成(448/16)² 784。再往上看做文档理解常在 1024×1024 的分辨率下跑假设 patch size 用 14token 数就变成(1024/14)² ≈ 5350个。LLM 的 self-attention 计算量是O(n²)的这是个躲不开的数学事实。视觉 token 从 196 涨到 5000 多attention 的计算量增长接近 700 倍这还是在完全不考虑 LLM 本身文本 token 的情况下。换句话说去掉 ViT 省下的那点计算开销在序列长度带来的 attention 开销面前很可能直接倒亏。这里还有一个非常容易被忽略的点ViT 在多模态模型里不只是做特征提取它还在悄悄扮演一个降采样器的角色。很多架构在 ViT 最后一层会接 pooling 或者 Q-Former把视觉 token 数从几百上千压缩到几十个再送进 LLM。去掉 ViT 之后视觉 token 就失去了一个天然的压缩机会你必须在自己的方案里重新设计降采样逻辑。2.3 第三堵墙视觉特征空间和语言语义空间的鸿沟LLM 的输入 embedding 是从海量语料里端到端学出来的它们分布在一个语义聚类非常明显的高维空间里相似的词靠近不相似的远离。这个空间是 LLM 能够流畅生成语言的基础。而 patch embedding 是什么它只是一次线性投影把像素块映射到某个高维空间。这个空间的坐标轴来自像素统计特征和语言语义空间没有天然的对应关系。如果直接把这两种分布差异巨大的 token embedding 混在一起送给 LLMLLM 的每一层都要花费额外的容量去协调两个“语言不通”的空间效果自然好不到哪里去。这也是为什么主流 MLLM 架构里ViT 后面一定要再接一个 projectorMLP、Q-Former 之类干的就是把视觉特征“翻译”到语言空间这件事。去掉 ViT 之后这个翻译负担并不会消失只会转移给 LLM 自己。这三堵墙合在一起基本解释了为什么主流方案宁愿背一个重的 ViT也不走“直接 patch embedding”这条轻量路线。但如果你资源受限、任务边界清晰或者就是想在架构上做点不一样的尝试也不是完全没有破局的办法。关键在于改变训练策略而不是硬碰硬地去撞这三堵墙。3. 一条能走通的路让文本损失反过来塑造 patch embedding先说大多数人的第一反应直接把 patch embedding 接 LLM然后把 ViT 换成一套预训练好的 patch embedding 权重不就行了吗比如从 CLIP 里抽出 patch embedding 层来用。我最早也这么干过效果非常拧巴。原因在于传统的视觉预训练目标对比学习、重建、自监督学到的是“通用视觉好特征”这个特征空间和“对语言模型预测下一个词最有用的特征空间”是两回事。一个特征可能特别适合做图像检索但对语言模型判断“图中人物是否在微笑”帮助甚微。你把一个为了别的任务优化的特征空间强行接到 LLM 上中间的语义断层是治不好的。正确的思路恰恰相反patch embedding 不要预训练直接当作 LLM 输入侧的一组可学习参数用 LLM 的文本生成损失从零开始端到端训练它。乍一听这个想法有点吓人——视觉编码器不预训练那不是从零开始学看东西吗但实验做下来发现在资源和任务可控的前提下这条路完全可行而且效果比“预训练 patch embedding 对齐模块”好不少。为什么关键在于梯度路径的变化。去掉 ViT 之后patch embedding 产生的梯度只有一条通路经过 LLM 的所有层最后从语言模型的损失传回来。这意味着 patch embedding 必须学会以“语言模型能识别的格式”来压缩视觉信息。它学到的不是一个独立的视觉特征提取器而是语言模型输入侧的一层“视觉词法层”——它的编码方式是被下游语言任务反向塑造的。我在实验中做了三组方案对比结果很有意思方案对齐方式参数量细粒度描述能力训练稳定性冻结 ViT projector固定视觉特征只学翻译层低差特征不匹配任务稳定微调 ViT projector视觉和翻译一起学高好但显存压力大中等容易过拟合无预训练 patch embedding 文本损失端到端无显式对齐由语言任务塑造最低好任务匹配度高需要精心调参这里最直观的指标是模型在视觉上下文下的困惑度。同样是 1B 左右的模型用文本损失直接塑造的 patch embedding在细粒度描述任务上的困惑度明显低于“预训练 projector”方案。尤其是需要模型说出物体颜色、相对位置、动作细节这类信息时gap 比想象中更大。这个路线的底层逻辑其实就是让视觉特征在训练过程中向语言模型可以消费的方向生长。语言任务成了视觉特征学习的天花板也成了它的导航标。这也引出了下一节的核心怎么让 patch embedding 真正地对齐到语言词的语义空间里。4. 词表对齐patch embedding 对齐语言词表的实践细节4.1 把视觉输入当成一种“动态词表”要让这个方案跑得稳一个很关键的思想实验是别把 patch embedding 当成“连续特征”尝试把它当作一种“离散视觉词表”的 soft 输入。具体做法参考了 VQVector Quantization思路。维护一个可学习的 codebook也就是一组有限的视觉词向量每个 patch embedding 通过最近邻匹配映射到 codebook 里的某一个词上然后把这个词对应的向量作为 LLM 的输入。训练时LLM 在预测下一个文本 token而视觉侧的更新信号来自“这个视觉词是否帮助语言模型预测得更准”。这个机制本质上是强制视觉 token 和语言 token 进入同一个“语义投票”系统里。语言模型在预测下一个词时看到的画面信息和文本信息都变成了可比较的分布视觉词和文本词在同一个概率空间里竞争、协作。这样训练出来的视觉词和语言词的 embedding会在语义空间里逐渐形成对应的簇结构也就是一种真正的“词表对齐”。直接连续 embedding 的问题在于它没有这种被强制离散化的过程视觉特征很容易“躲”在一个语言模型感知不到的区域里自说自话。当然离散化之后可以使用直通估计器解决梯度回传问题这是在工程上绕不开的细节。4.2 下词预测任务是整个对齐的引擎对齐不是靠一个单独的 loss 项而是靠“下词预测”这个任务本身来驱动的。模型读入视觉 token然后去预测下一个文本 token。看起来平平无奇但这个过程中视觉 token 被拉进了语言模型的概率计算里——预测正确的那个词它的 score 必须高而它之所以会高部分原因来自视觉 token 提供了足够的信息。我实验中一个很重要的观察是codebook 里被激活的视觉词数量在训练早期会急剧上升随后趋于稳定。这不只是视觉侧在聚类也是视觉词和文本词在 embedding 空间里互相锚定的过程。激活的视觉词过多说明视觉特征发散、没有对齐过少说明信息被过度压缩了。理想状态下激活词数量应该恰好覆盖任务所需的视觉概念范围。训练时还可以给视觉-文本对齐加一点显式的锚点策略随机把一些文本 token 的位置与它对应的视觉区域绑定让模型在生成这个文本 token 时必须显式地“看”对应的视觉输入。锚点比例anchor rate我从 5% 到 60% 都试过最终落在 15%~40% 这个区间效果比较稳定。太低的时候模型倾向于用语言先验作答视觉信息基本被忽略太高的时候视觉 token 过度主导模型反而失去了推理和泛化能力回答开始变得“只贴图、不会想”。4.3 一个数据实验同参数量下对齐质量对比我跑过一个最直观的对比实验同样 1B 的 LLM、同样的训练数据量唯一的区别是视觉侧接入方式。方案 A 用离线预训练的 ViT 特征加一个 MLP projectorfreeze ViT 只调 projector方案 B 用无预训练的 patch embedding配合离散视觉词表全程用文本损失端到端训练。训练到同样的 step 之后做视觉问答评估方案 B 在“需要视觉细节才能答对”的题目上表现更好准确率高出大约 6~8 个百分点但在纯知识类问题不需要看图也能答上两者没有显著差异。这说明端到端 text-loss 塑造的 patch embedding 确实把有限的信息容量用在了语言任务真正关心的视觉细节上而不是浪费在和任务无关的通用视觉属性上。这里顺带提醒一句离线预训练 ViT 这套范式在数据量足够大的时候并没有错错的是在小数据、小模型的场景里硬套它。大模型 大数据时离线预训练的通用视觉特征加上大规模对齐数据效果依然是最稳的。直接 patch embedding 的真正价值是在资源受限、任务边界明确的场景里做到“够用就好”。5. 实操避坑分辨率、位置编码、初始化这些细节决定成败以下每一条都是我在实际训练中踩过的坑排序不分先后但每一条都直接影响最终效果。5.1 patch size别在琐碎的调参里丢细节不走 ViT 之后patch size 的选择比在 ViT 时代更敏感。16×16 patch 在 224 分辨率下是 196 个 token视觉细节保真度够用但模型对一些细小物体的边缘和空间关系学得很模糊。换成 14×14token 数到 256细节能力立刻提升但训练时间大概涨了 20%~30%。不要只看 token 数patch size 变小意味着每个 token 的信息密度变低了LLM 需要更多注意力去组合这些碎片开销并不只是线性增长。如果你做的是 OCR、图表理解这种对细节要求很高的任务靠缩小 patch size 的边际收益很快会到头。建议在 patch embedding 之后加一个轻量的局部对齐增强模块用几层卷积或 depthwise conv 对 embedding 做局部邻近融合这能很大程度弥补 ViT 早期层缺失带来的局部建模短板。这个模块的参数量很小但对细粒度任务提升显著。5.2 位置编码这里的位置编码比平时更重要ViT 在的时候空间信息一部分靠位置编码一部分靠 Transformer 层内部的 attention 模式来隐式建模。去掉 ViT 之后位置编码变成了唯一的空间信息来源它的质量直接决定模型能不能正确地理解“左边、右边、上面、下面”这类概念。我在固定分辨率场景下对比过两类方案可学习绝对位置编码和 2D RoPE。固定 224×224 输入时可学习绝对位置编码更快收敛训练也更稳但一旦要把模型迁移到更高分辨率比如 448需要做位置编码插值效果衰减非常明显。如果你确定只在固定分辨率下使用用可学习绝对位置编码是更省事的选择如果产品上线后可能需要适配多种输入尺寸建议直接上 2D RoPE省得后面为了一个分辨率改动重新训模型。5.3 初始化直接随机初始化会让人很痛苦无预训练 patch embedding 看起来省事但直接用随机初始化会让训练前期异常煎熬损失值高得离谱收敛速度感人。我的经验是从 CLIP ViT 的 patch embedding 权重拷贝过来做初始化。这个操作不涉及“用预训练视觉特征”只是借了一个还不错的几何初始位置。实验下来初始化良好的模型在 1/3 的训练步数内就能追上随机初始化模型在全部训练步数上的效果。你仍然是用文本损失端到端塑造它只是给了一个更平滑的起点。5.4 梯度稳定性文本任务很容易淹没视觉信号端到端训练时一个隐藏问题是梯度失衡。LLM 本身很强文本任务的梯度非常大patch embedding 从远端得到的梯度经过多层衰减后很容易被 LLM 内部梯度淹没。加上视觉序列通常较长训练时 loss 容易出现剧烈震荡。处理方式有两个我建议一起用。一是对视觉侧的梯度做 clip设定一个较小的 max norm让视觉信号更新得更保守二是在 LLM 输入层之前加一个 LayerNorm 接住视觉 embedding稳定它进入 LLM 时的分布防止后面层被视觉分布的漂移干扰。这个 LayerNorm 加不加训练曲线差异非常明显。5.5 Pointing坐标指示任务对方位感知的挑战是隐藏的大坑如果你以为直接 patch embedding 只影响画质细节那你会在 Pointing 类任务上被重重打脸。所谓 Pointing就是模型需要输出目标在图像中的坐标位置比如“请指出图中红衣服的人并给出它的坐标”。实测表明同样的数据量下直接 patch embedding 的方案在 Pointing 任务上的点选准确率明显低于带 ViT 的标准 MLLM 架构。原因是位置识别这件事极度依赖底层的空间结构建模。ViT 的层次化结构天然会让不同层关注不同尺度的空间关系而 CNN 有平移等变性这些对“准确定位”极其重要。patch embedding 只靠位置编码提供的粗粒度空间线索很难在像素级别上定位目标。如果你的产品需求里有任何坐标输出、目标定位、区域选取这类能力坦白说不建议走直接 patch embedding 这条路老老实实保留视觉 Transformer 是更稳妥的选择。如果非要走那至少要在 patch embedding 后面补上能恢复局部空间关系的模块并预期 Pointing 准确率会有一个明显的折扣。6. 什么样的场景最适合这个方案如果只看前面的分析可能觉得这个方案到处是坑。但换个角度看它有两个很突出的优点参数少、没有独立视觉预训练。这决定了它的适用场景非常明确。比较适合的场合是资源受限的端侧或小模型场景。比如在 1B 以下的模型上做单图 captioning、简单的场景描述、物体识别直接用 patch embedding 文本损失端到端训练可以在模型容量有限的前提下把视觉信息“翻译成文本”的效率拉满。因为在这种场景里你根本没有余量去背一个 ViT 和一套对齐模块。不适合的场合也很清晰高分辨率输入、细粒度 grounding、坐标输出、复杂多图推理。这几个场景里视觉特征的深度和空间精度是刚需省掉 ViT 就是拿核心能力换一点点资源节省非常不划算。另外提醒一句如果你想把这个方案推广到多图输入序列长度问题会进一步恶化。多图意味着视觉 token 数量成倍增长除非你愿意接一个强力的 token 压缩模块否则 LLM 的 attention 代价会很快失控。在轻量级架构讨论里“去掉 ViT”经常被当成一个激进的简化方案来调侃但真正动手试过之后才会发现这个方案逼着你想明白一件事视觉特征在语言模型里到底要承担什么角色。你省掉的不只是一个 Transformer 编码器而是省掉了一套预先定义好“什么是好视觉特征”的规则然后把定义权交给了语言任务本身。这个交换在特定约束下是合理的但前提是你完全清楚自己在牺牲什么、补偿什么。如果这篇文章让你对“直接 patch embedding”这个方向有了更具体的判断那我的实验就没有白做。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →