pub struct RopeFreqs {
pub full: Vec<f32>,
pub swa: Option<Vec<f32>>,
}Expand description
The resolved per-band RoPE divisors, for BOTH kinds of layer.
llama.cpp splits RoPE per layer in two places, not one:
// src/llama-model.cpp:2029-2035
float llama_model::get_rope_freq_base (const llama_cparams & cparams, int il) const {
return hparams.is_swa(il) ? hparams.rope_freq_base_train_swa : cparams.rope_freq_base;
}
float llama_model::get_rope_freq_scale(const llama_cparams & cparams, int il) const {
return hparams.is_swa(il) ? hparams.rope_freq_scale_train_swa : cparams.rope_freq_scale;
}and every alternating-SWA graph calls both, per layer
(gemma3.cpp:112-121, gemma2.cpp:79-80, laguna.cpp:182-183).
ferrox folds llama.cpp’s freq_scale into these divisors – linear
scaling by s is exactly “divide every band by s” – so the SCALE
half of that split has to live here, beside the BASE half in
ModelConfig::rope_theta_swa.
It did not, and Gemma-3 4B/12B/27B paid for it: their headers declare
rope.scaling.type = linear, factor = 8, gemma3.cpp never assigns
rope_freq_scale_train_swa so it keeps its 1.0f default
(src/llama-hparams.h:129), and five layers in every six are sliding
(sliding_window_pattern = 6, last-dense). ferrox rotated all of
them at p/8 where llama.cpp rotates at p – fluent, and worse the
longer the prompt. Invisible to the audit because the fixture is
Gemma-3-1B, the one size with no rope_scaling at all.
The two fields are one struct so that answering the base question without answering the scale question does not compile.
Fields§
§full: Vec<f32>What the FULL-ATTENTION layers divide each band’s theta by.
swa: Option<Vec<f32>>What the SLIDING layers divide by, when the architecture does not
let them inherit the model’s trained RoPE scale
(capability::swa_rope_scale_follows_model). None means they
inherit Self::full, which is llama.cpp’s behaviour for every
architecture that assigns rope_freq_scale_train_swa from
rope_freq_scale_train.
“No divisors at all” is spelled as an all-ones vector rather than a third state: dividing by one is exactly not dividing, and one fewer state is one fewer thing two call sites can disagree about.
Implementations§
Trait Implementations§
impl StructuralPartialEq for RopeFreqs
Auto Trait Implementations§
impl Freeze for RopeFreqs
impl RefUnwindSafe for RopeFreqs
impl Send for RopeFreqs
impl Sync for RopeFreqs
impl Unpin for RopeFreqs
impl UnsafeUnpin for RopeFreqs
impl UnwindSafe for RopeFreqs
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more