Coverage for wrapper/flux/flux_xfuser.py: 89%
57 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-09 04:47 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-09 04:47 +0000
1# from https://github.com/xdit-project/xDiT/blob/main/examples/flux_usp_example.py
2# from https://github.com/chengzeyi/ParaAttention/blob/main/examples/run_flux.py
4import torch
5import functools
6import types
8from typing import Optional
9from typing import Any
11from diffusers import DiffusionPipeline
13from xfuser.core.distributed import get_runtime_state
14from xfuser.core.distributed import get_classifier_free_guidance_world_size
15from xfuser.core.distributed import get_classifier_free_guidance_rank
16from xfuser.core.distributed import get_cfg_group
17from xfuser.core.distributed import get_sequence_parallel_world_size
18from xfuser.core.distributed import get_sequence_parallel_rank
19from xfuser.core.distributed import get_sp_group
21from xfuser.model_executor.models.transformers.transformer_flux import xFuserFluxAttnProcessor
24def parallelize_transformer(pipe: DiffusionPipeline) -> DiffusionPipeline:
25 transformer = getattr(pipe, "transformer")
26 assert transformer is not None, "pipe has no transformer attribute"
27 original_forward = transformer.forward
29 @functools.wraps(transformer.__class__.forward)
30 def new_forward(
31 self: Any,
32 hidden_states: torch.Tensor,
33 encoder_hidden_states: Optional[torch.Tensor] = None,
34 *args: Any,
35 timestep: Optional[torch.LongTensor] = None,
36 img_ids: Optional[torch.Tensor] = None,
37 txt_ids: Optional[torch.Tensor] = None,
38 **kwargs: Any,
39 ) -> Any:
40 cfg_world = get_classifier_free_guidance_world_size()
41 cfg_rank = get_classifier_free_guidance_rank()
42 sp_world = get_sequence_parallel_world_size()
43 sp_rank = get_sequence_parallel_rank()
44 if hidden_states.shape[0] % cfg_world != 0:
45 raise ValueError(f"Cannot split {hidden_states.shape[0]} ({hidden_states.shape}) into {cfg_world} parts")
46 if hidden_states.shape[-2] % sp_world != 0:
47 raise ValueError(f"Cannot split {hidden_states.shape[-2]} ({hidden_states.shape}) into {sp_world} parts")
48 assert encoder_hidden_states is not None, "encoder_hidden_states must not be None"
49 if encoder_hidden_states.shape[-2] % sp_world != 0:
50 get_runtime_state().split_text_embed_in_sp = False
51 else:
52 get_runtime_state().split_text_embed_in_sp = True
54 if isinstance(timestep, torch.Tensor) and timestep.ndim != 0 and timestep.shape[0] == hidden_states.shape[0]:
55 timestep = torch.chunk(timestep, cfg_world, dim=0)[cfg_rank]
56 hidden_states = torch.chunk(hidden_states, cfg_world, dim=0)[cfg_rank]
57 hidden_states = torch.chunk(hidden_states, sp_world, dim=-2)[sp_rank]
58 encoder_hidden_states = torch.chunk(encoder_hidden_states, cfg_world, dim=0)[cfg_rank]
59 if get_runtime_state().split_text_embed_in_sp:
60 encoder_hidden_states = torch.chunk(encoder_hidden_states, sp_world, dim=-2)[sp_rank]
61 assert img_ids is not None, "img_ids must not be None"
62 img_ids = torch.chunk(img_ids, sp_world, dim=-2)[sp_rank]
63 if get_runtime_state().split_text_embed_in_sp:
64 assert txt_ids is not None, "txt_ids must not be None when split_text_embed_in_sp is True"
65 txt_ids = torch.chunk(txt_ids, sp_world, dim=-2)[sp_rank]
67 for block in transformer.transformer_blocks + transformer.single_transformer_blocks:
68 block.attn.processor = xFuserFluxAttnProcessor()
70 output = original_forward(
71 hidden_states,
72 encoder_hidden_states,
73 *args,
74 timestep=timestep,
75 img_ids=img_ids,
76 txt_ids=txt_ids,
77 **kwargs,
78 )
80 return_dict = not isinstance(output, tuple)
81 sample = output[0]
82 sample = get_sp_group().all_gather(sample, dim=-2)
83 sample = get_cfg_group().all_gather(sample, dim=0)
84 if return_dict:
85 return output.__class__(sample, *output[1:])
86 return (sample, *output[1:])
88 bound_forward: Any = types.MethodType(new_forward, transformer)
89 transformer.forward = bound_forward
91 return pipe