3636logger = 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
6187def _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