[diffusion] refactor: refactor fuse qkv with QKVParallelLinear linear (#15090)
Co-authored-by: Mick <mickjagger19@icloud.com>
This commit is contained in:
@@ -21,8 +21,27 @@ class FluxArchConfig(DiTArchConfig):
|
|||||||
guidance_embeds: bool = False
|
guidance_embeds: bool = False
|
||||||
axes_dims_rope: Tuple[int, int, int] = (16, 56, 56)
|
axes_dims_rope: Tuple[int, int, int] = (16, 56, 56)
|
||||||
|
|
||||||
|
stacked_params_mapping: list[tuple[str, str, str]] = field(
|
||||||
|
default_factory=lambda: [
|
||||||
|
# (param_name, shard_name, shard_id)
|
||||||
|
(".to_qkv", ".to_q", "q"),
|
||||||
|
(".to_qkv", ".to_k", "k"),
|
||||||
|
(".to_qkv", ".to_v", "v"),
|
||||||
|
(".to_added_qkv", ".add_q_proj", "q"),
|
||||||
|
(".to_added_qkv", ".add_k_proj", "k"),
|
||||||
|
(".to_added_qkv", ".add_v_proj", "v"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
param_names_mapping: dict = field(
|
param_names_mapping: dict = field(
|
||||||
default_factory=lambda: {
|
default_factory=lambda: {
|
||||||
|
# QKV fusion mappings
|
||||||
|
r"(.*)\.to_q\.(weight|bias)$": (r"\1.to_qkv.\2", 0, 3),
|
||||||
|
r"(.*)\.to_k\.(weight|bias)$": (r"\1.to_qkv.\2", 1, 3),
|
||||||
|
r"(.*)\.to_v\.(weight|bias)$": (r"\1.to_qkv.\2", 2, 3),
|
||||||
|
r"(.*)\.add_q_proj\.(weight|bias)$": (r"\1.to_added_qkv.\2", 0, 3),
|
||||||
|
r"(.*)\.add_k_proj\.(weight|bias)$": (r"\1.to_added_qkv.\2", 1, 3),
|
||||||
|
r"(.*)\.add_v_proj\.(weight|bias)$": (r"\1.to_added_qkv.\2", 2, 3),
|
||||||
r"transformer\.(\w*)\.(.*)$": r"\1.\2",
|
r"transformer\.(\w*)\.(.*)$": r"\1.\2",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,8 +21,28 @@ class QwenImageArchConfig(DiTArchConfig):
|
|||||||
guidance_embeds: bool = False
|
guidance_embeds: bool = False
|
||||||
axes_dims_rope: Tuple[int, int, int] = (16, 56, 56)
|
axes_dims_rope: Tuple[int, int, int] = (16, 56, 56)
|
||||||
|
|
||||||
|
stacked_params_mapping: list[tuple[str, str, str]] = field(
|
||||||
|
default_factory=lambda: [
|
||||||
|
# (param_name, shard_name, shard_id)
|
||||||
|
(".to_qkv", ".to_q", "q"),
|
||||||
|
(".to_qkv", ".to_k", "k"),
|
||||||
|
(".to_qkv", ".to_v", "v"),
|
||||||
|
(".to_added_qkv", ".add_q_proj", "q"),
|
||||||
|
(".to_added_qkv", ".add_k_proj", "k"),
|
||||||
|
(".to_added_qkv", ".add_v_proj", "v"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
param_names_mapping: dict = field(
|
param_names_mapping: dict = field(
|
||||||
default_factory=lambda: {
|
default_factory=lambda: {
|
||||||
|
# QKV fusion mappings
|
||||||
|
r"(.*)\.to_q\.(weight|bias)$": (r"\1.to_qkv.\2", 0, 3),
|
||||||
|
r"(.*)\.to_k\.(weight|bias)$": (r"\1.to_qkv.\2", 1, 3),
|
||||||
|
r"(.*)\.to_v\.(weight|bias)$": (r"\1.to_qkv.\2", 2, 3),
|
||||||
|
r"(.*)\.add_q_proj\.(weight|bias)$": (r"\1.to_added_qkv.\2", 0, 3),
|
||||||
|
r"(.*)\.add_k_proj\.(weight|bias)$": (r"\1.to_added_qkv.\2", 1, 3),
|
||||||
|
r"(.*)\.add_v_proj\.(weight|bias)$": (r"\1.to_added_qkv.\2", 2, 3),
|
||||||
|
# LoRA mappings
|
||||||
r"^(transformer_blocks\.\d+\.attn\..*\.lora_[AB])\.default$": r"\1",
|
r"^(transformer_blocks\.\d+\.attn\..*\.lora_[AB])\.default$": r"\1",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ By default, trace files are saved in the ./logs/ directory. The exact output fil
|
|||||||
```bash
|
```bash
|
||||||
[mm-dd hh:mm:ss] Saving profiler traces to: /sgl-workspace/sglang/logs/mocked_fake_id_for_offline_generate-5_steps-global-rank0.trace.json.gz
|
[mm-dd hh:mm:ss] Saving profiler traces to: /sgl-workspace/sglang/logs/mocked_fake_id_for_offline_generate-5_steps-global-rank0.trace.json.gz
|
||||||
```
|
```
|
||||||
|
{request_id}-{num_steps}_steps-global-rank{rank}.trace.json.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
Example: `mocked_fake_id_for_offline_generate-5_steps-global-rank0.trace.json.gz`
|
||||||
|
|
||||||
### View Traces
|
### View Traces
|
||||||
|
|
||||||
|
|||||||
@@ -692,10 +692,6 @@ class TransformerLoader(ComponentLoader):
|
|||||||
|
|
||||||
model = model.eval()
|
model = model.eval()
|
||||||
|
|
||||||
if hasattr(model, "fuse_qkv_projections"):
|
|
||||||
logger.info("Fusing QKV projections for better performance")
|
|
||||||
model.fuse_qkv_projections()
|
|
||||||
|
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,17 +36,16 @@ from sglang.multimodal_gen.runtime.layers.attention import USPAttention
|
|||||||
|
|
||||||
# from sglang.multimodal_gen.runtime.layers.layernorm import LayerNorm as LayerNorm
|
# from sglang.multimodal_gen.runtime.layers.layernorm import LayerNorm as LayerNorm
|
||||||
from sglang.multimodal_gen.runtime.layers.layernorm import RMSNorm
|
from sglang.multimodal_gen.runtime.layers.layernorm import RMSNorm
|
||||||
from sglang.multimodal_gen.runtime.layers.linear import ReplicatedLinear
|
from sglang.multimodal_gen.runtime.layers.linear import (
|
||||||
|
QKVParallelLinear,
|
||||||
|
ReplicatedLinear,
|
||||||
|
)
|
||||||
from sglang.multimodal_gen.runtime.layers.mlp import MLP
|
from sglang.multimodal_gen.runtime.layers.mlp import MLP
|
||||||
from sglang.multimodal_gen.runtime.layers.rotary_embedding import (
|
from sglang.multimodal_gen.runtime.layers.rotary_embedding import (
|
||||||
NDRotaryEmbedding,
|
NDRotaryEmbedding,
|
||||||
_apply_rotary_emb,
|
_apply_rotary_emb,
|
||||||
)
|
)
|
||||||
from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT
|
from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT
|
||||||
from sglang.multimodal_gen.runtime.models.dits.utils import (
|
|
||||||
delete_projection_layers,
|
|
||||||
fuse_linear_projections,
|
|
||||||
)
|
|
||||||
from sglang.multimodal_gen.runtime.platforms import (
|
from sglang.multimodal_gen.runtime.platforms import (
|
||||||
AttentionBackendEnum,
|
AttentionBackendEnum,
|
||||||
current_platform,
|
current_platform,
|
||||||
@@ -56,45 +55,21 @@ from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
|
|||||||
logger = init_logger(__name__) # pylint: disable=invalid-name
|
logger = init_logger(__name__) # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
||||||
def _get_projections(attn: "FluxAttention", hidden_states, encoder_hidden_states=None):
|
def _get_qkv_projections(
|
||||||
query, _ = attn.to_q(hidden_states)
|
|
||||||
key, _ = attn.to_k(hidden_states)
|
|
||||||
value, _ = attn.to_v(hidden_states)
|
|
||||||
|
|
||||||
encoder_query = encoder_key = encoder_value = None
|
|
||||||
if encoder_hidden_states is not None and attn.added_kv_proj_dim is not None:
|
|
||||||
encoder_query, _ = attn.add_q_proj(encoder_hidden_states)
|
|
||||||
encoder_key, _ = attn.add_k_proj(encoder_hidden_states)
|
|
||||||
encoder_value, _ = attn.add_v_proj(encoder_hidden_states)
|
|
||||||
|
|
||||||
return query, key, value, encoder_query, encoder_key, encoder_value
|
|
||||||
|
|
||||||
|
|
||||||
def _get_fused_projections(
|
|
||||||
attn: "FluxAttention", hidden_states, encoder_hidden_states=None
|
attn: "FluxAttention", hidden_states, encoder_hidden_states=None
|
||||||
):
|
):
|
||||||
qkv, _ = attn.to_qkv(hidden_states)
|
qkv, _ = attn.to_qkv(hidden_states)
|
||||||
query, key, value = qkv.chunk(3, dim=-1)
|
query, key, value = qkv.chunk(3, dim=-1)
|
||||||
|
|
||||||
encoder_query = encoder_key = encoder_value = None
|
encoder_query = encoder_key = encoder_value = None
|
||||||
if encoder_hidden_states is not None and hasattr(attn, "to_added_qkv"):
|
if encoder_hidden_states is not None and attn.added_kv_proj_dim is not None:
|
||||||
added_qkv, _ = attn.to_added_qkv(encoder_hidden_states)
|
added_qkv, _ = attn.to_added_qkv(encoder_hidden_states)
|
||||||
encoder_query, encoder_key, encoder_value = added_qkv.chunk(3, dim=-1)
|
encoder_query, encoder_key, encoder_value = added_qkv.chunk(3, dim=-1)
|
||||||
|
|
||||||
return query, key, value, encoder_query, encoder_key, encoder_value
|
return query, key, value, encoder_query, encoder_key, encoder_value
|
||||||
|
|
||||||
|
|
||||||
def _get_qkv_projections(
|
|
||||||
attn: "FluxAttention", hidden_states, encoder_hidden_states=None
|
|
||||||
):
|
|
||||||
if attn.fused_projections:
|
|
||||||
return _get_fused_projections(attn, hidden_states, encoder_hidden_states)
|
|
||||||
return _get_projections(attn, hidden_states, encoder_hidden_states)
|
|
||||||
|
|
||||||
|
|
||||||
class FluxAttention(torch.nn.Module, AttentionModuleMixin):
|
class FluxAttention(torch.nn.Module, AttentionModuleMixin):
|
||||||
_supports_qkv_fusion = True
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
query_dim: int,
|
query_dim: int,
|
||||||
@@ -125,11 +100,15 @@ class FluxAttention(torch.nn.Module, AttentionModuleMixin):
|
|||||||
self.added_proj_bias = added_proj_bias
|
self.added_proj_bias = added_proj_bias
|
||||||
|
|
||||||
self.norm_q = RMSNorm(dim_head, eps=eps)
|
self.norm_q = RMSNorm(dim_head, eps=eps)
|
||||||
|
|
||||||
self.norm_k = RMSNorm(dim_head, eps=eps)
|
self.norm_k = RMSNorm(dim_head, eps=eps)
|
||||||
self.to_q = ReplicatedLinear(query_dim, self.inner_dim, bias=bias)
|
|
||||||
self.to_k = ReplicatedLinear(query_dim, self.inner_dim, bias=bias)
|
# Use QKVParallelLinear for fused QKV projections
|
||||||
self.to_v = ReplicatedLinear(query_dim, self.inner_dim, bias=bias)
|
self.to_qkv = QKVParallelLinear(
|
||||||
|
hidden_size=query_dim,
|
||||||
|
head_size=dim_head,
|
||||||
|
total_num_heads=num_heads,
|
||||||
|
bias=bias,
|
||||||
|
)
|
||||||
|
|
||||||
if not self.pre_only:
|
if not self.pre_only:
|
||||||
self.to_out = torch.nn.ModuleList([])
|
self.to_out = torch.nn.ModuleList([])
|
||||||
@@ -142,14 +121,12 @@ class FluxAttention(torch.nn.Module, AttentionModuleMixin):
|
|||||||
if added_kv_proj_dim is not None:
|
if added_kv_proj_dim is not None:
|
||||||
self.norm_added_q = RMSNorm(dim_head, eps=eps)
|
self.norm_added_q = RMSNorm(dim_head, eps=eps)
|
||||||
self.norm_added_k = RMSNorm(dim_head, eps=eps)
|
self.norm_added_k = RMSNorm(dim_head, eps=eps)
|
||||||
self.add_q_proj = ReplicatedLinear(
|
# Use QKVParallelLinear for added (encoder) QKV projections
|
||||||
added_kv_proj_dim, self.inner_dim, bias=added_proj_bias
|
self.to_added_qkv = QKVParallelLinear(
|
||||||
)
|
hidden_size=added_kv_proj_dim,
|
||||||
self.add_k_proj = ReplicatedLinear(
|
head_size=dim_head,
|
||||||
added_kv_proj_dim, self.inner_dim, bias=added_proj_bias
|
total_num_heads=num_heads,
|
||||||
)
|
bias=added_proj_bias,
|
||||||
self.add_v_proj = ReplicatedLinear(
|
|
||||||
added_kv_proj_dim, self.inner_dim, bias=added_proj_bias
|
|
||||||
)
|
)
|
||||||
self.to_add_out = ReplicatedLinear(self.inner_dim, query_dim, bias=out_bias)
|
self.to_add_out = ReplicatedLinear(self.inner_dim, query_dim, bias=out_bias)
|
||||||
|
|
||||||
@@ -166,30 +143,6 @@ class FluxAttention(torch.nn.Module, AttentionModuleMixin):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.fused_projections = False
|
|
||||||
|
|
||||||
@torch.no_grad()
|
|
||||||
def fuse_projections(self):
|
|
||||||
if self.fused_projections:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.to_qkv = fuse_linear_projections(
|
|
||||||
self.to_q, self.to_k, self.to_v, self.use_bias, ReplicatedLinear
|
|
||||||
)
|
|
||||||
delete_projection_layers(self, ["to_q", "to_k", "to_v"])
|
|
||||||
|
|
||||||
if self.added_kv_proj_dim is not None:
|
|
||||||
self.to_added_qkv = fuse_linear_projections(
|
|
||||||
self.add_q_proj,
|
|
||||||
self.add_k_proj,
|
|
||||||
self.add_v_proj,
|
|
||||||
self.added_proj_bias,
|
|
||||||
ReplicatedLinear,
|
|
||||||
)
|
|
||||||
delete_projection_layers(self, ["add_q_proj", "add_k_proj", "add_v_proj"])
|
|
||||||
|
|
||||||
self.fused_projections = True
|
|
||||||
|
|
||||||
def forward(
|
def forward(
|
||||||
self,
|
self,
|
||||||
x: torch.Tensor,
|
x: torch.Tensor,
|
||||||
@@ -445,6 +398,8 @@ class FluxTransformer2DModel(CachableDiT):
|
|||||||
Reference: https://blackforestlabs.ai/announcing-black-forest-labs/
|
Reference: https://blackforestlabs.ai/announcing-black-forest-labs/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
param_names_mapping = FluxConfig().arch_config.param_names_mapping
|
||||||
|
|
||||||
def __init__(self, config: FluxConfig, hf_config: dict[str, Any]) -> None:
|
def __init__(self, config: FluxConfig, hf_config: dict[str, Any]) -> None:
|
||||||
super().__init__(config=config, hf_config=hf_config)
|
super().__init__(config=config, hf_config=hf_config)
|
||||||
self.config = config.arch_config
|
self.config = config.arch_config
|
||||||
@@ -503,15 +458,6 @@ class FluxTransformer2DModel(CachableDiT):
|
|||||||
bias=True,
|
bias=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def fuse_qkv_projections(self):
|
|
||||||
for block in list(self.transformer_blocks) + list(
|
|
||||||
self.single_transformer_blocks
|
|
||||||
):
|
|
||||||
if hasattr(block.attn, "fuse_projections") and getattr(
|
|
||||||
block.attn, "_supports_qkv_fusion", True
|
|
||||||
):
|
|
||||||
block.attn.fuse_projections()
|
|
||||||
|
|
||||||
def forward(
|
def forward(
|
||||||
self,
|
self,
|
||||||
hidden_states: torch.Tensor,
|
hidden_states: torch.Tensor,
|
||||||
|
|||||||
@@ -23,15 +23,12 @@ from diffusers.models.normalization import AdaLayerNormContinuous
|
|||||||
from sglang.multimodal_gen.configs.models.dits.flux import FluxConfig
|
from sglang.multimodal_gen.configs.models.dits.flux import FluxConfig
|
||||||
from sglang.multimodal_gen.runtime.layers.attention import USPAttention
|
from sglang.multimodal_gen.runtime.layers.attention import USPAttention
|
||||||
from sglang.multimodal_gen.runtime.layers.layernorm import RMSNorm
|
from sglang.multimodal_gen.runtime.layers.layernorm import RMSNorm
|
||||||
|
from sglang.multimodal_gen.runtime.layers.linear import QKVParallelLinear
|
||||||
from sglang.multimodal_gen.runtime.layers.rotary_embedding import (
|
from sglang.multimodal_gen.runtime.layers.rotary_embedding import (
|
||||||
NDRotaryEmbedding,
|
NDRotaryEmbedding,
|
||||||
_apply_rotary_emb,
|
_apply_rotary_emb,
|
||||||
)
|
)
|
||||||
from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT
|
from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT
|
||||||
from sglang.multimodal_gen.runtime.models.dits.utils import (
|
|
||||||
delete_projection_layers,
|
|
||||||
fuse_linear_projections,
|
|
||||||
)
|
|
||||||
from sglang.multimodal_gen.runtime.platforms import (
|
from sglang.multimodal_gen.runtime.platforms import (
|
||||||
AttentionBackendEnum,
|
AttentionBackendEnum,
|
||||||
current_platform,
|
current_platform,
|
||||||
@@ -41,40 +38,18 @@ from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
|
|||||||
logger = init_logger(__name__) # pylint: disable=invalid-name
|
logger = init_logger(__name__) # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
||||||
def _get_projections(attn: "Flux2Attention", hidden_states, encoder_hidden_states=None):
|
|
||||||
query = attn.to_q(hidden_states)
|
|
||||||
key = attn.to_k(hidden_states)
|
|
||||||
value = attn.to_v(hidden_states)
|
|
||||||
|
|
||||||
encoder_query = encoder_key = encoder_value = None
|
|
||||||
if encoder_hidden_states is not None and attn.added_kv_proj_dim is not None:
|
|
||||||
encoder_query = attn.add_q_proj(encoder_hidden_states)
|
|
||||||
encoder_key = attn.add_k_proj(encoder_hidden_states)
|
|
||||||
encoder_value = attn.add_v_proj(encoder_hidden_states)
|
|
||||||
|
|
||||||
return query, key, value, encoder_query, encoder_key, encoder_value
|
|
||||||
|
|
||||||
|
|
||||||
def _get_fused_projections(
|
|
||||||
attn: "Flux2Attention", hidden_states, encoder_hidden_states=None
|
|
||||||
):
|
|
||||||
qkv = attn.to_qkv(hidden_states)
|
|
||||||
query, key, value = qkv.chunk(3, dim=-1)
|
|
||||||
|
|
||||||
encoder_query = encoder_key = encoder_value = None
|
|
||||||
if encoder_hidden_states is not None and hasattr(attn, "to_added_qkv"):
|
|
||||||
added_qkv = attn.to_added_qkv(encoder_hidden_states)
|
|
||||||
encoder_query, encoder_key, encoder_value = added_qkv.chunk(3, dim=-1)
|
|
||||||
|
|
||||||
return query, key, value, encoder_query, encoder_key, encoder_value
|
|
||||||
|
|
||||||
|
|
||||||
def _get_qkv_projections(
|
def _get_qkv_projections(
|
||||||
attn: "Flux2Attention", hidden_states, encoder_hidden_states=None
|
attn: "Flux2Attention", hidden_states, encoder_hidden_states=None
|
||||||
):
|
):
|
||||||
if attn.fused_projections:
|
qkv, _ = attn.to_qkv(hidden_states)
|
||||||
return _get_fused_projections(attn, hidden_states, encoder_hidden_states)
|
query, key, value = qkv.chunk(3, dim=-1)
|
||||||
return _get_projections(attn, hidden_states, encoder_hidden_states)
|
|
||||||
|
encoder_query = encoder_key = encoder_value = None
|
||||||
|
if encoder_hidden_states is not None and attn.added_kv_proj_dim is not None:
|
||||||
|
added_qkv, _ = attn.to_added_qkv(encoder_hidden_states)
|
||||||
|
encoder_query, encoder_key, encoder_value = added_qkv.chunk(3, dim=-1)
|
||||||
|
|
||||||
|
return query, key, value, encoder_query, encoder_key, encoder_value
|
||||||
|
|
||||||
|
|
||||||
class Flux2SwiGLU(nn.Module):
|
class Flux2SwiGLU(nn.Module):
|
||||||
@@ -120,8 +95,6 @@ class Flux2FeedForward(nn.Module):
|
|||||||
|
|
||||||
|
|
||||||
class Flux2Attention(torch.nn.Module, AttentionModuleMixin):
|
class Flux2Attention(torch.nn.Module, AttentionModuleMixin):
|
||||||
_supports_qkv_fusion = True
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
query_dim: int,
|
query_dim: int,
|
||||||
@@ -150,9 +123,13 @@ class Flux2Attention(torch.nn.Module, AttentionModuleMixin):
|
|||||||
self.added_kv_proj_dim = added_kv_proj_dim
|
self.added_kv_proj_dim = added_kv_proj_dim
|
||||||
self.added_proj_bias = added_proj_bias
|
self.added_proj_bias = added_proj_bias
|
||||||
|
|
||||||
self.to_q = torch.nn.Linear(query_dim, self.inner_dim, bias=bias)
|
# Use QKVParallelLinear for fused QKV projections
|
||||||
self.to_k = torch.nn.Linear(query_dim, self.inner_dim, bias=bias)
|
self.to_qkv = QKVParallelLinear(
|
||||||
self.to_v = torch.nn.Linear(query_dim, self.inner_dim, bias=bias)
|
hidden_size=query_dim,
|
||||||
|
head_size=dim_head,
|
||||||
|
total_num_heads=num_heads,
|
||||||
|
bias=bias,
|
||||||
|
)
|
||||||
|
|
||||||
# QK Norm
|
# QK Norm
|
||||||
self.norm_q = RMSNorm(dim_head, eps=eps)
|
self.norm_q = RMSNorm(dim_head, eps=eps)
|
||||||
@@ -165,14 +142,12 @@ class Flux2Attention(torch.nn.Module, AttentionModuleMixin):
|
|||||||
if added_kv_proj_dim is not None:
|
if added_kv_proj_dim is not None:
|
||||||
self.norm_added_q = RMSNorm(dim_head, eps=eps)
|
self.norm_added_q = RMSNorm(dim_head, eps=eps)
|
||||||
self.norm_added_k = RMSNorm(dim_head, eps=eps)
|
self.norm_added_k = RMSNorm(dim_head, eps=eps)
|
||||||
self.add_q_proj = torch.nn.Linear(
|
# Use QKVParallelLinear for added (encoder) QKV projections
|
||||||
added_kv_proj_dim, self.inner_dim, bias=added_proj_bias
|
self.to_added_qkv = QKVParallelLinear(
|
||||||
)
|
hidden_size=added_kv_proj_dim,
|
||||||
self.add_k_proj = torch.nn.Linear(
|
head_size=dim_head,
|
||||||
added_kv_proj_dim, self.inner_dim, bias=added_proj_bias
|
total_num_heads=num_heads,
|
||||||
)
|
bias=added_proj_bias,
|
||||||
self.add_v_proj = torch.nn.Linear(
|
|
||||||
added_kv_proj_dim, self.inner_dim, bias=added_proj_bias
|
|
||||||
)
|
)
|
||||||
self.to_add_out = torch.nn.Linear(self.inner_dim, query_dim, bias=out_bias)
|
self.to_add_out = torch.nn.Linear(self.inner_dim, query_dim, bias=out_bias)
|
||||||
|
|
||||||
@@ -189,30 +164,6 @@ class Flux2Attention(torch.nn.Module, AttentionModuleMixin):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.fused_projections = False
|
|
||||||
|
|
||||||
@torch.no_grad()
|
|
||||||
def fuse_projections(self):
|
|
||||||
if self.fused_projections:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.to_qkv = fuse_linear_projections(
|
|
||||||
self.to_q, self.to_k, self.to_v, self.use_bias, torch.nn.Linear
|
|
||||||
)
|
|
||||||
delete_projection_layers(self, ["to_q", "to_k", "to_v"])
|
|
||||||
|
|
||||||
if self.added_kv_proj_dim is not None:
|
|
||||||
self.to_added_qkv = fuse_linear_projections(
|
|
||||||
self.add_q_proj,
|
|
||||||
self.add_k_proj,
|
|
||||||
self.add_v_proj,
|
|
||||||
self.added_proj_bias,
|
|
||||||
torch.nn.Linear,
|
|
||||||
)
|
|
||||||
delete_projection_layers(self, ["add_q_proj", "add_k_proj", "add_v_proj"])
|
|
||||||
|
|
||||||
self.fused_projections = True
|
|
||||||
|
|
||||||
def forward(
|
def forward(
|
||||||
self,
|
self,
|
||||||
hidden_states: torch.Tensor,
|
hidden_states: torch.Tensor,
|
||||||
@@ -655,6 +606,8 @@ class Flux2Transformer2DModel(CachableDiT):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
param_names_mapping = FluxConfig().arch_config.param_names_mapping
|
||||||
|
|
||||||
def __init__(self, config: FluxConfig, hf_config: dict[str, Any]):
|
def __init__(self, config: FluxConfig, hf_config: dict[str, Any]):
|
||||||
super().__init__(config=config, hf_config=hf_config)
|
super().__init__(config=config, hf_config=hf_config)
|
||||||
patch_size: int = config.patch_size
|
patch_size: int = config.patch_size
|
||||||
@@ -746,15 +699,6 @@ class Flux2Transformer2DModel(CachableDiT):
|
|||||||
|
|
||||||
self.gradient_checkpointing = False
|
self.gradient_checkpointing = False
|
||||||
|
|
||||||
def fuse_qkv_projections(self):
|
|
||||||
for block in list(self.transformer_blocks) + list(
|
|
||||||
self.single_transformer_blocks
|
|
||||||
):
|
|
||||||
if hasattr(block.attn, "fuse_projections") and getattr(
|
|
||||||
block.attn, "_supports_qkv_fusion", True
|
|
||||||
):
|
|
||||||
block.attn.fuse_projections()
|
|
||||||
|
|
||||||
def forward(
|
def forward(
|
||||||
self,
|
self,
|
||||||
hidden_states: torch.Tensor,
|
hidden_states: torch.Tensor,
|
||||||
|
|||||||
@@ -16,60 +16,35 @@ from diffusers.models.normalization import AdaLayerNormContinuous
|
|||||||
from sglang.multimodal_gen.configs.models.dits.qwenimage import QwenImageDitConfig
|
from sglang.multimodal_gen.configs.models.dits.qwenimage import QwenImageDitConfig
|
||||||
from sglang.multimodal_gen.runtime.layers.attention import USPAttention
|
from sglang.multimodal_gen.runtime.layers.attention import USPAttention
|
||||||
from sglang.multimodal_gen.runtime.layers.layernorm import LayerNorm, RMSNorm
|
from sglang.multimodal_gen.runtime.layers.layernorm import LayerNorm, RMSNorm
|
||||||
from sglang.multimodal_gen.runtime.layers.linear import ReplicatedLinear
|
from sglang.multimodal_gen.runtime.layers.linear import (
|
||||||
|
QKVParallelLinear,
|
||||||
|
ReplicatedLinear,
|
||||||
|
)
|
||||||
from sglang.multimodal_gen.runtime.layers.triton_ops import (
|
from sglang.multimodal_gen.runtime.layers.triton_ops import (
|
||||||
apply_rotary_embedding,
|
apply_rotary_embedding,
|
||||||
fuse_scale_shift_kernel,
|
fuse_scale_shift_kernel,
|
||||||
)
|
)
|
||||||
from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT
|
from sglang.multimodal_gen.runtime.models.dits.base import CachableDiT
|
||||||
from sglang.multimodal_gen.runtime.models.dits.utils import (
|
|
||||||
delete_projection_layers,
|
|
||||||
fuse_linear_projections,
|
|
||||||
)
|
|
||||||
from sglang.multimodal_gen.runtime.platforms import AttentionBackendEnum
|
from sglang.multimodal_gen.runtime.platforms import AttentionBackendEnum
|
||||||
from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
|
from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger
|
||||||
|
|
||||||
logger = init_logger(__name__) # pylint: disable=invalid-name
|
logger = init_logger(__name__) # pylint: disable=invalid-name
|
||||||
|
|
||||||
|
|
||||||
def _get_projections(
|
def _get_qkv_projections(
|
||||||
attn: "QwenImageCrossAttention", hidden_states, encoder_hidden_states=None
|
|
||||||
):
|
|
||||||
img_query, _ = attn.to_q(hidden_states)
|
|
||||||
img_key, _ = attn.to_k(hidden_states)
|
|
||||||
img_value, _ = attn.to_v(hidden_states)
|
|
||||||
|
|
||||||
txt_query = txt_key = txt_value = None
|
|
||||||
if encoder_hidden_states is not None and hasattr(attn, "add_q_proj"):
|
|
||||||
txt_query, _ = attn.add_q_proj(encoder_hidden_states)
|
|
||||||
txt_key, _ = attn.add_k_proj(encoder_hidden_states)
|
|
||||||
txt_value, _ = attn.add_v_proj(encoder_hidden_states)
|
|
||||||
|
|
||||||
return img_query, img_key, img_value, txt_query, txt_key, txt_value
|
|
||||||
|
|
||||||
|
|
||||||
def _get_fused_projections(
|
|
||||||
attn: "QwenImageCrossAttention", hidden_states, encoder_hidden_states=None
|
attn: "QwenImageCrossAttention", hidden_states, encoder_hidden_states=None
|
||||||
):
|
):
|
||||||
img_qkv, _ = attn.to_qkv(hidden_states)
|
img_qkv, _ = attn.to_qkv(hidden_states)
|
||||||
img_query, img_key, img_value = img_qkv.chunk(3, dim=-1)
|
img_query, img_key, img_value = img_qkv.chunk(3, dim=-1)
|
||||||
|
|
||||||
txt_query = txt_key = txt_value = None
|
txt_query = txt_key = txt_value = None
|
||||||
if encoder_hidden_states is not None and hasattr(attn, "to_added_qkv"):
|
if encoder_hidden_states is not None and attn.added_kv_proj_dim is not None:
|
||||||
txt_qkv, _ = attn.to_added_qkv(encoder_hidden_states)
|
txt_qkv, _ = attn.to_added_qkv(encoder_hidden_states)
|
||||||
txt_query, txt_key, txt_value = txt_qkv.chunk(3, dim=-1)
|
txt_query, txt_key, txt_value = txt_qkv.chunk(3, dim=-1)
|
||||||
|
|
||||||
return img_query, img_key, img_value, txt_query, txt_key, txt_value
|
return img_query, img_key, img_value, txt_query, txt_key, txt_value
|
||||||
|
|
||||||
|
|
||||||
def _get_qkv_projections(
|
|
||||||
attn: "QwenImageCrossAttention", hidden_states, encoder_hidden_states=None
|
|
||||||
):
|
|
||||||
if attn.fused_projections:
|
|
||||||
return _get_fused_projections(attn, hidden_states, encoder_hidden_states)
|
|
||||||
return _get_projections(attn, hidden_states, encoder_hidden_states)
|
|
||||||
|
|
||||||
|
|
||||||
class QwenTimestepProjEmbeddings(nn.Module):
|
class QwenTimestepProjEmbeddings(nn.Module):
|
||||||
def __init__(self, embedding_dim):
|
def __init__(self, embedding_dim):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -260,8 +235,6 @@ class QwenEmbedRope(nn.Module):
|
|||||||
|
|
||||||
|
|
||||||
class QwenImageCrossAttention(nn.Module):
|
class QwenImageCrossAttention(nn.Module):
|
||||||
_supports_qkv_fusion = True
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
dim: int, # query_dim
|
dim: int, # query_dim
|
||||||
@@ -286,26 +259,30 @@ class QwenImageCrossAttention(nn.Module):
|
|||||||
self.qk_norm = qk_norm
|
self.qk_norm = qk_norm
|
||||||
self.eps = eps
|
self.eps = eps
|
||||||
self.parallel_attention = parallel_attention
|
self.parallel_attention = parallel_attention
|
||||||
|
self.added_kv_proj_dim = added_kv_proj_dim
|
||||||
|
|
||||||
|
# Use QKVParallelLinear for fused QKV projections
|
||||||
|
self.to_qkv = QKVParallelLinear(
|
||||||
|
hidden_size=dim,
|
||||||
|
head_size=head_dim,
|
||||||
|
total_num_heads=num_heads,
|
||||||
|
bias=True,
|
||||||
|
)
|
||||||
|
|
||||||
# layers
|
|
||||||
self.to_q = ReplicatedLinear(dim, dim)
|
|
||||||
self.to_k = ReplicatedLinear(dim, dim)
|
|
||||||
self.to_v = ReplicatedLinear(dim, dim)
|
|
||||||
if self.qk_norm:
|
if self.qk_norm:
|
||||||
self.norm_q = RMSNorm(head_dim, eps=eps) if qk_norm else nn.Identity()
|
self.norm_q = RMSNorm(head_dim, eps=eps) if qk_norm else nn.Identity()
|
||||||
self.norm_k = RMSNorm(head_dim, eps=eps) if qk_norm else nn.Identity()
|
self.norm_k = RMSNorm(head_dim, eps=eps) if qk_norm else nn.Identity()
|
||||||
|
|
||||||
self.inner_dim = out_dim if out_dim is not None else head_dim * num_heads
|
self.inner_dim = out_dim if out_dim is not None else head_dim * num_heads
|
||||||
self.inner_kv_dim = self.inner_dim
|
self.inner_kv_dim = self.inner_dim
|
||||||
|
|
||||||
if added_kv_proj_dim is not None:
|
if added_kv_proj_dim is not None:
|
||||||
self.add_k_proj = ReplicatedLinear(
|
# Use QKVParallelLinear for added (encoder) QKV projections
|
||||||
added_kv_proj_dim, self.inner_kv_dim, bias=True
|
self.to_added_qkv = QKVParallelLinear(
|
||||||
)
|
hidden_size=added_kv_proj_dim,
|
||||||
self.add_v_proj = ReplicatedLinear(
|
head_size=head_dim,
|
||||||
added_kv_proj_dim, self.inner_kv_dim, bias=True
|
total_num_heads=num_heads,
|
||||||
)
|
bias=True,
|
||||||
if context_pre_only is not None:
|
|
||||||
self.add_q_proj = ReplicatedLinear(
|
|
||||||
added_kv_proj_dim, self.inner_dim, bias=True
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if context_pre_only is not None and not context_pre_only:
|
if context_pre_only is not None and not context_pre_only:
|
||||||
@@ -338,31 +315,6 @@ class QwenImageCrossAttention(nn.Module):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
self.fused_projections = False
|
|
||||||
self.added_kv_proj_dim_val = added_kv_proj_dim
|
|
||||||
|
|
||||||
@torch.no_grad()
|
|
||||||
def fuse_projections(self):
|
|
||||||
if self.fused_projections:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.to_qkv = fuse_linear_projections(
|
|
||||||
self.to_q, self.to_k, self.to_v, use_bias=False, linear_cls=ReplicatedLinear
|
|
||||||
)
|
|
||||||
delete_projection_layers(self, ["to_q", "to_k", "to_v"])
|
|
||||||
|
|
||||||
if self.added_kv_proj_dim_val is not None and hasattr(self, "add_q_proj"):
|
|
||||||
self.to_added_qkv = fuse_linear_projections(
|
|
||||||
self.add_q_proj,
|
|
||||||
self.add_k_proj,
|
|
||||||
self.add_v_proj,
|
|
||||||
use_bias=True,
|
|
||||||
linear_cls=ReplicatedLinear,
|
|
||||||
)
|
|
||||||
delete_projection_layers(self, ["add_q_proj", "add_k_proj", "add_v_proj"])
|
|
||||||
|
|
||||||
self.fused_projections = True
|
|
||||||
|
|
||||||
def forward(
|
def forward(
|
||||||
self,
|
self,
|
||||||
hidden_states: torch.Tensor,
|
hidden_states: torch.Tensor,
|
||||||
@@ -579,6 +531,8 @@ class QwenImageTransformer2DModel(CachableDiT):
|
|||||||
_skip_layerwise_casting_patterns = ["pos_embed", "norm"]
|
_skip_layerwise_casting_patterns = ["pos_embed", "norm"]
|
||||||
_repeated_blocks = ["QwenImageTransformerBlock"]
|
_repeated_blocks = ["QwenImageTransformerBlock"]
|
||||||
|
|
||||||
|
param_names_mapping = QwenImageDitConfig().arch_config.param_names_mapping
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
config: QwenImageDitConfig,
|
config: QwenImageDitConfig,
|
||||||
@@ -625,13 +579,6 @@ class QwenImageTransformer2DModel(CachableDiT):
|
|||||||
self.inner_dim, patch_size * patch_size * self.out_channels, bias=True
|
self.inner_dim, patch_size * patch_size * self.out_channels, bias=True
|
||||||
)
|
)
|
||||||
|
|
||||||
def fuse_qkv_projections(self):
|
|
||||||
for block in self.transformer_blocks:
|
|
||||||
if hasattr(block.attn, "fuse_projections") and getattr(
|
|
||||||
block.attn, "_supports_qkv_fusion", True
|
|
||||||
):
|
|
||||||
block.attn.fuse_projections()
|
|
||||||
|
|
||||||
def forward(
|
def forward(
|
||||||
self,
|
self,
|
||||||
hidden_states: torch.Tensor,
|
hidden_states: torch.Tensor,
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
from typing import Union
|
|
||||||
|
|
||||||
import torch
|
|
||||||
import torch.nn as nn
|
|
||||||
|
|
||||||
from sglang.multimodal_gen.runtime.layers.linear import ReplicatedLinear
|
|
||||||
|
|
||||||
|
|
||||||
def fuse_linear_projections(
|
|
||||||
q_proj: Union[nn.Linear, ReplicatedLinear],
|
|
||||||
k_proj: Union[nn.Linear, ReplicatedLinear],
|
|
||||||
v_proj: Union[nn.Linear, ReplicatedLinear],
|
|
||||||
use_bias: bool,
|
|
||||||
linear_cls: type = None,
|
|
||||||
) -> Union[nn.Linear, ReplicatedLinear]:
|
|
||||||
device = q_proj.weight.data.device
|
|
||||||
dtype = q_proj.weight.data.dtype
|
|
||||||
|
|
||||||
concatenated_weights = torch.cat(
|
|
||||||
[q_proj.weight.data, k_proj.weight.data, v_proj.weight.data]
|
|
||||||
)
|
|
||||||
in_features = concatenated_weights.shape[1]
|
|
||||||
out_features = concatenated_weights.shape[0]
|
|
||||||
|
|
||||||
if linear_cls is None:
|
|
||||||
linear_cls = type(q_proj)
|
|
||||||
|
|
||||||
fused_layer = linear_cls(in_features, out_features, bias=use_bias)
|
|
||||||
fused_layer.weight.data = concatenated_weights.to(device=device, dtype=dtype)
|
|
||||||
|
|
||||||
if use_bias:
|
|
||||||
concatenated_bias = torch.cat(
|
|
||||||
[q_proj.bias.data, k_proj.bias.data, v_proj.bias.data]
|
|
||||||
)
|
|
||||||
fused_layer.bias.data = concatenated_bias.to(device=device, dtype=dtype)
|
|
||||||
|
|
||||||
return fused_layer
|
|
||||||
|
|
||||||
|
|
||||||
def delete_projection_layers(module: nn.Module, layer_names: list[str]) -> None:
|
|
||||||
for name in layer_names:
|
|
||||||
if hasattr(module, name):
|
|
||||||
delattr(module, name)
|
|
||||||
@@ -584,7 +584,7 @@
|
|||||||
"48": 247.48,
|
"48": 247.48,
|
||||||
"49": 247.54
|
"49": 247.54
|
||||||
},
|
},
|
||||||
"expected_e2e_ms": 16563.83,
|
"expected_e2e_ms": 18382.19,
|
||||||
"expected_avg_denoise_ms": 260.76,
|
"expected_avg_denoise_ms": 260.76,
|
||||||
"expected_median_denoise_ms": 247.84
|
"expected_median_denoise_ms": 247.84
|
||||||
},
|
},
|
||||||
@@ -706,7 +706,7 @@
|
|||||||
"TimestepPreparationStage": 2.9,
|
"TimestepPreparationStage": 2.9,
|
||||||
"LatentPreparationStage": 1.25,
|
"LatentPreparationStage": 1.25,
|
||||||
"ImageVAEEncodingStage": 1655.89,
|
"ImageVAEEncodingStage": 1655.89,
|
||||||
"DenoisingStage": 100544.98,
|
"DenoisingStage": 106972.82,
|
||||||
"DecodingStage": 1355.52,
|
"DecodingStage": 1355.52,
|
||||||
"per_frame_generation": null
|
"per_frame_generation": null
|
||||||
},
|
},
|
||||||
@@ -753,7 +753,7 @@
|
|||||||
"39": 1599.78
|
"39": 1599.78
|
||||||
},
|
},
|
||||||
"expected_e2e_ms": 123182.9887,
|
"expected_e2e_ms": 123182.9887,
|
||||||
"expected_avg_denoise_ms": 2513.52,
|
"expected_avg_denoise_ms": 2831.00,
|
||||||
"expected_median_denoise_ms": 1600.09
|
"expected_median_denoise_ms": 1600.09
|
||||||
},
|
},
|
||||||
"wan2_1_i2v_14b_480P_2gpu": {
|
"wan2_1_i2v_14b_480P_2gpu": {
|
||||||
|
|||||||
Reference in New Issue
Block a user