想象你开了家“智能厨房”:顾客发来一张4K高清美食照,后厨要“看懂”这张照片并给出点评。问题来了——照片被切成几万个小方块,每块都像一粒“食材块”,AI大模型处理每个食材块都要花费精力,还要让所有食材块两两“打招呼”。食材块越多,厨房越忙乱:灶台(显存)被塞爆,出餐(推理)慢如蜗牛。聪明的厨师长想出了三个妙招:划掉没人点的菜(剪枝)、把相似食材拼成拼盘(合并)、把一堆食材熬成浓缩高汤(学习型压缩)。这套“菜单精简术”,在AI领域就叫视觉token压缩。本文将用厨房比喻贯穿全程,带你理解多模态模型如何用更少的token,看懂更多的图片信息。
掌握视觉token压缩,等于掌握了多模态大模型推理成本的“开关旋钮”——无论做推理优化还是系统落地,都能精准地让模型跑得更快、花得更少。
目录
可视化演示
展示视觉Token从压缩前到压缩后的流动过程,以及压缩率与信息保留的权衡关系
本节配有交互动效(进入视口后自动加载,约 3KB)。
视觉Token压缩流:密集→稀疏 压缩前:高分辨率图片产生大量视觉Token 压缩后:保留关键信息,Token数大幅减少 压缩率 = 1 - N_after / N_before 流动粒子表示Token在压缩模块中的变换过程
压缩缘起:图解token爆炸
王姐经营一家“智能厨房”。她新接了一套豪华业务:顾客传来一张 4K 高清美食照片,后厨要根据照片出菜。但照片进了后厨,先被切成密密麻麻的小方块——每一个小方块都是一个“食材块”,也就是 AI 术语里的视觉token。一张高清图轻松产生几千到几万个食材块。更麻烦的是,每次分析图片,后厨都要让所有食材块两两“打招呼”(自注意力计算)。几万个块互相打招呼,灶台(显存)瞬间被塞满,出餐(推理)慢如蜗牛王姐急需一套菜单精简方案。
专业地说,把图片编码成视觉token是大模型“看懂”图片的第一步,但token数量直接决定了后续 Transformer 层的计算量。设token数量为 N,自注意力的时间开销是 O(N²) 级别——N 翻倍,开销翻 4 倍。高分辨率图片带来的正是这种平方级灾难。这也是为什么“高清图+大模型”的组合在工程上如此昂贵:不是模型不想看细节,是计算量不允许。
为了量化问题,引入模型计算量的度量公式:
其中 N 是视觉 token 数量,d 是每个 token 的特征维度。N 越大,计算与显存开销呈平方级膨胀——这就是必须对视觉 token 进行压缩的根本原因。
1. token 数量:N 表示图片被切块后生成的视觉 token 个数,相当于后厨的“食材块数量”。
2. 平方膨胀:每个 token 都要与其余 token 计算相关性,总配对数是 N² 量级,所以计算量随 N 平方增长。
3. 维度开销:d 是每个 token 向量的维度,影响每次配对的运算量,维度越高单次越贵。
理解了平方膨胀,就明白为什么“高清图+大模型”这么烧钱。压缩的终极目标,正是把公式里的 N 从几万降到几百,让后厨的灶台喘口气,同时保住菜品质量——这是后面所有压缩技法的共同出发点。
注意力剪枝:低分Token淘汰赛
王姐翻看一周的菜单记录:100 道菜里有 80 道从没人点过。把这些冷门菜划掉,后厨腾出大量空间,招牌菜照样受欢迎。AI 里也有一本类似的“点单记录”——注意力分数。
Transformer 计算时,每个 token 都会“看”其他 token 一眼,看的强度用注意力分数 α 表示。α 高表示这个 token 与全局语义关系密切,就像老客人常点的招牌菜;α 低表示它在当前上下文里几乎不被需要,就像无人问津的冷门菜。所有分数经 softmax 归一化后加起来等于 1,相当于一笔“注意力预算”。
注意力分数的计算方式如下:
每个 token 的整体重要性 score(t_i) 可取它被其他 token 关注的平均分数。剪枝规则就是设定阈值 τ,低于阈值的 token 直接淘汰:
1. 内积相关度:查询 Q_i 与键 K_j 的内积衡量两个 token 的相关程度,数值越大关联越强。
2. 缩放稳定:除以 √d_k 防止内积过大导致 softmax 梯度消失,是一种数值稳定技巧。
3. 归一化投票:softmax 保证每一行注意力权重和为 1,形成一张“注意力预算表”。
4. 阈值筛选:score 低于 τ 的 token 从序列中删除,剩下的 token 数量大幅减少。
注意力剪枝就像划菜单:速度快、无需额外训练,是工程上最常用的“第一刀”。但要注意划得太狠会连招牌菜的配菜一起划掉——注意力分数低的 token 未必真的没用,这是第五节要探讨的权衡。
聚类合并:相似Token拼盘
王姐发现厨房里有 6 道鸡肉菜口味相似,与其各备一份,不如合成一份“百鸡拼盘”——顾客尝到的是多重风味的融合,后厨却只准备一份食材。token 聚类合并就是在做这种拼盘。
比起直接删除,合并更温和。它先把语义相近的 token 归为一簇,再用一个代表向量替代整簇。总 token 数从 N 降到 K,而每簇的信息都保留了大头。最经典的实现是 K-Means 聚类,也可以用图结构或注意力关系来划分簇。
K-Means 的簇中心公式:
更精细的做法是带注意力权重的融合,让重要 token 在代表向量里占更大话语权:
1. 簇集合:S_k 表示第 k 簇的 token 下标集合,来自聚类算法(如 K-Means)的划分结果。
2. 平均代表:c_k 是簇内所有 token 向量取平均,作为这簇的“团宠代表”输出。
3. 注意力加权:比起等权平均,用 α 加权能让更重要的 token 在代表向量里有更大发言权。
4. 替代输出:合并后原 N 个 token 被 K 个代表向量替代,K 由预设的压缩目标决定。
聚类合并的优点是不太“挑食”——没有单独牺牲某个 token,而是把相似信息搅拌在一起,语义损失比硬剪枝更平缓。缺点是要预先定 K 值,就像拼盘的种类得提前设计,定得太粗容易串味。
学习型压缩:可训练的浓缩器
前面两种方法都是“从现有菜里减或拼”。王姐还想要一种更高级的招:像把几十公斤食材熬成一罐浓缩高汤宝——体积小到装进口袋,味道却浓缩了全部精华。学习型压缩模块就是这罐高汤宝。
学习型压缩不直接保留或平均现有 token,而是训练一组“可学习的查询向量”,让它去原始 token 集合里“打探”信息,再输出一组全新的、更少的压缩 token。典型结构包括 Perceiver、Q-Former、Query-based Pooling。整个过程端到端可微,优化器直接告诉压缩器:哪些信息值得留。
核心计算是交叉注意力:
其中 Q_learnable 是 M 个可学习查询向量,T_src 是原始 N 个视觉 token,输出 T_c 是 M 个压缩 token,且 M 远小于 N。
1. 可学习查询:Q_learnable 是模型自己学出来的 M 个查询向量,相当于 M 个“高汤配方”。
2. 交叉注意力:用查询向量与源 token 做交叉注意力,让每个查询决定“从哪些食材取多少味”。
3. 输出压缩:输出 M 个压缩 token,M 远小于 N,随后送入 LLM 参与后续计算。
4. 端到端训练:压缩器与整个多模态模型一起反向传播,自动学会保留什么、舍弃什么。
高汤宝的妙处在于通用——炒菜、煮面、煲汤都能放。学习型压缩输出的 token 同样可以喂给 LLM 的任何层,灵活性远超“删几道菜”,代价是需要训练,成本更高。
取舍之道:压缩率与信息保留
王姐试了几轮:把菜单砍到只剩 5 道菜,出餐飞快,但老顾客抱怨“想吃的菜没了”;保留 50 道,菜齐了,灶台又忙不过来。压缩率与信息保留就是这么一对跷跷板。
压缩率 R 量化“砍了多少”:
R = 0.75 表示从 100 个 token 压到 25 个。压缩率越高计算越省,但 token 越少细节越容易失真——一张图里的小猫、路牌文字、医疗器械上的刻度,都可能被当成“低分 token”旋掉。不同任务容忍度天差地别:闲聊场景压缩 90% 依然流畅;细粒度视觉问答压缩 50% 就开始掉准确率。
1. 原始数量:N_in 为压缩前视觉 token 总数,即压缩器的“输入食材块数”。
2. 输出数量:N_out 为压缩后 token 总数,即压缩器的“输出食材块数”。
3. 比例换算:1 减去两者比值,得到“被砍掉的比例”,结果在 0 到 1 之间。
4. 压缩率解读:0.5 表示砍掉一半;0.9 表示砍掉九成,接近极限压缩。
压缩率是“省了多少”的仪表盘,信息保留是“顾客还满意吗”的评分表,两者要一起看。工程上不是一味追求最大压缩率,而是先画一条“速度-准确率”曲线:测出基准延迟与准确率,再逐步加大压缩率,找到准确率跌幅可接受的最大压缩点——这就是王姐的“甜点压缩率”。
工程实践:落地压缩方案
王姐筹备“压缩厨房”时发现,纸上谈兵与真火烹饪之间隔着无数细节。把剪枝、合并、学习压缩组装成生产线,需要注意选设备、定标准、避坑。
工程落地有三条主线。第一,位置选择:压缩模块一般放在视觉编码器之后、进入 LLM 之前,这样能同时削减自注意力计算与 KV cache 内存;部分方案也在 LLM 浅层做渐进压缩。第二,硬件适配:剪枝产生稀疏矩阵,若没有配套 kernel 优化,实际推理并不会变快甚至更慢——“理论省了,硬件没省”。第三,恢复训练:压缩后的模型通常要做轻量微调或知识蒸馏,把压缩带来的语义损失“补回来”。
加速效果可以用压缩比估算:
当 token 从 N 减到 N/4,理论计算加速约 16 倍,显存占用降为 1/4——前提是硬件能用满。
1. 压缩倍数:N_in 除以 N_out 得到 token 缩减倍率,比如 4 倍。
2. 平方加速:自注意力计算量随 token 个数平方级下降,所以加速比是倍率的平方。
3. 显存变化:KV cache 与 token 数成线性关系,token 减半则显存占用也近似减半。
4. 理论 vs 实际:最终收益要乘以硬件稀疏计算利用率,实际落地需实测验证。
王姐的最终厨房是这样的:剪枝负责“清冷菜”,合并负责“拼盘”,学习压缩负责“熬高汤”,三者按任务需求组装,再用基准测试校准“甜点区”。这样的压缩厨房,出餐又快,顾客还挑不出毛病。
AI 应用场景
高分辨率文档解析加速
阶段:推理优化
解决的问题:税务、法律 PDF 扫描件动辄几千乘几千像素,切块后 token 上万,多模态大模型逐页解析要数秒到数十秒,根本无法支撑批量归档。传统做法是整图喂入,延迟和成本都不可控。
具体案例:某文档智能平台用“注意力剪枝 + 聚类合并”组合:OCR 后的 token 减到 1/4,页均解析时间从 8 秒降到 1.8 秒,关键表格与印章信息保留率达 99.2%,批量归档成本大幅下降。
医疗影像辅助诊断
阶段:压缩器设计 + 微调
解决的问题:CT、MRI 图像信息密度高,盲目剪枝可能把病灶边缘当成噪声丢掉,医生无法接受这种风险。传统方案要么牺牲分辨率,要么牺牲推理速度。
具体案例:医院 AI 团队用学习型压缩模块(Q-Former 结构)加少量临床样本微调,将每张影像的 token 从 4800 压到 300,肺结节检测召回率仅下滑 0.8%,推理延迟从 4.2 秒降至 0.9 秒,实时阅片辅助成为可能。
视频流式理解
阶段:在线推理
解决的问题:视频每秒 24 帧,逐帧转 token 会瞬间击穿显存。传统做法是抽帧,但抽帧会丢掉关键动作信息。
具体案例:安防厂商对相邻帧做聚类合并,把相似画面聚成“镜头 token”,再结合时间维剪枝,输入 LLM 的 token 量减少 70%,在边缘服务器上实现了实时异常行为检测和自然语言报警描述。
Python 演示
import numpy as npfrom sklearn.cluster import KMeans def compute_attention_scores(q, k): """计算每个 token 的平均注意力分数""" d = q.shape[-1] scores = np.exp(q @ k.T / np.sqrt(d)) scores = scores / scores.sum(axis=-1, keepdims=True) return scores.mean(axis=0) def prune_tokens(T, tau): """阈值剪枝:删除注意力分数低于 tau 的 token""" scores = compute_attention_scores(T, T) keep_idx = np.where(scores >= tau)[0] return T[keep_idx], keep_idx def merge_tokens(T, n_clusters): """聚类合并:用簇中心替代原 token""" km = KMeans(n_clusters=n_clusters, n_init=10, random_state=42) labels = km.fit_predict(T) centers = np.array([T[labels == c].mean(axis=0) for c in range(n_clusters)]) return centers, labels def compress_pipeline(q, tau=0.5, keep_ratio=0.5): """全流程:剪枝 + 聚类合并""" T_pruned, kept = prune_tokens(q, tau) n_out = max(1, int(len(T_pruned) * keep_ratio)) T_merged, labels = merge_tokens(T_pruned, n_out) return T_merged, len(q), len(T_merged) if __name__ == "__main__": np.random.seed(42) N, d = 200, 64 tokens = np.random.randn(N, d) merged, n_in, n_out = compress_pipeline(tokens, tau=0.5, keep_ratio=0.4) rate = 1 - n_out / n_in print(f"原始 token: {n_in} -> 压缩后: {n_out}, 压缩率: {rate:.2f}")
q @ k.T / np.sqrt(d)计算所有 token 两两之间的缩放内积,衡量相关度。scores.mean(axis=0)对每列取平均,得到每个 token 被其他 token 关注的平均分数。keep_idx = np.where(scores >= tau)[0]阈值剪枝:只保留分数不低于 τ 的 token。km.fit_predict(T)用 K-Means 对保留的 token 做语义聚类。T[labels == c].mean(axis=0)每个簇取平均向量作为簇中心,替代整簇 token。n_out = max(1, int(len(T_pruned) * keep_ratio))根据保留比例确定压缩后的目标 token 数。rate = 1 - n_out / n_in打印压缩率,即被削减的 token 占比。
常见误区
误区很多人以为视觉 token 压缩就是把图片模糊化或缩小分辨率,就像手机相册压缩照片一样,直接把图片变小变糊。
正解其实 token 压缩发生在“特征空间”——token 不是像素,而是带有语义的小方块。压缩是在保留重要语义的前提下减少冗余块,和像素级缩放完全是两码事。就像做拼盘不是把菜捣碎,而是把口味相似的菜合并成一份,顾客依然能尝到多重风味。
为何常见:因为“压缩”这个词大家最熟悉的含义就是图片体积压缩,容易把图片压缩的直觉迁移到 token 压缩上。
误区压缩率拉满,token 越少模型跑得越快,那肯定压缩率越高越好,直接压到 10% 不是更香吗?
正解压缩率太高会丢失小物体、文字、边缘等关键细节,导致视觉问答准确率断崖式下跌。实践中要根据任务找“甜点压缩率”——通常在 50%~75% 区间性能代价可控,超过 85% 后多数细粒度任务会明显劣化。
为何常见:推理延迟随 token 数急剧上升,让人本能地想拼命压低 token 数,而忽略了信息保留这一端。
误区注意力分数就是 token 重要性的唯一标尺,分数低的都是噪声,直接删掉肯定没问题。
正解注意力分数低不代表信息无用。有些 token 在当前层不重要,但在后续层与其他 token 配合后会产生关键语义;而且分数逐层变化,一层被剪的 token 换个层可能很重要。因此剪枝要谨慎,多层渐进剪枝比单层一刀切更安全。
为何常见:注意力分数直观易懂,既有数值又有可视化热力图,很容易被过度解读成“重要性排名”。
误区一套压缩配置走天下,OCR、医疗、视频都用同样的剪枝阈值和合并比例。
正解OCR 任务需要保留文字和边缘细节,医疗图像需要保护病灶区域,自然场景图则可以大刀阔斧地剪。压缩策略要跟着任务的数据分布和下游指标走,每个场景都要单独做基准测试。
为何常见:简化思维作祟,觉得压缩是通用工具,忽略了不同任务的 token 分布和对细节的敏感度差异巨大。
面试题
Q1. 视觉 token 是怎么产生的?
- A.图片像素直接按行排列
- B.图片切块经编码器嵌入← 正确答案
- C.LLM 内部随机生成
- D.文本分词器处理图片
答案:B。视觉 token 由图片切成 patch(小方块)后,经视觉编码器(如 ViT)嵌入得到向量,类似把食材切成小块再编号入库。像素按行排列只是原始数据,未经编码不构成 token;随机生成和文本分词器都与视觉无关。
Q2. 自注意力计算量随 token 数如何增长?
- A.随 token 数线性增长
- B.呈平方级爆炸式增长← 正确答案
- C.与 token 数完全无关
- D.仅受 batch 大小影响
答案:B。每个 token 都要与其他 token 计算两两相关性,配对总数是 N² 量级,所以计算量随 token 数平方增长。这就像后厨每新增一个食材块,都要和所有其他食材块打一次招呼,招呼次数是平方级上升。
Q3. 视觉 token 压缩的主要收益是什么?
- A.降低推理延迟和显存占用← 正确答案
- B.提升图片的分辨率画质
- C.增加模型参数量
- D.减少训练数据的噪声
答案:A。压缩 token 直接减小自注意力的 N² 计算量,同时缩减 KV cache 显存,是最核心的收益。分辨率画质是输入侧的事,压缩不会提升画质,反而可能损失细节;参数量与压缩无关。
Q4. 注意力剪枝时,token 去留的判断依据是什么?
- A.token 对应的注意力分数← 正确答案
- B.token 在图片中的坐标
- C.token 的 RGB 像素值
- D.token 的文本标签
答案:A。剪枝看的是注意力分数——token 被其他 token 关注的平均强度,类似菜单上菜品的真实点单热度。坐标、像素值、文本标签都不是注意力机制产出的重要性依据。
Q5. 压缩率 R = 1 - N_out/N_in,当 R = 0.75 时表示什么?
- A.保留了原有 75% 的 token
- B.删除了原有 75% 的 token← 正确答案
- C.token 数量减少了 75 倍
- D.token 数量增加了 4 倍
答案:B。R 是“被砍掉的比例”,0.75 表示从 100 个 token 压到 25 个,删掉了四分之三。注意区分“压缩率”和“保留率”——保留率才是 N_out/N_in = 0.25。
Q6. 下面哪些属于 token 合并的典型做法?
- A.K-Means 簇中心替代← 正确答案
- B.注意力加权融合← 正确答案
- C.随机删除一半 token
- D.按坐标横平竖直切图
答案:AB。K-Means 聚类和注意力加权融合都属于“合并”,把多个 token 的信息聚合成一个代表。随机删除属于剪枝而非合并;按坐标切图只是空间裁剪,不涉及语义融合。
Q7. 压缩模块通常可以加在哪些位置?
- A.视觉编码器输出之后← 正确答案
- B.LLM 各层之间← 正确答案
- C.训练数据加载阶段
- D.像素解码写入阶段
答案:AB。压缩 token 的本质是减少进入或流经 LLM 的 token 数,因此加在编码器输出后或 LLM 层间都有效。数据加载和像素解码阶段 token 还没生成,压缩无从谈起。
Q8. 为什么剪枝后实际推理可能没有变快?
- A.稀疏矩阵未获 kernel 优化← 正确答案
- B.剪枝算法本身存在 bug
- C.被剪 token 数量过少
- D.压缩只影响显存不影响速度
答案:A。剪枝产生的是稀疏矩阵,如果底层硬件 kernel 不支持稀疏加速,矩阵仍会被填充成稠密格式计算,理论节省无法兑现。就像菜单划掉了几道菜,但后厨还是把所有食材按老流程过一遍,自然快不起来。
Q9. 关于压缩率与信息保留的权衡,下列说法正确的是?
- A.压缩率越高推理越快← 正确答案
- B.压缩率越高信息丢失越多← 正确答案
- C.不同任务容忍度不同← 正确答案
- D.压缩对模型效果无影响
答案:ABC。压缩率与信息保留是跷跷板:压缩率升高带来速度收益,同时加大信息丢失风险,且任务越细粒度越敏感。D 明显错误——压缩必然改变信息量,只是影响大小因任务而异。
Q10. 为什么压缩一般放在视觉编码器之后、进入 LLM 之前,而非只在 LLM 内部做?
- A.提前压缩同时降低两类开销← 正确答案
- B.LLM 内部不支持压缩操作
- C.视觉编码器输出无需压缩
- D.压缩过程只能执行一次
答案:A。在进入 LLM 前压缩,既能减少每层自注意力的 N² 计算量,又能缩减 KV cache 显存——一处压缩,全链路受益。若只在 LLM 内部压缩,前面的层已经按原始 token 数白算了一遍。B、C、D 均不符合实际。