Nex-N2.5-Pro多模态输入指南:图像与视频处理参数全解析——从patch_size到768帧视频抽帧
Nex-N2.5-Pro 是一款面向长程 Agent 任务的多模态大模型,原生支持图像与视频输入。本指南完整解析它的视觉处理参数:patch_size=16的动态分辨率切块、2fps 视频抽帧、max_frames=768帧上限、2×2 空间合并与视觉 Token 占位机制,并给出 Token 消耗估算公式,帮助你在 3 分钟内搞懂图像和视频是如何被模型"看见"的。
🧩 Nex-N2.5-Pro 多模态架构速览:3 个文件定义输入通路
理解多模态输入,只需要看模型仓库中的三类文件:
| 文件 | 作用 |
|---|---|
| config.json | 模型主干 + 视觉编码器(vision_config)参数 |
| preprocessor_config.json / processor_config.json | 图像/视频前处理管线参数(切块、抽帧、归一化) |
| chat_template.jinja | 对话模板,决定图片/视频如何嵌入消息 |
从 config.json 的vision_config可以看到视觉编码器(ViT)的核心配置:27 层、隐藏层 1152、16 个注意力头、patch_size=16、temporal_patch_size=2、spatial_merge_size=2,输出投影到 4096 维以对齐语言模型。
几个关键的 Token ID(定义于 config.json):
image_token_id: 248056、video_token_id: 248057:视觉内容在序列中的占位符vision_start_token_id: 248053、vision_end_token_id: 248054:包裹每段视觉内容
值得注意的是,该模型采用 FP8 量化以压缩体积,但量化忽略列表中包含了re:.*visual.*(见 config.json),视觉塔保持 bfloat16 不压缩,从硬件层面保障了视觉理解质量。语言侧则提供 256K(max_position_embeddings: 262144)的超长上下文,为多轮"截图—推理—再截图"的 Agent 循环留足空间。
🖼️ 图像输入参数解析:patch_size=16 如何切屏?
动态分辨率:shortest_edge 与 longest_edge 划定像素预算
Nex-N2.5-Pro 继承 Qwen-VL 系处理器的**动态分辨率(AnyRes)**思路,没有固定输入尺寸。图像处理器为Qwen2VLImageProcessorFast(见 preprocessor_config.json),核心参数如下:
| 参数 | 值 | 含义 |
|---|---|---|
patch_size | 16 | 图像被切成 16×16 像素的小块 |
merge_size | 2 | 每 2×2 个 patch 合并为 1 个视觉 Token |
resample | 3(双三次插值) | 缩放时保持画面平滑 |
shortest_edge | 65536 | 每帧最少 65536 像素(约 256×256) |
longest_edge | 16777216 | 每帧最多约 1677 万像素(≈4096×4096) |
image_mean/image_std | 0.5 / 0.5 | 像素归一化到 [-1, 1] |
流程很直观:图像先按宽高比缩放到"总像素数落在 65536~16777216 之间",再对齐到 32 像素的整数倍,最后切成 16×16 的 patch。这意味着分辨率越高,模型看到的细节越多,但消耗的 Token 也越多。
一张图占多少 Token?一个简单公式
由于merge_size=2,每 2×2 个 patch(即 32×32 = 1024 像素)生成 1 个视觉 Token:
视觉 Token 数 ≈ 图像总像素 ÷ 1024
几个典型示例:
| 图像尺寸 | 总像素 | 视觉 Token 数 |
|---|---|---|
| 640×360(手机截图) | 230400 | 225 |
| 1280×720(高清截图) | 921600 | 900 |
| 1920×1080(全屏截图) | 2073600 | 2025 |
| 4096×4096(像素上限) | 16777216 | 16384 |
对做计算机操作(Computer Use)的 Agent 场景,一张 1080p 屏幕截图约 2000 Token——这正是 Nex-N2.5-Pro 长程任务中"观察屏幕→决策→验证"循环的成本单位。
🎬 视频抽帧流水线:从原始视频到 768 帧的三步路径
视频处理器Qwen3VLVideoProcessor的完整参数见 processor_config.json,抽帧过程分三步:
第一步:按 fps=2 抽帧,min_frames=4 保底
fps: 2:每秒均匀抽取 2 帧,一段 30 秒的视频会得到 60 帧min_frames: 4:再短的片段也至少取 4 帧,保证时序信息成立do_sample_frames: true:自动完成均匀抽帧,无需手动切帧
第二步:2 帧组成一个时间块(temporal_patch_size=2)
temporal_patch_size: 2表示相邻 2 帧在时间维上打包成 1 个"时间 patch"。模型不是逐帧观看,而是以"帧对"为单位感知运动——抽到的 60 帧最终变成 30 个时间单元,既保留动态信息,又将序列长度减半。
第三步:视频总 Token 估算
每帧仍按"像素 ÷ 1024"折算空间 Token,再乘以时间单元数:
视频视觉 Token 数 ≈ (抽帧数 ÷ 2) × (每帧像素 ÷ 1024)
以 1280×720(900 Token/帧)为例:
| 视频时长(2fps 抽帧) | 抽帧数 | 时间单元 | 视觉 Token 数 |
|---|---|---|---|
| 30 秒 | 60 帧 | 30 | 27000 |
| 5 分钟 | 600 帧 | 300 | 270000 |
| 6 分钟(上限) | 768 帧 | 384 | 345600 |
max_frames: 768是抽帧硬上限,对应 2fps 下约 6 分钟的视频。超过 6 分钟时,处理器会自动把整个视频降采样到 768 帧——视频越长,有效帧率越低,细节感知越稀疏。同时注意:768 帧在 720p 下约产生 34.5 万 Token,会超出 256K 上下文,因此实际能装下的视频时长取决于分辨率,低分辨率可以处理更长内容。视频处理器的像素预算也略宽于图像:shortest_edge: 4096、longest_edge: 25165824(见 processor_config.json)。
另外,语言侧采用 mRoPE 多模态位置编码,mrope_section: [11, 11, 10](见 config.json)将位置维度拆分为时间、高、宽三个方向,让模型能精确理解"哪一帧、画面哪个位置"发生了什么。
📋 关键参数速查表(来自 preprocessor_config.json 与 processor_config.json)
| 参数 | 图像 | 视频 | 说明 |
|---|---|---|---|
patch_size | 16 | 16 | 空间切块边长 |
temporal_patch_size | 2 | 2 | 时间维打包帧数 |
merge_size | 2 | 2 | 空间 2×2 合并 |
size.shortest_edge | 65536 | 4096 | 最小像素预算 |
size.longest_edge | 16777216 | 25165824 | 最大像素预算 |
resample | 3 | 3 | 双三次插值 |
fps | — | 2 | 抽帧帧率 |
max_frames | — | 768 | 抽帧上限 |
min_frames | — | 4 | 抽帧下限 |
rescale_factor | 0.00392… | 0.00392… | 像素 ÷255 |
image_mean/image_std | 0.5 / 0.5 | 0.5 / 0.5 | 归一化参数 |
⚡ 这些参数是随模型仓库下发的固定默认值,推理服务(如 SGLang 部署,见 README.md)启动时自动加载,绝大多数用户无需手动配置——理解它们的价值在于估算多模态输入的 Token 成本,合理控制截图分辨率和视频长度。
💬 图像和视频如何写入对话?chat_template.jinja 详解
通过 OpenAI 兼容 API 发送消息时,在content数组中混排文本与视觉内容即可。从 chat_template.jinja 的渲染逻辑可以看到模板支持两类视觉条目:
- 图像:条目含
image、image_url键,或type == 'image' - 视频:条目含
video键,或type == 'video'
模板会把它们转换为视觉占位 Token(即前文提到的 248056 / 248057,并由 248053 / 248054 包裹),处理器随后把真实的 patch 特征填充进去。两个实用细节:
- System 消息禁止包含图像/视频——模板会直接抛出异常(chat_template.jinja)
- 启用
add_vision_id后,多张图会依次标注 "Picture 1:"、"Picture 2:",方便你在提问中用编号精确指代,例如"对比 Picture 1 和 Picture 2 的差异"
最小请求结构示意(非必须代码,帮助理解消息形态):
{"role": "user", "content": [ {"type": "image_url", "image_url": {"url": "data:image/png;base64,..."}}, {"type": "video", "video": "/path/or/url.mp4"}, {"type": "text", "text": "描述这张截图中的报错原因"} ]}❓ 新手常见问题
Q1:为什么上限是 768 帧?是精度不够吗?不是。768 帧 ÷ 2fps ≈ 6 分钟,是"视频时长 × 分辨率 × 2 帧/秒"三者之间的成本平衡点。帧数与空间 Token 共同消耗 256K 上下文,硬上限保证了极端长视频也不会拖垮请求。
Q2:图片会被拉伸变形吗?不会。动态分辨率只缩放总像素数,宽高比保持不变,且用双三次插值(resample=3)保证缩放平滑;缩放到 32 像素整数倍后切块,不会裁切边缘内容。
Q3:FP8 量化会降低视觉理解效果吗?视觉塔被显式排除在量化之外(bf16 全精度,见 config.json),FP8 只作用于语言模型线性层,视觉感知质量不受压缩影响。
Q4:截图应该给多大分辨率?建议 1280×720 ~ 1920×1080。低于 720p 可能漏掉小控件文字,高于 1080p 的 Token 增长很快而收益有限。Agent 循环中若上下文吃紧,可主动降分辨率换更长历史。
总结
Nex-N2.5-Pro 的多模态输入链路可以浓缩为一句话:图像按"像素÷1024"动态折算 Token,视频按 2fps 抽帧(4~768 帧)再按 2 帧一打包。所有参数在 preprocessor_config.json 与 processor_config.json 中开箱即用,掌握 Token 估算公式后,你就能在分辨率、视频时长与上下文预算之间做出最优取舍,把视觉能力充分发挥在截图理解、网页浏览与长视频分析等真实 Agent 场景中。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考