Part of Language AI Handbook
Explains how Position Interpolation extends transformer context windows by scaling position indices to stay within training distributions.
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Position Interpolation
Modern language models face a fundamental tension: training on long sequences is expensive, but real-world applications demand them. A model trained on 2,048 tokens might encounter documents with 8,000 tokens, conversations spanning 16,000 tokens, or codebases requiring even longer context. When RoPE-based models try to process positions beyond their training range, performance degrades rapidly. The rotation angles reach values the model has never seen, producing attention patterns that bear no resemblance to what was learned.
To appreciate why this is such a thorny problem, recall how Rotary Position Embeddings work. RoPE encodes position information directly into the query and key vectors by rotating them. Each dimension pair in the embedding vector rotates at a characteristic frequency, and the interaction between two positions during attention is determined by the relative rotation between those dimension pairs. The model learns, during pretraining, which relative rotation patterns correspond to meaningful positional relationships. Positions that are two tokens apart produce one rotation pattern; positions that are fifty tokens apart produce another. These learned associations are what allow the model to understand that "the dog chased the cat" has a different meaning than "the cat chased the dog," even when both sentences contain the same words.
The problem is that this learned mapping is bounded. A model trained on sequences up to 2,048 tokens never encounters position 3,000, or 5,000, or 8,000. The rotation angles at those positions fall entirely outside the training distribution. The model has no principled way to interpret them. In the best case, performance degrades gracefully. In the worst case, the attention mechanism produces completely incoherent patterns, essentially treating every token as equally relevant (or irrelevant) to every other token regardless of distance.
Position Interpolation, introduced by Chen et al. in 2023, offers an elegant solution: instead of extrapolating to unseen positions, we interpolate within the familiar range. Rather than assigning position 4,096 a rotation angle the model has never encountered, we scale all positions down so they fit within the original training range. Position 4,096 becomes position 2,048 after scaling, and the model sees familiar rotation angles even as it processes longer sequences.
The key insight is that interpolation is a much more forgiving operation for neural networks than extrapolation. When you ask a model to evaluate a rotation angle it has seen during training, it can use everything it learned. When you ask it to evaluate a rotation angle it has never seen, it must generalize beyond its experience. Neural networks are notoriously good at the former and notoriously unreliable at the latter. Position Interpolation trades one well-defined problem (out-of-distribution angles) for a different, more tractable one (compressed angular resolution).
This chapter develops Position Interpolation from first principles. We'll start by understanding why RoPE fails at extrapolation, derive the interpolation formula, implement it in code, and explore its limitations. By the end, you'll understand both the elegance of this approach and why subsequent methods like NTK-aware scaling were developed to address its shortcomings.
The Extrapolation Problem
Before we can appreciate the solution, we need to understand the failure mode in precise terms. The extrapolation problem is not just that "big numbers are bad." It arises from a specific mismatch between what the model learned and what it is asked to do, and the details of that mismatch matter for understanding why Position Interpolation works.
RoPE encodes position through rotation. At position , each dimension pair of the query and key vectors is rotated by an angle proportional to . The key idea is that each dimension pair rotates at a different frequency, creating a unique positional signature. Think of it as a clock with many hands, each ticking at a different speed. The pattern formed by the positions of all the hands at a given moment encodes the current "time" (position). Two different positions will have two different hand configurations. The rotation angle for dimension pair at position is computed as:
where:
- : the rotation angle (in radians) applied to dimension pair at sequence position
- : the position index in the sequence (0, 1, 2, ..., for a sequence of length )
- : the dimension pair index (0, 1, 2, ..., )
- : the total embedding dimension (typically 64, 128, or larger)
- : a constant that controls the range of frequencies (typically 10000)
- : the base frequency for dimension pair , which decreases exponentially as increases
The exponential decay in the base frequency means that dimension pair 0 rotates fastest (with radian per position), while higher-indexed pairs rotate progressively slower. This creates a multi-scale representation where different dimension pairs capture positional information at different granularities. The fastest dimension pairs complete a full rotation every few positions, making them sensitive to fine-grained local position distinctions. The slowest dimension pairs complete a rotation only after tens of thousands of positions, making them sensitive to coarse global structure. Together, they form a rich positional encoding that the transformer can read like a coordinate system.
Notice that the angular resolution of this coordinate system is calibrated to the training sequence length. The frequencies were chosen (using the base of 10,000) so that the full spectrum of rotation patterns fits comfortably within the context window. When you push beyond that window, you are not just asking the model to handle new numbers. You are asking it to interpret rotation patterns that were never part of the coordinate system it was trained to read.

