HybridToken-VLM: Hybrid Token Compression for Vision-Language Models
Paper: arXiv:2512.08240 Code: jushengzhang/HybridToken-VLM Code reference:
main@29486cb(2026-03-15) Authors: Jusheng Zhang, Xiaoyang Guo, Kaitong Cai, Qinhan Lv, Yijia Fan, Wenhao Chai, Jian Wang, Keze Wang Affiliations: Sun Yat-sen University, Princeton University, Snap Inc. Year: 2025
1. Motivation (研究动机)
1.1 背景:VLM 视觉 token 的计算瓶颈
现代 VLM (如 LLaVA) 使用 ViT-L/14 将图像编码为 个 patch token,输入 LLM 后注意力计算复杂度为 ,对于 ,单层即需约 浮点运算,迅速耗尽 GPU 显存。
1.2 现有方案的两难困境
| 压缩范式 | 代表方法 | 核心限制 |
|---|---|---|
| 连续压缩 (Pooling/Aggregation) | VoCo-LLaMA, Q-Former | 语义稀释 (Semantic Dilution): ,高频纹理噪声主导熵 ,淹没离散语义 |
| 离散量化 (VQ Codebook) | VQ-VAE, MoVQ | 粒度间隙 (Granularity Gap): $I(z_d; D) \le \log |
| 结构化剪枝 (Token Pruning) | ToMe, FastV, PDrop | 结构坍塌 (Structure Collapse): 去除 token 破坏拓扑先验,低 token 区间性能骤降 |
核心洞察: 单 token 连续瓶颈无法同时编码离散语义 和连续细节 ——这是一个表征容量冲突 (Capacity Conflict),而非简单的信息丢失问题。
2. Idea (核心思想)
在压缩前注入少量离散语义锚点,使高层语义在瓶颈前就被显式保留,连续通道则专注于细粒度细节,两者通过解纠缠注意力掩码融合为单个混合 latent。

