Prhub

#50000 [New model] Kimi K3

原始 PR 作者 ZJY0516 合并时间 2026-07-30 18:49 文件变更 82 提交数 35 评论 48 代码增减 +2931 / -1349

执行摘要

新增 Kimi K3 模型,集成 MLA/MoE/GDN 并重构通信后端

PR body 明确指出核心目标是添加 Kimi-K3 模型支持,利用自定义 kernel( DeepGEMM、FlashInfer )进行高性能推理,并支持 Speculative Decoding、多模态、结构化输出等功能。同时发布博客文章说明优化细节。

此 PR 值得精读,特别是 MLA 后端自动选择逻辑、MNNVL 分布式通信增强、以及 KDA 权重加载器的兼容性设计。同时关注后续对 MXFP4 后端选择的重构和 Rust 转义安全修复。

讨论亮点
  1. MXFP4 后端选择硬编码问题:BowenBao 在 mxfp4.py 评论中指出,K3 的 SiTU AITER 后端选择应通过通用 MXFP4 后端 oracle 自动路由,而非单独硬编码。zyongye 回应已在后续提交中解决,并保留为后续优化。
  2. DeepGEMM 仓库 URL 问题:tlrmchlsmth 指出 CMake 中 DeepGEMM 仓库从匿名 HTTPS 改为 SSH 认证 URL,导致 CI 无法构建。ZJY0516 回复已修复为正确 URL。
  3. Info 日志打印完整 Prompt 风险:chatgpt-codex-connector( Codex )在 vllm/renderers/hf.py 指出 INFO 级别记录完整 prompt(含系统指令、用户消息等)存在敏感信息泄露风险,且对长上下文造成 CPU 和 log 开销。该反馈未在 PR 中得到直接回应。
  4. AMD 环境变量命名标准化:tjtanaa 建议将 AITER_SITUV2_A8W4 环境变量按 vLLM 规范命名为 VLLM_ROCM_USE_AITER_MOE_SITUV2_A8W4,并缓存在 vllm/_aiter_ops.py 中而非在热路径读取。评审者同意此方案,但当前 PR 保留原样以待后续重构。
  5. Rust 端 XTML 属性转义不完整:depthfirst-app bot 扫描发现 Rust 渲染器和解析器的 escape_attr_value 仅转义 &" 而未处理 <>,可能导致结构标签注入。该问题属于自动化发现,状态待确认。

实现拆解

  1. 模型架构迁移:删除旧的 vllm/model_executor/models/kimi_linear.py,将模型定义迁移到 vllm/models/kimi_k3/ 目录,包含 KimiMLP、KimiMoE、KimiMLAAttention、KimiDecoderLayer 等组件。同时更新配置类 KimiK3ForConditionalGenerationConfig 以路由 MXFP4 checkpoint 到正确的量化接口。
  2. Gated Delta Network 注意力重构:重写 vllm/model_executor/layers/mamba/gdn/kimi_gdn_linear_attn.py,统一 KDA 注意力内核注册方式,引入兼容旧版 4D 参数的权重加载器 a_log_weight_loader,并新增 _KimiGDNMergedColumnParallelLinear 处理合并投影中的复制分片。
  3. 视觉编码器适配:在 vllm/model_executor/models/kimi_k25_vit.py 中提取 get_pos_embeds 方法,分离位置嵌入计算;为 ROCm 平台添加 MIOpen conv2d 的 AITER Triton fallback;新增 _make_vision_norm 工厂函数以支持多种归一化层。
  4. 分布式通信增强:在 vllm/distributed/device_communicators/custom_all_reduce.py 中添加 MNNVL( NVLink )缓冲区分配和多级 all-gather/reduce-scatter 支持,将支持的 world size 扩展至 16,并集成 torch.distributed._symmetric_memory
  5. MLA 解码后端优化:在 vllm/v1/attention/backends/mla/flashinfer_mla.py 中实现 MLA decode 后端自动选择逻辑,处理 trtllm-gen 无法支持的 head 数并回退到 cute-dsl,并引入持久化 multi-CTA KV 计数器缓冲区以减少每步 launch 开销。
  6. Triton Kernel Warmup:新增 vllm/model_executor/warmup/kimi_k3_triton_warmup.py,在 worker 启动时预热 attn_res 和 speculative KDA kernel,避免首次调用时的编译开销。
  7. 测试与配置:增加 tests/models/test_dspark_mla.pytests/transformers_utils/test_dspark_mla_config.py 测试 Speculative Decoding 权重映射和配置合法性;添加 vllm/transformers_utils/configs/k3_dspark.py 配置类;在 mxfp4.py 中集成 AITER SiTU kernel 选择逻辑。
