Replace the re-export stubs with real vendored copies of the fastvideo modeling
+ layer + supporting infra, for the kept diffusion models (wan21, wan_causal,
ltx2, flux2, matrixgame2). v2 now imports ZERO `fastvideo.*` — it is
self-contained. (bagel/qwen_omni load from vllm_omni, an external pkg, not
fastvideo; cosmos3's load_id was already dangling — both out of scope here.)
Vendored (cp + `sed fastvideo. -> v2.`):
- models/ the 5 models' nn.Module dits/vaes/encoders/audio/upsamplers + the
component loader/ + the lazy class registry (other families' rows are
dormant/lazy — only the 5 resolve).
- layers/ attention/ platforms/ distributed/ configs/ logging_utils/ hooks/
third_party/pynvml + top-level forward_context/fastvideo_args/envs/logger/
utils/version — copied verbatim (layers et al. 'as is').
- api/ slimmed to schema + results (the VideoGenerator's config dataclasses);
the fastvideo parser/presets/overrides (which pull the pipeline runtime) are
intentionally NOT vendored — v2 has its own runtime/loop.
Decoupling surgery (cut the loader's coupling to the fastvideo runtime):
- configs/pipeline_registry.py (vendored from fastvideo/registry.py, renamed to
avoid colliding with v2/registry.py): dropped the _register_presets() auto-call
and matrixgame3 (removed model); config-class resolution preserved.
- configs/pipelines/__init__.py: dropped the registry back-edge (fixes an import
cycle) — base.py imports the registry lazily where used.
- torch_backend: load_component now uses v2.models.loader.
The only remaining external 'fastvideo*' refs are `fastvideo_kernel` (the
separate optional CUDA-kernel pkg for sparse/MoBA attention) — guarded; the dense
TORCH_SDPA path v2 uses never imports it.
Vendored subtrees added to the pre-commit exclude (faithful copies, mirroring the
existing fastvideo/models exclusion — not re-linted, to stay re-syncable).
Verified: grep finds zero fastvideo-package imports in v2/; Wan2.1 T2V on H100 is
BIT-IDENTICAL to the fastvideo-backed path (same .npy SHA256, byte-for-byte); CPU
mini 156 (154 passed + 2 env-skipped on x86, torch present). Backup: branch v2_backup.
124 lines
5.0 KiB
Python
124 lines
5.0 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# Adapted from: https://github.com/vllm-project/vllm/blob/main/vllm/distributed/device_communicators/cpu_communicator.py
|
|
|
|
import os
|
|
|
|
import torch
|
|
from torch.distributed import ProcessGroup
|
|
|
|
from v2.platforms.interface import CpuArchEnum
|
|
|
|
from .base_device_communicator import DeviceCommunicatorBase
|
|
|
|
|
|
class CpuCommunicator(DeviceCommunicatorBase):
|
|
|
|
def __init__(self,
|
|
cpu_group: ProcessGroup,
|
|
device: torch.device | None = None,
|
|
device_group: ProcessGroup | None = None,
|
|
unique_name: str = ""):
|
|
super().__init__(cpu_group, device, device_group, unique_name)
|
|
self.dist_module = torch.distributed
|
|
|
|
from v2.platforms import current_platform
|
|
|
|
if (current_platform.get_cpu_architecture() == CpuArchEnum.X86) and hasattr(
|
|
torch.ops._C, "init_shm_manager") and unique_name.startswith("tp"):
|
|
self.dist_module = _CPUSHMDistributed(self)
|
|
|
|
def all_reduce(self,
|
|
input_: torch.Tensor,
|
|
op: torch.distributed.ReduceOp | None = torch.distributed.ReduceOp.SUM) -> torch.Tensor:
|
|
self.dist_module.all_reduce(input_, group=self.device_group, op=op)
|
|
return input_
|
|
|
|
def gather(self, input_: torch.Tensor, dst: int = 0, dim: int = -1) -> torch.Tensor | None:
|
|
"""
|
|
NOTE: We assume that the input tensor is on the same device across
|
|
all the ranks.
|
|
NOTE: `dst` is the local rank of the destination rank.
|
|
"""
|
|
world_size = self.world_size
|
|
assert -input_.dim() <= dim < input_.dim(), (f"Invalid dim ({dim}) for input tensor with shape {input_.size()}")
|
|
if dim < 0:
|
|
# Convert negative dim to positive.
|
|
dim += input_.dim()
|
|
|
|
# Allocate output tensor.
|
|
gather_list = [torch.empty_like(input_) for _ in range(world_size)] if self.rank_in_group == dst else None
|
|
|
|
# Gather.
|
|
self.dist_module.gather(input_, gather_list, dst=self.ranks[dst], group=self.device_group)
|
|
|
|
output_tensor = torch.cat(gather_list, dim=dim) if self.rank_in_group == dst else None
|
|
return output_tensor
|
|
|
|
def all_gather(self, input_: torch.Tensor, dim: int = -1) -> torch.Tensor:
|
|
if dim < 0:
|
|
# Convert negative dim to positive.
|
|
dim += input_.dim()
|
|
input_size = input_.size()
|
|
# NOTE: we have to use concat-style all-gather here,
|
|
# stack-style all-gather has compatibility issues with
|
|
# torch.compile . see https://github.com/pytorch/pytorch/issues/138795
|
|
output_size = (input_size[0] * self.world_size, ) + input_size[1:]
|
|
# Allocate output tensor.
|
|
output_tensor = torch.empty(output_size, dtype=input_.dtype, device=input_.device)
|
|
# All-gather.
|
|
self.dist_module.all_gather_into_tensor(output_tensor, input_, group=self.device_group)
|
|
|
|
# Reshape
|
|
output_tensor = output_tensor.reshape((self.world_size, ) + input_size)
|
|
output_tensor = output_tensor.movedim(0, dim)
|
|
output_tensor = output_tensor.reshape(input_size[:dim] + (self.world_size * input_size[dim], ) +
|
|
input_size[dim + 1:])
|
|
return output_tensor
|
|
|
|
|
|
class _CPUSHMDistributed:
|
|
|
|
def __init__(self, communicator: CpuCommunicator):
|
|
instance_identifier = os.environ["VLLM_DIST_IDENT"]
|
|
unique_name = communicator.unique_name
|
|
instance_identifier = f"{instance_identifier}-{unique_name}"
|
|
self.communicator = communicator
|
|
|
|
group_ranks = [str(rank) for rank in self.communicator.ranks]
|
|
shm_group_identifier = f"[{'-'.join(group_ranks)}]"
|
|
self.group_name = f"{instance_identifier}-{shm_group_identifier}-cpushm"
|
|
|
|
self.handle = self._init_cpu_shm()
|
|
|
|
def _init_cpu_shm(self) -> int:
|
|
handle = torch.ops._C.init_shm_manager(
|
|
self.group_name,
|
|
self.communicator.world_size,
|
|
self.communicator.rank,
|
|
)
|
|
torch.distributed.barrier(self.communicator.device_group)
|
|
torch.ops._C.join_shm_manager(
|
|
handle,
|
|
self.group_name,
|
|
)
|
|
torch.distributed.barrier(self.communicator.device_group)
|
|
|
|
return int(handle)
|
|
|
|
def all_reduce(self, input: torch.Tensor, group: ProcessGroup | None = None) -> None:
|
|
torch.ops._C.shm_allreduce(self.handle, input)
|
|
|
|
def gather(self,
|
|
input: torch.Tensor,
|
|
gather_list: list[torch.Tensor] | None,
|
|
dst: int = -1,
|
|
group: ProcessGroup | None = None) -> None:
|
|
# Note: different from the torch gather, here we use local dst rank.
|
|
torch.ops._C.shm_gather(self.handle, input, gather_list, torch.distributed.get_group_rank(group, dst))
|
|
|
|
def all_gather_into_tensor(self,
|
|
output: torch.Tensor,
|
|
input: torch.Tensor,
|
|
group: ProcessGroup | None = None) -> None:
|
|
torch.ops._C.shm_all_gather(self.handle, input, output)
|