During training on sequences of length , the model sees positions . The rotation angles range from 0 to for each dimension pair. Every pattern the model has learned to interpret lies somewhere in this bounded space.
What happens when we present the model with position ? The rotation angle exceeds anything seen during training. For the fastest-rotating dimensions (where is large), these new angles produce embedding rotations the attention mechanism has never learned to interpret. In practice, this means that when a token at position 3,000 tries to attend to a token at position 100, the relative rotation computed from those positions falls entirely outside what the model learned during training. The attention score becomes meaningless, not because the model cannot compute a number, but because the number it computes carries no learned meaning.
Let's visualize this problem by examining the rotation angles at different positions.
import numpy as np
def compute_rope_angles(positions, d_model=64, base=10000):
"""Compute RoPE rotation angles for given positions.
Args:
positions: Array of position indices
d_model: Embedding dimension
base: Base for frequency computation
Returns:
angles: Array of shape (len(positions), d_model/2)
"""
# Compute frequencies for each dimension pair
dim_pairs = d_model // 2
i = np.arange(dim_pairs)
theta = 1.0 / (base ** (2 * i / d_model))
# Compute angles: outer product of positions and frequencies
positions = np.array(positions)
angles = np.outer(positions, theta)
return angles
# Training range: positions 0 to 2047 (2K context)
train_length = 2048
train_positions = np.arange(train_length)
train_angles = compute_rope_angles(train_positions)
# Extended range: positions 0 to 8191 (4x context)
extended_length = 8192
extended_positions = np.arange(extended_length)
extended_angles = compute_rope_angles(extended_positions)
# Find maximum angles seen during training vs extension
max_train_angles = train_angles[-1] # Angles at position 2047
max_extended_angles = extended_angles[-1] # Angles at position 8191Maximum rotation angles by dimension pair (radians): -------------------------------------------------- Pair Training (pos 2047) Extended (pos 8191) -------------------------------------------------- 0 2047.00 8191.00 1 1535.03 6142.38 2 1151.11 4606.14 3 863.21 3454.12 31 0.27 1.09
For the fastest-rotating dimension pair (pair 0), the model sees angles up to about 2,047 radians during training. Extending to 4x the context pushes this to over 8,000 radians. While both values wrap around the unit circle many times, the relative patterns between dimension pairs change in ways the model hasn't learned.
The real problem becomes clear when we examine what happens to attention patterns. During training, the model learns that certain rotation angle combinations correspond to meaningful relative positions. When extrapolated angles produce unfamiliar combinations, the learned attention patterns break down.

