Skip to main content

05 - 看:图像视频怎么被理解

用户拍了张菜单照片,问「这个有什么推荐」。

照片 3024×4032,手机随手拍的。它要怎么进到模型里?

02 篇给过答案的形状:模态编码器把它变成一串向量,输入投影器把这串向量对齐到 LLM 的空间。这一篇拆开「模态编码器」这一格。

先给结论,它是整篇的主线:分辨率会直接变成 token 账单。用户随手拍的一张图,可能比他打的字贵一百倍。

一、把图切成方块

做法叫 ViT(Vision Transformer,视觉 Transformer)。想法很直白:Transformer 只会处理序列,那就把图切成小方块,每块当一个词

一张 448×448 的图,按 14 像素一块切原图448 × 448切成 32×32 = 1024 块同一个编码器逐块算成向量1024 个向量,从左到右、从上到下排成一条于是这张图在 LLM 眼里就是 1024 个 token —— 跟一篇一千多字的文档一样长。而用户只打了七个字。
切块的边长通常是 14 或 16 像素。很多模型还会再把相邻的 2×2 合成一块(叫 patch merge 或 pixel shuffle),1024 就降到 256 —— 代价是细节变粗,OCR 类任务会受影响。

二、分辨率就是账单

上一节那个 1024,是按 448×448 算的。可用户那张照片是 3024×4032。

早期做法是强行缩放到固定尺寸,比如都缩成 448×448。好处是 token 数恒定、显存好估、编码器能捕成 CUDA Graph;坏处是一张竖着的菜单被压扁,小字全糊,OCR 直接废掉。

后来的做法叫动态分辨率:图多大就按多大切,不缩放。Qwen2-VL 这一代开始普遍这么做。

代价立刻显现:

输入按固定 448按动态分辨率
一张 448×448 的图1024 块1024 块
用户那张 3024×40321024 块(但字糊了)约 62000 块
合成 2×2 之后256约 15500

一张手机原图能顶十几篇长文档。 所以所有支持动态分辨率的模型都必须设一个上限,超了就等比缩小 —— 这个上限(通常叫 max_pixels 之类)是部署时最该先确认的参数之一。

动态分辨率让显存变得不好估

固定分辨率时,一张图就是 1024 个 token,容量规划是道算术题。

动态分辨率之后,同样是「一张图」,token 数可能差 60 倍。你没法再按「平均每请求多少 token」去规划,只能按上限规划 —— 于是平时大量浪费,而一旦有人上传高清图,又可能撞穿。

三、另一种接法:把视觉参数塞进 LLM 里

前面讲的都是「编码器出向量 → 投影器对齐 → 塞进序列」,LLM 本身一个参数都不改。

还有一条路:在 LLM 每一层里额外加一套只处理视觉 token 的参数。CogVLM 叫它 visual expert(视觉专家),17B 里有 10B 是视觉参数、7B 是语言参数。

两种接法的差别,在服务上很实际:

投影器接法视觉专家接法
LLM 权重完全不动,可以跟纯文本服务共用改了,得单独部署一份
训练成本只训投影器,便宜要训一套新参数
效果视觉信息「翻译」进来,有损耗视觉和文本在每一层深度融合,细粒度任务更强
显存跟原 LLM 差不多显著更大

大多数产品用第一种,因为它便宜、灵活、能跟已有的文本服务复用同一套权重。

四、视频:再乘一个帧数

视频没有本质新东西,就是图片乘帧数,但这个乘法很吓人。

一段 10 秒的视频,按每秒抽 2 帧就是 20 帧。每帧哪怕只算 256 块,也是 5120 个 token。按每秒抽 8 帧,就是 20480。

所以视频这边所有工程手段都在做同一件事:少要几帧、每帧少要几块

  • 降抽帧率。多数场景每秒 1~2 帧就够,剧烈运动才需要更高。
  • 时间维合并。相邻两帧的相同位置合成一个 token,直接砍一半。
  • 按内容抽帧。画面没怎么变的段落少抽几帧。
判断一个多模态服务贵不贵,先问三个数
  1. 一张图切成多少块(分辨率 ÷ 块边长,再看合不合并)
  2. 视频每秒抽几帧
  3. 有没有 token 数上限,上限是多少

这三个数一乘,就是你的账单。模型参数量反而不是主要因素。

五、服务视角:编码器是那个卡住所有人的家伙

前面都是模型视角。换成服务视角,视觉编码器有一个很讨厌的性质。

不是一步一步算的,是一口气算完。一张图 1024 块,一次前向全算完,这期间 GPU 被它占满。

而同一时刻,可能有三十个用户正在等着模型一个字一个字往外吐。编码器一跑,这三十个人全都得停下等

一次图像编码,代价是「编码时间 × 正在等字的人数」正常解码解码解码解码解码每步 5 ms,30 个人的字稳定往外冒来了张图解码图像编码,一口气算完,中途插不进任何东西解码影响这段时间里,30 个正在等字的人全部停住并发 8 时你损失 8 人份,并发 64 时损失 64 人份 —— 这是乘法,不是加法。并发越高,一次编码的破坏力越大。更麻烦的是它在监控上隐形:这段时间 GPU 是满载的,利用率曲线看不��出异常,只能看到延迟毫无规律地跳。框架对付它的办法是给编码器设预算、限制一步能编几张图,见 09 篇。
这也是为什么很多框架把「同一张图的编码结果」缓存起来 —— 同一个用户对着一张菜单连问五个问题,只该编一次。怎么判断「是同一张图」,是 09 篇的主题。

下一篇06 - 画,反过来看图像和视频是怎么被生成出来的。