基于KTransformers在300I DUO单机部署满血版DeepSeek-R1的实践

部署运行你感兴趣的模型镜像

一、痛点和机遇

DeepSeek R1满血版(671B)模型在FP16精度下,权重大小达1.3TB,W8A8量化后的权重大小仍为700G+,300I DUO单机显存(384G)无法装载,若要加载FP16精度的模型权重至少需4台服务器。

然而若使用多台300I DUO的服务器采用多机分布式的部署方式,如下图所示,由于300I DUO无物理网卡,跨节点通信需绕路CPU,性能和带宽瓶颈导致通讯受阻,实测仅700MB/s的带宽。

因此,如何在单机有限的显存资源下部署并运行满血版的DeepSeek-R1大模型成为挑战和机遇。清华大学的KTransformers开源项目,基于单机4090(24G VRAM)运行DeepSeek-R1 满血版,单路推理速度达14tokens/s,该项目通过CPU Offload,将部分GPU运算转移到CPU和DRAM进行计算,实现CPU/GPU异构推理,用内存代替显存,用INT8/INT4量化减少内存资源需求,为我们提供了不错的借鉴思路。以下实践我们基于KTransformers在300I DUO单机加载满血版DeepSeek-R1权重(HBM+DRAM),实现CPU+NPU的混合推理。

二、环境准备

2.1 NPU驱动:24.1.RC3

2.2 CANN版本:8.1.RC1

2.3 KTransformers版本:0.2.1

2.4 模型权重

FP16类型的原始权重文件需要1.3TB,需提前申请和挂载数据盘或大磁盘,我们采用W8A8的方式将其量化,量化后的模型权重大小约为643G。由于开源KTransformers推理框架使用的模型权重为GGUF格式,所以首先需要在框架代码中扩展Safetensor格式模型权重的加载方式。

三、适配和编译

由于开源KTransformers对ARM架构的支持度不高,社区发布的Release版本中的whl包也只有X86架构的,且社区源码面向的是NVIDIA的CUDA生态,因此需要在我们的鲲鹏和昇腾硬件上进行额外的代码修改和适配,包括编译脚本中增加GCC的ARM编译选项、删除ARM不支持的cpufeature三方库、CPU算子的适配、移除CUDA相关的依赖、Torch替换为Torch_NPU等,最终成功在我们的服务器(KunPeng + 300I DUO)上编译并安装完成。

四、推理服务启动

4.1 模型配置

修改model_path对应路径下的config.json文件配置(以下配置仅供参考):

{
  "architectures": [
    "DeepseekV3ForCausalLM"
  ],
  "first_k_dense_replace": 3,
  "hidden_act": "silu",
  "hidden_size": 7168,
  "intermediate_size": 18432,
  "kv_lora_rank": 512,
  "model_type": "deepseek_v3",
  "moe_intermediate_size": 2048,
  "moe_layer_freq": 1,
  "n_group": 8,
  "n_routed_experts": 256,
  "n_shared_experts": 1,
  "norm_topk_prob": true,
  "num_attention_heads": 128,
  "num_experts_per_tok": 8,
  "num_hidden_layers": 61,
  "num_key_value_heads": 128,
  "num_nextn_predict_layers": 1,
  "q_lora_rank": 1536,
  "qk_nope_head_dim": 128,
  "qk_rope_head_dim": 64,
  "scoring_func": "sigmoid",
  "topk_group": 4,
  "topk_method": "noaux_tc",
  "torch_dtype": "float16",
  "transformers_version": "4.46.3",
  "use_cache": true,
  "v_head_dim": 128,
  "vocab_size": 129280,
  "...": ...
}

4.2 推理框架配置

KTransformers 最主要的设计目标是实现一套易用的基于模板规则的注入框架,允许开发人员很方便得用优化后的变体替换原始的Torch模块,我们修改optimize_rule_path对应目录下的注入规则配置(仅供参考):

- match:
    class: ktransformers.models.modeling_deepseek_v3.DeepseekV3RotaryEmbedding
  replace:
    class: ktransformers.operators.RoPE.YarnRotaryEmbeddingV3
    kwargs:
      generate_device: "npu"
      prefill_device: "npu"
