Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/transformers/modeling_rope_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,7 @@ def standardize_rope_params(self):
rope_parameters.setdefault("rope_type", rope_parameters.get("type", "default"))
rope_parameters.setdefault("rope_theta", rope_theta)
if partial_rotary_factor is not None:
rope_parameters["partial_rotary_factor"] = partial_rotary_factor
rope_parameters.setdefault("partial_rotary_factor", partial_rotary_factor)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't force override if the dict has a value set, mirror setdefault(rope_theta) above, a missed bug from months ago

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

uh oh do we maybe have a test for that


# Force set the default type to model's expected `default_rope`. For most models it's a no-op
# used only to keep BC with old ckpt that require axial rope type
Expand All @@ -812,7 +812,7 @@ def standardize_rope_params(self):
rope_parameters[layer_type].setdefault("rope_type", rope_parameters[layer_type].get("type", "default"))
rope_parameters[layer_type].setdefault("rope_theta", rope_theta)
if partial_rotary_factor is not None:
rope_parameters[layer_type]["partial_rotary_factor"] = partial_rotary_factor
rope_parameters[layer_type].setdefault("partial_rotary_factor", partial_rotary_factor)

if rope_parameters[layer_type]["rope_type"] in ["llama3", "yarn", "longrope"]:
self.rope_parameters[layer_type].setdefault(
Expand Down
65 changes: 40 additions & 25 deletions src/transformers/models/cosmos3_edge/modeling_cosmos3_edge.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from ...masking_utils import create_causal_mask
from ...modeling_layers import GradientCheckpointingLayer
from ...modeling_outputs import BaseModelOutputWithPast, BaseModelOutputWithPooling, CausalLMOutputWithPast
from ...modeling_rope_utils import ROPE_INIT_FUNCTIONS
from ...modeling_rope_utils import ROPE_INIT_FUNCTIONS, dynamic_rope_update
from ...modeling_utils import ALL_ATTENTION_FUNCTIONS, PreTrainedModel
from ...processing_utils import Unpack
from ...utils import (
Expand All @@ -55,8 +55,6 @@


class Cosmos3EdgeTextRotaryEmbedding(nn.Module):
"""Interleaved M-RoPE used for Cosmos3 Edge text and visual tokens."""

@deprecate_kwarg("device", version="5.18")
def __init__(self, config: Cosmos3EdgeTextConfig, device=None):
super().__init__()
Expand All @@ -73,42 +71,59 @@ def __init__(self, config: Cosmos3EdgeTextConfig, device=None):

self.inv_freq = nn.Buffer(inv_freq, persistent=False)
self.original_inv_freq = nn.Buffer(inv_freq.clone(), persistent=False)
self.mrope_section = config.rope_parameters.get("mrope_section", [24, 20, 20])

@staticmethod
@deprecate_kwarg("device", version="5.18")
def compute_default_rope_parameters(
config: Cosmos3EdgeTextConfig, device=None, **kwargs
) -> tuple[torch.Tensor, float]:
"""Construct an axis-aware inverse-frequency matrix for interleaved temporal, height, and width RoPE."""
"""
Computes the inverse frequencies according to the original RoPE implementation
Args:
config ([`~transformers.PreTrainedConfig`]):
The model configuration.
Returns:
Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the
post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE).
"""
base = config.rope_parameters["rope_theta"]
dim = config.head_dim
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.float) / dim))
dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads

indices = torch.arange(inv_freq.shape[0])
mrope_section = config.rope_parameters["mrope_section"]
height_mask = (indices % 3 == 1) & (indices < mrope_section[1] * 3)
width_mask = (indices % 3 == 2) & (indices < mrope_section[2] * 3)
temporal_mask = ~(height_mask | width_mask)
inv_freq = torch.stack(
(
inv_freq * temporal_mask,
inv_freq * height_mask,
inv_freq * width_mask,
)
)
return inv_freq.to(device), 1.0
attention_factor = 1.0 # Unused in this type of RoPE
# Compute the inverse frequencies
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.float) / dim))
return inv_freq.to(device), attention_factor

@torch.no_grad()
@dynamic_rope_update
def forward(self, x, position_ids):
position_ids = position_ids.permute(1, 2, 0).float()
# In contrast to other models, Cosmos3EdgeText has different position ids for the grids
# So we expand the inv_freq to shape (3, ...)
inv_freq_expanded = self.inv_freq[None, None, :, None].float().expand(3, position_ids.shape[1], -1, 1)
position_ids_expanded = position_ids[:, :, None, :].float() # shape (3, bs, 1, positions)

