ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

InternVL2-Pretrain-Models的Pixel Shuffle与mlp1投影器:图像特征如何压缩成LLM的词汇

InternVL2-Pretrain-Models的Pixel Shuffle与mlp1投影器:图像特征如何压缩成LLM的词汇

【免费下载链接】InternVL2-Pretrain-Models

项目地址:https://ai.gitcode.com/OpenGVLab/InternVL2-Pretrain-Models
点击查看免费下载

InternVL2-Pretrain-Models 是 InternVL 2.0 多模态大语言模型 Stage-1 阶段的多模态预训练模型仓库,提供从 InternVL2-1B 到 Llama3-76B 共 7 个规格的预训练权重。这篇文章带你拆解其中最关键的两个组件:Pixel Shuffle 空间重排与mlp1 投影器,看看一张图片的像素特征是如何一步步压缩成 LLM 能读懂的"词汇向量"的。

一、为什么图像特征必须先"压缩"

多模态模型的基本思路是:让 ViT 视觉编码器看图,再把图像特征塞进语言模型的输入序列。但直接塞会有个尴尬的问题——token 太多。

InternVL2 系列把图片统一缩放到 448×448,用 14×14 的 patch 切块,一张图会切出 32×32 =1024 个 patch token。而且 InternVL2 支持动态分辨率:一张大图最多可切成 12 个 patch(max_dynamic_patch: 12),也就是 12288 个视觉 token。

对 LLM 来说,注意力计算量随序列长度平方增长。如果把 1 万多个视觉 token 原样喂给 LLM,推理成本会失控。InternVL2 的解法分两步走:

  1. Pixel Shuffle:把 2×2 相邻的 4 个空间 token 合并成 1 个,token 数降为 1/4,细节信息搬进通道维度而不是丢弃;
  2. mlp1 投影:把视觉隐层维度"翻译"成 LLM 的隐层维度。

二、Pixel Shuffle:一次纯重排,1024 变 256

Pixel Shuffle 的实现非常"轻量"——它在 modeling_internvl_chat.py 的pixel_shuffle方法中,不引入任何可学习参数,只做张量形状的重组(reshape + permute):

  • 输入:ViT 输出的特征网格(以 1B 为例是 32×32×1024)
  • 按downsample_ratio = 0.5重排:纵向每 2 行并成 1 行,横向每 2 列并成 1 列
  • 输出:16×16 的网格,通道数变为原来的 4 倍(1024 → 4096)

可以把它想象成"4 宫格拼图":每个输出 token 不再只代表 1 个 patch,而是打包了 2×2 邻域共 4 个 patch 的完整特征。空间分辨率减半,但局部细节没有丢失,只是从"位置"挪到了"通道"里。

以 InternVL2-1B(ViT 隐层 1024、LLM 隐层 896)为例,整个过程是这样的:

阶段空间网格通道维度token 数
ViT 原始输出32×3210241024
Pixel Shuffle 之后16×164096256
mlp1 投影之后16×16896256

一个容易踩坑的细节:pixel_shuffle支持两个版本(modeling_internvl_chat.py)。ps_version='v1'重排后忘记把高、宽维度换回来,会导致图像特征转置(上下左右错位);v2修复了这个问题。本仓库所有模型的 config.json 里都是"ps_version": "v2"。

三、mlp1 投影器:ViT 与 LLM 之间的"翻译官"

重排之后通道维度变成vit_hidden × 4,但它仍然属于"视觉空间",LLM 看不懂。mlp1就是那座桥,定义在 modeling_internvl_chat.py:

  • LayerNorm:先对 4 倍通道维做归一化,稳定数值分布
  • Linear:把vit_hidden × 4映射到 LLM 的llm_hidden_size
  • GELU:非线性激活
  • Linear:在 LLM 维度内再变换一次

这其实是多模态社区经典的"两层 MLP projector"(早期 LLaVA 同款结构),特点是参数量小、表达能力够用。各规格模型的维度换算一览(数据来自各目录下的 config.json):

模型ViT 隐层Shuffle 后输入LLM 隐层(输出)
InternVL2-1B10244096896
InternVL2-2B102440962048
InternVL2-4B102440963072
InternVL2-8B102440964096
InternVL2-26B3200128006144
InternVL2-40B3200128007168
Llama3-76B3200128008192

📌 注意小模型(1B/2B/4B/8B)用的是 InternViT-300M,隐层 1024;大模型(26B 及以上)用 InternViT-6B,隐层 3200。mlp1 是从零开始训练的连接层——它正是 Stage-1 预训练阶段让"视觉词汇"和"语言词汇"学会对齐的关键部件。

四、完整数据流:从像素到 LLM 输入

extract_feature方法(modeling_internvl_chat.py)把上述流程串成 4 步:

  1. 取 ViT 特征:默认select_layer = -1,即取最后一层输出;
  2. 去掉 CLS token:vit_embeds[:, 1:, :]只保留 patch 特征;
  3. Pixel Shuffle 压缩:网格 32×32 → 16×16,通道 ×4;
  4. mlp1 投影:压到 LLM 隐层维度,得到每 patch256 个"图像词汇"(num_image_token = (448/14)² × 0.5² = 256)。

接下来,forward在 modeling_internvl_chat.py 中做一个巧妙操作:找到输入序列里所有<IMG_CONTEXT>占位符(img_context_token_id),用 256 个图像向量整体替换掉它们的词嵌入。于是 LLM 读到的就是一段"图像词汇 + 文本词汇"混合的序列,无需任何交叉注意力模块。

五、关键配置参数速查

以上行为都由 configuration_internvl_chat.py 定义的参数控制,在各模型目录的 config.json 中可直接查看:

参数本仓库取值作用
downsample_ratio0.5Pixel Shuffle 缩放比例,token 数按平方压缩
ps_versionv2使用修复了转置 bug 的重排版本
select_layer-1取 ViT 最后一层特征
force_image_size448图像统一缩放尺寸
min/max_dynamic_patch1 / 12动态分辨率的 patch 数范围,对应 256~3072 个图像 token

六、小结:一套极简但高效的压缩方案

InternVL2-Pretrain-Models 的视觉-语言对齐设计,本质上是"先无损压缩、再线性翻译":

  • Pixel Shuffle 用零参数的重排把视觉 token 减到 1/4,同时保住局部细节;
  • mlp1 两层 MLP 完成跨模型的维度翻译,参数开销极小;
  • 配合动态 patch 机制,模型可按图分配 256~3072 个 token,在精度与成本之间灵活权衡。

这套方案也正是 InternVL 2.0 能用 8k 上下文处理多图、长文、视频的基础——理解了这两个组件,你就读懂了该仓库最核心的架构思想。

【免费下载链接】InternVL2-Pretrain-Models

项目地址:https://ai.gitcode.com/OpenGVLab/InternVL2-Pretrain-Models
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进