refactor(vllm): use native IPC engine for colocated weight sync#345
refactor(vllm): use native IPC engine for colocated weight sync#345miracle0517 wants to merge 2 commits into
Conversation
Replace the custom colocated IPC handle gathering and worker chunk RPC path with vLLM/vLLM-Ascend native IPC weight transfer engines. Route generated update_info through VLLMEngine.update_weights and vLLM's /update_weights endpoint, initialize colocated transfer engines once during connection, and update unit tests for the native colocated transfer flow. Signed-off-by: wuxiang <498160096@qq.com>
Documentation build overview
45 files changed ·
|
There was a problem hiding this comment.
Code Review
This pull request refactors the colocated vLLM weight synchronization mechanism to leverage native IPC transfer engines (NPUIPCWeightTransferEngine and IPCWeightTransferEngine) for both NPU and CUDA platforms, removing custom IPC gathering and serialization logic. It also introduces shape-changing MoE restore patches and updates associated unit tests and scripts. Feedback on the changes suggests calling .contiguous() on transposed tensors in the NPU worker's wake_up patch to prevent potential runtime crashes or silent correctness issues caused by non-contiguous memory layouts on NPU platforms.
| for name, param in model.named_parameters(): | ||
| if "w2_weight" in name and param.shape[2] == hidden_size: | ||
| transposed = param.transpose(1, 2) | ||
| elif "w13_weight" in name and param.shape[1] == hidden_size: | ||
| transposed = param.transpose(1, 2) | ||
| else: | ||
| continue | ||
| parent_name, param_name = name.rsplit(".", 1) | ||
| parent = model.get_submodule(parent_name) | ||
| setattr(parent, param_name, torch.nn.Parameter(transposed, requires_grad=False)) |
There was a problem hiding this comment.
On NPU platforms, custom operators (such as those in Ascend/ATB) are highly sensitive to tensor memory layout and typically require contiguous tensors. Transposing a tensor via param.transpose(1, 2) returns a non-contiguous view, which can lead to silent correctness issues, runtime crashes, or memory access violations during execution. Calling .contiguous() on the transposed tensor ensures it is safely laid out in memory before wrapping it in a Parameter.
| for name, param in model.named_parameters(): | |
| if "w2_weight" in name and param.shape[2] == hidden_size: | |
| transposed = param.transpose(1, 2) | |
| elif "w13_weight" in name and param.shape[1] == hidden_size: | |
| transposed = param.transpose(1, 2) | |
| else: | |
| continue | |
| parent_name, param_name = name.rsplit(".", 1) | |
| parent = model.get_submodule(parent_name) | |
| setattr(parent, param_name, torch.nn.Parameter(transposed, requires_grad=False)) | |
| for name, param in model.named_parameters(): | |
| if "w2_weight" in name and param.shape[2] == hidden_size: | |
| transposed = param.transpose(1, 2).contiguous() | |
| elif "w13_weight" in name and param.shape[1] == hidden_size: | |
| transposed = param.transpose(1, 2).contiguous() | |
| else: | |
| continue | |
| parent_name, param_name = name.rsplit(".", 1) | |
| parent = model.get_submodule(parent_name) | |
| setattr(parent, param_name, torch.nn.Parameter(transposed, requires_grad=False)) |
ad53378 to
c5446b7
Compare
|
|
||
|
|
||
| def _patch_npu_colocate_worker() -> None: | ||
| """Skip layerwise_reload in NPUWorker weight-update hooks (colocate OOM fix).""" |
There was a problem hiding this comment.
Please call out in the PR that this intentionally re-enables native layerwise on NPU (previously skipped for OOM). Any memory regress vs the old skip path?
There was a problem hiding this comment.
Please call out in the PR that this intentionally re-enables native layerwise on NPU (previously skipped for OOM). Any memory regress vs the old skip path?
We conducted a comparative experiment on Qwen3-30B. The peak memory usage of the new version compared to the old version is 35.51 GB vs. 34.89 GB, with a difference within 1.78%
|
With native IPC, rank0 now fans out one merged-UUID payload to all colocated engines. Confirmed OK for multi-engine colocate, not only single-engine 30B? |
Signed-off-by: wuxiang <498160096@qq.com>
c5446b7 to
92a4fe9
Compare
uuid is generated in npu_ipc_engine( physical_npu_id = npu_generate_uuid() = f"{get_ip()}-{physical_device}"), so it is unique. And it is tested ok in multi-engine colocate。 |
Summary
1.Replace VIME's custom colocated IPC weight-sync implementation with the native weight transfer engines provided by vLLM and vLLM-Ascend.
This removes the manual IPC handle gathering, serialization, and worker-side chunk loading path while aligning colocated weight updates with vLLM's native /update_weights lifecycle.
2.Fix fused MoE weight shape mismatches during layerwise reload on Ascend NPU.
What changed
NPUIPCWeightTransferEngineon Ascend to send colocated weights.update_infopayloads throughVLLMEngine.update_weightsand vLLM's/update_weightsendpoint.start_weight_update/finish_weight_updatestate machine with checkpoint-format loading.update_weights_from_tensor/update_weights_chunkRPC pathWhy
1.The previous implementation duplicated functionality already supported by vLLM's native IPC transfer engines and required VIME to maintain custom GPU-slot gathering, IPC handle reconstruction, and worker RPC code.
Using the native transfer path reduces VIME-specific integration code and keeps colocated weight synchronization aligned with upstream vLLM and vLLM-Ascend behavior.
2.vLLM-Ascend may reload fused MoE weights with a transposed layout. Direct copying causes
npu_grouped_matmulshape errors, while skip wake up transpose can solve it.Testing
pytest tests/unit/backends/megatron_utils/update_weight/test_update_weight_from_tensor.py -qpytest tests/unit/backends/vllm_utils/test_vllm_engine.py -qpytest tests/unit/backends/megatron_utils/update_weight/test_update_weight_from_tensor.py -qComparison of reward and train_rollout_logprob_abs_diff curves between colocated and non-colocated training:

