专家并行负载均衡器 (EPLB)¶
为什么需要 EPLB?¶
在使用专家并行(EP)时,不同的专家被分配到不同的 NPU 上。由于不同专家的负载可能随当前工作负载而变化,因此保持各 NPU 之间的负载均衡至关重要。我们采用冗余专家策略,通过复制高负载专家,然后启发式地将这些复制的专家打包到 NPU 上,以确保它们之间的负载均衡。此外,得益于 MoE 模型中使用的组限制专家路由,我们还会尽可能将同一组的专家放置在同一节点上,以减少跨节点数据传输。
为便于复现和部署,vLLM Ascend 在 vllm_ascend/eplb/core/policy 中支持已部署的 EP 负载均衡算法。该算法根据预估的专家负载计算平衡的专家复制和放置方案。请注意,预测专家负载的具体方法不在本仓库范围内。一种常见的方法是使用历史统计数据的移动平均值。

如何使用 EPLB?¶
请参考用户指南中的 EPLB 部分以获取详细信息:如何使用 EPLB
工作原理?¶
EPLB 模块架构
vllm_ascend
├── eplb
│ ├── adaptor
│ │ └── vllm_adaptor.py
│ ├── core
│ │ ├── policy
│ │ │ ├── policy_abstract.py
│ │ │ ├── policy_default_eplb.py
│ │ │ ├── policy_factory.py
│ │ │ ├── policy_flashlb.py
│ │ │ ├── policy_random.py
│ │ │ └── policy_swift_balancer.py
│ │ ├── eplb_device_transfer_loader.py
│ │ ├── eplb_utils.py
│ │ └── eplb_worker.py
│ ├── eplb_updator.py
│ └── utils.py
└───────────
1. 适配器模块
处理不同 MoE 模型类型的注册与适配
vllm_adaptor.py
支持 Qwen3-MoE 和 DeepSeek 模型的实现,标准化策略算法的参数处理
2. 核心模块
实现核心算法、更新及异步处理
-
策略子模块
采用工厂模式实例化的负载均衡算法policy_abstract.py
负载均衡策略接口的抽象类policy_default_eplb.py
开源 EPLB 论文算法的默认实现policy_swift_balancer.py
针对低带宽设备(如 A2)优化专家交换的增强版本policy_flashlb.py
基于阈值的调整,通过逐层波动检测降低操作成本policy_random.py
用于基础测试的随机策略policy_factory.py
用于自动实例化算法的策略工厂
-
eplb_device_transfer_loader.py
管理专家表/权重的传输与更新 eplb_utils.py
专家表初始化与映射的工具函数eplb_worker.py
异步算法编排与结果处理
3. 系统组件
eplb_updator.py
推理工作流中负载均衡的中央协调器utils.py
EPLB 接口注册的通用工具函数
关键优化:
- 保持原有结构的同时提升技术清晰度
- 标准化术语
- 通过简洁描述增强算法区分度
- 通过分层呈现改善范围界定
- 在优化可读性的同时保留文件/类关系
默认算法¶
分层负载均衡¶
当服务器节点数能整除专家组数时,我们使用分层负载均衡策略来利用组限制专家路由。首先将专家组均匀打包到各节点上,确保不同节点间的负载均衡。然后在每个节点内复制专家。最后将复制的专家打包到各个 NPU 上,确保它们之间的负载均衡。分层负载均衡策略可用于预填充阶段,此时使用较小的专家并行度。
全局负载均衡¶
在其他情况下,我们使用全局负载均衡策略,该策略不考虑专家组,全局复制专家,并将复制的专家打包到各个 NPU 上。此策略可用于解码阶段,此时使用较大的专家并行度。
添加新的 EPLB 策略¶
如果你想向 vllm_ascend 添加新的 eplb 策略,必须遵循以下步骤:
-
继承
EplbPolicy中的policy_abstract.py抽象类,并重写rebalance_experts接口,确保输入参数current_expert_table、expert_workload和返回类型newplacement保持一致。 例如:class RandomLoadBalance(EplbPolicy): def rebalance_experts(self, current_expert_table, expert_workload): new_table = copy.deepcopy(current_expert_table) num_layers = len(current_expert_table) for i in range(num_layers): # randomly choose two card # indices = random.sample(range(num_card), 2) indices = [3, 1] # swap redundant experts expert_id_to_exchange = new_table[i][indices[0]][-1].clone() new_table[i][indices[0]][-1] = new_table[i][indices[1]][-1] new_table[i][indices[1]][-1] = expert_id_to_exchange return 1, [-i for i in range(num_layers)], new_table -
要添加新的 EPLB 算法,请在
PolicyFactory的policy_factory.py中包含策略类型及其对应的实现类。
添加新的 MoE 模型¶
模型集成实现指南
- 适配器文件修改
- 继承或修改
vllm_ascend/eplb/adaptor/vllm_adaptor.py - 添加关键参数的处理逻辑:
num_dense_layersglobal_expert_numnum_roe_layers
-
确保在
model_register函数中同步参数。例如:
修改
__init__的vllm_adaptor.py以添加新的 moe 模型 eplb 参数:if self.model.config.model_type == "qwen3_moe": self.num_dense_layers = 0 self.global_expert_num = self.model.config.num_experts修改
model_register的vllm_adaptor.py以注册新 moe 模型的 eplb 参数: -
MoE 特性集成
- 使用 MoE 特定方法扩展
vllm_ascend/eplb/utils.py -
实现专家路由或权重管理所需的功能
-
注册逻辑更新
- 在
model_register函数中添加补丁逻辑 -
保持与现有模型类型的向后兼容性
-
验证与测试
- 验证各层之间的参数一致性
- 测试专家表的跨设备通信
- 与基线实现(例如 Qwen3-MoE)进行基准测试对比
关键实现说明:
- 保留抽象类中的现有接口契约
- 使用装饰器实现非侵入式补丁集成
- 利用
eplb_utils.py进行共享专家映射操作
DFX¶
参数校验¶
整型参数¶
所有整型输入参数必须显式指定其最大值和最小值,并进行有效值校验。例如,expert_heat_collection_interval 必须大于 0:
@staticmethod
def check_iterations(iterations):
if not isinstance(iterations, int):
raise TypeError(f"The {iterations} is not int.")
if iterations <= 0:
raise ValueError(
f"The {iterations} can not be less than or equal to 0.")
if iterations > sys.maxsize:
raise ValueError(
f"The {iterations} can not be larger than {sys.maxsize}")
文件路径¶
必须检查 EPLB 文件路径的合法性,例如文件路径是否有效以及是否具有适当的读写权限。例如:
@staticmethod
def check_expert_map_path(expert_map):
if expert_map is None:
return
if not isinstance(expert_map, str):
raise TypeError("The expert_map is not str.")
if not expert_map.strip():
raise ValueError("The expert_map is not empty.")
_, ext = os.path.splitext(expert_map)
if ext.lower() != ".json":
raise TypeError("The expert_map is not json.")
if not os.path.exists(expert_map):
raise ValueError("The expert_map does not exist.")
try:
with open(expert_map, "w", encoding='utf-8') as f:
f.read()
except Exception as e:
raise IOError(
f"Fail read expert info from {expert_map}, please check the reading permission of {expert_map} : {e}"
)
函数规范¶
初始化函数¶
所有 EPLB 参数必须在初始化时进行默认初始化,并指定参数类型和默认值以便正确处理。
通用函数¶
所有方法参数必须指定参数类型和默认值,函数必须包含对默认参数的默认返回值处理。建议使用 try-except 块处理函数体,指定捕获的异常类型和失败处理方式(例如记录异常或返回失败状态)。
一致性¶
专家映射¶
专家映射在初始化和更新过程中必须全局唯一。在初始化时的多节点场景下,应使用分布式通信验证每个 rank 上专家映射的一致性。如果不一致,应通知用户哪些 rank 的映射不一致。 在更新过程中,如果仅更改了少数层或某个 rank 的专家表,则必须将更新后的专家表与 EPLB 的上下文同步,以确保全局一致性。
专家权重¶
更新专家权重时,请确保已释放为专家权重分配的内存,或者该专家(指旧版本)不再使用。
限制¶
使用 EPLB 前,启动脚本并添加 export DYNAMIC_EPLB="true"。
在执行负载数据收集(或性能数据收集)前,启动脚本并添加 export EXPERT_MAP_RECORD="true"。