The plot reveals the core issue. Fast-rotating dimensions (low indices) experience dramatic angle increases during extrapolation. The angle at position 8191 for dimension pair 0 is four times larger than at position 2047. Meanwhile, slow-rotating dimensions (high indices) barely change. This asymmetric behavior disrupts the carefully balanced patterns the model learned during training.
The asymmetry matters for an important reason. The fast-rotating dimensions are responsible for distinguishing nearby positions, the very cases where the model most needs accurate positional information. When a model must determine whether a pronoun refers to the noun in the immediately preceding clause versus the one three sentences earlier, it relies on high-frequency positional signals. Those are exactly the signals that break under extrapolation. The slow-rotating dimensions, which encode coarse global position, remain more stable but are not sufficient on their own.
The Interpolation Insight
We've seen that extrapolation fails because the model encounters rotation angles outside its training distribution. But what if we could ensure that every position, no matter how far into the extended sequence, produces angles the model has already seen? This is the core intuition behind Position Interpolation.
The key insight is deceptively simple: the model does not care about absolute positions. It cares about rotation patterns. If we can arrange for every position in the extended sequence to produce a rotation pattern that falls within the training distribution, the model can apply what it learned even on longer sequences. We achieve this by scaling positions down rather than letting them grow without bound.
From Intuition to Formulation
Think of the training range as a ruler with marks at integer positions from 0 to 2,047. During training, the model learned to interpret positions at every mark on this ruler. Now we have a longer sequence with 8,192 tokens. We need to assign each token a position, and we want every position to fall on the original ruler. The solution is not to build a longer ruler; it is to compress the new tokens so they all fit within the existing ruler's range. We can imagine each position being lightly etched between the existing marks, creating a finer-grained version of the original scale. The marks are denser, but they all fall within the same range the model already knows.
If we want to process a sequence of length where , we define a scale factor that maps the extended range back to the familiar one:
where:
- : the scale factor, always between 0 and 1 when extending context
- : the maximum sequence length seen during training (e.g., 2048)
- : the target extended sequence length (e.g., 8192)
This scale factor answers the question: "How much do we need to shrink the extended positions to fit them within the training range?" For a 4x extension (2K to 8K), , meaning every position is compressed to one-quarter of its original value.
Position Mapping in Action
Let's trace through concrete examples to see how this mapping works. For a model trained on 2,048 positions processing an 8,192-token sequence:
| Actual Position | Scaled Position () | Interpretation |
|---|---|---|
| 0 | 0 | Start of sequence, unchanged |
| 2,048 | 512 | Maps to quarter of training range |
| 4,096 | 1,024 | Maps to midpoint of training range |
| 8,191 | 2,047.75 | Maps to end of training range |
Every position in the extended sequence, no matter how large, maps to a value the model encountered during training. Position 8,191 in the extended sequence produces the same rotation pattern as position 2,047 would in the original system. The endpoint of the 8K sequence is treated the same as the endpoint of the 2K training window. Everything in between is compressed proportionally.
Position Interpolation scales position indices by a factor before computing RoPE rotation angles. This keeps all rotation angles within the range seen during training, trading extrapolation for interpolation.
In practice, this means that neighboring tokens in a very long context window are closer together in "position space" than they would be in a shorter sequence. The model must learn, through fine-tuning, that a small angular difference now represents a larger actual distance. This is a much easier learning problem than generalizing to entirely unseen rotation patterns. You are adjusting the calibration of a known instrument rather than inventing a new one from scratch.
When LLaMA was released in early 2023, its 2,048-token context window felt limiting for serious document-processing tasks. A typical academic paper, legal contract, or book chapter often exceeds this limit. Several approaches competed to extend it. YaRN (Yet another RoPE extensioN) and ALiBi each offered different strategies. Position Interpolation, published by Chen et al. at Meta AI in June 2023, was notable for its simplicity and the efficiency of its fine-tuning recipe: roughly 1,000 gradient steps on long-context data, compared to the billions of tokens required for full pretraining. Its analysis of the frequency spectrum degradation also laid the conceptual groundwork for NTK-aware scaling, which improved upon it within months. The rapid progression from 2K to 32K to 100K+ context lengths in 2023 was enabled largely by these interpolation-based techniques.
Deriving the Modified RoPE Formula
Now we can formalize this intuition mathematically. The derivation proceeds in three steps, each building naturally on the previous. The goal is to arrive at a modified formula that takes an actual position in the extended sequence and returns a rotation angle that falls within the range the model saw during training.
Step 1: Recall the original RoPE rotation angle.
In standard RoPE, the rotation angle for dimension pair at position is simply the product of position and base frequency:
where is the base frequency for dimension pair . This formula produces angles that grow linearly with position, which is exactly the behavior that causes extrapolation to fail when exceeds the training range.
Step 2: Apply position scaling to compress the range.
Position Interpolation modifies this formula by scaling the position index before computing the rotation. Instead of using directly, we use :
We can rearrange this expression to reveal an important insight:
where:
- : the position-interpolated rotation angle for dimension pair at position
- : the actual position in the extended sequence
- : the scale factor ()
- : the original base frequency for dimension pair
The rearrangement shows two equivalent interpretations of Position Interpolation:
- Scale the position: Compute angles for position using original frequencies
- Scale the frequency: Compute angles for position using reduced frequencies
Both perspectives lead to the same result, but the second interpretation proves useful for implementation.
Step 3: Express as modified base frequency.
Let's push the algebraic manipulation further to see what Position Interpolation does to the effective RoPE base:
We can factor out the scale to express this in terms of a modified base:
This reveals that Position Interpolation is mathematically equivalent to using a larger effective base:
For extending from 2K to 8K context (), the effective base becomes . Why does a larger base help? Recall that the base frequency is . A larger base produces smaller frequencies, which means slower rotations for all dimension pairs. Slower rotations let us fit more positions into the same angular range before exceeding the training maximum.
Connecting Math to Mechanism
The mathematical derivation reveals something elegant: Position Interpolation doesn't change the fundamental structure of RoPE. It doesn't add new components or modify the attention mechanism. It simply asks: "What if we used a different base constant from the start?" The answer is that a larger base would have allowed longer sequences all along, but at the cost of reduced angular resolution between nearby positions.
This insight also explains why fine-tuning is necessary. The model learned to associate certain rotation patterns with certain relative distances. When we compress positions, those associations break. A distance of 100 positions now produces the same rotation pattern as 25 positions would have during training. Fine-tuning recalibrates these associations.
Notice that this is a rather gentle disruption. The model already knows how to process relative distances of 0 to 2,047. After Position Interpolation, a distance of 8,191 compresses to 2,047. A distance of 4,096 compresses to 1,024. The relative ordering of all positions is preserved. No two distinct positions are mapped to the same effective position (the mapping is injective). The only change is that the "units" of the positional coordinate system have been rescaled by a factor of four. Fine-tuning teaches the model that the rescaled units are still meaningful, just on a different scale.
Think of it like switching from measuring distances in meters to measuring them in kilometers. All the same relationships hold; the numbers are just four times smaller. A person who knows that 100 meters is a short sprint can quickly adapt to understanding that 0.1 kilometers is also a short sprint. The positional geometry is preserved; only the units change.
A Worked Example
Before writing code, let's work through a concrete numerical example to solidify the concept. This will make the subsequent implementation much easier to follow.
Suppose we have a model with (two dimension pairs, which is unrealistically small but easy to trace), , trained on sequences up to positions. We now want to process a sequence of positions.
The scale factor is:
The base frequencies for our two dimension pairs ( and with ) are:
Now consider position in the extended sequence. Under standard RoPE (no interpolation), the rotation angles would be:
- Dimension pair 0: radians
- Dimension pair 1: radians
The training maximum (at position 7) was:
- Dimension pair 0: radians
- Dimension pair 1: radians
Position 12 exceeds the training maximum for both dimension pairs. The fast-rotating dimension pair 0 is especially far outside the training range (12.0 vs 7.0 radians).
Under Position Interpolation, we scale the position first: . The rotation angles become:
- Dimension pair 0: radians (within training max of 7.0)
- Dimension pair 1: radians (within training max of 0.07)
Both angles now fall within the range the model saw during training. The model can apply its learned interpretation of these rotation patterns to process what is effectively a mid-sequence position. The trade-off is that position 12 in the extended sequence "feels like" position 6 in the original sequence, meaning the model perceives it as occupying roughly the middle of the context rather than three-quarters of the way through. Fine-tuning corrects this calibration.

