【免费下载链接】InternVL3-78B-Pretrained
InternVL3-78B-Pretrained是书生(InternVL)系列的多模态大语言模型(MLLM),支持一次对话中同时理解多张图片。本文将带你快速搞懂它在多图对话时的两种官方玩法:拼接图像(combined images)与独立图像(separate images)——何时该用哪种、num_patches_list参数到底在做什么、以及两种写法的完整示例。
一、先搞懂:动态分辨率决定了"每张图有多少块"
在讲玩法之前,先理解一个关键机制,它是两种玩法差异的根源。
InternVL3 采用动态分辨率策略:一张图会被切成若干个 448×448 像素的 tile(块),图片越大、比例越"方",切出的块数越多;若开启了use_thumbnail(本项目配置为开启),还会额外追加一张缩略图作为"全局视角"。
也就是说,每张图贡献给模型的视觉块数(patch 数)是不一样的。config.json 中的max_dynamic_patch: 12表示单张图最多切 12 块。
image1.jpg ──> [tile][tile][tile][thumb] → 4 个视觉块 image2.jpg ──> [tile][tile][thumb] → 3 个视觉块模型内部用<IMG_CONTEXT>占位符来承接这些视觉块,占位符的个数必须和实际切出的块数严格对应。这正是"拼接"与"独立"两种写法分歧所在。
二、玩法一:拼接图像(combined images)
什么时候用?
把多张图的视觉块首尾相接成一个整体,在提问中只放一个<image>占位符。此时模型会把所有视觉内容当作"一张大拼图"来理解,写法最简单。
关键步骤
- 分别加载两张图(
load_image已内置动态切块逻辑); - 用
torch.cat在维度 0 上拼接,得到合并的pixel_values; - 提问中只写一个
<image>,不需要传num_patches_list——chat 方法 内部默认把所有视觉块算作一张图:
pixel_values1 = load_image('./examples/image1.jpg', max_num=12).to(torch.bfloat16).cuda() pixel_values2 = load_image('./examples/image2.jpg', max_num=12).to(torch.bfloat16).cuda() pixel_values = torch.cat((pixel_values1, pixel_values2), dim=0) question = '<image>\nDescribe the two images in detail.' response, history = model.chat(tokenizer, pixel_values, question, generation_config, history=None, return_history=True)完整可运行示例见 README.md。
特点
- ✅ 写法最少,一个
<image>搞定; - ⚠️ 模型无法从结构上区分哪些块来自图1、哪些来自图2,做"两张图的相似/差异对比"时,指代可能不够精确;
- ⚠️ 若某张图恰好是单块,其缩略图与主 tile 内容相近,拼接后信息略有冗余。
三、玩法二:独立图像(separate images)
什么时候用?
当你需要模型明确区分每张图(比如"图1和图2有什么不同"),就应使用独立图像模式。核心是给model.chat传一个num_patches_list参数,声明"前 N 块属于图1,后 M 块属于图2"。
关键步骤
- 拼接视觉块时,记下每张图各自的块数;
- 提问中为每张图各放一个
<image>,并加上Image-1:、Image-2:这样的编号提示; - 把块数列表传给
num_patches_list:
pixel_values = torch.cat((pixel_values1, pixel_values2), dim=0) num_patches_list = [pixel_values1.size(0), pixel_values2.size(0)] # 如 [4, 3] question = 'Image-1: <image>\nImage-2: <image>\nDescribe the two images in detail.' response, history = model.chat(tokenizer, pixel_values, question, generation_config, num_patches_list=num_patches_list, history=None, return_history=True)完整示例见 README.md。
内部发生了什么?
在 modeling_internvl_chat.py 中,chat方法会按num_patches_list逐个替换每个<image>占位符:每替换一个,就为该图展开对应数量的<IMG_CONTEXT>token。例如num_patches_list=[4, 3]时:
- 第 1 个
<image>→<img>+ 4×256 个<IMG_CONTEXT>+</img> - 第 2 个
<image>→<img>+ 3×256 个<IMG_CONTEXT>+</img>
这样每个图的视觉块就被"框"在各自的<img></img>边界内,模型天然知道图的边界在哪里。若传错块数(总数对不上),第 262 行 的assert会直接报错提醒你。
四、选型对比:一张表看懂该选哪个
| 对比维度 | 拼接图像(combined) | 独立图像(separate) |
|---|---|---|
| 提问中的占位符 | 1 个<image> | 每张图 1 个<image> |
是否需要num_patches_list | 否(默认全部算一张图) | 必须,且总数要等于视觉块总数 |
| 图片边界感知 | 弱,视为一张"大图" | 强,<img></img>明确分隔 |
| 适合场景 | 整体描述、氛围理解 | 图片对比、"图1是什么/图2是什么"类问答 |
| 写法复杂度 | ⭐ 最简单 | ⭐⭐ 多一步记录块数 |
💡经验法则:做图片对比(相似点/差异点)时优先用独立图像模式;只是让模型"综合看看这几张图"时,拼接模式足够且更省事。
五、环境准备与上手清单
在跑多图对话之前,先确认这几件事:
- 硬件:
load_in_8bit=True时约需 2 张 80GB 显卡;16-bit(bf16)至少 3 张 80GB 显卡(见 README.md); - 依赖:
transformers>=4.37.2,并设置trust_remote_code=True加载本仓库的自定义代码; - 上下文长度:多图意味着视觉 token 更多,必要时调大
session_len/上下文窗口; - 批量与视频场景:
batch_chat与视频多轮对话同样依赖num_patches_list来划分每个样本的视觉块,用法与本文一致。
六、相关文件速查
| 内容 | 路径 |
|---|---|
| 快速开始与完整多图示例 | README.md |
chat/batch_chat多图实现源码 | modeling_internvl_chat.py |
动态分辨率配置(max_dynamic_patch、use_thumbnail) | config.json |
| 视觉塔(ViT)实现 | modeling_intern_vit.py |
| 对话模板定义 | conversation.py |
| 示例图片 1 | examples/image1.jpg |
| 示例图片 2 | examples/image2.jpg |
掌握"拼接"与"独立"这两种多图对话方式后,你就能充分发挥 InternVL3-78B-Pretrained 的多图理解能力:简单场景用最省事的拼接模式,对比分析类任务则切换到带num_patches_list的独立模式,让模型真正看清"哪张是哪张"。
【免费下载链接】InternVL3-78B-Pretrained
相关推荐
InternVL3-78B-Instruct多图理解实战:拼接图像与独立图像两种模式差异及最佳实践
InternVL3 78B Instruct多图理解实战:拼接图像与独立图像两种模式差异及最佳实践 InternVL3 78B Instruct 是 OpenG
InternVL2-26B 多图对话实战:拼接图像与独立图像两种模式一次讲透
InternVL2 26B 多图对话实战:拼接图像与独立图像两种模式一次讲透 InternVL2 26B 是 InternVL 2.0 系列的指令微调多模态大模
InternVL3-1B-Pretrained 图像描述实战:单图对话、多图对比与视频理解的 3 种玩法
InternVL3 1B Pretrained 图像描述实战:单图对话、多图对比与视频理解的 3 种玩法 InternVL3 1B Pretrained 是书生
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考