Figure 1 解读: 对比三种压缩策略。(a) VoCo-LLaMA 将 576 个 patch 直接压缩为 1 个 <voco> token,丢失语义结构;(b) HTC-VLM 在 576 个连续 patch 前添加 4 个 MGVQ 离散语义 token,形成 580 token 混合序列,再通过 Disentanglement Mask 压缩为 1 个 <voco> token,同时保留语义和视觉细节。
3. Method (方法)
3.1 整体架构
Figure 2 解读: HTC-VLM 完整架构对比。(a) Pooling 方法直接平均/池化视觉 embedding,丢失空间信息;(b) VoCo-LLaMA 用 Vision Encoder + Media Projector 压缩为单 token;(c) HTC-VLM (本文) 包含双通道:连续通道 (CLIP ViT-L → Linear Projector → 576 patch embeddings) 和离散通道 (MGVQ → 2-layer MLP → 4 discrete tokens),拼接后经 Disentanglement Attention Mask 压缩为 <voco> token,最终输入 LLaVA 进行推理。
3.2 双通道设计
连续通道:细粒度细节
: CLIP ViT-L/14 (frozen) : 线性投影 ,对齐 LLM embedding 空间 保留高维流形上的纹理梯度、姿态变化等连续特征
离散通道:高层语义锚点
: MGVQ 量化器 (Multi-Group VQ), codebook, groups, 16x 下采样 : 量化特征 : 论文 Table 6 / Eq. 4 写作 2-layer MLP (, GELU 激活) released code 中的 LlavaLlamaForCausalLM.projector 实际为 14112 -> 16384 -> 16384,再 reshape 为 输出 : 4 个离散语义 token / semantic anchors
论文公式与 released code 实现差异:论文文字把离散 projector 记为 ;main@29486cb 的 llava/model/language_model/llava_llama_1stg.py 实际创建 nn.Sequential(nn.Linear(14112, 16384), nn.GELU(), nn.Linear(16384, 16384)),而 llava/model/llava_arch.py 将输出 reshape 为 4 个 4096 维 discrete embeddings。笔记后续伪代码以 released code 为准,同时保留论文表格中的配置以便对照。
3.3 融合与 Disentanglement Bottleneck
混合序列构建
关键设计:离散 token 放在连续 patch 前面 (Pre-fusion),利用 autoregressive transformer 的 “Prompting Effect”,使语义锚点作为后续 patch 处理的语义上下文。
Disentanglement Attention Mask
三个关键约束:
- 视觉 token 互相独立: 内部 token 之间 时注意力为 ,防止 oversmoothing
- 信息瓶颈强制: 文本 token 不能直接 attend 到原始视觉 patch,只能通过
<voco>获取视觉信息 - Star-Graph 拓扑: 信息流仅从 和 单独流向
<voco>,形成星形图结构
<voco> Latent 提取
最终 transformer 层对应 <voco> 位置的隐状态即为压缩后的混合 latent 。
3.4 训练目标
基于变分推断框架,训练目标可分解为 ELBO:
实际训练 loss:
近似展开为:
梯度动力学: 增强语义聚类 (最大化 ), 细化细节表征空间。
3.5 伪代码(基于 released code)
Code reference:
main@29486cb(2026-03-15) — pseudocode and mapping based on this commit
3.5.1 MGVQ 离散语义通道
class MGVQQuantizer(nn.Module):
def __init__(self, ckpt="./llava/model/MGVQ/checkpoints/mgvq_f16c32_g8.pt"):
super().__init__()
self.model = MGVQ_HF(
Namespace(
vq_model="mgvq-f16c32",
vq_ckpt=ckpt,
codebook_size=16384,
codebook_dim=32,
codebook_groups=8,
groups_to_use=8,
ds_rate=16,
)
)
state = torch.load(ckpt, map_location="cpu")
self.model.load_state_dict(state["model"], strict=True)
self.model.eval().requires_grad_(False)
def forward(self, image_tensor):
# released code receives CLIP-normalized images, denormalizes to [0, 1],
# then maps to [-1, 1] before MGVQ encode.
x = imagenet_denorm(image_tensor)
x = x * 2.0 - 1.0
quant, codebook_usage, _ = self.model.encode(x)
# quant: [B, C, H', W'] -> [B, 1, 14112]
quant = quant.permute(0, 2, 3, 1).view(image_tensor.shape[0], 1, -1)
return quant.contiguous().to(device=image_tensor.device, dtype=image_tensor.dtype)这段对应 llava/model/MGVQQuantizer.py:MGVQ checkpoint 被严格加载,模型设为 eval 且冻结,因此离散语义通道不是 end-to-end 更新 codebook,而是把外部 MGVQ tokenizer 当作固定 semantic anchor generator。
3.5.2 离散 projector 与连续 patch 拼接
class LlavaLlamaForCausalLM(...):
def __init__(self, config):
self.image_quantizer = None
self.projector = nn.Sequential(
nn.Linear(14112, 16384),
nn.GELU(),
nn.Linear(16384, 16384),
)
def build_hybrid_image_features(model, images):
# Continuous branch: LLaVA vision tower + mm_projector -> [576, 4096]
image_features = model.encode_images(images)
# Discrete branch: frozen MGVQ + projector -> [B, 1, 16384] -> [B, 4, 4096]
discrete_embeds = model.projector(model.image_quantizer(images))
discrete_embeds = discrete_embeds.view(
discrete_embeds.size(0),
-1,
image_features[0].size(-1),
)
# Pre-fusion: 4 discrete semantic anchors are prepended before 576 continuous patches.
hybrid_features = []
for idx, continuous_patches in enumerate(image_features):
semantic_anchors = discrete_embeds[idx]
hybrid_features.append(torch.cat([semantic_anchors, continuous_patches], dim=0))
return hybrid_features, discrete_embeds.shape[1]这段对应 llava/model/llava_arch.py:image_features = self.encode_images(images) 产生连续 patch;discrete_embeds = self.projector(self.image_quantizer(images)) 产生离散 anchor;torch.cat([de, cf], dim=0) 实现 pre-fusion。这里的 discrete_id_nums 是 4,最终形成 580 个视觉 token。
3.5.3 <voco> token 注入与训练样本构造
def preprocess_multimodal_conversation(conversation, tokenizer, has_image=True):
if has_image:
# released code fixes the number of <voco> tokens to 1.
maybe_voco_str = "".join(["<voco>" for _ in range(1)])
prompt = "<image>\n" + maybe_voco_str + "\n" + (
conversation.replace("<image>", "").replace("\n", "")
)
input_ids = tokenizer_image_token(prompt, tokenizer, return_tensors="pt")
return input_ids
return tokenizer(conversation, return_tensors="pt").input_ids
def attach_quantizer_and_train(model, tokenizer, training_args):
tokenizer.add_special_tokens({"additional_special_tokens": ["<voco>"]})
model.resize_token_embeddings(len(tokenizer))
voco_token = tokenizer.additional_special_tokens_ids[-1]
model.image_quantizer = MGVQQuantizer()
model.image_quantizer.model.to(device=model.device, dtype=model.dtype)
freeze_quantizer(model, enable=True)
return voco_token这段对应 llava/train/train_compress.py:训练 preprocessing 明确把 <image>\n<voco>\n 放在对话开头;训练函数添加 <voco> special token、resize embedding、挂载 MGVQQuantizer() 并冻结 image_quantizer.* 参数。
3.5.4 Star-Graph / Disentanglement mask
def reverse_cumsum(x):
return x + torch.sum(x, dim=-1, keepdims=True) - torch.cumsum(x, dim=-1)
def make_mask_post_last_voco(inputs, voco_token):
return (reverse_cumsum(inputs == voco_token) >= 1)
def make_mask_pre_first_voco(inputs, voco_token):
return ((inputs == voco_token).cumsum(-1) >= 1)
def make_voco_mask_llava(inputs, voco_token):
pre_voco_mask = make_mask_post_last_voco(inputs, voco_token)[:, None, None]
post_voco_mask = make_mask_pre_first_voco(inputs, voco_token)[:, None, None]
pre_voco_time_mask = pre_voco_mask.permute((0, 1, 3, 2))
mask = torch.where(pre_voco_time_mask, pre_voco_mask, post_voco_mask)
has_voco = (inputs == voco_token).any(-1)[:, None, None, None]
return torch.where(has_voco, mask, True)这段对应 llava/model/language_model/llava_llama_1stg.py:代码先在 prepare_inputs_labels_for_multimodal 里记录 <voco> 相对序列尾部的位置,再在 LLaMA forward 中把这些位置标成 32000 并调用 make_voco_mask_llava。实现层面不是单独构造论文 Algorithm 3 那样的显式矩阵,而是在 4D attention mask 上叠加一层 voco-specific mask。
3.5.5 Code-to-paper mapping
| Paper Concept | Released source file | Key symbol / behavior |
|---|---|---|
| 连续视觉通道 | llava/model/llava_arch.py | encode_images(images) + mm_projector(image_features) |
| MGVQ 离散 tokenizer | llava/model/MGVQQuantizer.py | MGVQQuantizer.forward, self.model.encode(x), checkpoint mgvq_f16c32_g8.pt |
| 离散 projector | llava/model/language_model/llava_llama_1stg.py | self.projector = nn.Sequential(nn.Linear(14112,16384), GELU, nn.Linear(16384,16384)) |
Pre-fusion [v_d; V] | llava/model/llava_arch.py | new_cf = torch.cat([de, cf], dim=0) |
<voco> special token | llava/train/train_compress.py | tokenizer.add_special_tokens({"additional_special_tokens": ["<voco>"]}) |
对话模板中插入 <voco> | llava/train/train_compress.py | conversations = [f"<image>\\n{maybe_voco_str}\\n" + ...] |
| voco attention mask | llava/model/language_model/llava_llama_1stg.py | make_voco_mask_llava, attention_mask = attention_mask + attention_mask_voco |
| 训练入口 | llava/train/train.py | imports train_compress and calls train_compress(attn_implementation="sdpa") |
| 训练 launcher | scripts/finetune_voco_llama.sh | 8×A100-style deepspeed include, Vicuna-7B, CLIP ViT-L/14-336 |
3.6 信息论分析
Theorem 1 (Semantic-Detail Capacity Conflict): 对于纯连续压缩,当 有界时, as increases,因为高频细节 () 的 Entropy Domination 饱和了有限容量。
Theorem 2 (Disentangled Sufficiency): 混合先验 降低了 ,使得 的连续容量可专用于编码细节 :
混合 latent 作为联合分布 的充分统计量。
4. Experimental Setup (实验设置)
4.1 训练配置:论文表格 vs released launcher
训练配置必须区分论文 Table 6 与 released code。论文给的是实验配置摘要;仓库里真正可执行的 launcher 是 scripts/finetune_voco_llama.sh,并且 README 里写的 bash scripts/finetune.sh 与仓库当前文件名不一致。
| 项目 | 论文 Table 6 | released code / launcher |
|---|---|---|
| Vision encoder | CLIP-ViT-L/14-336px, frozen | --vision_tower openai/clip-vit-large-patch14-336 |
| Continuous projector | Linear 1024 -> 4096 | llava/model/llava_arch.py 的 mm_projector,launcher 用 --mm_projector_type mlp2x_gelu |
| Discrete quantizer | MGVQ, K=16384, G=8 | MGVQQuantizer(vq_ckpt="./llava/model/MGVQ/checkpoints/mgvq_f16c32_g8.pt") |
| Discrete projector | 论文写 14112 -> 8192 -> 4096 | code 写 14112 -> 16384 -> 16384 后 reshape 成 4 x 4096 |
| LLM backbone | LLaVA-1.5 / Vicuna-7B-v1.5 | --model_name_or_path lmsys/vicuna-7b-v1.5 |
| 视觉序列长度 | 4 + 576 = 580 visual tokens | torch.cat([de, cf], dim=0);<voco> 作为额外 special token |
| 训练数据 | visual instruction tuning | --data_path ./playground/data/llava_v1_5_mix665k.json |
| 图像根目录 | COCO/GQA/OCR-VQA/TextVQA/VG | --image_folder ./playground/data |
| GPU | 8× NVIDIA A100 80GB | deepspeed --include localhost:0,1,2,3,4,5,6,7 |
| Epochs | 未在 Table 6 明说 | --num_train_epochs 2 |
| Per-device train batch | Table 6 给 global batch 256 | --per_device_train_batch_size 8 |
| Gradient accumulation | Table 6 写 1 | launcher 写 --gradient_accumulation_steps 2 |
| Learning rate | Table 6 写 2e-4 cosine | launcher 写 --learning_rate 2e-5 + --lr_scheduler_type cosine |
| Weight decay | Table 6 写 0.1 | launcher 写 --weight_decay 0. |
| Warmup | Table 6 写 1,500 steps | launcher 写 --warmup_ratio 0.03 |
| Precision | bfloat16 | --bf16 True, --tf32 True |
| Context length | 未在 Table 6 明说 | --model_max_length 2048 |
| Save strategy | 未在 Table 6 明说 | --save_strategy steps, --save_steps 50000, --save_total_limit 1 |
论文公式与 released code 实现差异:训练超参也存在 paper-vs-code gap。若复现实验,应优先以 scripts/finetune_voco_llama.sh 为准记录实际运行命令;若引用论文报告的 2e-4 / global batch 256 / weight decay 0.1 / warmup 1500,需要明确它来自论文 Table 6,而不是当前 released launcher。
4.2 数据集与评测协议
训练侧 README 要求准备的视觉数据源包括: COCO train2017 GQA images OCR-VQA images TextVQA train_val_images VisualGenome VG_100K 与 VG_100K_2 released launcher 使用 LLaVA instruction mix: ./playground/data/llava_v1_5_mix665k.json 该文件名表明 instruction tuning mix 规模为 665k;note 只把它作为 released code 的数据路径,不额外推断各子集精确样本数。 主实验评测覆盖 7 个 visual understanding benchmark: GQA:视觉问答 / compositional reasoning,报告 accuracy。 VQAv2:通用视觉问答,报告 accuracy。 MMBench:综合多模态能力,报告 benchmark score。 MME:perception/cognition 综合分数,数值量纲与 accuracy 不同。 POPE:hallucination / object existence 判断。 SEED-Bench:多模态理解综合 benchmark。 ScienceQA-Image:图像条件科学问答。
论文还补充使用: MME 的 16 个 test samples 做 <voco> attention heatmap。 S-10 / D-10 probing tasks 检查 z_voco、v_d、\bar{V} 的语义与细节可解码性。 GQA/VQAv2 token-budget sweep 比较 1→576 tokens 下的 retention 曲线。
4.3 Baselines 与指标
| Baseline / variant | 压缩范式 | 作用 |
|---|---|---|
| Upper Bound | 576 visual tokens | 不压缩 LLaVA-style full visual tokens |
| Lower Bound | no image / weak visual input | retention 归一化的下界 |
| Q-Former | learnable query aggregation | 连续 latent 聚合代表 |
| Average Pooling | pooling | 最简单 continuous compression |
| Token Merging / ToMe | merging / pruning | 结构化 token reduction |
| FastV / PDrop | pruning / dropping | 低预算 token selection |
| SparseVLM | sparse visual token selection | 中等 token budget baseline |
| VoCo-LLaMA | one-token continuous <voco> | 最关键的 continuous-only 1-token 对照 |
| Discrete-only | MGVQ discrete tokens only | 测试纯离散量化是否损失细节 |
| HTC-VLM | hybrid latent | 4 discrete semantic anchors + 576 continuous patches + 1 <voco> |
平均 retention 的定义是 per-benchmark 归一化:
论文报告的 Avg. 是跨 benchmark retention 的平均值;因此 MME 这类非百分制分数不会直接与 GQA/VQAv2 accuracy 简单求均值。
5. Experimental Results (实验结果)
5.1 主实验:单 token 压缩 (580:1)
| 模型 | Tokens | GQA | VQAv2 | MMBench | MME | POPE | SEED | SQA | Avg(%) |
|---|---|---|---|---|---|---|---|---|---|
| Upper Bound | 576 | 61.1 | 77.7 | 64.0 | 1487.2 | 85.0 | 57.9 | 66.5 | 100% |
| Q-Former | 1 | 51.1 | 63.4 | 51.7 | 1079.7 | 77.3 | 47.2 | 62.7 | 57.2% |
| Avg. Pool | 1 | 52.9 | 65.0 | 55.5 | 1210.3 | 79.1 | 50.3 | 62.2 | 64.1% |
| VoCo-LLaMA | 1 | 57.4 | 71.8 | 57.9 | 1241.4 | 81.5 | 48.8 | 66.3 | 81.0% |
| HTC-VLM (ours) | 1 hybrid | 57.6 | 72.4 | 60.0 | 1265.2 | 82.8 | 49.8 | 67.7 | 87.2% |
| Lower Bound | 1 | 37.7 | 41.2 | 22.3 | 617.3 | 53.9 | 36.9 | 60.7 | 0% |
核心发现: HTC-VLM 在所有 7 个 benchmark 上全面超越 VoCo-LLaMA (+6.2% 平均保持率),尤其在语义密集型任务 (MMBench +2.1, SQA +1.4) 和细节敏感型任务 (POPE +1.3, MME +23.8) 上均有显著提升。
5.2 多 Token Budget 对比
| Budget | HTC-VLM | VoCo-LLaMA | SparseVLM | FastV | ToMe |
|---|---|---|---|---|---|
| 64 tok | 89.8% | 78.0% | 89.3% | 72.0% | 71.1% |
| 128 tok | 93.8% | 92.2% | 96.7% | 85.1% | 81.9% |
| 192 tok | 94.2% | 90.7% | 99.1% | 86.4% | 88.9% |
HTC-VLM 在全 token 范围内保持最平滑的性能衰减曲线,尤其在极端压缩 (1-4 token) 区间远超所有基线。
Figure 4 解读: Performance vs. Token Budget 曲线。HTC-VLM (蓝色实线) 在整个 1-576 token 范围内保持最平滑的衰减,尤其在 1-32 token 极端压缩区间仍保持稳定,而 VoCo-LLaMA 在 16 token 以下急剧下降。结构化剪枝方法 (ToMe, FastV, PDrop) 表现为阶梯式跳变,因为它们只支持特定粒度 ({64, 128, 192})。
5.3 注意力分析与语义解耦验证
Figure 3 解读: <voco> token 的注意力热力图对比。左图为 HTC-VLM,前 4 列对应离散语义 token,显示 <voco> 对离散锚点的注意力权重显著高于后续 image patch tokens,验证了离散锚点的语义引导作用。右图为 VoCo-LLaMA,注意力在所有 16 个 image patch 上分布均匀,缺乏语义聚焦。
5.4 表征探测 (Representation Probing)
| 表征类型 | Detail 任务 (D-10) | Semantic 任务 (S-10) |
|---|---|---|
| 离散 | 25.44% | 20.83% |
| 连续 | 27.19% | 26.67% |
| 混合 | 30.70% | 26.67% |
混合 latent 在两类任务上均取得最优,验证了压缩机制同时保留语义和细节的能力。
5.5 消融实验