Implementing Position Interpolation
With the mathematical foundation in place, let's translate Position Interpolation into code. The implementation is remarkably simple: we compute the scale factor, multiply positions by that factor, and then proceed with standard RoPE angle computation.
Computing Interpolated Angles
The core function takes positions along with both the training and target lengths. It computes the scale factor internally, scales all positions, and returns angles that stay within the training range.
def compute_interpolated_angles(
positions, d_model=64, base=10000, train_length=2048, target_length=8192
):
"""Compute position-interpolated RoPE angles.
Args:
positions: Array of position indices
d_model: Embedding dimension
base: Base for frequency computation
train_length: Maximum position seen during training
target_length: Target extended context length
Returns:
angles: Array of shape (len(positions), d_model/2)
"""
# Compute scale factor
scale = train_length / target_length
# Scale positions
positions = np.array(positions)
scaled_positions = positions * scale
# Compute frequencies (unchanged from original RoPE)
dim_pairs = d_model // 2
i = np.arange(dim_pairs)
theta = 1.0 / (base ** (2 * i / d_model))
# Compute angles with scaled positions
angles = np.outer(scaled_positions, theta)
return angles, scale
# Compute interpolated angles for the extended range
interp_angles, scale = compute_interpolated_angles(
extended_positions, train_length=train_length, target_length=extended_length
)Verifying the Angle Bounds
The critical test: do the interpolated angles at the maximum extended position match the training maximum? Let's compare the angles at position 8191 across three methods.
Scale factor: 0.2500 Maximum angles comparison at position 8191: ------------------------------------------------------------ Method Pair 0 Pair 15 Pair 31 ------------------------------------------------------------ Original RoPE 8191.00 109.2287 1.092287 Position Interpolation 2047.75 27.3072 0.273072 Training max (pos 2047) 2047.00 27.2972 0.272972
The results confirm our mathematical derivation. With Position Interpolation, the maximum angles at position 8191 match the training maximum at position 2047 across all dimension pairs. Original RoPE would produce angles 4x larger at the extended position, but Position Interpolation compresses them back into the familiar range.
This verification step is important because it rules out subtle numerical errors. The interpolated angles should match the training maximum within floating-point precision. If they don't, it indicates a bug in the scale factor computation or the position scaling logic.
Let's visualize this comparison as a heatmap to see the pattern across all dimension pairs simultaneously.

The heatmap makes the difference visually striking. The top row shows the intense "heat" of original RoPE's extrapolated angles, especially in the fast-rotating dimensions on the left. Position Interpolation (middle row) shows the same pattern as the training maximum (bottom row), confirming that we've successfully mapped extended positions back into familiar territory.
Visualizing the Position Mapping
Let's visualize this compression graphically. The plot below shows how actual positions in the extended sequence map to effective positions for RoPE computation.

Interpolation vs Extrapolation: A Closer Look
Why does interpolation work better than extrapolation? The answer lies in how neural networks generalize. During training, the model learns attention patterns for rotation angles in a specific range. These learned patterns form a continuous function over that range.
When we extrapolate, we ask the model to generalize this function to inputs it has never seen. Neural networks are notoriously poor at extrapolation; they often produce arbitrary outputs outside their training distribution. This is not a failure of the specific model; it is a fundamental property of function approximators trained with finite data. The model's learned function is essentially undefined outside the convex hull of its training inputs, and there is no reason to expect it to behave sensibly there.
When we interpolate, we stay within the training distribution but query it at finer-grained positions. The model can use its learned continuous representations to handle intermediate values. This works because neural network functions are typically smooth within the training region. They do not suddenly develop sharp discontinuities or erratic behavior between two neighboring training points. An interpolated position between two training positions is handled gracefully by the smooth learned function.
Consider an analogy. Imagine training someone to recognize temperatures between 0°C and 100°C, using only integer values. If you then ask them about 200°C, they must extrapolate beyond their experience, and their predictions become unreliable. They have no basis for judgment. But if you ask about 37.5°C, they can interpolate from their knowledge of 37°C and 38°C. The intermediate value lies in a region they understand, and their estimate will be close to correct because temperature perception is continuous.
The same principle applies to rotation angles. The model's attention mechanism is a smooth function of rotation angles within the training range. Interpolated positions produce rotation angles that lie between training values, and the model's smooth learned function handles them well. Extrapolated positions produce angles beyond the training range, where the function is unpredictable.
Let's quantify this by examining how the angle differences (which determine attention scores) change under interpolation.
def compute_relative_angles(positions, d_model=64, base=10000, scale=1.0):
"""Compute relative rotation angles between consecutive positions.
Args:
positions: Array of position indices
d_model: Embedding dimension
base: Base for frequency computation
scale: Position scale factor (1.0 for standard RoPE)
Returns:
relative_angles: Angle difference between position m and m-1
"""
positions = np.array(positions) * scale
dim_pairs = d_model // 2
i = np.arange(dim_pairs)
theta = 1.0 / (base ** (2 * i / d_model))
# Relative angle is just theta * scale (constant for all positions)
relative_angles = theta * scale
return relative_angles
# Compare relative angles for standard RoPE vs interpolated
standard_relative = compute_relative_angles(extended_positions, scale=1.0)
interpolated_relative = compute_relative_angles(extended_positions, scale=scale)Rotation angle per position step (radians): ------------------------------------------------------- Pair Standard RoPE Position Interpolation ------------------------------------------------------- 0 1.000000 0.250000 1 0.749894 0.187474 2 0.562341 0.140585 15 0.013335 0.003334 31 0.000133 0.000033
The relative angle per position step shrinks with interpolation. In standard RoPE, moving one position rotates dimension pair 0 by 1 radian. With 4x interpolation, the same step rotates by only 0.25 radians. This compression is the trade-off at the heart of Position Interpolation: we maintain familiar absolute angles but reduce the angular resolution between nearby positions.
The reduction in relative angle is uniform across all dimension pairs. Every frequency is scaled by the same factor . This uniformity is both Position Interpolation's strength and its weakness. It is a strength because it is simple, easy to implement, and easy to analyze. It is a weakness because different frequencies have different sensitivities to this scaling. The high-frequency dimensions, which originally distinguished positions that are just a few tokens apart, now must make do with one-quarter of their original angular resolution. The low-frequency dimensions, which already had coarse resolution, are relatively unaffected because they were not being used for fine-grained discrimination in the first place.

