From 68a4573627eac1e434a1fe225dc3493ffeab2093 Mon Sep 17 00:00:00 2001 From: Yuhao Yang <47235274+yhyang201@users.noreply.github.com> Date: Tue, 31 Mar 2026 14:14:59 +0800 Subject: [PATCH] [diffusion] fix: fix Flux.2 with tp(#21664) --- .../runtime/models/dits/flux_2.py | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/python/sglang/multimodal_gen/runtime/models/dits/flux_2.py b/python/sglang/multimodal_gen/runtime/models/dits/flux_2.py index 1651cdba1..5b2a69a32 100644 --- a/python/sglang/multimodal_gen/runtime/models/dits/flux_2.py +++ b/python/sglang/multimodal_gen/runtime/models/dits/flux_2.py @@ -438,7 +438,10 @@ class Flux2ParallelSelfAttention(torch.nn.Module, AttentionModuleMixin): self.norm_q = RMSNorm(dim_head, eps=eps) self.norm_k = RMSNorm(dim_head, eps=eps) - # Fused attention output projection + MLP output projection + # Fused attention output + MLP output projection. + # Input is [attn_shard | mlp_shard] (independently sharded by + # MergedColumnParallelLinear), so patch weight loader to pick the + # correct non-contiguous columns per rank. self.to_out = RowParallelLinear( self.inner_dim + self.mlp_hidden_dim, self.out_dim, @@ -447,6 +450,8 @@ class Flux2ParallelSelfAttention(torch.nn.Module, AttentionModuleMixin): quant_config=quant_config, prefix=f"{prefix}.to_out" if prefix else "to_out", ) + if self.tp_size > 1: + self._patch_to_out_weight_loader() self.attn = USPAttention( num_heads=self.local_heads, @@ -456,6 +461,24 @@ class Flux2ParallelSelfAttention(torch.nn.Module, AttentionModuleMixin): causal=False, ) + def _patch_to_out_weight_loader(self) -> None: + inner_dim, mlp_dim = self.inner_dim, self.mlp_hidden_dim + tp_size, tp_rank = self.tp_size, self.to_out.tp_rank + + def _loader(param, loaded_weight): + input_dim = getattr(param, "input_dim", None) + if input_dim is not None: + a = inner_dim // tp_size + m = mlp_dim // tp_size + attn_cols = loaded_weight.narrow(input_dim, tp_rank * a, a) + mlp_cols = loaded_weight.narrow(input_dim, inner_dim + tp_rank * m, m) + param.data.copy_(torch.cat([attn_cols, mlp_cols], dim=input_dim)) + else: + param.data.copy_(loaded_weight) + + self.to_out.weight_loader = _loader + self.to_out.weight.weight_loader = _loader + def forward( self, hidden_states: torch.Tensor,