# Copyright (c) 2025 Bytedance Ltd. and/or its affiliates and/or its affiliates # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import numpy as np import torch from diffusers.models.embeddings import get_1d_rotary_pos_embed as _get_1d_rotary_pos_embed from einops import repeat from torch import nn from vllm_omni.platforms import current_omni_platform def apply_real_rotary_emb(x: torch.Tensor, freqs_cos: torch.Tensor, freqs_sin: torch.Tensor) -> torch.Tensor: """ Apply real-valued rotary embeddings to input tensor. Args: x: Input tensor of shape [..., seq_len, num_heads, dim] or [..., seq_len, dim] freqs_cos: Cosine frequencies of shape [batch, seq_len, dim] or [seq_len, dim] freqs_sin: Sine frequencies of shape [batch, seq_len, dim] or [seq_len, dim] Returns: Tensor with rotary embeddings applied """ # x: [batch, seq_len, num_heads, dim] or [batch, seq_len, dim] # freqs_cos: [batch, seq_len, dim] or [seq_len, dim] # freqs_sin: [batch, seq_len, dim] or [seq_len, dim] x_shape = x.shape if len(x_shape) == 4: batch, seq_len, num_heads, dim = x_shape x_reshaped = x.view(batch, seq_len, num_heads, dim // 2, 2) elif len(x_shape) == 3: batch, seq_len, dim = x_shape num_heads = None x_reshaped = x.view(batch, seq_len, dim // 2, 2) else: raise ValueError(f"Unsupported x shape: {x.shape}") # freqs_cos/sin: [batch, seq_len, dim] or [seq_len, dim] # Expand freqs_cos/sin to [batch, seq_len, dim] if needed if freqs_cos.dim() == 2: # [seq_len, dim] -> [1, seq_len, dim] freqs_cos = freqs_cos.unsqueeze(0) freqs_sin = freqs_sin.unsqueeze(0) if freqs_cos.shape[0] == 1 and batch > 1: freqs_cos = freqs_cos.expand(batch, -1, -1) freqs_sin = freqs_sin.expand(batch, -1, -1) # Reshape freqs to [batch, seq_len, dim//2, 2] freqs_cos_reshaped = freqs_cos.view(batch, seq_len, dim // 2, 2) freqs_sin_reshaped = freqs_sin.view(batch, seq_len, dim // 2, 2) cos_1 = freqs_cos_reshaped[..., 0] # [batch, seq_len, dim//2] cos_2 = freqs_cos_reshaped[..., 1] # [batch, seq_len, dim//2] sin_1 = freqs_sin_reshaped[..., 0] # [batch, seq_len, dim//2] sin_2 = freqs_sin_reshaped[..., 1] # [batch, seq_len, dim//2] # Broadcast cos/sin to match x_reshaped if len(x_shape) == 4: # [batch, seq_len, 1, dim//2] cos_1 = cos_1.unsqueeze(2) cos_2 = cos_2.unsqueeze(2) sin_1 = sin_1.unsqueeze(2) sin_2 = sin_2.unsqueeze(2) x1 = x_reshaped[..., 0] # [..., seq_len, num_heads, dim//2] or [..., seq_len, dim//2] x2 = x_reshaped[..., 1] # same out1 = x1 * cos_1 - x2 * sin_1 out2 = x1 * sin_2 + x2 * cos_2 out = torch.stack([out1, out2], dim=-1) return out.view(*x_shape) def get_1d_rotary_pos_embed_real( dim: int, pos: np.ndarray | int, theta: float = 10000.0, linear_factor: float = 1.0, ntk_factor: float = 1.0, freqs_dtype: torch.dtype = torch.float32, ): freqs_cos, freqs_sin = _get_1d_rotary_pos_embed( dim, pos, theta=theta, use_real=True, linear_factor=linear_factor, ntk_factor=ntk_factor, repeat_interleave_real=True, freqs_dtype=freqs_dtype, ) return freqs_cos, freqs_sin class RotaryPosEmbedReal(nn.Module): def __init__( self, theta: int, axes_dim: tuple[int, int, int], axes_lens: tuple[int, int, int], patch_size: int = 2 ): super().__init__() self.theta = theta self.axes_dim = axes_dim self.axes_lens = axes_lens self.patch_size = patch_size @staticmethod def get_freqs_real( axes_dim: tuple[int, int, int], axes_lens: tuple[int, int, int], theta: int ) -> list[tuple[torch.Tensor, torch.Tensor]]: freqs_real = [] freqs_dtype = torch.float64 if current_omni_platform.supports_float64() else torch.float32 for i, (d, e) in enumerate(zip(axes_dim, axes_lens)): cos_emb, sin_emb = get_1d_rotary_pos_embed_real(d, e, theta=theta, freqs_dtype=freqs_dtype) freqs_real.append((cos_emb, sin_emb)) return freqs_real def _get_freqs_real( self, freqs_real: list[tuple[torch.Tensor, torch.Tensor]], ids: torch.Tensor ) -> tuple[torch.Tensor, torch.Tensor]: device = ids.device if ids.device.type == "mps": ids = ids.to("cpu") cos_result = [] sin_result = [] for i in range(len(self.axes_dim)): freqs_cos, freqs_sin = freqs_real[i] freqs_cos = freqs_cos.to(ids.device) freqs_sin = freqs_sin.to(ids.device) index = ids[:, :, i : i + 1].repeat(1, 1, freqs_cos.shape[-1]).to(torch.int64) cos_result.append(torch.gather(freqs_cos.unsqueeze(0).repeat(index.shape[0], 1, 1), dim=1, index=index)) sin_result.append(torch.gather(freqs_sin.unsqueeze(0).repeat(index.shape[0], 1, 1), dim=1, index=index)) combined_cos = torch.cat(cos_result, dim=-1).to(device) combined_sin = torch.cat(sin_result, dim=-1).to(device) return combined_cos, combined_sin def forward( self, freqs_real, attention_mask, l_effective_ref_img_len, l_effective_img_len, ref_img_sizes, img_sizes, device ): batch_size = len(attention_mask) p = self.patch_size encoder_seq_len = attention_mask.shape[1] l_effective_cap_len = attention_mask.sum(dim=1).tolist() l_effective_cap_len = [int(len) for len in l_effective_cap_len] seq_lengths = [ int(cap_len + sum(ref_img_len) + img_len) for cap_len, ref_img_len, img_len in zip(l_effective_cap_len, l_effective_ref_img_len, l_effective_img_len) ] max_seq_len = max(seq_lengths) max_ref_img_len = max([int(sum(ref_img_len)) for ref_img_len in l_effective_ref_img_len]) max_img_len = int(max(l_effective_img_len)) # Create position IDs position_ids = torch.zeros(batch_size, int(max_seq_len), 3, dtype=torch.int32, device=device) for i, (cap_seq_len, seq_len) in enumerate(zip(l_effective_cap_len, seq_lengths)): # add text position ids position_ids[i, :cap_seq_len] = repeat( torch.arange(cap_seq_len, dtype=torch.int32, device=device), "l -> l 3" ) pe_shift = cap_seq_len pe_shift_len = cap_seq_len if ref_img_sizes[i] is not None: for ref_img_size, ref_img_len in zip(ref_img_sizes[i], l_effective_ref_img_len[i]): H, W = ref_img_size ref_H_tokens, ref_W_tokens = H // p, W // p assert ref_H_tokens * ref_W_tokens == ref_img_len # add image position ids row_ids = repeat( torch.arange(ref_H_tokens, dtype=torch.int32, device=device), "h -> h w", w=ref_W_tokens ).flatten() col_ids = repeat( torch.arange(ref_W_tokens, dtype=torch.int32, device=device), "w -> h w", h=ref_H_tokens ).flatten() position_ids[i, pe_shift_len : pe_shift_len + ref_img_len, 0] = pe_shift position_ids[i, pe_shift_len : pe_shift_len + ref_img_len, 1] = row_ids position_ids[i, pe_shift_len : pe_shift_len + ref_img_len, 2] = col_ids pe_shift += max(ref_H_tokens, ref_W_tokens) pe_shift_len += ref_img_len H, W = img_sizes[i] H_tokens, W_tokens = H // p, W // p assert H_tokens * W_tokens == l_effective_img_len[i] row_ids = repeat(torch.arange(H_tokens, dtype=torch.int32, device=device), "h -> h w", w=W_tokens).flatten() col_ids = repeat(torch.arange(W_tokens, dtype=torch.int32, device=device), "w -> h w", h=H_tokens).flatten() assert pe_shift_len + l_effective_img_len[i] == seq_len position_ids[i, pe_shift_len:seq_len, 0] = pe_shift position_ids[i, pe_shift_len:seq_len, 1] = row_ids position_ids[i, pe_shift_len:seq_len, 2] = col_ids # Get combined rotary embeddings (real version) freqs_cos, freqs_sin = self._get_freqs_real(freqs_real, position_ids) # create separate rotary embeddings for captions and images cap_freqs_cos = torch.zeros( batch_size, encoder_seq_len, freqs_cos.shape[-1], device=device, dtype=freqs_cos.dtype ) cap_freqs_sin = torch.zeros( batch_size, encoder_seq_len, freqs_sin.shape[-1], device=device, dtype=freqs_sin.dtype ) ref_img_freqs_cos = torch.zeros( batch_size, max_ref_img_len, freqs_cos.shape[-1], device=device, dtype=freqs_cos.dtype ) ref_img_freqs_sin = torch.zeros( batch_size, max_ref_img_len, freqs_sin.shape[-1], device=device, dtype=freqs_sin.dtype ) img_freqs_cos = torch.zeros(batch_size, max_img_len, freqs_cos.shape[-1], device=device, dtype=freqs_cos.dtype) img_freqs_sin = torch.zeros(batch_size, max_img_len, freqs_sin.shape[-1], device=device, dtype=freqs_sin.dtype) for i, (cap_seq_len, ref_img_len, img_len, seq_len) in enumerate( zip(l_effective_cap_len, l_effective_ref_img_len, l_effective_img_len, seq_lengths) ): cap_freqs_cos[i, :cap_seq_len] = freqs_cos[i, :cap_seq_len] cap_freqs_sin[i, :cap_seq_len] = freqs_sin[i, :cap_seq_len] ref_img_freqs_cos[i, : sum(ref_img_len)] = freqs_cos[i, cap_seq_len : cap_seq_len + sum(ref_img_len)] ref_img_freqs_sin[i, : sum(ref_img_len)] = freqs_sin[i, cap_seq_len : cap_seq_len + sum(ref_img_len)] img_freqs_cos[i, :img_len] = freqs_cos[ i, cap_seq_len + sum(ref_img_len) : cap_seq_len + sum(ref_img_len) + img_len ] img_freqs_sin[i, :img_len] = freqs_sin[ i, cap_seq_len + sum(ref_img_len) : cap_seq_len + sum(ref_img_len) + img_len ] return ( (cap_freqs_cos, cap_freqs_sin), (ref_img_freqs_cos, ref_img_freqs_sin), (img_freqs_cos, img_freqs_sin), (freqs_cos, freqs_sin), l_effective_cap_len, seq_lengths, )