Fine-tuning for Extended Context
Position Interpolation alone doesn't magically enable long context. While the rotation angles stay within the training distribution, the model still encounters unfamiliar situations. Two tokens that were 100 positions apart during training now produce the same relative rotation as tokens 400 positions apart in the extended sequence. The model must learn to interpret these compressed position signals.
This recalibration is the heart of what fine-tuning accomplishes. Before fine-tuning, the model has a deeply ingrained prior: a rotation difference of means that the two tokens are a certain distance apart. That prior was learned from billions of training examples where a relative rotation of, say, 0.25 radians in dimension pair 0 always indicated that the tokens were separated by about one position. After Position Interpolation, that same rotation difference now indicates a separation of about four positions. The model's prior is wrong, and without correction, it produces suboptimal attention patterns.
This is where fine-tuning comes in. After applying Position Interpolation, models typically undergo a short fine-tuning phase on long-context data. The good news: this fine-tuning is remarkably efficient. Chen et al. found that only about 1,000 fine-tuning steps were needed to adapt a 2K-context LLaMA model to 8K context, compared to the billions of tokens used in original pretraining.
Why does the fine-tuning converge so quickly? Several factors contribute. First, the basic capability to model language, understand syntax, and reason about text is entirely preserved. The model does not need to relearn how language works; it just needs to relearn the scale of its positional coordinate system. Second, all rotation angles remain within the training distribution, meaning the model's existing representations are never completely invalidated. They are being recalibrated, not rebuilt. Third, the mapping from old positions to new positions is simple and consistent: a uniform linear scaling. Once the model grasps this scaling, it can generalize across all positions in the extended sequence.
In practice, long-context fine-tuning data does not need to be task-specific. A diverse mix of long documents, ranging from books and articles to code and conversations, is sufficient for the model to recalibrate its positional understanding. The training objective can be the same standard next-token prediction used in pretraining.
Position Interpolation requires fine-tuning to achieve good performance. Without fine-tuning, the model may produce coherent outputs at the new context length, but perplexity typically increases. The fine-tuning phase teaches the model to interpret the compressed position signals correctly.
The amount of fine-tuning required scales with the context extension factor. Extending by 2x (e.g., 2K to 4K) typically requires only a few hundred fine-tuning steps and causes minimal degradation in the model's existing capabilities. Extending by 4x (2K to 8K) requires roughly 1,000 steps. Extending by 8x or more requires proportionally more fine-tuning and tends to produce greater degradation in short-context performance, because the positional compression forces the model to sacrifice local resolution. For production deployments, 4x extension is generally considered the practical limit for Position Interpolation without significant quality loss. Beyond 4x, NTK-aware scaling or YaRN-style methods tend to outperform plain Position Interpolation.
Let's simulate what fine-tuning might need to correct by examining how attention patterns change under interpolation.
def simulate_attention_decay(distances, d_model=64, base=10000, scale=1.0):
"""Simulate how attention might decay with distance.
This is a simplified model showing how rotation angle magnitudes
change with position distance, affecting attention patterns.
Args:
distances: Array of position distances
d_model: Embedding dimension
base: Base for frequency computation
scale: Position scale factor
Returns:
decay_scores: Simulated attention decay (not actual attention)
"""
distances = np.array(distances) * scale
dim_pairs = d_model // 2
i = np.arange(dim_pairs)
theta = 1.0 / (base ** (2 * i / d_model))
# Total rotation magnitude for each distance
angles = np.outer(distances, theta)
# Simulate decay based on angle variance across dimensions
# (This is illustrative, not actual attention computation)
angle_variance = np.var(angles, axis=1)
return angle_variance
distances = np.arange(1, 4097)
standard_decay = simulate_attention_decay(distances, scale=1.0)
interp_decay = simulate_attention_decay(distances, scale=0.25)

