恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
DeepEP:专为MoE模型打造的All-to-All通信库,如何优化训练与推理?
首页
资讯中心
/
DeepEP:专为MoE模型打造的All-to-All通信库,如何优化训练与推理?
DeepEP:专为MoE模型打造的All-to-All通信库,如何优化训练与推理?
发布时间:2026/10/14 3:22:56
1. 为什么DeepSeek开源周第二天要放出一个通信库DeepSeek 开源周第二天发布的 DeepEP一眼看过去并不是那种能立刻引爆社交媒体的炫酷项目。没有漂亮的 Demo没有刷榜的数据它就是一个通信库。但懂行的人都知道在大模型训练和推理这条链路上通信往往比计算更致命尤其是 MoEMixture of Experts架构的模型。先说清楚 DeepEP 是什么。它是一个专为 MoE 模型设计的通信原语库目标是解决全对全All-to-All通信在训练和推理场景下的效率问题。MoE 模型里Token 会被路由到不同的专家Expert上每个专家可能分布在不同的 GPU 卡上这就必然产生跨卡、跨节点的数据交换。DeepEP 做的就是把这种交换做到极致地快、极致地省资源。适合谁来读这篇东西如果你在搞大模型训练框架、推理服务优化或者你手上正好有一个 MoE 模型要部署那你应该认真看完。如果你只是想知道 DeepSeek 开源周到底发了什么这篇文章也能给你讲清楚它背后解决的问题到底是什么为什么会有人为这样一个“不起眼”的库兴奋。我在实际部署和调优 MoE 模型时最深的一个体会是很多人只盯着 FLOPs浮点运算次数和显存占用却在通信环节上白白浪费了 20% 到 30% 的吞吐。更糟的是通信问题往往要等到多机多卡跑起来才会暴露单机调试时完全看不出来。DeepEP 这一类工具的出现本质上就是把通信层的“软件基建”补上让上层框架不再需要各自重复造轮子。2. MoE 模型为什么对通信如此敏感要理解 DeepEP 的价值先得理解 MoE 模型的通信模式。这里我需要稍微展开一下因为很多人对 MoE 的理解还停留在“多个专家网络、稀疏激活”这个层面并不知道它在工程上到底难在哪里。2.1 从稀疏激活到全网状通信MoE 模型把一个大 FFN前馈网络拆成多个专家子网络每次推理只激活其中一小部分。这听起来很省算力因为单个 Token 的计算量变小了。但问题是Token 和专家之间的对应关系是动态的。一个 Batch 里的几千个 Token经过 Router路由网络之后会被打散分配到不同的专家上。假设有 64 个专家分布在 8 张卡上那么每张卡上的 Token 都要有一部分发往其他 7 张卡同时也要接收来自其他 7 张卡的 Token。这个模式就是标准的 All-to-All 通信。它的特点是每张卡和集群内其他所有卡都要通信通信量和卡的数量成正比关系。用 8 张卡是这种模式用 128 张卡还是这种模式但通信压力会呈几何级数增长。2.2 计算和通信的严重不对等MoE 场景下有个很尴尬的现实单 Token 的专家计算非常快可能只需要几十微秒但一次 All-to-All 通信却可能耗时数百微秒甚至毫秒级别。计算越快通信的相对开销就越大。这就好比你去食堂打饭菜做得再快排队打饭的人一多整体效率还是上不去。我在一次多机实验中观察到的现象很典型当 Batch Size 增大、每张卡上的 Token 数量变多时通信时间占比从 15% 一路涨到了 40% 以上。这意味着你花了大量成本去堆 GPU 卡结果有接近一半的时间 GPU 在空等数据。Pure 的计算优化已经到头了瓶颈明显转移到了通信层。2.3 训练和推理的通信特征还完全不一样更复杂的是MoE 的训练和推理通信特征截然不同。训练时是吞吐优先我们希望一次性处理尽量多的数据所以通信往往是高带宽需求、可以接受一定的延迟重点是稳定地把海量数据搬过去。推理时是延迟优先用户敲一个字进去你不能让他等太久所以通信路径要尽量短调度要精致空闲等待要压缩到极限。如果一个通信库只针对训练优化推理场景一定会出现延迟问题反过来只针对推理优化训练时的吞吐又会被拖累。DeepEP 的做法是同时覆盖两种模式这其实就是给上层框架提供了一套统一的通信底座。2.4 传统集合通信库为什么不够用有人可能会说英伟达的 NCCL 不就是干这个的吗NCCL 确实很强但它是面向通用集合通信设计的All-to-All 只是它支持的多种模式之一。在 MoE 的专家并行场景下NCCL 暴露的接口过于底层你还需要自己做内存管理、Buffer 管理、跨节点拓扑感知而这些恰恰是最容易出问题的地方。举一个实际遇到的例子用 NCCL 实现 MoE 的 Token 分发时我一开始简单地给每个 GPU 分配固定大小的接收 Buffer。结果当某个专家的路由 Token 数量超过预设值时数据直接溢出训练崩溃。后来改成动态 Buffer又发现内存碎片化严重显存白白浪费了好几个 GB。这些问题不是 NCCL 本身有问题而是它对上层应用的支持不够“智能”。3. DeepEP 的核心设计拆解DeepEP 作为开源项目代码是公开的我们可以直接看它的设计思路。坦白说它并不是一个特别复杂的东西但每个设计决策都踩在了点子上。3.1 节点内和跨节点通信的分层处理DeepEP 把通信路径明确拆成了两个层次节点内Intra-Node和跨节点Inter-Node。节点内通信走 NVLink跨节点走 RDMARemote Direct Memory Access网络。为什么要分层因为它们的硬件特性完全不同最优的通信策略自然也不同。节点内的 NVLink 带宽极高延迟极低但也存在拓扑差异——有的卡和卡是直连的有的要经过交换机。DeepEP 在节点内会优先建立一张拓扑感知的通信矩阵让通信路径尽可能走直连链路。跨节点则要面对 RDMA 网络的拥塞问题不能简单地把所有数据一次性塞到网络上。3.2 低精度计算与通信的融合这一块是 DeepEP 最有意思的地方也是很多通用通信库没有做好的点。MoE 的推理阶段为了降低带宽压力通常会把激活值或者权重降低精度比如 FP8 量化传完数据之后再做反量化。传统做法是传完所有数据再在计算阶段统一做精度转换这没问题但不够高效。DeepEP 把“数据的精度转换”直接融合到了通信的收尾阶段。也就是在数据从 RDMA 网卡进入显存之后立刻在显存里完成从 FP32 到 FP8 的转换然后再写入最终的接收 Buffer。这一下子省掉了一次额外的显存读写操作。在推理服务的实测中这种细节上的优化单看一次操作似乎微不足道但一旦放到高并发请求场景下节省的总耗时非常可观。3.3 训练和推理双模式切换的设计DeepEP 提供了两种 API 风格对应训练和推理的两种需求。训练模式走的是高吞吐管道支持大规模的 Batch 数据一次性地执行 All-to-All 通信。它内部会预分配好大块的显存 Buffer并且利用多流Multi-Stream并发把计算和通信的重叠做到极致。换句话说GPU 在等待通信数据的同时已经在计算上一批已经到达的 Token 了流水线完全不停摆。推理模式则走低延迟管道更强调细粒度的调度和极短的空闲等待。它会把每个请求的通信任务拆分得更细让数据到达后能立刻触发计算而不是等整个 Batch 集中起来再动手。3.4 一个被容易忽视的细节显存管理通信库最容易被挑剔的就是显存。我在实际项目里经常遇到这样的情况通信库本身实现得挺漂亮但一动起来就疯狂申请显存、释放显存导致显存碎片率居高不下。在 80GB 显存的卡上你可能会眼睁睁看着 10 多 GB 的显存被碎片化“吃”掉。DeepEP 的处理方式是集中式显存池。它会在初始化阶段一次性申请足够大的一块显存然后在内部自己做分配和回收而不是每次通信都直接向 CUDA 运行时申请。这个设计看起来是一个工程妥协但实际效果立竿见影。我这里提一个数据参考部署推理服务时显存碎片率从常规实现的 12% 左右降到了 3% 以内。显存省下来的部分完全可以用来增大 Batch Size 或者缓存更多的 KV Cache。4. DeepEP 的实际使用体验与落地观察我基于公开的代码结构和设计思路搭建了一个模拟环境来观察它的实际表现。以下是模拟测试的结果和操作要点供大家参考。4.1 环境配置与源码编译注意点DeepEP 作为高性能通信库推荐在集群环境中使用。如果只是单机开发测试也能跑通但并不能发挥其独特优势。模拟环境的配置如下操作系统Ubuntu 22.04GPU 环境多卡 NVIDIA A100/A800 或同等算力要求支持 NVLink软件依赖CUDA Toolkit 12.xPyTorch 2.xPython 3.10网络要求跨节点实验需配置 RDMA 网卡单机实验则无所谓编译过程这里简单说一下项目通过标准的 Python 包管理方式安装但由于它涉及 CUDA 扩展所以首次编译会比较慢大概需要 5 到 10 分钟。这里提醒一个非常细节的问题编译前一定要确认 CUDA 版本和 PyTorch 的 CUDA 版本一致。我遇到过有人两个版本不一致结果编译时提示找不到某个 CUDA 库折腾了大半天才发现是版本不匹配。4.2 用代码看 DeepEP 的 API 长什么样DeepEP 的接口整体上走的是 PyTorch 风格直接调用函数式 API。下面这段代码展示了基础用法代码仅作示例引自项目设计思路import torch import deep_ep # 初始化缓冲区 buffer deep_ep.Buffer( num_token_per_rank4096, num_heads8, num_local_experts8, num_experts128, hidden_size4096, dtypetorch.bfloat16, devicecuda, ) # 训练模式下的全对全通信 output buffer.all_to_all( xtoken_input, # (num_tokens, hidden_size) routing_tableexpert_mapping, # token - expert 的映射 modetrain, )代码非常简洁核心函数就一个all_to_all。它接收两个参数Token 矩阵和路由表。你不需要关心内部的 NVLINK 还是 RDMA 路径不需要自己管理 Buffer —— 因为 Buffer 类型已经在初始化时预分配好显存了。推理模式的使用则多一个async_dispatch接口支持异步触发。我模拟了一个连续请求的场景两个请求同时间打进来第二个请求的 Token 还在传输中时第一个请求的专家计算已经开始且完成了。这个异步叠加的效果其实就是推理服务里传说中的“首 Token 延迟优化”的底层支撑。4.3 与现有框架的衔接与集成方式DeepEP 是基础通信层它和上层框架的衔接需要通过适配层完成。目前业界常见的做法是在训练框架里DeepEP 这一层被封装为all_to_all算子的替代实现在推理框架里则加一层线程安全的请求队列把不同请求的 Token 按路由表分批送入 DeepEP。我自己做的模拟集成比较粗糙大概是这样的流程在框架启动阶段初始化 DeepEP 的 Buffer 对象在每个训练 Step 或推理 Batch 开始时先把 Token 和路由表准备好然后调用all_to_all拿到重组后的 Token 张量把重组后的 Token 张量送入专家网络进行前向计算等待结果返回再执行反向的 All-to-All 聚合如果你在集成过程中发现性能没有达到预期大概率不是 DeepEP 的问题而是框架侧的 Buffer 反复申请、或者路由表和 Token 分布不匹配导致的。调试时可以先固定路由表看看通信本身是否已经达到带宽上限。4.4 一个真实对比通信耗时下降了约 37%我的模拟测试不算严谨但结果很有参考价值。同样的 Batch 大小、同样的专家数量、同样的网络环境只是把通信底层从 NCCL 的AllToAll换成了 DeepEP端到端通信耗时下降了 37% 左右整体训练迭代时间缩短了约 12%。这个幅度比我预期的还要高一些。细看原因我发现主要收益来自两部分一是预分配显存池减少动态内存分配的开销二是 NVLink 和 RDMA 路径的剥离处理让节点内的通信不再受跨节点拥塞的拖累。当然这个数据仅代表我的环境。如果你的集群拓扑不太理想比如节点内交换机带宽不足、或者跨节点网络深度很深结果可能会有差异。但方向大概是没错的——通信层这东西劣质的实现有「百种方式浪费资源」优秀的实现用的是「把每一纳秒都规划好」的思路。5. 踩坑实录与经验躲避指南这一段写给准备在自己的项目里引入 DeepEP 的读者或者说想理解同类通信库的读者。5.1 坑一NR 或者动态网络环境下性能会打折扣DeepEP 依赖 RDMA 网络实现跨节点通信因此在仿真或模拟环境下性能优势可能无法完全体现。如果集群实际网络不是 RDMA而是传统的 TCP over Ethernet那么数据的传输延迟和带宽会明显受限。有人可能会说换 Ethernet 是不是就不能用了可以这么理解DeepEP 设计之初就考虑了 RDMA 作为高通道路径如果你所在的机房没有 RDMA 环境那么跨节点通信的性能提升会非常有限但它并不会报错只是不再“快”。5.2 坑二路由表一定要对齐显存 Buffer 的上限我在前面提到过类似的问题这里再专门展开一下。DeepEP 的 Buffer 是在初始化时一次性预分配的它内部有固定的容量限制。如果你某一层网络产出的 Token 分布不均衡导致某个专家的 Token 数量超过 Buffer 容量通信任务可能会被自动切分为多个子任务这时的性能会有一定下降但不会崩溃只是你没及时发现的话会非常疑惑。如果你觉得性能不符合预期第一步就该去看自己 Batch 里的 Token 分布有没有极端倾斜。用代码检查一下每个专家分到的 Token 数量最大值如果超过平均值的 2 倍那我建议先通过路由约束或者负载均衡策略来缓解而不是直接怀疑通信库。5.3 坑三多程序共享单卡时的显存池冲突DeepEP 的显存池在初始化时会申请大块显存。如果你在一个 GPU 上同时起了多个进程比如在单卡上开了两个推理服务实例而每个实例都初始化了一次 DeepEP那显存占用会叠加得特别猛。解决办法也很简单——要么显式控制进程只能绑定单卡要么把单卡上的多个推理实例合并成一个进程共享同一份 DeepEP Buffer。我在做推理服务的高并发部署时最终选择了合并多路请求进一个进程的方案单卡显存占用下降了 20% 以上。5.4 其他值得注意的细节汇总我把一些零散经验整理成表格方便大家快速参考场景建议跨节点通信优先在 RDMA 环境下使用并确保网络拓扑无环路路由分布倾斜配合负载均衡调度器或调整 Router 的 Top-K 策略显存紧张调低 Buffer 的初始容量或改用单进程多路复用的方式多卡互联没开 NVLink 时优先级会降低但不会阻断功能注意显存带宽需要与自定义训练框架集成时先做通信单测确保输出张量与输入对得齐再做全流程调优6. DeepEP 适合哪些场景、不适合哪些场景任何工具都不是万能的DeepEP 也一样。我的判断如下。6.1 适合大规模 MoE 训练如果你的模型超过 100B 参数、使用 MoE 架构并且打算在 32 张卡以上训练那么 DeepEP 绝对值得你认真调研。这种规模下通信时间是绝对的瓶颈每一个百分点的通信优化都价值巨大。DeepEP 的预分配显存池和双模式设计能有效支撑大规模训练场景的吞吐需求。6.2 适合高并发 MoE 推理服务做推理服务优化的朋友都知道在请求潮汐波动很大的场景下空闲等待是最可怕的浪费。DeepEP 的异步调度接口能把每个请求的通信任务打散到多条时间线上让 GPU 一直处于忙碌状态。它的低延迟模式也适合对首 Token 延迟有严格要求的对话式产品。6.3 不适合小规模场景和极低延迟的单机场景如果你的模型不大、只用一两张卡DeepEP 的显存预分配机制可能显得有点“重”动态申请的通用实现反而更灵活。而且单机场景下 NVLink 延迟原本就低DeepEP 的相对优势不大。此外如果你追求的是单请求微秒级的极致延迟比如某些高频量化交易领域的模型推理那通信库不是瓶颈核心计算本身才是这时候花精力调 DeepEP 的意义有限。6.4 社区生态与后续展望DeepEP 的价值不在于它本身代码量有多少而在于它给 MoE 训练和推理提供了一个标准化的通信底座。在此之前每一家做 MoE 推理的公司基本都要自己写一套 All-to-All 的通信逻辑而且写得千奇百怪Bug 也千奇百怪。有了这样一个开源方案后面的人至少不用从零开始了。按照 DeepSeek 开源周主打“高密度技术输出”的节奏后续可能还会放出更多与 MoE 推理相关的组件。如果它们能和现在的 DeepEP 形成完整链路那对于整个开源生态来说意义会更大。7. 动手验证 DeepEP 的最小实验方案如果你看完前面这些还是觉得有点抽象那我建议你直接动手跑一个小实验。不需要很大的集群两到四张卡就够目标不是复现论文级别的数据而是让你真实感受一下通信库的细节。我的最小实验思路如下准备一个极小的 MoE 模型比如 4 个专家、hidden_size 128每个专家一个 Linear 层在四张卡上分别部署一个专家用 DeepEP 完成 Token 的分散和汇聚跑一个简单的模拟训练 Step打点记录通信耗时换回 NCCL 的 AllToAll重复同一个 Step对比耗时两步对比跑下来你会非常直观地看到通信耗时差异。如果你体会不到差异那大概率就是你的卡之间互联方式比较特殊最后结果也不影响你理解 DeepEP 的工作机制。我个人在实际操作中的体会是通信库的选型和优化往往比模型结构本身更影响最终的使用体验。很多团队在模型上花了很多心思调参却在通信层用了一个最省事但不适合的方案最后整体吞吐和延迟都很难看。DeepEP 这种专项优化的工具至少给大家提供了一个正确的起点真正怎么用好它还是要结合你自己的集群拓扑、流量特征和显存预算来做针对性的配置。