multimodalart's picture
multimodalart HF Staff
Bernini-Diffusers-v2 r2v demo
fed6c68 verified
Raw
History Blame Contribute Delete
3.91 kB
# Copyright (c) 2026 Bytedance Ltd. and/or its affiliate
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Minimal parallel state: data parallel + Ulysses sequence parallel.
Single-GPU inference uses the default state (Ulysses disabled) and pulls in no
extra dependency. Multi-GPU sequence parallel delegates the actual collective
communication to Open-VeOmni, which is imported lazily only when enabled.
"""
import os
import torch.distributed as dist
class ParallelState:
"""Process-group layout for a single inference run.
Rank layout: consecutive blocks of ``ulysses_size`` ranks form one Ulysses
sequence-parallel group; ranks sharing the same in-block offset form one
data-parallel group.
"""
def __init__(self, ulysses_size: int = 1):
self.world_size = int(os.environ.get("WORLD_SIZE", "1"))
self.rank = int(os.environ.get("RANK", "0"))
if self.world_size % ulysses_size != 0:
raise ValueError(
f"world_size ({self.world_size}) must be divisible by "
f"ulysses_size ({ulysses_size})"
)
self.ulysses_size = ulysses_size
self.dp_size = self.world_size // ulysses_size
self.ulysses_rank = self.rank % ulysses_size
self.dp_rank = self.rank // ulysses_size
self.ulysses_group = None
self.dp_group = None
@property
def ulysses_enabled(self) -> bool:
return self.ulysses_size > 1
@property
def sp_enabled(self) -> bool:
return self.ulysses_enabled
@property
def sp_size(self) -> int:
return self.ulysses_size
@property
def sp_group(self):
return self.ulysses_group
_PARALLEL_STATE = ParallelState(ulysses_size=1)
def get_parallel_state() -> ParallelState:
return _PARALLEL_STATE
def init_parallel_state(ulysses_size: int = 1) -> ParallelState:
"""Build the data-parallel / Ulysses process groups.
``torch.distributed`` must already be initialized when ``ulysses_size > 1``.
"""
global _PARALLEL_STATE
ps = ParallelState(ulysses_size)
if ps.ulysses_enabled:
# Ulysses groups: consecutive blocks of `ulysses_size` ranks.
for i in range(ps.dp_size):
ranks = list(range(i * ulysses_size, (i + 1) * ulysses_size))
group = dist.new_group(ranks)
if ps.rank in ranks:
ps.ulysses_group = group
# Data-parallel groups: one rank from each Ulysses group.
for i in range(ulysses_size):
ranks = list(range(i, ps.world_size, ulysses_size))
group = dist.new_group(ranks)
if ps.rank in ranks:
ps.dp_group = group
# Register the Ulysses group with Open-VeOmni so its native sequence-
# parallel primitives use the exact same communication semantics as
# veomni_editing Gradio inference.
from veomni.distributed.parallel_state import init_parallel_state as init_veomni_parallel_state
from veomni.distributed.sequence_parallel.comm import (
set_ulysses_sequence_parallel_group,
set_unified_sequence_parallel_group,
)
init_veomni_parallel_state(dp_size=ps.dp_size, ulysses_size=ulysses_size)
set_ulysses_sequence_parallel_group(ps.ulysses_group)
set_unified_sequence_parallel_group(ps.ulysses_group)
_PARALLEL_STATE = ps
return ps