The plots illustrate the core transformation. With Position Interpolation, a distance of 4,096 positions produces the same rotation angle pattern as a distance of 1,024 positions in standard RoPE. Fine-tuning teaches the model that this compressed pattern now represents the longer distance.
The second plot also reveals something subtle: at very short distances (the first few hundred positions), the interpolated angle variance closely tracks the standard RoPE curve. This is because short distances already produced small angles in standard RoPE, and compressing them by 4x still leaves them small. The model's short-range attention patterns are least disrupted by Position Interpolation. The most significant disruption occurs at distances approaching the training context limit, where standard RoPE produces its largest relative angles and Position Interpolation compresses them the most.
A Complete Implementation
Let's put everything together into a complete Position Interpolation implementation that can be applied to RoPE. The class below combines all the pieces we've developed: scale factor computation, position scaling, frequency precomputation, and rotation matrix construction. Understanding this implementation end-to-end is valuable because production implementations in frameworks like Hugging Face Transformers follow exactly the same logic, just with additional optimizations for batched computation on GPU hardware.
class RoPEWithPositionInterpolation:
"""RoPE implementation with Position Interpolation support."""
def __init__(
self, d_model, base=10000, train_length=2048, target_length=None
):
"""Initialize RoPE with optional Position Interpolation.
Args:
d_model: Embedding dimension (must be even)
base: Base for frequency computation
train_length: Maximum position seen during training
target_length: Extended context length (None = no interpolation)
"""
if d_model % 2 != 0:
raise ValueError("d_model must be even for RoPE")
self.d_model = d_model
self.base = base
self.train_length = train_length
# Compute scale factor for Position Interpolation
if target_length is not None and target_length > train_length:
self.scale = train_length / target_length
else:
self.scale = 1.0
# Precompute frequencies
dim_pairs = d_model // 2
i = np.arange(dim_pairs)
self.theta = 1.0 / (base ** (2 * i / d_model))
def get_rotation_matrix(self, position):
"""Get the block-diagonal rotation matrix for a position.
Args:
position: Integer position index
Returns:
R: Rotation matrix of shape (d_model, d_model)
"""
# Apply position scaling
scaled_pos = position * self.scale
# Compute angles for each dimension pair
angles = scaled_pos * self.theta
# Build block-diagonal rotation matrix
R = np.zeros((self.d_model, self.d_model))
for i, angle in enumerate(angles):
cos_a, sin_a = np.cos(angle), np.sin(angle)
idx = 2 * i
R[idx, idx] = cos_a
R[idx, idx + 1] = -sin_a
R[idx + 1, idx] = sin_a
R[idx + 1, idx + 1] = cos_a
return R
def apply(self, x, positions):
"""Apply RoPE to input vectors.
Args:
x: Input array of shape (seq_len, d_model)
positions: Position indices for each element
Returns:
rotated: Rotated vectors of shape (seq_len, d_model)
"""
seq_len = x.shape[0]
rotated = np.zeros_like(x)
for i, pos in enumerate(positions):
R = self.get_rotation_matrix(pos)
rotated[i] = R @ x[i]
return rotatedThe implementation's most important property is that it falls back to standard RoPE when no target length is specified or when the target length is within the training limit. This makes it a drop-in replacement that adds zero overhead for standard use cases.
Let's verify that our implementation produces the expected behavior.
# Create instances with and without interpolation
rope_standard = RoPEWithPositionInterpolation(d_model=64, train_length=2048)
rope_interpolated = RoPEWithPositionInterpolation(
d_model=64, train_length=2048, target_length=8192
)
# Test on a sample vector at an extended position. The hidden setup cell seeds
# the chapter once so all render variants stay deterministic.
test_vector = np.random.randn(64)
test_position = 6000 # Beyond training range
# Get rotation matrices
R_standard = rope_standard.get_rotation_matrix(test_position)
R_interpolated = rope_interpolated.get_rotation_matrix(test_position)
R_training_equiv = rope_standard.get_rotation_matrix(test_position * 0.25)Testing at position 6000 (training limit: 2048) Interpolation scale factor: 0.25 Rotation matrix diagonal (cos of angles) for first 5 dimension pairs: ---------------------------------------------------------------------- Pair Standard Interpolated Training Equiv ---------------------------------------------------------------------- 0 0.903912 -0.110267 -0.110267 1 0.822743 0.988599 0.988599 2 0.999746 0.005640 0.005640 3 -0.365213 -0.467238 -0.467238 4 0.987955 -0.999246 -0.999246 Note: 'Interpolated' and 'Training Equiv' columns should match, since position 6000 × 0.25 = 1500.0
The interpolated rotation matrix at position 6,000 matches the standard rotation matrix at position 1,500, confirming that our implementation correctly maps extended positions back to the training range.
The "Training Equiv" column in the output is computed by scaling position 6,000 by 0.25 to get 1,500, then applying standard RoPE. The "Interpolated" column applies Position Interpolation directly. They should be identical up to floating-point precision. This equivalence provides a sanity check and the mathematical guarantee that Position Interpolation delivers: every position in the extended sequence is handled exactly as if it were a proportionally smaller position in the original system.
Limitations of Position Interpolation
Position Interpolation enables longer context, but it comes with trade-offs. Understanding these limitations helps explain why subsequent methods like NTK-aware scaling were developed. This is not a criticism of Position Interpolation; every technique has a regime where it works well and a regime where it struggles. Knowing the boundaries helps you choose the right tool for each situation.
Reduced positional resolution. The most significant limitation is reduced angular resolution between nearby positions. When we compress 8,192 positions into the range of 2,048, each position step produces 1/4 the rotation of the original. Two tokens that are adjacent in the extended sequence differ by the same rotation as tokens 0.25 positions apart in the original. This compression can make it harder for the model to distinguish nearby positions, potentially affecting tasks requiring fine-grained positional awareness. Tasks like coreference resolution (determining which pronoun refers to which noun), syntactic dependency parsing, and named entity recognition all benefit from accurate local position signals. These may degrade with aggressive context extension via Position Interpolation.
# Compute the effective position resolution
def compute_position_resolution(scale, d_model=64, base=10000):
"""Compute the angular resolution between adjacent positions.
Returns the minimum angle difference that can distinguish
two adjacent positions.
"""
dim_pairs = d_model // 2
i = np.arange(dim_pairs)
theta = 1.0 / (base ** (2 * i / d_model))
# Resolution is the angle per position step after scaling
resolution = theta * scale
return resolution
# Compare resolution at different extension factors
extension_factors = [1, 2, 4, 8, 16]
resolutions = []
for factor in extension_factors:
scale = 1.0 / factor
res = compute_position_resolution(scale)
resolutions.append(res)
Non-uniform frequency scaling. Position Interpolation applies the same scale factor to all frequency components. However, different frequencies may require different treatment. High-frequency components (fast-rotating dimensions) are most affected by the reduced resolution because they distinguish local positions. Low-frequency components (slow-rotating dimensions) were already coarse and are less impacted. This uniform scaling is suboptimal, which motivated the development of NTK-aware scaling that treats frequencies differently.
The key intuition about frequency-selective treatment is this: the low-frequency dimensions have wavelengths that already exceed the training context length. They were not being used to distinguish individual positions at all; they were encoding coarse global structure. Reducing their frequency further does not materially change their behavior. The high-frequency dimensions, by contrast, were the primary source of precise positional information. Halving or quartering their frequency degrades exactly the information the model relied on most. A smarter approach would apply no scaling (or minimal scaling) to high-frequency dimensions and apply more scaling to low-frequency dimensions. This is the idea behind NTK-aware scaling, which we will explore in the next chapter.
Fine-tuning requirement. While Position Interpolation requires far less fine-tuning than training from scratch, it still requires some adaptation. This limits scenarios where you need to extend context on the fly without access to fine-tuning data or compute. Some applications, particularly in deployment environments with strict latency and cost constraints, cannot afford even a 1,000-step fine-tuning run. For these use cases, methods that can extend context without any fine-tuning are more practical.
Perplexity increase. Even after fine-tuning, models with Position Interpolation often show slightly higher perplexity compared to models trained directly on longer sequences. The compression introduces information loss that fine-tuning can mitigate but not fully eliminate. The perplexity gap widens with larger extension factors. A 2x extension causes minimal perplexity increase. A 4x extension causes a modest increase that fine-tuning largely recovers. Beyond 8x, the perplexity gap can become significant, particularly for text types that rely on fine-grained positional cues.
Recency bias disruption. Many language models develop a recency bias: they attend more strongly to nearby tokens than to distant ones. This bias is often useful because nearby context is usually more relevant. Position Interpolation disrupts this bias in a specific way: the effective "distance" between nearby tokens is reduced by the scale factor. Under 4x compression, two adjacent tokens feel like they are 0.25 positions apart rather than 1 position apart. The model's recency bias may weaken as a result, because the gradient between "near" and "far" tokens becomes less steep. Whether this is harmful depends on the task. For tasks where distant context is important (like question answering over long documents), a flatter recency bias may be helpful.
Let's quantify how different dimension pairs are affected by the uniform scaling.
def analyze_frequency_impact(
train_length=2048, target_length=8192, d_model=64, base=10000
):
"""Analyze how Position Interpolation affects different frequency bands."""
scale = train_length / target_length
dim_pairs = d_model // 2
i = np.arange(dim_pairs)
theta = 1.0 / (base ** (2 * i / d_model))
# Wavelength: positions for one complete rotation
wavelength = 2 * np.pi / theta
# After interpolation, effective wavelength in terms of original positions
effective_wavelength = wavelength / scale
# Categorize by frequency band
high_freq_mask = wavelength < 100
mid_freq_mask = (wavelength >= 100) & (wavelength < 1000)
low_freq_mask = wavelength >= 1000
return {
"wavelength": wavelength,
"effective_wavelength": effective_wavelength,
"theta": theta,
"scaled_theta": theta * scale,
"high_freq": high_freq_mask,
"mid_freq": mid_freq_mask,
"low_freq": low_freq_mask,
}
freq_analysis = analyze_frequency_impact()Frequency Band Analysis: ====================================================================== High frequency (wavelength < 100 positions): 10 dimension pairs Mid frequency (100 ≤ wavelength < 1000): 8 dimension pairs Low frequency (wavelength ≥ 1000): 14 dimension pairs Impact of 4× Position Interpolation: ---------------------------------------------------------------------- High Frequency Band: Original rotation/position: 0.377347 radians Scaled rotation/position: 0.094337 radians Original wavelength: 31.6 positions Effective wavelength: 126.5 positions Mid Frequency Band: Original rotation/position: 0.025295 radians Scaled rotation/position: 0.006324 radians Original wavelength: 376.9 positions Effective wavelength: 1507.5 positions Low Frequency Band: Original rotation/position: 0.001577 radians Scaled rotation/position: 0.000394 radians Original wavelength: 13217.1 positions Effective wavelength: 52868.3 positions
The analysis reveals the asymmetric impact. High-frequency dimension pairs, which originally completed a rotation every 6-50 positions, now require 4x as many positions to complete the same rotation. This directly impairs local position discrimination: the model can no longer tell apart tokens that are 1, 2, or 3 positions away from each other as accurately as it could before. Low-frequency dimension pairs, already operating at wavelengths of thousands of positions, remain capable of distinguishing positions at the extended range, because their wavelengths are still shorter than the new context length.
This analysis is not just theoretical. Empirical results from the original Position Interpolation paper and from subsequent work show that models extended with 4x interpolation perform comparably to their original 2K versions on most benchmarks, with the main degradation appearing on tasks where local syntactic precision matters. The asymmetric frequency impact explains why.

