Skip to content

Commit c6e0680

Browse files
committed
review: keep bria and nucleusmoe out
1 parent 6d84695 commit c6e0680

3 files changed

Lines changed: 55 additions & 32 deletions

File tree

src/diffusers/hooks/text_kv_cache.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2026 The HuggingFace Team. All rights reserved.
1+
# Copyright 2025 The HuggingFace Team. All rights reserved.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -136,7 +136,7 @@ def new_forward(self, module: torch.nn.Module, *args, **kwargs):
136136

137137
if image_rotary_emb is not None:
138138
_, txt_freqs = image_rotary_emb
139-
txt_key = _apply_rotary_emb_nucleus(txt_key, txt_freqs)
139+
txt_key = _apply_rotary_emb_nucleus(txt_key, txt_freqs, use_real=False)
140140

141141
block_state.kv_cache[cache_key] = (txt_key, txt_value)
142142

src/diffusers/models/transformers/transformer_bria_fibo.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ def _get_qkv_projections(attn: "BriaFiboAttention", hidden_states, encoder_hidde
6464
return _get_projections(attn, hidden_states, encoder_hidden_states)
6565

6666

67-
# Copied from diffusers.models.transformers.transformer_flux.FluxAttnProcessor with FluxAttnProcessor->BriaFiboAttnProcessor, FluxAttention->BriaFiboAttention
6867
class BriaFiboAttnProcessor:
6968
_attention_backend = None
7069
_parallel_config = None
@@ -85,19 +84,17 @@ def __call__(
8584
attn, hidden_states, encoder_hidden_states
8685
)
8786

88-
# Reshape by a fixed ``head_dim`` and let ``-1`` absorb the head count. Under tensor parallelism each rank
89-
# holds a column-sharded slice (``attn.heads // tp_degree`` heads); this keeps the processor TP-agnostic.
90-
query = query.unflatten(-1, (-1, attn.head_dim))
91-
key = key.unflatten(-1, (-1, attn.head_dim))
92-
value = value.unflatten(-1, (-1, attn.head_dim))
87+
query = query.unflatten(-1, (attn.heads, -1))
88+
key = key.unflatten(-1, (attn.heads, -1))
89+
value = value.unflatten(-1, (attn.heads, -1))
9390

9491
query = attn.norm_q(query)
9592
key = attn.norm_k(key)
9693

9794
if attn.added_kv_proj_dim is not None:
98-
encoder_query = encoder_query.unflatten(-1, (-1, attn.head_dim))
99-
encoder_key = encoder_key.unflatten(-1, (-1, attn.head_dim))
100-
encoder_value = encoder_value.unflatten(-1, (-1, attn.head_dim))
95+
encoder_query = encoder_query.unflatten(-1, (attn.heads, -1))
96+
encoder_key = encoder_key.unflatten(-1, (attn.heads, -1))
97+
encoder_value = encoder_value.unflatten(-1, (attn.heads, -1))
10198

10299
encoder_query = attn.norm_added_q(encoder_query)
103100
encoder_key = attn.norm_added_k(encoder_key)
@@ -471,7 +468,7 @@ def __init__(
471468
self.time_embed = BriaFiboTimestepProjEmbeddings(embedding_dim=self.inner_dim, time_theta=time_theta)
472469

473470
if guidance_embeds:
474-
self.guidance_embed = BriaFiboTimestepProjEmbeddings(embedding_dim=self.inner_dim, time_theta=time_theta)
471+
self.guidance_embed = BriaFiboTimestepProjEmbeddings(embedding_dim=self.inner_dim)
475472

476473
self.context_embedder = nn.Linear(self.config.joint_attention_dim, self.inner_dim)
477474
self.x_embedder = torch.nn.Linear(self.config.in_channels, self.inner_dim)
@@ -564,7 +561,7 @@ def forward(
564561

565562
temb = self.time_embed(timestep, dtype=hidden_states.dtype)
566563

567-
if guidance is not None:
564+
if guidance:
568565
temb += self.guidance_embed(guidance, dtype=hidden_states.dtype)
569566

570567
encoder_hidden_states = self.context_embedder(encoder_hidden_states)

src/diffusers/models/transformers/transformer_nucleusmoe_image.py

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,52 @@
3636
logger = logging.get_logger(__name__)
3737

3838

39-
def _apply_rotary_emb_nucleus(x: torch.Tensor, freqs: torch.Tensor) -> torch.Tensor:
40-
"""Apply rotary position embeddings to `x` using real-valued cos/sin.
41-
42-
`freqs` holds the per-position rotation *angles* with shape `[seq_len, head_dim // 2]`. The real cos/sin rotation
43-
is numerically identical to the equivalent complex-exponential formulation.
39+
def _apply_rotary_emb_nucleus(
40+
x: torch.Tensor,
41+
freqs_cis: torch.Tensor | tuple[torch.Tensor],
42+
use_real: bool = True,
43+
use_real_unbind_dim: int = -1,
44+
) -> tuple[torch.Tensor, torch.Tensor]:
45+
"""
46+
Apply rotary embeddings to input tensors using the given frequency tensor. This function applies rotary embeddings
47+
to the given query or key 'x' tensors using the provided frequency tensor 'freqs_cis'. The input tensors are
48+
reshaped as complex numbers, and the frequency tensor is reshaped for broadcasting compatibility. The resulting
49+
tensors contain rotary embeddings and are returned as real tensors.
4450
4551
Args:
46-
x (`torch.Tensor`): Query or key tensor to rotate, shape `[B, S, H, D]`.
47-
freqs (`torch.Tensor`): Rotation angles, shape `[S, D // 2]`.
52+
x (`torch.Tensor`):
53+
Query or key tensor to apply rotary embeddings. [B, S, H, D] xk (torch.Tensor): Key tensor to apply
54+
freqs_cis (`tuple[torch.Tensor]`): Precomputed frequency tensor for complex exponentials. ([S, D], [S, D],)
4855
4956
Returns:
50-
`torch.Tensor`: `x` with rotary embeddings applied.
57+
tuple[torch.Tensor, torch.Tensor]: tuple of modified query tensor and key tensor with rotary embeddings.
5158
"""
52-
# Adjacent feature pairs (2k, 2k+1) share angle k, so each angle is repeated twice along the last dim; unsqueeze
53-
# the head axis so the freqs broadcast over heads (this is what keeps it tensor-parallel-agnostic).
54-
cos = torch.cos(freqs).repeat_interleave(2, dim=-1).unsqueeze(1) # [S, 1, D]
55-
sin = torch.sin(freqs).repeat_interleave(2, dim=-1).unsqueeze(1) # [S, 1, D]
56-
x_real, x_imag = x.reshape(*x.shape[:-1], -1, 2).unbind(-1) # [B, S, H, D//2]
57-
x_rotated = torch.stack([-x_imag, x_real], dim=-1).flatten(3) # [B, S, H, D]
58-
return (x.float() * cos + x_rotated.float() * sin).to(x.dtype)
59+
if use_real:
60+
cos, sin = freqs_cis # [S, D]
61+
cos = cos[None, None]
62+
sin = sin[None, None]
63+
cos, sin = cos.to(x.device), sin.to(x.device)
64+
65+
if use_real_unbind_dim == -1:
66+
# Used for flux, cogvideox, hunyuan-dit
67+
x_real, x_imag = x.reshape(*x.shape[:-1], -1, 2).unbind(-1) # [B, S, H, D//2]
68+
x_rotated = torch.stack([-x_imag, x_real], dim=-1).flatten(3)
69+
elif use_real_unbind_dim == -2:
70+
# Used for Stable Audio, OmniGen, CogView4 and Cosmos
71+
x_real, x_imag = x.reshape(*x.shape[:-1], 2, -1).unbind(-2) # [B, S, H, D//2]
72+
x_rotated = torch.cat([-x_imag, x_real], dim=-1)
73+
else:
74+
raise ValueError(f"`use_real_unbind_dim={use_real_unbind_dim}` but should be -1 or -2.")
75+
76+
out = (x.float() * cos + x_rotated.float() * sin).to(x.dtype)
77+
78+
return out
79+
else:
80+
x_rotated = torch.view_as_complex(x.float().reshape(*x.shape[:-1], -1, 2))
81+
freqs_cis = freqs_cis.unsqueeze(1)
82+
x_out = torch.view_as_real(x_rotated * freqs_cis).flatten(3)
83+
84+
return x_out.type_as(x)
5985

6086

6187
def _compute_text_seq_len_from_mask(
@@ -144,8 +170,8 @@ def __init__(self, theta: int, axes_dim: list[int], scale_rope=False):
144170
@staticmethod
145171
def _rope_params(index, dim, theta=10000):
146172
assert dim % 2 == 0
147-
# Return the raw rotation angles (real); cos/sin are taken later in _apply_rotary_emb_nucleus.
148173
freqs = torch.outer(index, 1.0 / torch.pow(theta, torch.arange(0, dim, 2).to(torch.float32).div(dim)))
174+
freqs = torch.polar(torch.ones_like(freqs), freqs)
149175
return freqs
150176

151177
def forward(
@@ -270,8 +296,8 @@ def __call__(
270296

271297
if image_rotary_emb is not None:
272298
img_freqs, txt_freqs = image_rotary_emb
273-
img_query = _apply_rotary_emb_nucleus(img_query, img_freqs)
274-
img_key = _apply_rotary_emb_nucleus(img_key, img_freqs)
299+
img_query = _apply_rotary_emb_nucleus(img_query, img_freqs, use_real=False)
300+
img_key = _apply_rotary_emb_nucleus(img_key, img_freqs, use_real=False)
275301

276302
if cached_txt_key is not None and cached_txt_value is not None:
277303
txt_key, txt_value = cached_txt_key, cached_txt_value
@@ -285,7 +311,7 @@ def __call__(
285311
txt_key = attn.norm_added_k(txt_key)
286312

287313
if image_rotary_emb is not None:
288-
txt_key = _apply_rotary_emb_nucleus(txt_key, txt_freqs)
314+
txt_key = _apply_rotary_emb_nucleus(txt_key, txt_freqs, use_real=False)
289315

290316
joint_key = torch.cat([img_key, txt_key], dim=1)
291317
joint_value = torch.cat([img_value, txt_value], dim=1)

0 commit comments

Comments
 (0)