
【免费下载链接】InternVL3-14B-Instruct项目地址https://ai.gitcode.com/OpenGVLab/InternVL3-14B-Instruct点击查看免费下载InternVL3-14B-Instruct 是 OpenGVLab 开源的多模态大语言模型MLLM采用经典的 ViT-MLP-LLM 架构。多模态大模型最烧资源的地方就是视觉 Token一张 448×448 的图片切块就能产出 1024 个视觉 Token动态分辨率下轻松上万。本文逐行拆解 InternVL3-14B-Instruct 中像素重排Pixel Shuffle MLP 连接器这两段核心源码讲清楚它如何用零参数手段把 1024 个视觉 Token 压缩到 256 个砍掉 3/4再把视觉特征翻译成 Qwen2.5-14B 语言模型听得懂的向量。为什么多模态大模型要砍视觉 Token在动手读源码前先建立一个直观认知阶段单张 448×448 图块 Token 数说明ViT 输出原始1024每个 14×14 patch 对应 1 个 TokenPixel Shuffle 之后2562×2 邻域合并减少 75%12 个图块 缩略图极端情况13312 →3328动态分辨率最坏情形Token 数量直接决定两件事显存与 KV Cache每个视觉 Token 都要在 LLM 里占一份 KV Cache13312 个 Token 意味着巨大的上下文开销注意力开销Attention 计算量与序列长度平方成正比Token 砍到 1/4注意力成本降到1/16。InternVL 系列的解法是不在信息上做减法而是把相邻 2×2 个视觉 Token 的特征在通道维拼接——空间分辨率降 4 倍特征维度升 4 倍信息一点没丢。这就是下面要逐行分析的pixel_shuffle。一个 448×448 图块为什么有 1024 个 Token打开 config.json 可以看到视觉编码器的关键配置image_size: 448config.json每个图块固定为 448×448 像素patch_size: 14config.jsonViT 以 14×14 为一个 patchhidden_size: 1024config.jsonViT 每个 patch 特征向量维度448 ÷ 14 32所以一张图块被切成32×32 1024 个 patchViT 输出 1024 个外加 1 个 CLS共 1025 个Token每个 Token 的维度是 1024。patch 卷积与位置编码的实现见 modeling_intern_vit.py。Pixel Shuffle 源码逐行解析零参数把 Token 数压到 1/4核心函数在 modeling_internvl_chat.py一共不到 15 行def pixel_shuffle(self, x, scale_factor0.5): n, w, h, c x.size() # N, W, H, C -- N, W, H * scale, C // scale x x.view(n, w, int(h * scale_factor), int(c / scale_factor)) # -- N, H * scale, W, C // scale x x.permute(0, 2, 1, 3).contiguous() # -- N, H * scale, W * scale, C // (scale ** 2) x x.view(n, int(h * scale_factor), int(w * scale_factor), int(c / (scale_factor * scale_factor))) if self.ps_version v1: warnings.warn(In ps_version v1, the height and width have not been swapped back, which results in a transposed image.) else: x x.permute(0, 2, 1, 3).contiguous() return x以单张图块为例输入形状是(1, 32, 32, 1024)即W32、H32、C1024。scale_factor0.5来自 config.json 中的downsample_ratio含义是空间尺寸减半。三步 view/permute 分别做了什么第 1 步x.view(n, w, h*0.5, c/0.5)→(1, 32, 16, 2048)把 H 方向每连续 2 个 patch 的特征向量首尾拼接成一个 2048 维向量。空间上 32 行变 16 行通道上 1024 变 2048。注意这一步只是内存视角的重解释view没有任何参数参与。第 2 步x.permute(0, 2, 1, 3).contiguous()→(1, 16, 32, 2048)交换 W、H 两个维度为下一步在 W 方向做同样的合并做准备。第 3 步x.view(n, h*0.5, w*0.5, c/0.25)→(1, 16, 16, 4096)把 W 方向每连续 2 列再拼进通道维通道 2048 → 4096。至此得到最终结果空间32×32 → 16×16Token 数 1024 → 256正好砍掉 3/4通道1024 → 4096放大 4 倍。整个操作等价于计算机视觉里常说的PixelUnshuffle / space-to-depth把空间冗余搬到通道冗余上零参数、无信息损失、纯重排代价几乎只有一两次内存拷贝。ps_version v1 与 v2 的区别最后 4 行是一个容易被忽略的历史包袱ps_version v1只做了一次 W/H 交换没有换回来结果输出的网格在数学上是转置的源码直接warnings.warn提醒图片被转置了ps_version v2多做一次permute(0, 2, 1, 3)把宽高换回正常方向。本仓库 config.json 中ps_version: v2即修复后的版本——读旧论文或旧仓库代码时若发现宽高方向怪怪的多半是 v1 的问题。MLP 连接器源码逐行解析把视觉特征翻译成 LLM 语言Pixel Shuffle 之后每个 Token 是 4096 维的 ViT 特征但语言模型 Qwen2.5-14B 的隐藏维度是5120config.json空间对不上。桥梁就是mlp1定义在 modeling_internvl_chat.pyvit_hidden_size config.vision_config.hidden_size # 1024 llm_hidden_size config.llm_config.hidden_size # 5120 self.mlp1 nn.Sequential( nn.LayerNorm(vit_hidden_size * int(1 / self.downsample_ratio) ** 2), # LN(4096) nn.Linear(vit_hidden_size * int(1 / self.downsample_ratio) ** 2, llm_hidden_size), # 4096→5120 nn.GELU(), nn.Linear(llm_hidden_size, llm_hidden_size) # 5120→5120 )逐层理解LayerNorm(4096)对 Pixel Shuffle 拼接出的 4096 维向量做归一化稳定数值分布Linear(4096 → 5120)把视觉空间投影到LLM 词嵌入空间GELU非线性激活让连接器具备非线性拟合能力Linear(5120 → 5120)在 LLM 空间内再做一次精调输出可直接混入文本序列的向量。两个细节值得注意输入维度vit_hidden_size * (1/downsample_ratio)**2正是ViT 维度 × 4与 Pixel Shuffle 的输出严格对齐——这两个模块的超参数是互相咬合设计的该连接器共约47.2M 参数4096×5120 5120×5120相对 14B 的 LLM 只占约 0.3%却是整个模型唯一的跨模态翻译官。extract_feature() 完整调用链上述两个模块的串接逻辑在 extract_feature() 中逐行对应def extract_feature(self, pixel_values): if self.select_layer -1: vit_embeds self.vision_model( pixel_valuespixel_values, output_hidden_statesFalse, return_dictTrue).last_hidden_state # ① 取 ViT 最终层输出 else: vit_embeds self.vision_model(...).hidden_states[self.select_layer] # ② 取指定中间层 vit_embeds vit_embeds[:, 1:, :] # ③ 去掉 CLS Token h w int(vit_embeds.shape[1] ** 0.5) # ④ 32 vit_embeds vit_embeds.reshape(vit_embeds.shape[0], h, w, -1) # ⑤ (B,32,32,1024) vit_embeds self.pixel_shuffle(vit_embeds, scale_factorself.downsample_ratio) # ⑥ (B,16,16,4096) vit_embeds vit_embeds.reshape(vit_embeds.shape[0], -1, vit_embeds.shape[-1]) # ⑦ (B,256,4096) vit_embeds self.mlp1(vit_embeds) # ⑧ (B,256,5120) return vit_embeds要点①select_layer控制取 ViT 的哪一层特征本仓库配置为-1config.json即最后一层③vit_embeds[:, 1:, :]切掉 CLS只保留 1024 个 patch Token——CLS 信息不参与后续的 Token 压缩④ 用开方反推网格边长1024 → 32再 reshape 成(B, 32, 32, 1024)交给 Pixel Shuffle⑧ 输出(B, 256, 5120)每张图块最终交给 LLM 的正是256 个 5120 维向量。视觉 Token 如何注入 Qwen2.5 语言模型压缩后的向量如何插进文本答案在 generate()聊天模板会把用户输入里的image占位符展开成img256 × 图块数个IMG_CONTEXT/img展开数量由 num_image_token 计算(448//14)² × 0.5² 256IMG_CONTEXT的 token id 见 added_tokens.jsongenerate()先把input_ids整体嵌入为input_embeds再找出所有等于IMG_CONTEXT的位置L332-L334把这些位置上的文本嵌入原位替换为extract_feature产出的视觉向量selected (input_ids self.img_context_token_id) input_embeds[selected] vit_embeds.reshape(-1, C).to(input_embeds.device)替换后的input_embeds直接进入language_model.generate(...)L340-L347LLM 从此看到的是一条视觉向量与文本向量无缝混排的序列——这就是 ViT-MLP-LLM 范式的最后一环。 补充InternVL3 还引入了 V2PEVariable Visual Position Encoding用更小、更灵活的位置增量 δ 为视觉 Token 编号配合压缩后的 Token 布局使模型在长上下文理解上比前代更强见 README.md。这个设计到底省了多少指标无 Pixel ShuffleInternVL3 方案收益单图块视觉 Token1024256−75%极端输入12 图块缩略图133123328上下文短 4 倍相关注意力计算量基准基准的 1/16显存/时延双降信息量1024×1024 维256×4096 维不变纯重排额外参数—MLP 约 47.2M仅占全模型 ~0.3%一句话总结用一次免费的内存重排换 75% 的 Token 预算再用 0.3% 的参数完成跨模态对齐——这是 InternVL3 系列能以 14B 规模支撑高分辨率、多图、视频输入的底层原因。新手速查关键源码文件路径文件作用config.jsondownsample_ratio、ps_version、select_layer、动态分辨率上下限等全部关键超参数modeling_internvl_chat.pypixel_shuffle()、mlp1、extract_feature()、Token 替换注入逻辑modeling_intern_vit.pyInternViT 视觉编码器patch 卷积、位置编码、Transformer 层configuration_intern_vit.pyViT 配置类hidden_size、patch_size等默认值configuration_internvl_chat.py组合配置类定义downsample_ratio、ps_version等字段added_tokens.jsonimg、IMG_CONTEXT等视觉占位 token 的 id 映射examples/image1.jpg仓库内置示例图片README 推理脚本的输入总结Pixel Shufflepixel_shuffleL168-L182两次view 两次permute把 32×32 的 Token 网格折叠成 16×16通道从 1024 升到 4096零参数砍掉 3/4 视觉 Tokenps_versionv2修复了 v1 的转置问题MLP 连接器mlp1L78-L83LayerNorm → Linear(4096→5120) → GELU → Linear(5120→5120)约 47.2M 参数是 ViT 与 Qwen2.5-14B 之间唯一的翻译桥Token 注入L332-L334IMG_CONTEXT位置的文本嵌入被视觉向量原位替换视觉与文本在同一序列中无缝混排。读懂这三段不到 40 行的源码你就掌握了 InternVL3-14B-Instruct 视觉侧设计的全部核心。✅赞分享【免费下载链接】InternVL3-14B-Instruct项目地址https://ai.gitcode.com/OpenGVLab/InternVL3-14B-Instruct点击查看免费下载相关推荐Pixel Shuffle 降维 4 倍的秘密InternVL2_5-8B-MPO MLP 连接器如何压缩视觉 Token 省算力Pixel Shuffle 降维 4 倍的秘密InternVL2_5 8B MPO MLP 连接器如何压缩视觉 Token 省算力 在 InternVL2_5视觉Token如何压缩4倍InternVL3-1B-AWQ的Pixel Shuffle降采样魔法视觉Token如何压缩4倍InternVL3 1B AWQ的Pixel Shuffle降采样魔法 InternVL3 1B AWQ 是开源多模态大模型InternVL2_5-38B-MPO Pixel Shuffle 代码级详解视觉Token如何减少到1/4InternVL2_5 38B MPO Pixel Shuffle 代码级详解视觉Token如何减少到1/4 InternVL2_5 38B MPO 是 Op上一篇从配置到部署AIMNet2-wb97m-d3模型参数详解与最佳实践下一篇【免费下载】 scrcpy常见问题解答从adb连接到设备控制的全面指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考