文件 模块 状态 重要度
vllm/model_executor/models/kimi_linear.py 模型层 removed 9.08
vllm/model_executor/warmup/kimi_k3_triton_warmup.py 预热模块 added 9.28
vllm/model_executor/layers/mamba/gdn/kimi_gdn_linear_attn.py KDA 注意力 modified 9.05
vllm/model_executor/models/kimi_k25_vit.py 视觉编码器 modified 8.91
vllm/distributed/device_communicators/custom_all_reduce.py 分布式通信 modified 8.65
vllm/v1/attention/backends/mla/flashinfer_mla.py MLA 后端 modified 8.41
vllm/model_executor/layers/quantization/mxfp4.py 量化层 modified 8.06

关键符号

KimiMLP KimiMoE KimiMLAAttention KimiDecoderLayer a_log_weight_loader _KimiGDNMergedColumnParallelLinear _warm_attn_res kimi_k3_triton_warmup _select_mla_decode_backend _get_multi_ctas_kv_counter_buffer custom_all_gather custom_reduce_scatter _use_k3_situ_aiter _setup_kernel_k3_situ

关键源码片段

vllm/model_executor/layers/mamba/gdn/kimi_gdn_linear_attn.py core-logic

重写 KDA 注意力内核注册方式,引入兼容旧格式的权重加载器和合并投影类

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM projectfrom collections.abc import Callable
import torch
from torch.nn.parameter import Parameter
# ... 其他导入# 经验下界,避免 KDA 门控数值下溢
_KDA_GATE_LOGBOUND_MIN = -5.0
​
​
def a_log_weight_loader(shard_axis: int) -> Callable[[torch.Tensor, torch.Tensor], None]:
    """
    加载 KDA A_log 权重:兼容旧版 4D 存储和新版 1D 存储。
    旧格式形状为 (1, 1, H, 1),本函数将其压缩为 1D 后再按 TP 分片。
    """
    def loader(param: torch.Tensor, loaded_weight: torch.Tensor) -> None:
        tp_rank = get_tensor_model_parallel_rank()
        shard_size = param.data.shape[shard_axis]
        start_idx = tp_rank * shard_size
​
        if loaded_weight.dim() == 4:
            # 旧格式:shape (1, 1, H, 1),展平为 (H,)
            assert loaded_weight.shape[:2] == (1, 1) and loaded_weight.shape[-1] == 1
            loaded_weight = loaded_weight.view(loaded_weight.shape[2])
​
        loaded_weight = loaded_weight.narrow(shard_axis, start_idx, shard_size)
        return default_weight_loader(param, loaded_weight)
​
    return loader
​
​
class _KimiGDNMergedColumnParallelLinear(MergedColumnParallelLinear):
    """
    合并投影线性层,其中一个输出需要在所有 TP rank 间复制。
    复制分片的实际大小为原始 output_size * tp_size,
    在 weight_loader 中临时将当前 rank 设为 0,复用父类的标准加载逻辑。
    """
    def __init__(self, input_size: int, output_sizes: list[int],
                 replicated_shard_id: int, tp_size: int, **kwargs):
        self.replicated_shard_id = replicated_shard_id
        output_sizes = output_sizes.copy()
        output_sizes[replicated_shard_id] *= tp_size
        super().__init__(input_size, output_sizes, **kwargs)
​
    def weight_loader(self, param: Parameter, loaded_weight: torch.Tensor,
                      loaded_shard_id: tuple[int, ...] | int | None = None) -> None:
        tp_rank = self.tp_rank
        param_tp_rank = getattr(param, "tp_rank", None)
        if loaded_shard_id == self.replicated_shard_id:
            # 复制分片:所有 rank 加载同一份完整权重
            self.tp_rank = 0
            if param_tp_rank is not None:
                param.tp_rank = 0
        try:
            super().weight_loader(param, loaded_weight, loaded_shard_id)
        finally:
            self.tp_rank = tp_rank
            if param_tp_rank is not None:
                param.tp_rank = param_tp_rank
vllm/model_executor/models/kimi_k25_vit.py refactor

提取 get_pos_embeds 方法,改善位置嵌入计算可复用性;添加 ROCm 平台 conv2d fallback

# Learnable2DInterpPosEmbDivided_fixed 的部分代码
class Learnable2DInterpPosEmbDivided_fixed(nn.Module):
    # ... 初始化略
​
    def get_pos_embeds(self, grid_thws: torch.Tensor | list[list[int]]) -> torch.Tensor:
        """
        仅计算位置嵌入,不涉及输入 x,方便外部调用和复用。
        """
        pos_embs = []
        grid_thw_list = grid_thws if isinstance(grid_thws, list) else grid_thws.tolist()
        for t, h, w in grid_thw_list:
            assert t <= self.num_frames
            if (h, w) == self.weight.shape[:-1]:
                pos_emb_2d = self.weight.flatten(end_dim=1)
            else:
                pos_emb_2d = get_rope_shape(self.weight,
                                            interpolation_mode=self.interpolation_mode,
                                            shape=(h, w))
            if t == 1:
                pos_emb_3d = pos_emb_2d
            else:
                pos_emb_3d = (pos_emb_2d.unsqueeze(0).repeat(t, 1, 1)
                              + self.time_weight[0:t])
            pos_embs.append(pos_emb_3d.reshape(-1, pos_emb_3d.shape[-1]))
        return torch.cat(pos_embs)
