Deepseek R2出现了?或者叫Deepseek V4?

27 阅读7分钟

FlashMLA 是 DeepSeek 开发的高性能注意力内核库,为 DeepSeek-V3 和 DeepSeek-V3.2-Exp 模型提供底层计算支持。在代码库中,除了已知的 V3.2 (V32) 架构外,还存在一个名为 model1 的配置类型。这个Model1会是新模型的代号吗? GitHub 仓库: deepseek-ai/FlashMLA

csrc/params.h 文件中,定义了一个枚举类型 ModelType

enum class ModelType {
    V32,     // DeepSeek V3.2
    MODEL1   // model1 配置
};

这意味着 FlashMLA 支持两种不同的模型架构。系统在运行时会根据输入张量的维度自动判断使用哪种模型类型,代码如下(csrc/api/sparse_decode.h:318-325):

ModelType model_type;
if (d_qk == 576) {
    model_type = ModelType::V32;
} else if (d_qk == 512) {
    model_type = ModelType::MODEL1;
} else {
    TORCH_CHECK(false, "Unsupported d_qk: ", d_qk);
}

结论:model1 是一个头部维度为 512 的模型配置,而 V32 (V3.2) 的头部维度为 576。


详细对比

核心维度参数

csrc/sm100/decode/head64/config.h:33-43 可以看到两种模型的详细配置:

参数V32model1含义
D_Q576512Query 头部维度
D_K576512Key 头部维度
D_V512512Value 头部维度
D_NOPE512448非位置编码部分维度
D_ROPE6464旋转位置编码维度

观察:model1 的总维度从 576 降至 512,其中 D_NOPE 从 512 降至 448,而 D_ROPE 保持 64 不变。这意味着 D_NOPE + D_ROPE = D_Q 在两种模型中都成立。

2 量化策略差异

从同一配置文件中可以看到:

参数V32model1
QUANT_TILE_SIZE12864
NUM_SCALES_EACH_TOKEN48

这意味着:

  • V32 每 128 个 FP8 值使用 1 个缩放因子
  • model1 每 64 个 FP8 值使用 1 个缩放因子

更细粒度的量化块(64 vs 128)配合更多的缩放因子(8 vs 4),表明 model1 采用了不同的量化精度策略。

3 RoPE 处理方式

从配置文件中的注释(csrc/sm100/decode/head64/config.h:39,55)可以看到:

static constexpr bool V_HAVE_ROPE = MODEL_TYPE == ModelType::V32 ? false : true;
static constexpr int K_ROPE_SW = MODEL_TYPE == ModelType::V32 ? 64 : 128;

以及 csrc/sm100/decode/head64/config.h:172 的注释:

// RoPE part, dequantized. SW64 in v32 mode, SW128 in MODEL1 mode

这表明:

  • V32 中 Value 不包含 RoPE,RoPE 部分存储在 SW64 内存区域
  • model1 中 Value 包含 RoPE,RoPE 部分存储在 SW128 内存区域

KV Cache 详解

每个 Token 的存储大小

csrc/api/sparse_decode.h:290-295 可以看到两种模型的 KV Cache 存储格式:

if (d_qk == 576 && d_v == 512) {
    // V3.2 style
    bytes_per_token = 512 + 64*2 + (512/128)*4;
} else if (d_qk == 512 && d_v == 512) {
    // MODEL1 style
    bytes_per_token = 448 + 64*2 + (448/64)*1 + 1;
}

计算结果

  • V32: 512 + 128 + 16 = 656 bytes/token
  • model1: 448 + 128 + 7 + 1 = 584 bytes/token (实际代码注释为 576,可能存在额外对齐)

存储结构分解

V32 格式 (656 bytes) :

  • NoPE 量化部分: 512 bytes (512 × float8_e4m3)
  • RoPE 部分: 128 bytes (64 × bfloat16 × 2,分别给 K 和 V)
  • 缩放因子: 16 bytes (4 × float32)

model1 格式:

  • NoPE 量化部分: 448 bytes (448 × float8_e4m3)
  • RoPE 部分: 128 bytes (64 × bfloat16 × 2)
  • 缩放因子: 8 bytes (7 × float8_e4m3,其中 1 个为填充)
  • 额外填充: 1 byte

TMA 张量步长

csrc/sm100/decode/head64/config.h:41 可以看到:

static constexpr int TMA_K_STRIDE = MODEL_TYPE == ModelType::V32 ?
    D_NOPE+2*D_ROPE+4*(D_NOPE/QUANT_TILE_SIZE) : D_NOPE+2*D_ROPE;

计算

  • V32: 512 + 128 + 4×(512/128) = 512 + 128 + 16 = 656
  • model1: 448 + 128 = 576

TMA (Tensor Memory Accelerator) 是 NVIDIA Hopper 架构引入的张量内存加速器,这个步长定义了张量在内存中的跨距。


