在 Atlas 上跑通 DeepSeek-R1:KTransformers 昇腾 NPU 部署实战
2026/9/8 19:53:35 网站建设 项目流程

在 Atlas 上跑通 DeepSeek-R1:KTransformers 昇腾 NPU 部署实战

【免费下载链接】ktransformersA Flexible Framework for Experiencing Heterogeneous LLM Inference/Fine-tune Optimizations项目地址: https://gitcode.com/GitHub_Trending/ktr/ktransformers

导语

为什么要把 LLM 搬到昇腾 NPU 上跑?最直接的答案是内存和成本。DeepSeek-R1 这类满血 MoE 模型的路由专家权重体量巨大,GPU 集群要么买不起、要么排队。Atlas 服务器配 1TB DDR5,用 CPU + NPU 异构分工承接推理,KTransformers 的 CPU 推理内核正好吃下这条路径——专家权重放在内存里,注意力与算子下沉到 NPU 执行。本文是一次真实部署的复盘:从 Atlas 硬件、CANN 软件栈、双权重合并,到 balance_serve 服务启动与性能核对,每一步的坑都标在原地。

部署前避坑清单

先知道会踩什么坑,后面装环境时心里有数:

  • transformers 版本被钉死在4.57.1,其他版本未验证,装错了直接报结构解析异常。
  • torch_npu 不能直接用 pypi 预编译包。因为涉及新增算子,必须从源码编译 v2.5.1 分支,且编译后版本号里的哈希后缀要手动去掉(见下文)。
  • 两份权重缺一不可。Q4 的 GGUF 与 W8A8 的 safetensor 必须先用合并脚本合成一份,只放一份进模型目录,服务起不来。
  • 400GB 物理内存是下限。满血版 DeepSeek-R1/V3 的路由专家权重需要约 400GB 物理内存,内存不足的机器别硬试。
  • CANN 环境变量没 source,一切白搭libhccl.solibascend_hal.so缺失都是同一个原因,速查表里给了解法,这里不重复展开。

搭建 Atlas 硬件与操作系统

本节目标是把一台 Atlas 2UP 变成可用的 300I A2 推理节点。硬件与系统版本按下表核对:

规格
服务器Atlas 2UP
NPU300I A2(当前 KTransformers 适配的 NPU 型号)
CPUHUAWEI Kunpeng 920 7270Z
内存DDR5 服务器内存(1TB)
操作系统Ubuntu 22.04 for aarch64
内核5.15.0-25-generic

装完系统后做两件事:关闭自动更新,并记录好 CANN、NPU 驱动的实际安装路径——后面 source 环境变量要用。硬件插拔与固件确认建议拉原厂支持一起完成,NPU 的固件版本直接影响后面 Kernel 能否加载。

配置 CANN 软件栈

软件栈分四层:HDK 固件驱动 → CANN → Python 环境 → torch_npu。顺序不能乱,版本必须严格对齐下表,任何一层漂移都会在算子加载阶段报错:

组件版本
Ascend HDK25.3.RC1
CANN8.3.RC1.alpha003(需装 ToolKit、Kernel、NNAL 三件)
Python3.11(conda 环境,一行conda create -n py311 python=3.11即可)
PyTorchtorch==2.5.1/torchvision==0.20.1/torchaudio==2.5.1
transformers4.57.1(必须,无替代)
torch_npuv2.5.1 分支源码编译

torch_npu 编译前,先把 CANN 与 NNAL 的环境加载进当前 shell:

source /usr/local/Ascend/ascend-toolkit/set_env.sh source /usr/local/Ascend/nnal/atb/set_env.sh

⚠️ 编译过程对 github、gitcode 等平台的网络访问敏感,网络不畅通时子模块拉取会静默失败。从源码仓库(Gitcode 上的 Ascend/pytorch)获取代码后编译 v2.5.1 分支。

编译装好后还有一个反直觉的步骤:打开 site-packages 下torch_npu/version.py(路径用pip show torch_npu确认),把形如__version__ = '2.5.1.post4+git69550dfc'的版本号改为__version__ = '2.5.1.post4'去掉哈希后缀。环境对版本号有严格匹配,带后缀会直接被拒。

合并 Q4 与 W8A8 双权重

KTransformers 对 NPU 路径的精度要求决定了权重要走"双份合并":Q4_K_M 的 GGUF 权重负责路由专家的 CPU 侧存储,W8A8 的 safetensor 权重负责 NPU 侧算子。两份原始权重都下载就位后,跑仓库里的合并脚本:

python merge_safetensor_gguf.py \ --safetensor_path /path/to/DeepSeek-R1-W8A8 \ --gguf_path /path/to/DeepSeek-R1-Q4_K_M \ --output_path /output/merged

