执行摘要
- 一句话:TurboQuant 支持混合模型并修复页面大小对齐
- 推荐动作:建议 TQ 使用者精读
config.py 中的 get_boundary_skip_layers 和 _get_full_attention_layer_indices,理解混合模型识别机制;如需在新架构上启用 TQ,需对应扩展该函数。平台层面的 LCM 页面大小设计值得参考。
功能与动机
TurboQuant 之前遇到 Mamba 等非注意力层时会抛出 NotImplementedError,导致混合模型无法使用。此外,混合模型的页面大小规划器使用了标准公式,与 TQ 的紧凑 KV 布局不匹配,触发断言;被跳过的层可能错误地强制使用 TURBOQUANT 注意力后端;ROCm 上的 flash_attn_varlen_func 不接受 out= 参数。
实现拆解
- 配置层扩展:修改
TurboQuantConfig.get_boundary_skip_layers 签名,接受 ModelConfig 而非 num_layers。对于混合模型 (is_hybrid=True),调用新增的 _get_full_attention_layer_indices 获取全注意力层全局索引并返回空跳过列表(边界保护对混合层数少的模型不适用);对于稠密模型,行为不变(跳过首尾各 2 层)。该函数统一处理三种混合模型约定:layer_types(Qwen3.5/Next)、layers_block_type(Jamba/Zamba2)、attn_type_list(MiniMax)。
- 引擎配置移除混合禁用:在
vllm/engine/arg_utils.py 中移除对混合模型的 raise NotImplementedError,改为直接调用 TurboQuantConfig.get_boundary_skip_layers(model_config),并简化跳过层合并逻辑。
- 平台页面大小适配:在
vllm/platforms/interface.py 的 _align_hybrid_block_size 中新增 turboquant_ 分支,使用 TQFullAttentionSpec 计算 TQ 专有的页面大小。当存在跳过层时,使用 lcm(tq_page, skip_page) 统一页面大小,确保合并器能正确对齐。
- 测试覆盖:新增
TestHybridAttentionIndices 类,验证 _get_full_attention_layer_indices 对三种混合约定的正确性;同时调整原有边界保护测试以使用新的 _dense_model_config 辅助构造 Mock 配置。
关键文件:
vllm/model_executor/layers/quantization/turboquant/config.py(模块 量化配置;类别 source;类型 data-contract;符号 get_boundary_skip_layers, from_cache_dtype, _get_full_attention_layer_indices): 核心配置逻辑,修改 get_boundary_skip_layers 签名为接受 ModelConfig,新增 _get_full_attention_layer_indices 识别混合模型的全注意力层,这是整个 PR 的数据契约变更。
tests/quantization/test_turboquant.py(模块 测试;类别 test;类型 test-coverage;符号 _dense_model_config, TestHybridAttentionIndices, _fake_model_config, test_layer_types_full_attention): 新增 TestHybridAttentionIndices 覆盖三种混合模型约定的索引识别;更新原有边界保护测试以适配新签名,确保回归。
vllm/engine/arg_utils.py(模块 引擎配置;类别 source;类型 core-logic): 引擎配置入口,移除了对混合模型的 raise NotImplementedError,将边界保护逻辑委托给 TurboQuantConfig.get_boundary_skip_layers。
vllm/platforms/interface.py(模块 平台接口;类别 source;类型 dependency-wiring): 在 _align_hybrid_block_size 中新增 TQ 分支,使用 TQFullAttentionSpec 计算页面大小,并通过 LCM 统一 TQ 层与跳过层的页面大小,确保混合模型缓存分配正确。
关键符号:TurboQuantConfig.get_boundary_skip_layers, TurboQuantConfig.from_cache_dtype, _get_full_attention_layer_indices, _dense_model_config, _fake_model_config, TestHybridAttentionIndices.test_layer_types_full_attention, TestHybridAttentionIndices.test_layers_block_type_jamba, TestHybridAttentionIndices.test_attn_type_list_minimax, TestHybridAttentionIndices.test_no_hybrid_hints_returns_empty
关键源码片段
vllm/platforms/interface.py
在 _align_hybrid_block_size 中新增 TQ 分支,使用 TQFullAttentionSpec 计算页面大小,并通过 LCM 统一 TQ 层与跳过层的页面大小,确保混合模型缓存分配正确。
# interface.py 片段:混合模型中 TurboQuant 的页面大小对齐
# (位于 _align_hybrid_block_size 方法内)
elif cache_config.cache_dtype.startswith("turboquant_"):
# TQ 使用紧凑的 Key-Value 打包布局,标准 FullAttentionSpec 公式
# 会过度估算大小,导致 unify_kv_cache_spec_page_size 断言失败。
# 当同时存在跳过层(标准布局)时,取两者的最小公倍数(LCM)
# 以确保所有注意力层页面大小统一。
tq_cfg = TurboQuantConfig.from_cache_dtype(
cache_config.cache_dtype, model_config.get_head_size()
)
tq_page = TQFullAttentionSpec(
block_size=1,
num_kv_heads=model_config.get_num_kv_heads(parallel_config),
head_size=model_config.get_head_size(),
head_size_v=model_config.get_head_size(),
dtype=kv_cache_dtype,
kv_quant_mode=kv_quant_mode,
tq_slot_size=tq_cfg.slot_size_aligned,
).page_size_bytes
if cache_config.kv_cache_dtype_skip_layers:
skip_page = FullAttentionSpec(
block_size=1,
num_kv_heads=model_config.get_num_kv_heads(parallel_config),
head_size=model_config.get_head_size(),
dtype=model_config.dtype, # 跳过层使用未量化 dtype
).page_size_bytes
# 使用 LCM 而非 max:skip_page 通常不是 tq_page 的整数倍,
# max 会导致下游无法统一页面大小。
attn_page_size_1_token = lcm(tq_page, skip_page)
else:
attn_page_size_1_token = tq_page
评论区精华
- 简化边界逻辑:mgoin 建议将
arg_utils.py 中的混合判断与跳过层生成全部放到 TurboQuantConfig.get_boundary_skip_layers 中,作者 JartX 采纳。
- 注意力后端选择:mgoin 质疑为何在
cuda.py 中特化处理 TQ 后端选择,JartX 解释是 RDNA 场景需要,最终移除了该特化,改为依赖统一的后端注册机制。
- kv_cache_utils 改动争议:mgoin 要求不要在
kv_cache_utils.py 中做侵入式修改以免影响其他路径,vibhavagarwal5 同意仅合并混合模型相关修复,作者随后还原了该文件的大幅改动。
- 性能验证:多位贡献者(huangzhilin-hzl, vibhavagarwal5, jhsmith409, webcodes-cz)在 H20、RTX 6000 Pro Blackwell、RTX 5090、A4000 等硬件上提供了 throughput 和 accuracy 数据,确认无回归且显著提升 KV 缓存容量。
- 简化边界保护逻辑 (design): JartX 采纳,将 Hybrid 判断移到 get_boundary_skip_layers,arg_utils 只负责调用和合并。
- 注意力后端选择特化 (design): JartX 移除了该特化代码,依赖后端注册流程。
- kv_cache_utils 改动范围 (correctness): JartX 还原了 kv_cache_utils 的大幅改动,将 LCM 逻辑移入 platforms/interface.py。
- 性能与精度验证 (performance): 验证通过,混合模型基线保持,显存压缩 2-4x。
风险与影响
关联脉络
- PR #40128 [TurboQuant] Fix page size alignment for hybrid models (in draft): 此 PR 的 LCM 页面大小对齐逻辑源自该闭源 PR,且提交记录中显式引用。
- PR #41123 [TurboQuant] Alternative page-size unification for hybrid Mamba+Attention: 在同一时间段处理类似问题,社区成员 MidasMining 提到两个 PR 重叠,本 PR 的方法更简洁。
参与讨论