Repository: huggingface/transformers
Pull request: fix: preserve rotary_pct across save/load cycle in GPTNeoX configs

## Summary
Fixes #44913

When creating a `GPTNeoXConfig` (or `GPTNeoXJapaneseConfig`) with a non-default `rotary_pct`, the value is lost after a `save_pretrained` / `from_pretrained` round-trip. This happens because `convert_rope_params_to_dict` unconditionally overwrites `partial_rotary_factor` with `kwargs.pop("rotary_pct", <default>)`. On reload, `rotary_pct` is absent from kwargs (it was saved inside `rope_parameters`), so the default silently replaces the correct value.

The fix uses the same `setdefault` pattern recommended by @zucchini-nlp from [`modeling_rope_utils.py` L646-648](https://github.com/huggingface/transformers/blob/55cc1a7fb8e53a5e7e35ca9cf9759498f20abb93/src/transformers/modeling_rope_utils.py#L645-L648): only set `partial_rotary_factor` if `rotary_pct` is explicitly passed; otherwise, use `setdefault` to preserve any value already present in `rope_parameters`.

Both `GPTNeoXConfig` and `GPTNeoXJapaneseConfig` had the same bug and are fixed together.

## Changes
- `src/transformers/models/gpt_neox/configuration_gpt_neox.py`: use `setdefault` for `partial_rotary_factor` instead of unconditional assignment
- `src/transformers/models/gpt_neox_japanese/configuration_gpt_neox_japanese.py`: same fix (default 1.0 instead of 0.25)

## Test plan
- [x] Verified `rotary_pct=0.5` survives save/load round-trip for both `GPTNeoXConfig` and `GPTNeoXJapaneseConfig`
- [x] Verified default `rotary_pct` (0.25 for GPTNeoX, 1.0 for Japanese) survives save/load round-trip
- [x] Ran `pytest tests/models/gpt_neox/test_modeling_gpt_neox.py -k config` -- all passed
- [x] Ran `pytest tests/models/gpt_neox_japanese/test_modeling_gpt_neox_japanese.py -k config` -- all passed
- [x] `ruff check` and `ruff format --check` pass on both files

AI assistance was used in drafting; all changes and tests were reviewed and validated by the submitter.

Changed files:
filename: src/transformers/models/gpt_neox/configuration_gpt_neox.py
patch: @@ -95,7 +95,7 @@ def convert_rope_params_to_dict(self, **kwargs):
         # Standardize and validate the correctness of rotary position embeddings parameters
         # Model uses non-standard naming for rope params, overwrite!
         self.rope_parameters.setdefault("rope_theta", kwargs.pop("rotary_emb_base", self.default_theta))
-        self.rope_parameters["partial_rotary_factor"] = kwargs.pop("rotary_pct", 0.25)
+        self.rope_parameters.setdefault("partial_rotary_factor", kwargs.pop("rotary_pct", 0.25))
         self.standardize_rope_params()
         return kwargs
 

filename: src/transformers/models/gpt_neox_japanese/configuration_gpt_neox_japanese.py
patch: @@ -72,7 +72,7 @@ def convert_rope_params_to_dict(self, **kwargs):
         # Standardize and validate the correctness of rotary position embeddings parameters
         # Model uses non-standard naming for rope params, overwrite!
         self.rope_parameters.setdefault("rope_theta", kwargs.pop("rotary_emb_base", self.default_theta))
-        self.rope_parameters["partial_rotary_factor"] = kwargs.pop("rotary_pct", 1.0)
+        self.rope_parameters.setdefault("partial_rotary_factor", kwargs.pop("rotary_pct", 1.0))
         self.standardize_rope_params()
         return kwargs