Files
deepseek-r1-kunlun-INT8/README.md
2026-10-30 17:29:26 +08:00

6.2 KiB
Raw Blame History

DeepSeek-R1 昆仑芯 INT8 转换

针对完整 DeepSeek-R1/V3 架构检查点。 依据已安装的 vllm==0.25.1、vllm-kunlun==0.25.1.dev0 实现

输出策略

权重 输出类型 原因
MLA q_a/q_b/kv_a/o 投影 逐输出通道 INT8 对接 KunlunScaledMMLinearKernel
58 层 MoE 的 256 个路由专家 gate/up/down 逐输出通道 INT8 对接 KunlunCompressedTensorsW8A8Int8MoEMethod
MLA kv_b_proj 反量化 BF16 对接 MLA 的 BF16 W_UK_T/W_UV 拆分路径
前三层 Dense MLP 反量化 BF16 真实样本逐通道 INT8 误差较大
共享专家 gate/up/down 反量化 BF16 真实样本逐通道 INT8 误差较大
Embedding、lm_head、norm、router、routing bias 原样保留 保持源类型和值
第 62 层 MTP,即 model.layers.61 不包含 本脚本输出普通推理版本,num_nextn_predict_layers=0

输出 compressed-tensors / int-quantized,权重逐通道静态对称 INT8,激活逐 token 动态对称 INT8;无需校准集。BF16 例外通过量化配置的 ignore 明确声明,包括 vLLM 融合后的 gate_up_proj 名称。保持源张量名称,由 vLLM 完成 Q/KV A 投影、gate/up 的融合与专家权重切分。

W[i,j] = W_fp8[i,j] * weight_scale_inv[i//128,j//128]
s[i,0] = max(abs(W[i,:])) / 127
W_int8[i,j] = clamp(round(W[i,j]/s[i,0]), -127, 127)

weight_scale_inv 保存的值用于乘法反量化,不能取倒数。 输出 INT8 scale 为 weight_scale,FP32,形状 [out_features,1]。 磁盘存 absmax/127,插件加载后自行乘 127,转换时不能提前乘。 BF16 例外输出 BF16(FP8 * block_scale),删除原 block scale,不产生 INT8 scale。 全零 INT8 行使用 q=0,s=1。

脚本按源索引定位跨分片的 scale,逐分片、逐矩阵、分行处理;不加载整个模型,不分配 XPU,不修改原始模型。 预检逐项验证前 61 层的全部 MLA/Dense/共享及路由专家投影、矩阵形状、FP8 格式和 scale 网格。

使用

脚本已部署到:

/mnt/data1/quant_tools/deepseek_r1_kunlun_int8/

预检不创建输出目录、不转换权重:

/opt/vllm_kunlun/bin/python \
  /mnt/data1/quant_tools/deepseek_r1_kunlun_int8/convert_deepseek_fp8_to_int8.py \
  --source /mnt/data1/deepseek-r1 \
  --output /mnt/data1/deepseek-r1-INT8 \
  --dry-run

开始全量转换:

/opt/vllm_kunlun/bin/python \
  /mnt/data1/quant_tools/deepseek_r1_kunlun_int8/convert_deepseek_fp8_to_int8.py \
  --source /mnt/data1/deepseek-r1 \
  --output /mnt/data1/deepseek-r1-INT8 \
  --threads 8

中断后在相同命令末尾添加 --resume。输出目录必须是独立空目录,或具有匹配的 conversion_state.json。默认 --chunk-rows 1024,恢复时必须与首次运行一致。每片先写临时文件,检查成功后重命名,再记录完成状态。完成时打印 Complete 并生成新配置、索引和 conversion_report.json,之后才可部署。

恢复时核实源配置和索引、源分片大小与时间戳;核实已完成输出分片大小、张量名称、类型、形状及 safetensors 文件结构。恢复检查不计算完整权重文件校验和。

2026-10-29 预检结果:45,032 个 FP8 矩阵,其中 44,788 个转 INT8,244 个转 BF16;160 个输出分片,预计张量数据 631.84 GiB。原始目录按真实张量计算为 641.29 GiB(含 MTP);源索引的 total_size 元数据偏大,脚本不使用该值估算转换空间。

首次部署参数

转换后可运行提供的启动示例:

bash /mnt/data1/quant_tools/deepseek_r1_kunlun_int8/serve_int8.sh

示例使用 TP=8、BF16、eager 模式、4096 上下文、单并发,每卡 KV cache 显式分配 4 GiB。 VLLM_KUNLUN_ENABLE_INT8_BMM=0 与 BF16 kv_b_proj 一致,不能设置为 1。 首测使用 TP,不沿用原命令中的 --enable-expert-parallel;当前 INT8 单体 MoE 路径的 EP 路由和专家重映射未验证。 这是准备好的初始参数,尚未完成完整模型启动或生成测试。

已完成的验证与范围

cd /mnt/data1/quant_tools/deepseek_r1_kunlun_int8
/opt/vllm_kunlun/bin/python test_conversion.py
/opt/vllm_kunlun/bin/python validate_kunlun_contract.py
/opt/vllm_kunlun/bin/python validate_sample_weights.py \
  --source /mnt/data1/deepseek-r1 \
  --report sample_validation_mixed.json
  • CPU 数值测试与合成检查点转换通过:包括跨分片 scale、非整块维度、全零行、BF16 例外、MTP 排除、配置/索引、断点恢复、源文件保护、拒绝覆盖和缺失投影检查。
  • 当前插件的 CPU 配置/参数约定检查通过:MLA 融合投影的 INT8 内核、路由专家 INT8 MoE、scale 乘 127、BF16 ignore 配置和 MLA BF16 权重拆分。测试模拟 TP rank/size,不是完整引擎启动或 XPU 算子执行。
  • 九个真实矩阵抽样通过:覆盖五类 MLA 投影、Dense MLP、共享专家、路由专家 gate/down。

初始 absmax INT8 基线中,Dense gate 样本 relative RMSE 为 10.10%,共享专家 gate 为 7.18%。将这两类投影改为 BF16 后,对应样本误差为 0.142% 和 0.152%;最终 INT8 样本误差约为 0.94%–1.99%,满足半个逐行量化步长的舍入误差界。相对误差均以 FP8 乘 block scale 后的 FP32 权重为参考;这些指标不代表任务准确率。

服务器上的 sample_validation.json 保存初始基线,sample_validation_mixed.json 保存最终策略结果。 这是从已量化 FP8 再转换的基线方案;全量转换、P800 推理及实际任务质量仍需分别验证。

2026-10-29 MLA 初始化问题及绕过

完整部署发现当前 FlashMLAImpl 缺少 vLLM 所要求的 forward_mha/forward_mqa,无法实例化。此前 CPU 权重准备检查未覆盖这个实例化步骤。权重无需重新转换。

新增 serve_int8_no_mla.sh,通过 VLLM_MLA_DISABLE=1 选择 DeepseekV2Attention 和昆仑芯普通 Attention,绕过不完整的 FlashMLA 接口;保持 TP=8、不启用 EP、eager、单并发、4096 上下文和每卡 4 GiB KV cache。关闭 MLA 增加 KV cache 开销,可能降低吞吐。该路径尚未经过完整模型启动和输出验证。

在容器内运行:

bash /mnt/data1/quant_tools/deepseek_r1_kunlun_int8/serve_int8_no_mla.sh