- match:
    name: "^model\\.layers\\.(?!.*self_attn\\.kv_b_proj).*$"  # regular expression
    class: torch.nn.Linear  # only match modules matching name and class simultaneously
  replace:
    class: ktransformers.operators.linear.KTransformersLinear  # optimized Kernel on quantized data types
    kwargs:
      generate_device: "npu"
      prefill_device: "npu"
      generate_op: "KLinearTorch"
      prefill_op: "KLinearTorch"
- match:
    name: "^model\\.layers\\..*\\.mlp$"
    class: ktransformers.models.modeling_deepseek_v3.DeepseekV3MoE
  replace:
    class: ktransformers.operators.experts.KDeepseekV3MoE     # mlp module with custom forward function
    kwargs:
      generate_device: "npu"
      prefill_device: "npu"
- match:
    class: ktransformers.models.modeling_deepseek_v3.MoEGate
  replace:
    class: ktransformers.operators.gate.KMoEGate
    kwargs:
      generate_device: "npu:0"
      prefill_device: "npu:0"
- match:
    name: "^model\\.layers\\..*\\.mlp\\.experts$"
  replace:
    class: ktransformers.operators.experts.KTransformersExperts     # custom MoE Kernel with expert paralleism
    kwargs:
      prefill_device: "cpu"
      prefill_op: "KExpertsCPU"
      generate_device: "cpu"
      generate_op: "KExpertsCPU"
      out_device: "npu"
  recursive: False # don't recursively inject submodules of this module
- match:
    name: "^model\\.layers\\..*\\.self_attn$"
  replace:
    class: ktransformers.operators.attention.KDeepseekV2Attention # optimized MLA implementation
    kwargs:
      generate_device: "npu"
      prefill_device: "npu"
- match:
    name: "^model$"
  replace:
    class: "ktransformers.operators.models.KDeepseekV2Model"
    kwargs:
      per_layer_prefill_intput_threshold: 0 # 0 is close layer wise prefill
- match:
    name: "^model.embed_tokens"
  replace:
    class: "default"
    kwargs:
      generate_device: "cpu"
      prefill_device: "cpu"

4.3 启动推理服务

设置CANN的环境变量,并启动KTransformers推理服务:

source /usr/local/Ascend/ascend-toolkit/set_env.sh
python -m ktransformers.local_chat --model_path xxx --gguf_path xxx  --optimize_rule_path xxx --max_new_tokens xxx --cpu_infer xxx

4.4 推理服务验证

以local chat的模式启动KTransformers,权重加载完成后,在终端会出现交互式的Chat界面,下图是推理请求的验证结果:

五、性能调优

在300I DUO单机上完成满血版DeepSeek的部署与启动之后,初始验证时在256输入和256输出,单并发的情况下,推理吞吐量只有0.1 tokens/s,该性能指标基本处于不可用的状态。为了进一步提升单机300I DUO上满血版DeepSeek-R1的推理性能,我们采取了一系列的性能优化手段,下面进行简单的方向性介绍。

5.1 CPU算子加速

KTransformers采用了高效的内核级优化技术,对模型中的关键操作进行优化,例如通过Intel AMX指令集优化以及引入cpufeature三方依赖,能实现更快的推理速度,但英特尔目前是唯一支持AMX 类似指令的CPU 供应商,且cpufeature仅支持X86架构,因此迫切需要在鲲鹏上实现CPU算子的加速。

我们对KTransformers中的llamafile算子进行了ARM上的扩展,基于鲲鹏的SVE指令集对GEMV(矩阵向量乘)以及GEMM(通用矩阵乘)实现了优化,配合鲲鹏CPU的多核优势使得卸载到CPU的MoE路由专家的计算速度较之前提升了50%+。

5.2 并行优化

KTransformers开源社区当前并未实现分布式并行策略,因此前文中提及的0.1 tokens/s的推理性能也是单芯上的测试结果。为了充分发挥我们服务器上4 * 300I DUO的算力,我们实现了张量并行(Tensor Parallelism, TP)的策略,在权重加载过程中根据TP_SIZE将权重切分到不同的Device,中间的计算结果通过torch.distributed的all_reduce、all_gather等集合通信算子进行规约或聚合,我们通过4卡8芯完成8TP的切分,推理的吞吐量也较之前有了较大幅度的提升。

5.3 算子下发优化

我们采用PyTorch Profiling接口对当前的性能瓶颈进行了采样和分析,通过MindStdio Insight可视化结果如下图所示:

从采样结果看,Host侧和Device侧执行算子之间的连线为竖线,表示下发即计算,且Device为Computing状态的周期占比极低,Device空转周期长,这是非常典型的Host Bound现象,Host侧算子下发速度慢,其在模型单层的运行过程中耗时占比高。由于KTransformers中算子的调度和执行采用的是单算子模式,因此,我们采取了以下方式进行了算子下发时长的优化:

  • 基于毕昇编译器LTO和PGO反馈编译、大页内存等技术,降低Cache Miss,提升Torch+TorchNPU的性能
  • 根据算子任务的处理器亲和性,识别核心任务线程绑定在NUMA节点的固定CPU核心,减少核间切换的开销
  • 使能task_queue算子下发队列优化,将算子下发任务分为两段,一部分任务放在新增的二级流水上,一、二级流水通过算子队列传递任务,相互并行,通过部分掩盖减少整体的下发耗时,提升端到端性能
  • Pytorch和Torch_NPU的热点模块改造以及热点函数优化

5.4 融合算子

从5.3的采样结果看,除了Host Bound现象严重,另外的一个问题就是小算子众多,推理过程中算子下发的整个流程时延消耗高,因此我们通过将多个小算子功能融合,例如用torch_npu.npu_rms_norm算子来替换KTransformers中DeepseekV3RMSNorm的forward逻辑,当然,更多的融合算子我们正在尝试对接。

5.5 Overlapping

DeepSeek的模型结构如下图所示:

从DeepSeek的模型计算的拓扑流程中可以看出,部分节点相互之间不存在依赖关系,因此可以并发执行来优化推理时延。比如图右上角部分的DeepSeekMoE中,路由专家被卸载到CPU上进行计算,而共享专家MLP是在NPU上进行计算,两者所在的硬件计算资源不同,因此可以通过并行执行来实现计算时延的掩盖,将总体的时延从X+Y降低到Min(X, Y)。

5.6 硬件亲和性优化

鲲鹏的CPU采用NUMA(非统一内存访问)架构,CPU访问不同的内存节点时间差异很大,内存访问时延:跨片 > 跨NUMA节点 > 相同NUMA节点内,因此在业务层面上会表现为明显的性能差异。由于MoE的路由专家我们卸载到了CPU上进行计算,为了充分利用NUMA系统,避免跨NUMA访存带来的时延,我们编译KTransformers时指定USE_NUMA=1启用数据并行, 整个模型权重复制到内存中两次,即分别存入两个NUMA节点,当然这也会带来两倍的内存开销。

另外,除了CPU的NUMA亲和性外,CPU和NPU之间也存在亲和性关系,例如在我们的服务器上可以通过执行以下命令来查询设备CPU和NPU的亲和性关系、多NPU之间的拓扑结构。

npu-smi info -t topo

查询到的拓扑结构如下图所示,由于CPU卸载的缘故,需要进行Device侧和Host侧的数据拷贝,我们通过绑核操作,将所有任务绑定在NPU对应NUMA的CPU核心上,避免Device侧和Host侧跨NUMA 节点的内存访问,来提升推理性能。

5.7 性能优化结果

通过上述各项推理性能优化手段,在256输入和256输出,单并发的情况下,推理吞吐量优化到14.5 tokens/s,如下图所示:

六、总结和下一步计划

通过对KTransformers的代码在鲲鹏和昇腾硬件上进行适配,我们在300I DUO单机(384G显存+1T内存)上成功部署并运行满血版DeepSeek-R1,并通过一系列的推理性能调优手段,将单路并发的推理吞吐量从最初的0.1 tokens/s提升到14.5 tokens/s,提升了100+倍。KTransformers开源社区最新发布的0.2.4版本已支持多路并发,后续我们将引入多路并发的能力并持续提升推理性能,包括但不限于:

  • MLA阶段算子融合或算子优化,降低Device侧计算时延
  • ......

您可能感兴趣的与本文相关的镜像

Wan2.2-T2V-A5B

Wan2.2-T2V-A5B

文生视频
Wan2.2

Wan2.2是由通义万相开源高效文本到视频生成模型,是有​50亿参数的轻量级视频生成模型,专为快速内容创作优化。支持480P视频生成,具备优秀的时序连贯性和运动推理能力