​
    def forward(self, x: torch.Tensor, grid_thws: torch.Tensor | list[list[int]]) -> torch.Tensor:
        # forward 方法简化,直接调用 get_pos_embeds
        return x + self.get_pos_embeds(grid_thws)# MoonVision3dPatchEmbed 中新增 _proj 方法用于 ROCm fallback
class MoonVision3dPatchEmbed(nn.Module):
    def _proj(self, x: torch.Tensor) -> torch.Tensor:
        # MIOpen conv2d 在 ROCm 高负载下间歇性失败;使用 AITER Triton 卷积
        if current_platform.is_rocm() and x.dtype in (torch.float16, torch.bfloat16):
            from aiter.ops.triton.conv.conv2d import conv2d
            return conv2d(x, self.proj.weight, self.proj.bias,
                          stride=self.patch_size, layout='nchw')
        return self.proj(x)

评论区精华

MXFP4 后端选择硬编码问题 设计

BowenBao 在 mxfp4.py 评论指出 K3 的 SiTU AITER 后端选择应通过通用 MXFP4 后端 oracle 自动路由,而非单独硬编码。后续多次评论均建议将后端逻辑放入 oracle。

结论:zyongye 回应已在后续提交中解决,并标记为后续优化项。 · 已解决

DeepGEMM 仓库 URL 从 HTTPS 改为 SSH 导致不可构建 infra

tlrmchlsmth 指出 CMake 中 DeepGEMM 仓库从匿名 HTTPS 改为 SSH 认证 URL (git@github.com:Inferact/DeepGEMM.git),导致 CI 无法构建。Codex 也报告此问题。

结论:ZJY0516 回复 'done',后续提交已修复为正确 URL。 · 已解决

Info 日志打印完整 Prompt 存在安全风险 安全

chatgpt-codex-connector 在 vllm/renderers/hf.py 指出新增的 INFO 级别日志记录完整渲染 prompt(包含系统指令、用户消息等),未提供显式 opt-in,存在敏感信息泄露风险且增加 CPU 开销。

结论:未在 PR 中得到回应,该问题被标记为待后续解决。 · 待处理

AMD 环境变量命名标准化与缓存 style

tjtanaa 建议将 envs.py 中的 `AITER_SITUV2_A8W4` 按 vLLM 规范命名为 `VLLM_ROCM_USE_AITER_MOE_SITUV2_A8W4`,并缓存在 `vllm/_aiter_ops.py` 中避免热路径重复读取。其它评审者赞同。

结论:评审者同意此方案,但当前 PR 保留原有写法,标记为后续重构。 · 已解决

Rust 端 XTML 属性转义不完整 安全

depthfirst-app bot 扫描发现 Rust 渲染器和解析器的 escape_attr_value 只转义 & 和 ",未处理 <、>,用户控制的工具名可注入 XTML 结构标签。

结论:该报告为自动扫描结果,未得到人工确认是否在本次 PR 解决。 · 待处理

风险与影响

  1. 兼容性风险:删除 vllm/model_executor/models/kimi_linear.py 会破坏依赖此旧文件的外部代码;新的模型配置类 KimiK3ForConditionalGenerationConfig 清除了原有 compressed-tensors 代码路径。
  2. 性能风险:Triton kernel warmup 会延长 Worker 启动时间;MLA 持久化计数器缓冲区增加固定显存占用(约 128 MB)。
  3. 安全风险vllm/renderers/hf.py 新增 INFO 级别日志输出完整渲染 prompt,可能泄露用户敏感信息;Rust 端 XTML 转义不完整可能允许注入。
  4. 依赖风险:需要私有分支的 FlashInfer( v0.6.16rc5 )和 DeepGEMM,开源构建可能因未公开依赖而失败。
  5. 测试覆盖:新增测试仅覆盖 Speculative Decoding 配置和权重映射,缺少端到端准确度测试(如 perplexity 对比)。

用户可以直接使用 moonshotai/Kimi-K3 模型进行推理,并利用多模态、工具调用、Speculative Decoding 等特性。系统层面,分布式通信后端支持 MNNVL 后可提升多机多卡效率;MLA 解码后端优化可改善冷启动和首 token 延迟。团队需维护大量新代码(模型定义、Rust 前端、KDA 内核、量化集成),社区贡献者可能从 MLA 和 MoE 优化中受益。影响范围覆盖模型执行器、v1 运行时、分布式通信、Rust 前端,因此影响程度高。

核心路径变更 安全风险 依赖私有仓库 缺少测试覆盖

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论