device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
with maybe_autocast(device_type=device_type, enabled=False):
freqs = position_ids.float() @ self.inv_freq.float().to(x.device)
emb = torch.cat((freqs, freqs), dim=-1)
cos = emb.cos() * self.attention_scaling
sin = emb.sin() * self.attention_scaling
with maybe_autocast(device_type=device_type, enabled=False): # Force float32
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(2, 3)
cos = freqs.cos() * self.attention_scaling
sin = freqs.sin() * self.attention_scaling

sin = self.recomposition_frequencies(sin)
cos = self.recomposition_frequencies(cos)
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)

def recomposition_frequencies(self, freq):
"""
Recompose the frequencies into the final spatial layout used per each grid.
"""
freqs_thw = freq[0] # just overwrite the first dimension T
for dim, offset in enumerate((1, 2), start=1): # H, W
length = self.mrope_section[dim] * 3
idx = slice(offset, length, 3)
freqs_thw[..., idx] = freq[dim, ..., idx]
return torch.cat((freqs_thw, freqs_thw), dim=-1)


def rotate_half(x):
"""Rotates half the hidden dims of the input."""
Expand Down
40 changes: 3 additions & 37 deletions src/transformers/models/cosmos3_edge/modular_cosmos3_edge.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@
from ...utils.generic import (
get_max_seqlen,
is_flash_attention_requested,
maybe_autocast,
merge_with_config_defaults,
)
from ...utils.output_capturing import capture_outputs
Expand All @@ -62,7 +61,6 @@
LlamaDecoderLayer,
LlamaModel,
LlamaRMSNorm,
LlamaRotaryEmbedding,
eager_attention_forward,
)
from ..qwen2_vl.modeling_qwen2_vl import (
Expand All @@ -72,6 +70,7 @@
TransformersKwargs,
)
from ..qwen3_5_moe.modeling_qwen3_5_moe import Qwen3_5MoeVisionPatchMerger
from ..qwen3_vl.modeling_qwen3_vl import Qwen3VLTextRotaryEmbedding
from ..qwen3_vl.processing_qwen3_vl import Qwen3VLProcessor
from ..siglip2.configuration_siglip2 import Siglip2VisionConfig
from ..siglip2.modeling_siglip2 import (
Expand Down Expand Up @@ -215,41 +214,8 @@ def validate_architecture(self):
raise TypeError("`vision_config` must be a `Cosmos3EdgeVisionConfig` or a dictionary.")


class Cosmos3EdgeTextRotaryEmbedding(LlamaRotaryEmbedding):
"""Interleaved M-RoPE used for Cosmos3 Edge text and visual tokens."""

def compute_default_rope_parameters(
config: Cosmos3EdgeTextConfig, device=None, **kwargs
) -> tuple[torch.Tensor, float]:
"""Construct an axis-aware inverse-frequency matrix for interleaved temporal, height, and width RoPE."""
base = config.rope_parameters["rope_theta"]
dim = config.head_dim
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.float) / dim))

indices = torch.arange(inv_freq.shape[0])
mrope_section = config.rope_parameters["mrope_section"]
height_mask = (indices % 3 == 1) & (indices < mrope_section[1] * 3)
width_mask = (indices % 3 == 2) & (indices < mrope_section[2] * 3)
temporal_mask = ~(height_mask | width_mask)
inv_freq = torch.stack(
(
inv_freq * temporal_mask,
inv_freq * height_mask,
inv_freq * width_mask,
)
)
return inv_freq.to(device), 1.0

@torch.no_grad()
def forward(self, x, position_ids):
position_ids = position_ids.permute(1, 2, 0).float()
device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
with maybe_autocast(device_type=device_type, enabled=False):
freqs = position_ids.float() @ self.inv_freq.float().to(x.device)
emb = torch.cat((freqs, freqs), dim=-1)
cos = emb.cos() * self.attention_scaling
sin = emb.sin() * self.attention_scaling
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
class Cosmos3EdgeTextRotaryEmbedding(Qwen3VLTextRotaryEmbedding):
pass
Comment on lines +217 to +218

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was really identical, we gotta be careful when reviewing models so contribs don't re-invent the wheel

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sadly will and can happen at times. This is why it's more important than ever to have a more uniform recipe 🫡