<think>好的,我现在需要帮助用户了解如何使用鲲鹏服务器和昇腾卡(Atlas 300I Pro)搭建DeepSeek-R1模型环境。首先,我需要回顾用户提供的引用内容,看看有没有相关的步骤或配置信息。 根据引用[3],提到了镜像准备的步骤,包括加载特定本的镜像和使用docker命令确认镜像名称和标签。这可能涉及到Docker环境的基础配置。另外,引用[2]提到了昇腾卡的型号和服务器类型,但具体的安装步骤可能还需要更多细节。 用户的需求是搭建部署环境,所以需要分步骤指导。首先,硬件准备部分,需要确认服务器和昇腾卡的兼容性,以及驱动安装。然后,软件环境方面,安装CANN工具包和MindSpore框架是必要的,因为这些是昇腾卡支持深度学习的关键组件。 接下来是镜像准备,引用[3]中的镜像名称和加载命令可以直接引用。之后,容器启动时需要挂载昇腾卡的设备文件,这样才能在容器内使用加速卡。下载模型后,可能需要配置相关的参数文件,特别是device_target设置为'Ascend',确保模型在昇腾卡上运行。 在验证环节,运行示例代码或推理脚本时需要注意环境变量,如ASCEND_VISIBLE_DEVICES指定使用的卡号。可能还需要安装额外的依赖库,比如transformers和accelerate,这些需要包含在Dockerfile或启动脚本中。 用户可能还会遇到驱动本不匹配、容器权限问题或者模型配置错误,这些都需要在注意事项中提到。例如,昇腾卡的驱动本与CANN工具包兼容性,以及挂载设备时的权限设置。 最后,生成相关问题需要考虑用户后续可能的需求,比如性能优化、多卡训练和模型蒸馏技术,这些都是搭建环境后可能遇到的进阶问题。需要确保问题覆盖常见的使用场景和潜在挑战,帮助用户进一步探索。</think>以下是如何使用鲲鹏服务器与昇腾卡(Atlas 300I Pro)搭建DeepSeek-R1-Distill-Qwen-7B模型环境的详细指南: ### 一、硬件环境准备 1. **服务器配置** - 选择鲲鹏920系列服务器(如Taishan 2280 V2),要求支持PCIe 4.0接口 - 安装昇腾Atlas 300I Pro加速卡,建议单卡显存≥32GB[^2] 2. **驱动安装** ```bash # 安装昇腾驱动包 sudo ./Ascend-hdk-310p-npu-driver_23.0.0_linux-aarch64.run --full # 验证驱动状态 npu-smi info ``` ### 二、软件环境搭建 1. **基础依赖安装** ```bash # 安装CANN工具包(本≥6.3.RC2) sudo ./Ascend-cann-toolkit_6.3.RC2_linux-aarch64.run --install # 配置环境变量 source /usr/local/Ascend/ascend-toolkit/set_env.sh ``` 2. **容器化部署** 使用官方提供的MindIE镜像[^3]: ```bash docker load -i mindie:1.0.0-300I-Duo-py311-openeuler24.03-lts docker run -it --name deepseek \ --device=/dev/davinci0 \ --device=/dev/davinci_manager \ -v /usr/local/Ascend/driver:/usr/local/Ascend/driver \ mindie:1.0.0-300I-Duo-py311-openeuler24.03-lts ``` ### 三、模型部署流程 1. **下载模型资源** ```bash git clone https://github.com/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B ``` 2. **配置模型参数** 修改`config.json`: ```json { "device_target": "Ascend", "precision_mode": "fp16", "graph_opts": {"hcom_parallel": "1"} } ``` 3. **启动推理服务** ```bash python infer.py \ --device_id 0 \ --model_path ./DeepSeek-R1-Distill-Qwen-7B \ --use_ascend True \ --batch_size 8 ``` ### 四、验证部署效果 ```python from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("deepseek-ai/DeepSeek-R1-Distill-Qwen-7B") model = AutoModelForCausalLM.from_pretrained("deepseek-ai/DeepSeek-R1-Distill-Qwen-7B", device_map="ascend:0") inputs = tokenizer("北京的名胜古迹有", return_tensors="pt").to("ascend:0") outputs = model.generate(**inputs, max_new_tokens=100) print(tokenizer.decode(outputs[0])) ``` ### 注意事项 1. 需确保昇腾驱动本与CANN工具包本严格匹配[^2] 2. 容器运行时必须挂载`/dev/davinci*`设备节点 3. 模型推理时建议设置环境变量: ```bash export ASCEND_VISIBLE_DEVICES=0 export TASK_QUEUE_ENABLE=1 ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值