The visualization shows how Position Interpolation uniformly scales all frequencies by the same factor (4x reduction). The vertical lines connecting original (circles) to scaled (squares) values have the same proportional length across all dimension pairs. This uniform treatment is the core limitation that NTK-aware scaling addresses.
From a signal processing perspective, what Position Interpolation does to the frequency spectrum is equivalent to applying a low-pass filter. All frequencies are attenuated by the same multiplicative factor, which is precisely what a pure scaling operation does in the frequency domain. Low-pass filtering preserves coarse structure but loses fine detail, which maps directly onto the observed behavior: long-range dependencies are handled well, but short-range positional precision suffers. NTK-aware scaling, by contrast, applies frequency-selective attenuation, preserving the high-frequency content and attenuating only the frequencies that need adjustment to accommodate the longer context.
Key Parameters
When implementing Position Interpolation, the following parameters control the behavior:
-
train_length: The maximum sequence length the model was originally trained on (e.g., 2048 for LLaMA). This defines the upper bound of positions the model has learned to interpret during pretraining. It is typically documented in the model's configuration file and is not something you change; it is a property of the pretrained model. -
target_length: The extended context length you want to support (e.g., 8192). Must be greater thantrain_lengthfor interpolation to apply. Choosing this value requires thinking about your actual use case: what is the longest document or conversation you expect to encounter? Setting this too large degrades performance at all lengths; setting it too small may leave some inputs truncated. -
scale: Computed astrain_length / target_length. This determines how much to compress positions. A scale of 0.25 means 4x context extension. Smaller scale values enable longer contexts but reduce positional resolution proportionally. You do not set this directly; it is derived from the other two parameters. -
base: The RoPE base constant (typically 10000). Position Interpolation effectively increases this tobase / scale, slowing all rotations uniformly. You normally leave this at the model's default; it only matters if you are experimenting with modified base values. -
d_model: The embedding dimension. Must be even since RoPE operates on dimension pairs. Each pair rotates at a different frequency determined by its index. This is fixed by the model architecture and cannot be changed during inference.
When selecting parameters, consider the trade-off between context length and positional resolution. Extending by 2x is generally safe with minimal fine-tuning. Extensions of 4x-8x work well but require more fine-tuning to recover performance. Extensions beyond 8x may significantly degrade the model's ability to distinguish nearby positions. There is also a practical memory consideration: quadrupling the context length requires roughly quadrupling the memory for the KV cache, assuming standard multi-head attention. Techniques like sliding-window attention or sparse attention can help here, but they are orthogonal to the position encoding question.
Summary
Position Interpolation provides an elegant solution to the context length extension problem. By scaling position indices rather than extrapolating to unseen values, it keeps all rotation angles within the training distribution. The key insights include:
-
Interpolation over extrapolation. Neural networks generalize poorly outside their training distribution. By scaling positions down instead of letting them grow, Position Interpolation stays within familiar territory. The model never sees a rotation angle it wasn't trained to interpret.
-
Simple implementation. The technique requires only a scale factor applied to position indices before computing RoPE. No architectural changes are needed. In terms of code, it is literally one multiplication.
-
Equivalent to base scaling. Position Interpolation is mathematically equivalent to using a larger RoPE base. A 4x extension from 2K to 8K is the same as using a base of 40,000 instead of 10,000. This equivalence is useful because it connects Position Interpolation to the broader family of scaled-base RoPE methods.
-
Efficient fine-tuning. Adapting a model to extended context requires only about 1,000 fine-tuning steps, orders of magnitude less than original pretraining. This efficiency comes from the fact that the model's general language understanding is preserved; only the positional calibration needs adjustment.
-
Uniform scaling limitation. All frequency components receive the same scaling treatment, which is suboptimal. High-frequency dimensions, which carry local position information, lose the most resolution. This is the most significant practical limitation and the primary motivation for subsequent methods.
Position Interpolation demonstrated that context length is not a fixed property of a pretrained model but rather a parameter that can be extended through lightweight adaptation. This insight was foundational for the wave of long-context models that appeared in 2023 and 2024. It showed that a model trained on 2K tokens could, with minimal effort, process 8K tokens reliably, and that this capability had been latent in the model all along, waiting for the right positional scaling to make it usable.
The limitations of Position Interpolation, particularly its uniform treatment of frequencies, motivated the development of NTK-aware scaling, which we'll explore in the next chapter. That technique applies frequency-dependent scaling, preserving high-frequency components while adjusting low-frequency ones, achieving better performance without sacrificing local positional awareness. Understanding why Position Interpolation falls short at high extension factors is precisely what makes NTK-aware scaling's design choices intuitive.
Quiz
Ready to test your understanding? Take this quick quiz to reinforce what you've learned about Position Interpolation and extending context length in language models.
Position Interpolation Quiz
Reference
Citation details
Cite or share this article.
Continue with the full handbook
This chapter is part of Language AI Handbook. Use the handbook page to browse the complete table of contents and continue reading in sequence.
Explore Language AI HandbookStay up to date
Get articles, book updates, and news delivered to your inbox.
No spam, unsubscribe anytime.
Join the community
Sign in to remove popups, track your reading progress, and join the discussion.

Comments
No comments yet. Be the first to share your thoughts!