class Cosmos3EdgeTextAttention(LlamaAttention):
Expand Down
29 changes: 13 additions & 16 deletions src/transformers/models/glm4v/modeling_glm4v.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ def __init__(self, config: Glm4vTextConfig, device=None):

@staticmethod
@deprecate_kwarg("device", version="5.18")
def compute_default_rope_parameters(config: Glm4vTextConfig, device=None, **kwargs) -> tuple[torch.Tensor, float]:
def compute_default_rope_parameters(config: Glm4vConfig, device=None, **kwargs) -> tuple[torch.Tensor, float]:
"""
Computes the inverse frequencies according to the original RoPE implementation
Args:
Expand All @@ -475,28 +475,29 @@ def compute_default_rope_parameters(config: Glm4vTextConfig, device=None, **kwar
return inv_freq.to(device), attention_factor

@torch.no_grad()
@dynamic_rope_update # power user: used with advanced RoPE types (e.g. dynamic rope)
@dynamic_rope_update
def forward(self, x, position_ids):
# In contrast to other models, GLM-V has different position ids for the grids
# In contrast to other models, Glm4vText has different position ids for the grids
# So we expand the inv_freq to shape (3, ...)
inv_freq_expanded = self.inv_freq[None, None, :, None].float().expand(3, position_ids.shape[1], -1, 1)
position_ids_expanded = position_ids[:, :, None, :].float() # shape (3, bs, 1, positions)

device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
with maybe_autocast(device_type=device_type, enabled=False): # Force float32
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(2, 3)
freqs = self.apply_mrope(freqs, self.mrope_section)
emb = torch.cat((freqs, freqs), dim=-1)
cos = emb.cos() * self.attention_scaling
sin = emb.sin() * self.attention_scaling
cos = freqs.cos() * self.attention_scaling
sin = freqs.sin() * self.attention_scaling

sin = self.recomposition_frequencies(sin)
cos = self.recomposition_frequencies(cos)
return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)

def apply_mrope(self, freqs, mrope_section):
section = mrope_section
chunks = freqs.split(section, dim=-1)
result = torch.cat([chunk[i % 3] for i, chunk in enumerate(chunks)], dim=-1)
return result
def recomposition_frequencies(self, freq):
"""
Recompose the frequencies into the final spatial layout used per each grid.
"""
freq = torch.cat([m[i % 3] for i, m in enumerate(freq.split(self.mrope_section, dim=-1))], dim=-1)
return freq.repeat_interleave(2, dim=-1)


def rotate_half_llm(x):
Expand Down Expand Up @@ -527,10 +528,6 @@ def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
cos = cos.unsqueeze(unsqueeze_dim)
sin = sin.unsqueeze(unsqueeze_dim)

# Interleave them instead of usual shape
cos = cos[..., : cos.shape[-1] // 2].repeat_interleave(2, dim=-1)
sin = sin[..., : sin.shape[-1] // 2].repeat_interleave(2, dim=-1)

# Keep half or full tensor for later concatenation
rotary_dim = cos.shape[-1]
q_rot, q_pass = q[..., :rotary_dim], q[..., rotary_dim:]
Expand Down
55 changes: 27 additions & 28 deletions src/transformers/models/glm4v/modular_glm4v.py
Comment thread
zucchini-nlp marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,21 @@
logging,
torch_compilable_check,
)
from ...utils.deprecation import deprecate_kwarg
from ...utils.generic import (
accepts_precomputed_kwargs,
maybe_autocast,
merge_with_config_defaults,
)
from ...utils.output_capturing import capture_outputs
from ...vision_utils import get_vision_attention_seqlens, get_vision_position_ids
from ..glm4.modeling_glm4 import Glm4MLP, Glm4RMSNorm, Glm4RotaryEmbedding, eager_attention_forward
from ..glm4.modeling_glm4 import Glm4MLP, Glm4RMSNorm, eager_attention_forward
from ..qwen2_5_vl.modeling_qwen2_5_vl import (
Qwen2_5_VisionPatchEmbed,
Qwen2_5_VLCausalLMOutputWithPast,
Qwen2_5_VLForConditionalGeneration,
Qwen2_5_VLMLP,
Qwen2_5_VLModelOutputWithPast,
Qwen2_5_VLPreTrainedModel,
Qwen2_5_VLRotaryEmbedding,
Qwen2_5_VLTextModel,
Qwen2_5_VLVisionAttention,
Qwen2_5_VLVisionBlock,
Expand Down Expand Up @@ -368,33 +367,37 @@ def __init__(self, config) -> None:
self.mlp = Glm4VisionMlp(config, bias=False)


class Glm4vTextRotaryEmbedding(Glm4RotaryEmbedding):
@deprecate_kwarg("device", version="5.18")
class Glm4vTextRotaryEmbedding(Qwen2_5_VLRotaryEmbedding):
def __init__(self, config: Glm4vTextConfig, device=None):
super().__init__()
self.mrope_section = config.rope_parameters.get("mrope_section", [8, 12, 12])

def forward(self, x, position_ids):
# In contrast to other models, GLM-V has different position ids for the grids
# So we expand the inv_freq to shape (3, ...)
inv_freq_expanded = self.inv_freq[None, None, :, None].float().expand(3, position_ids.shape[1], -1, 1)
position_ids_expanded = position_ids[:, :, None, :].float() # shape (3, bs, 1, positions)

device_type = x.device.type if isinstance(x.device.type, str) and x.device.type != "mps" else "cpu"
with maybe_autocast(device_type=device_type, enabled=False): # Force float32
freqs = (inv_freq_expanded.float() @ position_ids_expanded.float()).transpose(2, 3)
freqs = self.apply_mrope(freqs, self.mrope_section)
emb = torch.cat((freqs, freqs), dim=-1)
cos = emb.cos() * self.attention_scaling
sin = emb.sin() * self.attention_scaling
def compute_default_rope_parameters(config: Glm4vConfig, device=None, **kwargs) -> tuple[torch.Tensor, float]:
"""
Computes the inverse frequencies according to the original RoPE implementation
Args:
config ([`~transformers.PreTrainedConfig`]):
The model configuration.
Returns:
Tuple of (`torch.Tensor`, `float`), containing the inverse frequencies for the RoPE embeddings and the
post-processing scaling factor applied to the computed cos/sin (unused in this type of RoPE).
"""
base = config.rope_parameters["rope_theta"]
partial_rotary_factor = config.rope_parameters.get("partial_rotary_factor", 1.0)
head_dim = getattr(config, "head_dim", None) or config.hidden_size // config.num_attention_heads
dim = int(head_dim * partial_rotary_factor)

return cos.to(dtype=x.dtype), sin.to(dtype=x.dtype)
attention_factor = 1.0 # Unused in this type of RoPE
# Compute the inverse frequencies
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2, dtype=torch.float) / dim))
return inv_freq.to(device), attention_factor
Comment thread
zucchini-nlp marked this conversation as resolved.
Resolved

def apply_mrope(self, freqs, mrope_section):
section = mrope_section
chunks = freqs.split(section, dim=-1)
result = torch.cat([chunk[i % 3] for i, chunk in enumerate(chunks)], dim=-1)
return result
def recomposition_frequencies(self, freq):
"""
Recompose the frequencies into the final spatial layout used per each grid.
"""
freq = torch.cat([m[i % 3] for i, m in enumerate(freq.split(self.mrope_section, dim=-1))], dim=-1)
return freq.repeat_interleave(2, dim=-1)


def rotate_half_llm(x):
Expand Down Expand Up @@ -425,10 +428,6 @@ def apply_rotary_pos_emb(q, k, cos, sin, unsqueeze_dim=1):
cos = cos.unsqueeze(unsqueeze_dim)
sin = sin.unsqueeze(unsqueeze_dim)

# Interleave them instead of usual shape
cos = cos[..., : cos.shape[-1] // 2].repeat_interleave(2, dim=-1)
sin = sin[..., : sin.shape[-1] // 2].repeat_interleave(2, dim=-1)

Comment on lines -428 to -431

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is so weird 😆
It was doing too much so I moved interleave where it belongs, sadly though we still can't apply rope kernel

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argh I swear we can get there tho! I will maybe check whether I can work on the kernels side for this

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe open an issue for me :D

# Keep half or full tensor for later concatenation
rotary_dim = cos.shape[-1]
q_rot, q_pass = q[..., :rotary_dim], q[..., rotary_dim:]
Expand Down
Loading
Loading