deepinfer-eplb-migration

deepinfer/deepinfer/model_executor/eplb/__init__.py · a679bb8 · L195–278 · 固定 commit 上游

这是固定版本源码的只读摘录;可在线阅读,也可通过上游链接查看原文件。

195    def _initialize_shuffle(self) -> None:
196        """首次 rearrange:释放缓存显存防 OOM;单机时建 symm_mem 镜像走 IPC shuffle。"""
197        ep_group = self._ep_group
198        torch.cuda.empty_cache()
199        # TODO(NPU): NPU doesn't support symm_mem yet.
200        self._intranode_shuffle = PG.is_within_nvl_domain(ep_group) and PLATFORM.is_gpu
201        if not self._intranode_shuffle:
202            return
203
204        logger.info("[EPLB] shuffle intra node")
205        # 镜像只需容纳一层权重,shuffle 时逐层刷新复用。
206        self._symmetric_weight_buffers = [
207            symm_mem.empty(weight.shape, dtype=weight.dtype, device="cuda") for weight in self._expert_weights[0]
208        ]
209        self._symmetric_memory_handles = [symm_mem.rendezvous(buffer, ep_group) for buffer in self._symmetric_weight_buffers]
210        self._ipc_weight_buffers = [
211            [
212                handle.get_buffer(rank, buffer.shape, buffer.dtype)
213                for buffer, handle in zip(
214                    self._symmetric_weight_buffers,
215                    self._symmetric_memory_handles,
216                    strict=True,
217                )
218            ]
219            for rank in range(ep_group.size())
220        ]
221
222    @allow_cuda_sync()
223    def _rearrange_experts(self) -> None:
224        ep_group = self._ep_group
225        should_log_metrics = ep_group.rank() == 0
226        if should_log_metrics:
227            torch.cuda.synchronize()
228            start_time = time.perf_counter()
229
230        if not self._shuffle_initialized:
231            self._initialize_shuffle()
232            self._shuffle_initialized = True
233
234        # 窗口内各 logical expert 的 token 数:本地 physical 槽位聚合后全局 all-reduce
235        window_size, num_moe_layers, num_local_physical_experts = self._expert_count_window.shape
236        num_physical_experts = self.physical_to_logical_map.shape[1]
237        num_logical_experts = self.logical_count.shape[1]
238        local_physical_to_logical_map = self.physical_to_logical_map[
239            :,
240            ep_group.rank() * num_local_physical_experts : (ep_group.rank() + 1) * num_local_physical_experts,
241        ]
242        logical_expert_token_counts = torch.zeros(
243            window_size,
244            num_moe_layers,
245            num_logical_experts,
246            dtype=torch.int,
247            device=local_physical_to_logical_map.device,
248        )
249        logical_expert_token_counts.scatter_add_(
250            -1,
251            local_physical_to_logical_map.to(torch.int64).expand_as(self._expert_count_window),
252            self._expert_count_window,
253        )
254        dist.all_reduce(logical_expert_token_counts, group=ep_group)
255
256        next_physical_to_logical_map, next_logical_to_physical_map, next_logical_count = rebalance_experts_global(
257            logical_expert_token_counts,
258            num_physical_experts,
259            num_local_physical_experts,
260        )
261        if self._intranode_shuffle:
262            expert_model_parallel_shuffle_inplace_intranode(
263                self._ipc_weight_buffers,
264                self.physical_to_logical_map,
265                self._expert_weights,
266                next_physical_to_logical_map,
267                ep_group,
268            )
269        else:
270            expert_model_parallel_shuffle_inplace(
271                self.physical_to_logical_map,
272                self._expert_weights,
273                next_physical_to_logical_map,
274                ep_group,
275            )
276        self.physical_to_logical_map.copy_(next_physical_to_logical_map)
277        self.logical_to_physical_map.copy_(next_logical_to_physical_map)
278        self.logical_count.copy_(next_logical_count)