@@ -39,6 +39,49 @@ def _maybe_check_max_pos(positions: torch.Tensor, *, max_valid_pos: int) -> None
3939 )
4040
4141
42+ def _yarn_inv_freq (
43+ dim : int ,
44+ base : float ,
45+ rope_factor : float ,
46+ beta_fast : float ,
47+ beta_slow : float ,
48+ original_seq_len : int ,
49+ truncate : bool ,
50+ ) -> torch .Tensor :
51+ """Shared YaRN ("NTK-by-parts") inverse-frequency computation.
52+
53+ Single source of truth for both ``ComplexRoPE`` and ``CosSinRoPE`` so the
54+ two cache formats are guaranteed to agree. Follows the YaRN paper / HF
55+ convention: ``low <- beta_fast`` (extrapolation boundary), ``high <-
56+ beta_slow`` (interpolation boundary). ``truncate`` floors/ceils the cutoffs
57+ (DeepSeek style); ``truncate=False`` keeps fractional cutoffs (gpt-oss
58+ style). The range is always clamped to ``[0, dim/2 - 1]``. The YaRN
59+ attention "mscale" is intentionally NOT applied here -- the rope stays a
60+ pure rotation and the model folds mscale into its softmax scale.
61+ """
62+ inv_freq = 1.0 / (base ** (torch .arange (0 , dim , 2 )[: (dim // 2 )].float () / dim ))
63+
64+ def find_correction_dim (num_rotations : float ) -> float :
65+ return (dim * math .log (original_seq_len / (num_rotations * 2 * math .pi ))) / (
66+ 2 * math .log (base )
67+ )
68+
69+ low = find_correction_dim (beta_fast )
70+ high = find_correction_dim (beta_slow )
71+ if truncate :
72+ low = math .floor (low )
73+ high = math .ceil (high )
74+ low , high = max (low , 0 ), min (high , dim - 1 )
75+ assert (
76+ 0 < low < high < dim - 1
77+ ), f"Invalid YaRN params: 0 < { low } < { high } < { dim - 1 } "
78+
79+ ramp = ((torch .arange (dim // 2 , dtype = torch .float32 ) - low ) / (high - low )).clamp (
80+ 0 , 1
81+ )
82+ return inv_freq / rope_factor * ramp + inv_freq * (1 - ramp )
83+
84+
4285class RoPE (Module ):
4386 """Shared Rotary Position Embedding module.
4487
@@ -63,7 +106,7 @@ class Config(Module.Config):
63106 beta_fast : float = 32.0
64107 beta_slow : float = 1.0
65108 original_seq_len : int = 4096
66- mscale : float = 0.0
109+ truncate : bool = True
67110
68111 def __init__ (self , config : Config ):
69112 super ().__init__ ()
@@ -175,47 +218,15 @@ def _precompute_cache(self) -> torch.Tensor:
175218 freqs = torch .where (is_medium_freqs , smoothed_freqs , freqs )
176219 elif cfg .scaling == "yarn" and end > cfg .original_seq_len :
177220 # YaRN (DeepSeek V3 style)
178- beta_fast = cfg .beta_fast
179- beta_slow = cfg .beta_slow
180- base = theta
181- original_seq_len = cfg .original_seq_len
182- factor = cfg .rope_factor
183-
184- def find_correction_dim (
185- num_rotations : float , dim : int , base : float , max_seq_len : int
186- ) -> float :
187- return (
188- dim
189- * math .log (max_seq_len / (num_rotations * 2 * math .pi ))
190- / (2 * math .log (base ))
191- )
192-
193- def find_correction_range (
194- low_rot : float ,
195- high_rot : float ,
196- dim : int ,
197- base : float ,
198- max_seq_len : int ,
199- ) -> tuple [int , int ]:
200- low = math .floor (find_correction_dim (low_rot , dim , base , max_seq_len ))
201- high = math .ceil (find_correction_dim (high_rot , dim , base , max_seq_len ))
202- return max (low , 0 ), min (high , dim - 1 )
203-
204- def linear_ramp_factor (
205- min_val : float , max_val : float , dim : int
206- ) -> torch .Tensor :
207- if min_val == max_val :
208- max_val += 0.001
209- linear_func = (torch .arange (dim , dtype = torch .float32 ) - min_val ) / (
210- max_val - min_val
211- )
212- return torch .clamp (linear_func , 0 , 1 )
213-
214- low , high = find_correction_range (
215- beta_fast , beta_slow , dim , base , original_seq_len
221+ freqs = _yarn_inv_freq (
222+ dim ,
223+ theta ,
224+ cfg .rope_factor ,
225+ cfg .beta_fast ,
226+ cfg .beta_slow ,
227+ cfg .original_seq_len ,
228+ cfg .truncate ,
216229 )
217- smooth = 1 - linear_ramp_factor (low , high , dim // 2 )
218- freqs = freqs / factor * (1 - smooth ) + freqs * smooth
219230
220231 t = torch .arange (end , device = freqs .device )
221232 freqs = torch .outer (t , freqs ).float ()
@@ -270,48 +281,30 @@ def _precompute_cache(self) -> torch.Tensor:
270281 max_seq_len = cfg .max_seq_len
271282 base = cfg .theta
272283
273- freq = base ** (torch .arange (0 , dim , 2 )[: (dim // 2 )].float () / dim )
274- mscale = 1.0
275-
276284 if cfg .scaling == "llama" :
277285 raise NotImplementedError ("Cos/sin RoPE does not support Llama scaling." )
278286
279287 if cfg .scaling == "yarn" and cfg .rope_factor > 1.0 :
280- rope_factor = cfg .rope_factor
281- # YaRN mscale for attention magnitude preservation
282- mscale = 0.1 * math .log (rope_factor ) + 1.0
283-
284- # Compute correction range (NTK by parts)
285- d_half = dim / 2
286- low = (
287- d_half
288- * math .log (cfg .original_seq_len / (cfg .beta_slow * 2 * math .pi ))
289- / math .log (base )
290- )
291- high = (
292- d_half
293- * math .log (cfg .original_seq_len / (cfg .beta_fast * 2 * math .pi ))
294- / math .log (base )
288+ inv_freq = _yarn_inv_freq (
289+ dim ,
290+ base ,
291+ cfg .rope_factor ,
292+ cfg .beta_fast ,
293+ cfg .beta_slow ,
294+ cfg .original_seq_len ,
295+ cfg .truncate ,
295296 )
296- assert (
297- 0 < low < high < d_half - 1
298- ), f"Invalid YaRN params: 0 < { low } < { high } < { d_half - 1 } "
299-
300- ramp = (torch .arange (d_half , dtype = torch .float32 ) - low ) / (high - low )
301- mask = 1 - ramp .clamp (0 , 1 )
302-
303- interpolation = 1.0 / (rope_factor * freq )
304- extrapolation = 1.0 / freq
305- inv_freq = interpolation * (1 - mask ) + extrapolation * mask
306297 else :
307- inv_freq = 1.0 / freq
298+ inv_freq = 1.0 / (
299+ base ** (torch .arange (0 , dim , 2 )[: (dim // 2 )].float () / dim )
300+ )
308301
309302 t = torch .arange (max_seq_len , dtype = inv_freq .dtype , device = inv_freq .device )
310303 freqs = torch .outer (t , inv_freq ).float ()
311304 theta = torch .cat ([freqs , freqs ], dim = - 1 )
312305
313- cos = theta .cos () * mscale
314- sin = theta .sin () * mscale
306+ cos = theta .cos ()
307+ sin = theta .sin ()
315308 return torch .cat ([cos , sin ], dim = - 1 )
316309
317310 def _reshape_cache (
0 commit comments