内存布局与内核实现

SM100 架构下的内存布局

csrc/sm100/decode/head64/config.h:52-55

static constexpr int D_Q_SW128 = 512;
static constexpr int D_Q_SW64 = MODEL_TYPE == ModelType::V32 ? 64 : 0;
static_assert(D_Q_SW128 + D_Q_SW64 == D_Q);

这说明:

  • 两种模型都使用 SW128 存储前 512 维
  • V32 额外使用 SW64 存储剩余的 64 维
  • model1 不使用 SW64(因为总维度就是 512)

内核实例化文件

FlashMLA 为 model1 实现了专门的 CUDA 内核:

SM90 架构 (setup.py:78-79):

"csrc/sm90/decode/sparse_fp8/instantiations/model1_persistent_h64.cu",
"csrc/sm90/decode/sparse_fp8/instantiations/model1_persistent_h128.cu",

SM100 架构 (setup.py:103):

"csrc/sm100/decode/head64/instantiations/model1.cu",

这些实例化文件的内容非常简洁,例如 model1_persistent_h64.cu

#include "../splitkv_mla.cuh"namespace sm90::decode::sparse_fp8 {
​
template void run_flash_splitkv_mla_fp8_sparse_kernel<ModelType::MODEL1, 64>(
    const SparseAttnDecodeParams &params);
​
}

RoPE 处理的架构差异

csrc/sm100/decode/head64/kernel.cuh:532-580 的注释可以看到关键差异:

V32 的 RoPE 处理:

// V3.2: RoPE behaves like an extra block with size 64, so we can do RoPE first

RoPE 作为独立的 64 维块,可以先处理。

model1 的 RoPE 处理:

// MODEL1: RoPE is the last 64 dims within the full 512 dim, which couples
// with the last 64 dim from the NoPE part when performing dual GEMM.
//
// logical view: |0|1|2|3|4|5|6|7| (where 7 is the RoPE part)
// dual gemm's view:

RoPE 耦合在 512 维内部,需要与 dual GEMM 配合处理。


测试配置与支持特性

支持的特性列表

csrc/api/sparse_decode.h:14-28 定义的特性枚举:

enum class DecodeFeatures : int {
    HEAD_64, HEAD_128,
    HEAD_DIM_576, HEAD_DIM_512,
    V32_KVCACHE_FORMAT,
    MODEL1_KVCACHE_FORMAT,
    ATTN_SINK,
    TOPK_LENGTH,
    EXTRA_KVCACHE,
    EXTRA_TOPK_LENGTH
};

观察EXTRA_KVCACHEEXTRA_TOPK_LENGTH 是 model1 支持的特性。

架构支持矩阵

csrc/api/sparse_decode.h:156-180 可以看到:

实现类头数d_qk支持的 KV Cache 格式
Decode_Sm90_Impl64/128512/576V32, MODEL1
Decode_Sm100_Head64_Impl64512/576V32, MODEL1
Decode_Sm100_Head64x2_Impl128512/576V32, MODEL1
Decode_Sm100_Head128_Impl128512MODEL1 (仅)

注意Decode_Sm100_Head128_Impl 只支持 MODEL1_KVCACHE_FORMAT,不支持 V32。

model1 测试配置

tests/test_flash_mla_sparse_decoding.py:105-113 定义了 4 种 model1 配置:

配置h_qtopkextra_topkblock_sizeextra_block_size
CONFIG16412851225664
CONFIG2128128102425664
CONFIG36412810242562
CONFIG412812810242562

所有配置都包含 extra_s_k=16384extra_topk,表明 model1 专为需要额外 KV Cache 的场景设计。


技术总结

model1 的核心特征

基于代码分析,model1 具有以下特征:

  1. 更紧凑的维度:512 vs 576,是 2 的幂次,有利于内存对齐
  2. 更细粒度的量化:64 vs 128 的量化块大小
  3. 更多的缩放因子:8 vs 4
  4. 不同的 RoPE 处理:耦合在主维度内而非独立
  5. 支持额外 KV Cache:V32 不支持的特性

性能数据

从仓库 README 可以看到,稀疏 MLA 解码内核在 H800 SXM5 上:

  • 使用 FP8 KV Cache 时达到 410 TFLOPS
  • 在 B200 上达到 350 TFLOPS(未完全优化版本)

参考资料

  1. FlashMLA GitHub 仓库: github.com/deepseek-ai…

  2. 核心代码文件:

    • csrc/params.h - ModelType 枚举定义
    • csrc/api/sparse_decode.h - API 接口和特性定义
    • csrc/sm90/decode/sparse_fp8/config.h - SM90 配置
    • csrc/sm100/decode/head64/config.h - SM100 配置
    • tests/test_flash_mla_sparse_decoding.py - 测试配置