Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ def positional_embedding_type(self) -> PositionalEmbeddingType:

@property
def positional_embedding_config(self) -> Optional[RotateHalfConfig]:
rope_theta = getattr(self._config, "rope_theta", 1000000.0)
return RotateHalfConfig(theta_base=rope_theta)
return RotateHalfConfig(theta_base=self.rope_theta)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,26 @@ def positional_embedding_config(self) -> Optional[RotateHalfConfig]:
Derived helpers
"""

@property
def rope_theta(self) -> float:
"""The rotary base, read from wherever the installed transformers keeps it.

transformers 5.0 folded the rotary settings into ``config.rope_parameters`` and
dropped the ``rope_theta`` attribute, so reading the attribute alone raises
against a stock config on 5.x. ``exaone4_5`` already reads both spellings; this
is the same lookup for every model that reaches it through this base.
"""
theta = getattr(self._config, "rope_theta", None)
if theta is not None:
return theta

rope_parameters = getattr(self._config, "rope_parameters", None) or getattr(self._config, "rope_scaling", None)
if isinstance(rope_parameters, dict) and rope_parameters.get("rope_theta") is not None:
return rope_parameters["rope_theta"]

raise ValueError(f"{type(self._config).__name__} carries no rope_theta, either as an "
"attribute or in rope_parameters/rope_scaling.")

@cached_property
def n_heads_q_local(self) -> int:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def positional_embedding_type(self) -> PositionalEmbeddingType:

@property
def positional_embedding_config(self) -> Optional[RotateHalfConfig]:
return RotateHalfConfig(theta_base=self._config.rope_theta)
return RotateHalfConfig(theta_base=self.rope_theta)

"""
Forward implementations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def positional_embedding_type(self) -> PositionalEmbeddingType:

@property
def positional_embedding_config(self) -> Optional[RotateHalfConfig]:
return RotateHalfConfig(theta_base=self._config.rope_theta)
return RotateHalfConfig(theta_base=self.rope_theta)

"""
Forward implementations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def positional_embedding_config(self) -> Optional[RotateHalfConfig]:
"""
The positional embedding configuration for the model.
"""
return RotateHalfConfig(theta_base=self._config.rope_theta)
return RotateHalfConfig(theta_base=self.rope_theta)

"""
Inherited from `DSMoETransformerModelBase`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def positional_embedding_type(self) -> PositionalEmbeddingType:
@property
def positional_embedding_config(self) -> Optional[RotateHalfConfig]:
rotary_dim = int(self._config.partial_rotary_factor * self.head_size)
return RotateHalfConfig(rotate_dim=rotary_dim, theta_base=self._config.rope_theta)
return RotateHalfConfig(rotate_dim=rotary_dim, theta_base=self.rope_theta)

"""
Forward implementations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def positional_embedding_type(self) -> PositionalEmbeddingType:

@property
def positional_embedding_config(self) -> Optional[RotateHalfConfig]:
return RotateHalfConfig(theta_base=self._config.rope_theta)
return RotateHalfConfig(theta_base=self.rope_theta)

"""
Forward implementations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def positional_embedding_type(self) -> PositionalEmbeddingType:

@property
def positional_embedding_config(self) -> Optional[RotateHalfConfig]:
return RotateHalfConfig(theta_base=self._config.rope_theta)
return RotateHalfConfig(theta_base=self.rope_theta)

def make_norm_layer(self) -> None:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def positional_embedding_type(self) -> PositionalEmbeddingType:

@property
def positional_embedding_config(self) -> Optional[RotateHalfConfig]:
return RotateHalfConfig(theta_base=self._config.rope_theta)
return RotateHalfConfig(theta_base=self.rope_theta)

"""
Inherited from `DSMoETransformerModelBase`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0

# DeepSpeed Team
"""Inference V2 must find rope_theta wherever the installed transformers keeps it.

transformers 5.0 folded the rotary settings into ``config.rope_parameters`` and dropped
the ``rope_theta`` attribute. Models that read the attribute directly raise against a
stock config on 5.x; ``exaone4`` read it through a ``getattr`` default and silently used
that default instead of the value the config actually carries.
"""

from types import SimpleNamespace

import pytest

from deepspeed.inference.v2.model_implementations.inference_transformer_base import DSTransformerModelBase


class _Model:
"""Minimal stand-in that borrows the property under test."""

rope_theta = DSTransformerModelBase.rope_theta

def __init__(self, config):
self._config = config


def test_reads_the_legacy_attribute():
assert _Model(SimpleNamespace(rope_theta=500000.0)).rope_theta == 500000.0


def test_reads_rope_parameters_when_the_attribute_is_gone():
config = SimpleNamespace(rope_parameters={"rope_theta": 10000.0, "rope_type": "default"})

assert _Model(config).rope_theta == 10000.0


def test_reads_rope_scaling_when_that_is_the_only_dict():
config = SimpleNamespace(rope_scaling={"rope_theta": 1000000.0, "rope_type": "default"})

assert _Model(config).rope_theta == 1000000.0


def test_prefers_the_attribute_when_both_are_present():
config = SimpleNamespace(rope_theta=500000.0, rope_parameters={"rope_theta": 10000.0})

assert _Model(config).rope_theta == 500000.0


def test_raises_instead_of_guessing_when_nothing_carries_it():
# exaone4 used to fall back to 1e6 here, which is a silent 100x error against a
# config whose real base is 1e4.
with pytest.raises(ValueError, match="rope_theta"):
_ = _Model(SimpleNamespace()).rope_theta


@pytest.mark.parametrize(
"module_name, config_name",
[
("llama", "LlamaConfig"),
("mistral", "MistralConfig"),
("mixtral", "MixtralConfig"),
("phi", "PhiConfig"),
("phi3", "Phi3Config"),
("qwen2", "Qwen2Config"),
("qwen2_moe", "Qwen2MoeConfig"),
("exaone4", "Exaone4Config"),
],
)
def test_resolves_against_the_installed_transformers_configs(module_name, config_name):
"""Every config backing a V2 model must yield a base through one spelling or the other."""
importlib = pytest.importorskip("importlib")
try:
module = importlib.import_module(f"transformers.models.{module_name}.configuration_{module_name}")
config = getattr(module, config_name)()
except (ImportError, AttributeError):
pytest.skip(f"{config_name} is not available in the installed transformers")

assert _Model(config).rope_theta > 0
Loading