脚本位于 merge_tensors/。合并完成后,后续启动参数只指向合并后的目录,两份原始权重不再参与推理。

初始化项目与编译扩展

克隆仓库并拉取子模块:

git clone https://gitcode.com/gh_mirrors/ktr/ktransformers cd ktransformers git submodule update --init --recursive

进入编译前,先安装构建依赖并加载 CANN 环境:

source /usr/local/Ascend/ascend-toolkit/set_env.sh apt install cmake libhwloc-dev pkg-config bash ./install.sh

install.sh 会编译 CPU 侧的 kt-kernel 扩展与 llamafile 算子库。⚠️ 在 aarch64(ARM82)上,如果链接阶段报iqk_mul_mat相关错误,把 third_party/llamafile/iqk_mul_mat_arm82.cpp 文件内的两行宏定义注释掉即可通过编译:

// #define iqk_mul_mat iqk_mul_mat_arm82 // #define iqk_mul_mat_moe iqk_mul_mat_moe_arm82

这是 aarch64 工具链的已知适配点,x86 机器不用动这个文件。

启动 balance_serve 推理服务

服务入口是ktransformers/server/main.py,关键参数与 NPU 优化规则文件一起给出:

export USE_MERGE=0 export INF_NAN_MODE_FORCE_DISABLE=1 export TASK_QUEUE_ENABLE=0 source /usr/local/Ascend/ascend-toolkit/set_env.sh source /usr/local/Ascend/nnal/atb/set_env.sh python ktransformers/server/main.py \ --port 10002 \ --model_path <merged_weights> \ --gguf_path <merged_weights> \ --model_name DeepSeekV3ForCausalLM \ --optimize_config_path ./ktransformers/optimize/optimize_rules/npu/DeepSeek-V3-Chat-300IA2-npu-serve.yaml \ --max_new_tokens 1024 \ --cache_lens 20480 \ --backend_type balance_serve

环境变量逐个说明(故障排查时只需对照这一段,速查表不重复):

  • TASK_QUEUE_ENABLE=0:关闭任务队列,保证算子下发顺序严格有序,这是开启图下沉的前置条件;
  • USE_BALANCE_SERVE=1USE_NUMA=1:启用 balance_serve 后端与 NUMA 绑定,启动脚本中按需导出;
  • USE_MERGE=0:权重已离线合并,运行时不再做在线合并;
  • INF_NAN_MODE_FORCE_DISABLE=1:禁用推理期的 NaN 强制检查,省去每步的开销;
  • --backend_type balance_serve:指定服务后端;--cache_lens 20480决定 KV cache 预分配长度,按上下文预算调整。

优化规则文件位于 ktransformers/optimize/optimize_rules/npu/,300I A2 上 DeepSeek-V3 的服务化配置即上面启动参数引用的DeepSeek-V3-Chat-300IA2-npu-serve.yaml,同目录还有非 serve 版与 Qwen3 的对应配置可选。

用基准数据验证 NPU 推理性能

服务起来后,用固定长度 prompt 压一遍 prefill 与 decode。以下为 Batchsize=4、输出长度 1024 条件下的参考值(tokens/s):

Prompt 长度1K2K4K
Prefill174.68169.52167.15
Decode16.0716.1216.48

实测与参考值偏差超过 20% 时,先查 NPU 侧算子是否真的走下去了(npu-smi看利用率),再查cache_lens是否被默认值截断。需要定位慢算子时,用PROF_PREFILLPROF_DECODE两个环境变量分别开启两阶段的 profiling 输出。

故障速查

现象处理
libhccl.so缺失见上文「配置 CANN 软件栈」:当前 shell 先source /usr/local/Ascend/ascend-toolkit/set_env.sh
libascend_hal.so缺失补驱动库路径:export LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64/driver:$LD_LIBRARY_PATH
aarch64 编译期iqk_mul_mat链接错误注释 third_party/llamafile/iqk_mul_mat_arm82.cpp 中两行宏定义(见「初始化项目与编译扩展」节)
torch_npu 导入即报错检查version.py是否仍带+git...哈希后缀
服务启动 OOM物理内存不足 400GB,满血版无法容纳路由专家权重

下一步建议:把--cache_lens按业务真实上下文长度调到位,再用PROF_PREFILL抓一次 prefill 分布——prefill 吞吐从 170 tokens/s 量级再往上走,瓶颈基本都在长序列的注意力段。

【免费下载链接】ktransformersA Flexible Framework for Experiencing Heterogeneous LLM Inference/Fine-tune Optimizations项目地址: https://gitcode.com/GitHub_Trending/ktr/ktransformers

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询