Figure (Table 4) 解读: 消融实验总结页面,包含三组关键消融。(1) Hybrid vs. Non-Hybrid: 纯离散 33.3%、纯连续 81.0%、混合 87.2%,证明混合表征的必要性。(2) 离散 token 数量: 最优 (87.2%), 反而下降到 84.6%,说明过多离散 token 引入冗余。(3) 融合策略: Pre-fusion (离散在前) 最优 87.2%,Post-fusion 和 Mean fusion 均为 84.6%。
关键消融结果
| 消融维度 | 配置 | Retention |
|---|---|---|
| Hybrid vs. Non-Hybrid | Discrete-Only (441 tok) | 33.3% |
| Continuous-Only (576 tok) | 81.0% | |
| HTC-VLM (4+576 tok) | 87.2% | |
| 离散 token 数 | 1 / 2 / 4 / 8 | 83.9 / 84.9 / 87.2 / 84.6 |
| 融合策略 | Pre-fusion / Post / Mean | 87.2 / 84.6 / 84.6 |
| Anchor 类型 | Random Patches / Top-k Attn / K-Means / MGVQ | 82.5 / 85.1 / 85.8 / 87.2 |
| Mask 拓扑 | Full Graph / Star Graph | 85.4 / 87.2 |
5.6 推理效率
| 模型 | Latency (ms) | Throughput (img/s) | Memory (GB) |
|---|---|---|---|
| Vanilla LLaVA (576 tok) | 475 | 2.1 | 28.3 |
| SparseVLM (64 tok) | 165 | 5.6 | 15.8 |
| VoCo-LLaMA (1 tok) | 52 | 19.4 | 11.1 |
| HTC-VLM (1 tok) | 54 | 18.7 | 11.6 |
HTC-VLM 延迟仅比 VoCo-LLaMA 多 2ms (MGVQ encoder ~6ms,可与 ViT 并行隐藏) 相比 Vanilla LLaVA 加速 7.9x,相比 SparseVLM 加速 8.8x MGVQ 额外成本可忽略:轻量 CNN,~6ms,远小于 ViT 的 28.5ms
5.7 MGVQ Codebook 消融
| 配置 | GQA | TextVQA | Avg. Retention |
|---|---|---|---|
| G=4, K=8192 | 55.1 | 66.3 | 82.4% |
| G=4, K=16384 | 56.0 | 67.4 | 84.1% |
| G=8, K=8192 | 56.8 | 68.5 | 85.2% |
| G=8, K=16384 (ours) | 57.6 | 69.7 | 87.2% |
| G=8, K=32768 | 57.4 | 69.4 | 86.9% |
最佳配置 ,更大 codebook () 引入训练不稳定,性能反降。
5.8 总结与思考
5.8.1 核心贡献
- 表征分析: 首次从信息论角度揭示单 token 连续瓶颈的 “Semantic-Detail Capacity Conflict”,证明纯连续压缩的根本局限性 (Theorem 1)
- 混合解纠缠框架: 提出 discrete semantic anchors + continuous detail carriers 的双通道设计,通过 Disentanglement Attention Mask 实现 Star-Graph 拓扑的信息融合
- SOTA 单 token 压缩: 580:1 压缩比下 87.2% 性能保持率,全面超越 VoCo-LLaMA (81.0%),且推理效率几乎相同
5.8.2 局限性
仅支持单图: 未探索多图/视频场景,temporal cues 可能与混合 token 设计有交互 外部 VQ tokenizer: MGVQ 是预训练的外部模型,非端到端联合学习,可能限制适应性 固定压缩比: 所有图像统一压缩为 1 token,缺乏自适应机制
5.8.3 启发与延伸
语义锚点思想的通用性: 离散 token 作为 “meta-instruction” 引导压缩的思路可迁移到视频 VLM 的时序压缩——每帧用少量离散 token 锚定关键语义,连续通道保留运动细节 与 KV Cache 压缩的关系: Disentanglement Mask 的 Star-Graph 设计本质上限制了 attention 的有效范围,类似于 StreamingLLM 的 attention sink 机制,可能可以结合 可变压缩率: 结合 token budget 实验 (Table 2),HTC-VLM 从 1 到 576 token 平滑扩展的特性暗示了一个自适应 token 分配策略的可能——根据图像复杂度动态选择压缩率