Signed-off-by: KexiongYu <yukexiong1@huawei.com> Signed-off-by: zzh <943967662@qq.com> Co-authored-by: zzh <943967662@qq.com>
146 lines
5.6 KiB
Python
146 lines
5.6 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
|
|
from typing import Any
|
|
|
|
import torch
|
|
from vllm.logger import init_logger
|
|
|
|
from vllm_omni.diffusion.distributed.autoencoders.distributed_vae_executor import (
|
|
DistributedOperator,
|
|
DistributedVaeMixin,
|
|
GridSpec,
|
|
TileTask,
|
|
)
|
|
from vllm_omni.diffusion.models.hunyuan_image3.autoencoder import AutoencoderKLConv3D
|
|
|
|
logger = init_logger(__name__)
|
|
|
|
|
|
class DistributedAutoencoderKLHunyuan(AutoencoderKLConv3D, DistributedVaeMixin):
|
|
@classmethod
|
|
def from_config(cls, config: Any, **kwargs: Any):
|
|
model = super().from_config(config, **kwargs)
|
|
model.init_distributed()
|
|
return model
|
|
|
|
@classmethod
|
|
def from_pretrained(cls, *args: Any, **kwargs: Any):
|
|
model = super().from_pretrained(*args, **kwargs)
|
|
model.init_distributed()
|
|
return model
|
|
|
|
@property
|
|
def use_tiling(self) -> bool:
|
|
return self.use_spatial_tiling
|
|
|
|
@use_tiling.setter
|
|
def use_tiling(self, use_tiling: bool) -> None:
|
|
self.use_spatial_tiling = use_tiling
|
|
|
|
def tile_split(self, z: torch.Tensor) -> tuple[list[TileTask], GridSpec]:
|
|
_, _, _, height, width = z.shape
|
|
overlap_size = int(self.tile_latent_min_size * (1 - self.tile_overlap_factor))
|
|
blend_extent = int(self.tile_sample_min_size * self.tile_overlap_factor)
|
|
row_limit = int(self.tile_sample_min_size - blend_extent)
|
|
|
|
tiletask_list = []
|
|
for i in range(0, height, overlap_size):
|
|
for j in range(0, width, overlap_size):
|
|
tile = z[:, :, :, i : i + self.tile_latent_min_size, j : j + self.tile_latent_min_size]
|
|
tiletask_list.append(
|
|
TileTask(
|
|
len(tiletask_list),
|
|
(i // overlap_size, j // overlap_size),
|
|
tile,
|
|
workload=tile.shape[3] * tile.shape[4],
|
|
)
|
|
)
|
|
|
|
grid_spec = GridSpec(
|
|
split_dims=(3, 4),
|
|
grid_shape=(tiletask_list[-1].grid_coord[0] + 1, tiletask_list[-1].grid_coord[1] + 1),
|
|
tile_spec={"blend_extent": blend_extent, "row_limit": row_limit},
|
|
output_dtype=self.dtype,
|
|
)
|
|
return tiletask_list, grid_spec
|
|
|
|
def tile_exec(self, task: TileTask) -> torch.Tensor:
|
|
return self.decoder(task.tensor)
|
|
|
|
def tile_merge(self, coord_tensor_map: dict[tuple[int, ...], torch.Tensor], grid_spec: GridSpec) -> torch.Tensor:
|
|
grid_h, grid_w = grid_spec.grid_shape
|
|
result_rows = []
|
|
for i in range(grid_h):
|
|
result_row = []
|
|
for j in range(grid_w):
|
|
tile = coord_tensor_map[(i, j)]
|
|
if i > 0:
|
|
tile = self.blend_v(coord_tensor_map[(i - 1, j)], tile, grid_spec.tile_spec["blend_extent"])
|
|
if j > 0:
|
|
tile = self.blend_h(coord_tensor_map[(i, j - 1)], tile, grid_spec.tile_spec["blend_extent"])
|
|
result_row.append(tile[:, :, :, : grid_spec.tile_spec["row_limit"], : grid_spec.tile_spec["row_limit"]])
|
|
result_rows.append(torch.cat(result_row, dim=-1))
|
|
return torch.cat(result_rows, dim=-2)
|
|
|
|
def encode_tile_split(self, x: torch.Tensor) -> tuple[list[TileTask], GridSpec]:
|
|
_, _, _, height, width = x.shape
|
|
overlap_size = int(self.tile_sample_min_size * (1 - self.tile_overlap_factor))
|
|
blend_extent = int(self.tile_latent_min_size * self.tile_overlap_factor)
|
|
row_limit = int(self.tile_latent_min_size - blend_extent)
|
|
|
|
tiletask_list = []
|
|
for i in range(0, height, overlap_size):
|
|
for j in range(0, width, overlap_size):
|
|
tile = x[:, :, :, i : i + self.tile_sample_min_size, j : j + self.tile_sample_min_size]
|
|
tiletask_list.append(
|
|
TileTask(
|
|
len(tiletask_list),
|
|
(i // overlap_size, j // overlap_size),
|
|
tile,
|
|
workload=tile.shape[3] * tile.shape[4],
|
|
)
|
|
)
|
|
|
|
grid_spec = GridSpec(
|
|
split_dims=(3, 4),
|
|
grid_shape=(tiletask_list[-1].grid_coord[0] + 1, tiletask_list[-1].grid_coord[1] + 1),
|
|
tile_spec={"blend_extent": blend_extent, "row_limit": row_limit},
|
|
output_dtype=self.dtype,
|
|
)
|
|
return tiletask_list, grid_spec
|
|
|
|
def encode_tile_exec(self, task: TileTask) -> torch.Tensor:
|
|
return self.encoder(task.tensor)
|
|
|
|
def encode_tile_merge(
|
|
self, coord_tensor_map: dict[tuple[int, ...], torch.Tensor], grid_spec: GridSpec
|
|
) -> torch.Tensor:
|
|
return self.tile_merge(coord_tensor_map, grid_spec)
|
|
|
|
def spatial_tiled_encode(self, x: torch.Tensor):
|
|
if not self.is_distributed_enabled():
|
|
return super().spatial_tiled_encode(x)
|
|
|
|
logger.debug("Encode running with distributed executor")
|
|
return self.distributed_executor.execute(
|
|
x,
|
|
DistributedOperator(
|
|
split=self.encode_tile_split,
|
|
exec=self.encode_tile_exec,
|
|
merge=self.encode_tile_merge,
|
|
),
|
|
broadcast_result=True,
|
|
)
|
|
|
|
def spatial_tiled_decode(self, z: torch.Tensor):
|
|
if not self.is_distributed_enabled():
|
|
return super().spatial_tiled_decode(z)
|
|
|
|
logger.debug("Decode running with distributed executor")
|
|
return self.distributed_executor.execute(
|
|
z,
|
|
DistributedOperator(split=self.tile_split, exec=self.tile_exec, merge=self.tile_merge),
|
|
broadcast_result=True,
|
|
)
|