LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 158 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/8
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/11
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageClustering and PCACore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/24
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt Injection DefenseResponsible AI GovernanceData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BPrompt Optimization with DSPyModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/8
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned Classifier
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/15
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/19
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning & Test-Time Compute
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
Back to Topics
LearnTransformer Deep DivesPositional Encoding: RoPE & ALiBi
🧠HardTransformer Architecture

Positional Encoding: RoPE & ALiBi

Understand why transformers need position information, how sinusoidal encodings work, how RoPE and ALiBi encode relative position, and why long-context extrapolation needs careful evaluation.

34 min read
Learning path
Step 92 of 158 in the full curriculum
Vision Transformers and Image EncodersLayer Normalization: Pre-LN vs Post-LN

Vision Transformers showed why image patches need position. Text has the same problem: "The model loaded the checkpoint" and "The checkpoint loaded the model" use nearly the same words, but the order changes the meaning.

Self-attention has a surprising blind spot: by itself, it has no built-in notion of "first", "second", or "third" token. If you permute the input sequence, the outputs permute in the same way. This is called permutation equivariance, and it means the model needs a separate signal for where each token sits.

Positional encoding injects word-order information into an architecture that would otherwise be order-blind. The first step is seeing why position information is needed, then comparing the original sinusoidal approach with relative methods such as RoPE and ALiBi for long-context behavior.


The permutation equivariance problem

Self-attention computes:

Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right) VAttention(Q,K,V)=softmax(dk​​QKT​)V

What this equation says

Compare every query with all keys (QKTQK^TQKT), scale by dk\sqrt{d_k}dk​​ (key vector dimension) for stable softmax, convert scores to attention weights, then mix value vectors VVV using those weights.

This unmasked operation is permutation equivariant: if you shuffle the input token order, the output is shuffled in the same way. The attention weights QKTQK^TQKT depend on content, not position.[1]Reference 1Attention Is All You Need.https://arxiv.org/abs/1706.03762

Without positional information, transformers can't distinguish between different word orders, which can completely alter the meaning of a sentence. For example, these two sequences contain identical tokens but have very different semantics. When processed by a position-blind transformer, they produce the same attention pattern up to the same row/column permutation:

text
1"The model loaded the checkpoint" 2"checkpoint the loaded model The"

Meaning depends on word order, so the model needs a source of position information. A causal mask adds directional structure in decoder-only models, and NoPE experiments show that causal language models without explicit position encodings can still learn positional information.[2]Reference 2Transformer Language Models without Positional Encodings Still Learn Positional Information.https://arxiv.org/abs/2203.16634 The mask still provides no explicit coordinate or distance feature, which is why most architectures add or derive a separate position signal.

Permutation trace showing content-only attention shuffling outputs with input token order. Permutation trace showing content-only attention shuffling outputs with input token order.
Self-attention is content-based. Position encodings provide the missing signal for index, direction, and distance.

This tiny attention implementation verifies the property directly. It permutes input rows, recomputes attention, and gets exactly the permuted original output.

permutation-equivariance.py
1import math 2 3tokens = [[1.0, 0.0], [0.0, 1.0], [1.0, 1.0]] 4permutation = [2, 0, 1] 5 6def attention(rows: list[list[float]]) -> list[list[float]]: 7 scores = [ 8 [sum(q_i * k_i for q_i, k_i in zip(q, k)) / math.sqrt(2) for k in rows] 9 for q in rows 10 ] 11 outputs = [] 12 for row in scores: 13 normalizer = sum(math.exp(value) for value in row) 14 weights = [math.exp(value) / normalizer for value in row] 15 outputs.append([ 16 sum(weight * value[column] for weight, value in zip(weights, rows)) 17 for column in range(2) 18 ]) 19 return outputs 20 21baseline = attention(tokens) 22shuffled = attention([tokens[index] for index in permutation]) 23expected = [baseline[index] for index in permutation] 24 25same_output_up_to_permutation = all( 26 abs(actual - target) < 1e-12 27 for actual_row, target_row in zip(shuffled, expected) 28 for actual, target in zip(actual_row, target_row) 29) 30print(same_output_up_to_permutation) 31print([round(row[0], 3) for row in baseline]) 32print([round(row[0], 3) for row in shuffled])
Output
1True 2[0.802, 0.599, 0.752] 3[0.752, 0.802, 0.599]

Three families of solutions

Use this map to place each method before we walk through it step by step.

ApproachHow It WorksModifiesExamples
Absolute (additive)Add position vector to token embeddingEmbeddingsOriginal Transformer, BERT, GPT-2[1]Reference 1Attention Is All You Need.https://arxiv.org/abs/1706.03762[3]Reference 3BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding.https://arxiv.org/abs/1810.04805[4]Reference 4GPT-2 Source Implementation.https://github.com/openai/gpt-2/blob/master/src/model.py
Relative (multiplicative)Rotate Q/K vectors based on positionQ/K projectionsRoFormer, Llama family[5]Reference 5RoFormer: Enhanced Transformer with Rotary Position Embedding.https://arxiv.org/abs/2104.09864[6]Reference 6The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783
Relative (additive bias)Add distance bias to attention logitsAttention scoresALiBi paper[7]Reference 7Train Short, Test Long: Attention with Linear Biases Enables Input Length Generalization.https://arxiv.org/abs/2108.12409

The methods enter the transformer at different points. The three paths below are alternatives, not steps that every model applies together.

Diagram showing Token embedding, Absolute: add position vector, Project Q, K, V, and Projected Q, K. Diagram showing Token embedding, Absolute: add position vector, Project Q, K, V, and Projected Q, K.
Token embedding, Absolute: add position vector, Project Q, K, V, and Projected Q, K.
Three aligned transformer attention pipelines showing absolute position added to embeddings, RoPE rotations applied to projected queries and keys, and ALiBi distance penalties added to attention logits Three aligned transformer attention pipelines showing absolute position added to embeddings, RoPE rotations applied to projected queries and keys, and ALiBi distance penalties added to attention logits
Absolute encodings modify embeddings, RoPE modifies Q/K geometry, and ALiBi modifies attention logits.

Method 1: Sinusoidal positional encoding

The original approach[1]Reference 1Attention Is All You Need.https://arxiv.org/abs/1706.03762

Positional encoding resembles reading a clock. A clock uses multiple hands moving at different speeds (seconds, minutes, hours) to uniquely identify any moment in a 12-hour period. Sinusoidal positional encoding does the same thing for words in a sequence: each position gets a unique "fingerprint" made of sine and cosine waves at different frequencies. Low dimensions oscillate quickly (like seconds), while high dimensions oscillate slowly (like hours).

For position pos\text{pos}pos and dimension iii (where dmodeld_{\text{model}}dmodel​ is the embedding dimension):

PE(pos,2i)=sin⁡(pos100002i/dmodel)PE_{(\text{pos}, 2i)} = \sin\left(\frac{\text{pos}}{10000^{2i/d_{\text{model}}}}\right)PE(pos,2i)​=sin(100002i/dmodel​pos​)

PE(pos,2i+1)=cos⁡(pos100002i/dmodel)PE_{(\text{pos}, 2i+1)} = \cos\left(\frac{\text{pos}}{10000^{2i/d_{\text{model}}}}\right)PE(pos,2i+1)​=cos(100002i/dmodel​pos​)

What the sine and cosine waves mean

The combination of these sine and cosine waves creates a unique pattern for every position. Each pair of dimensions acts like one clock hand spinning at a particular speed. Position 0 starts every hand at 0 or 1. As you move down the sequence, each hand turns a little more, and the exact angle of every hand together forms a fingerprint that no other position shares.

Why sinusoids?

Because PEpos+kPE_{\text{pos}+k}PEpos+k​ can be expressed as a linear function of PEposPE_{\text{pos}}PEpos​:

PEpos+k=Rk⋅PEposPE_{\text{pos}+k} = R_k \cdot PE_{\text{pos}}PEpos+k​=Rk​⋅PEpos​

where RkR_kRk​ is a rotation matrix that depends only on offset kkk, not absolute position. This means the model can, in principle, learn to attend based on relative position.[1]Reference 1Attention Is All You Need.https://arxiv.org/abs/1706.03762

We can generate these multi-frequency sinusoidal positional encodings with plain Python. The function takes the maximum sequence length and embedding dimension as inputs to compute the required frequencies. It returns a table of positional encodings that can be added directly to token embeddings before they enter attention layers.

why-sinusoids.py
1import math 2 3def sinusoidal_positional_encoding( 4 max_len: int, 5 d_model: int, 6) -> list[list[float]]: 7 """Generate sinusoidal positional encodings.""" 8 assert d_model % 2 == 0 9 pe: list[list[float]] = [] 10 for pos in range(max_len): 11 row = [0.0] * d_model 12 for i in range(0, d_model, 2): 13 frequency = math.exp(-(math.log(10000.0) * i) / d_model) 14 angle = pos * frequency 15 row[i] = math.sin(angle) 16 row[i + 1] = math.cos(angle) 17 pe.append(row) 18 19 return pe # (max_len, d_model) 20 21pe = sinusoidal_positional_encoding(max_len=8, d_model=8) 22print(len(pe), len(pe[0])) 23print([round(x, 3) for x in pe[0]]) 24print(round(pe[2][0], 3)) 25print(round(pe[2][1], 3))
Output
18 8 2[0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0] 30.909 4-0.416

For the fastest pair (dimensions 0 and 1), position 2 means angle 2 radians, so we get sin⁡(2)≈0.909\sin(2) \approx 0.909sin(2)≈0.909 and cos⁡(2)≈−0.416\cos(2) \approx -0.416cos(2)≈−0.416. For the slowest pair (dimensions 6 and 7), position 2 means angle 0.002 radians, so the values stay extremely close to 0 and 1. This is the multi-scale fingerprint in action.

Frequency interpretation

Dimension pairWavelength (d=512)What it captures
(0,1)(0, 1)(0,1)∼6\sim 6∼6 tokensVery fine-grained local position
(64,65)(64, 65)(64,65)∼20\sim 20∼20 tokensMedium-scale structure
(510,511)(510, 511)(510,511)∼60,000\sim 60{,}000∼60,000 tokensVery coarse global position

The multi-scale frequencies mean the model can attend to both local and distant positions through different embedding dimensions, similar to how Fourier series decompose signals at multiple scales.

sinusoidal-wavelengths.py
1import math 2 3d_model = 512 4for first_dimension in [0, 64, 510]: 5 angular_frequency = 10000 ** (-first_dimension / d_model) 6 wavelength = 2 * math.pi / angular_frequency 7 print(first_dimension, round(wavelength))
Output
10 6 264 20 3510 60611
Exact sinusoidal positional encoding traces for dimension pairs 0 and 1, 64 and 65, and 510 and 511 at d_model 512, with sine and cosine waves sampled across positions and the resulting three-scale fingerprint at position 12 Exact sinusoidal positional encoding traces for dimension pairs 0 and 1, 64 and 65, and 510 and 511 at d_model 512, with sine and cosine waves sampled across positions and the resulting three-scale fingerprint at position 12
Sinusoidal encodings combine fast, medium, and slow waves. Each token position gets a multi-scale fingerprint.

Learned vs sinusoidal absolute encodings

Instead of fixed sinusoids, models like BERT (Bidirectional Encoder Representations from Transformers) and GPT-2 (Generative Pre-trained Transformer 2) use learned position embeddings: a trainable matrix P∈RLmax⁡×dP \in \mathbb{R}^{L_{\max} \times d}P∈RLmax​×d where each position gets its own optimizable vector.[3]Reference 3BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding.https://arxiv.org/abs/1810.04805[4]Reference 4GPT-2 Source Implementation.https://github.com/openai/gpt-2/blob/master/src/model.py

PropertySinusoidalLearned
Parameters0 (fixed formula)Lmax⁡×dL_{\max} \times dLmax​×d added params
FlexibilityFixed inductive biasAdapts to task
ExtrapolationBeyond Lmax⁡L_{\max}Lmax​ (in theory)Hard limit at Lmax⁡L_{\max}Lmax​
Performance in the original Transformer experimentStrong baselineNearly identical result

Vaswani et al. (2017) tested both and found "nearly identical results."[1]Reference 1Attention Is All You Need.https://arxiv.org/abs/1706.03762 Later architectures also explore relative-position methods, which insert position into attention in different ways.

Why add instead of concatenate?

A common intuition is that concatenating the positional vector to the token embedding (creating a 2d2d2d vector) would perfectly preserve both pieces of information. However, concatenation would either force the whole transformer to run at width 2d2d2d or require an extra projection layer to get back to ddd. If you keep the model width at 2d2d2d, square matrices like WQW_QWQ​, WKW_KWK​, and WVW_VWV​ become roughly 4x larger. Addition keeps the hidden width unchanged and lets downstream learned projections use the combined representation.

Addition doesn't guarantee that content and position stay neatly separated. It keeps the hidden width fixed and gives later learned projections one combined representation to use. Whether that works well is empirical: Vaswani et al. report nearly identical results for their sinusoidal and learned-position variants.[1]Reference 1Attention Is All You Need.https://arxiv.org/abs/1706.03762

Limitations of absolute methods

LimitationWhy it matters
Poor extrapolationQuality often degrades for positions beyond the training length.
Implicit relative positionThe model must learn relative offsets indirectly from absolute vectors.
Content-position mixingAdding position vectors to embeddings mixes content and position in the same stream.

Method 2: Rotary Position Embeddings (RoPE)

A relative-position approach

RoPE (Rotary Position Embeddings) was introduced in RoFormer and is used in Llama-family models described in Meta's Llama 3 report.[5]Reference 5RoFormer: Enhanced Transformer with Rotary Position Embedding.https://arxiv.org/abs/2104.09864[6]Reference 6The Llama 3 Herd of Models.https://arxiv.org/abs/2407.21783

Core insight

Instead of adding position to embeddings, rotate the query and key vectors in 2D subspaces. Holding the unrotated query and key fixed, the dot product between rotated vectors depends on their relative position.

Two RoPE unit-circle diagrams for query and key positions 2 and 1 versus 102 and 101 at frequency theta 0.5, showing different absolute angles but the same negative 0.5-radian phase gap and identical 0.877583 dot product Two RoPE unit-circle diagrams for query and key positions 2 and 1 versus 102 and 101 at frequency theta 0.5, showing different absolute angles but the same negative 0.5-radian phase gap and identical 0.877583 dot product
RoPE turns position into phase. Shift both tokens together and absolute angles change, but relative offset stays the same.

RoPE can be pictured as two dancers (a query and a key) on a circular stage. RoPE assigns each dancer a rotation angle based on their position in the sequence. When they face each other to "interact" (dot product), the positional part of that interaction depends on the difference in their angles, not their absolute positions. That difference gives RoPE relative position behavior: holding the dancers' starting poses fixed, positions 5 and 3 produce the same positional geometry as positions 105 and 103.

The math

For a 2D subspace (q2i,q2i+1)(q_{2i}, q_{2i+1})(q2i​,q2i+1​) at position mmm, apply rotation:

(q2i(m)q2i+1(m))=(cos⁡(mθi)−sin⁡(mθi)sin⁡(mθi)cos⁡(mθi))(q2iq2i+1)\begin{pmatrix} q_{2i}^{(m)} \\ q_{2i+1}^{(m)} \end{pmatrix} = \begin{pmatrix} \cos(m\theta_i) & -\sin(m\theta_i) \\ \sin(m\theta_i) & \cos(m\theta_i) \end{pmatrix} \begin{pmatrix} q_{2i} \\ q_{2i+1} \end{pmatrix}(q2i(m)​q2i+1(m)​​)=(cos(mθi​)sin(mθi​)​−sin(mθi​)cos(mθi​)​)(q2i​q2i+1​​)

How to read the rotation matrix

Take each consecutive pair of numbers in the query vector and spin them like a clock hand. How far they spin depends on two things: the token's position mmm (further in the sequence = more rotation) and the frequency θi\theta_iθi​ (each pair rotates at a different speed). The result: every position creates a unique rotational pattern that the model can use to figure out "how far apart are these two words?"

The frequency base follows the same pattern as sinusoidal encoding, but production RoPE usually applies it over the per-head rotary dimension, not the full model width:

θi=10000−2i/drotary\theta_i = 10000^{-2i/d_{\text{rotary}}}θi​=10000−2i/drotary​

If every head dimension is rotated, drotary=dkd_{\text{rotary}} = d_kdrotary​=dk​. Some architectures rotate only part of each head, so the config's rotary dimension is the value that matters.

Position differences

When computing q(m)⋅k(n)q^{(m)} \cdot k^{(n)}q(m)⋅k(n), the rotation matrices combine:

q(m)Tk(n)=qTR((n−m)θi)kq^{(m)T} k^{(n)} = q^T R((n-m)\theta_i) kq(m)Tk(n)=qTR((n−m)θi​)k

Toy numerical example (2D subspace). Suppose a query vector pair at position 5 and a key at position 2, both using frequency θ=0.5\theta = 0.5θ=0.5:

the-key-property.py
1import math 2 3def rotate_2d(vec: list[float], pos: int, theta: float) -> list[float]: 4 """Apply RoPE rotation to a 2D pair.""" 5 c, s = math.cos(pos * theta), math.sin(pos * theta) 6 x, y = vec 7 return [x * c - y * s, x * s + y * c] 8 9q = [0.8, 0.6] # original query pair 10k = [0.7, 0.5] # original key pair 11 12def dot(a: list[float], b: list[float]) -> float: 13 return sum(x * y for x, y in zip(a, b)) 14 15theta = 0.5 16score_a = dot(rotate_2d(q, 5, theta), rotate_2d(k, 2, theta)) 17score_b = dot(rotate_2d(q, 105, theta), rotate_2d(k, 102, theta)) 18 19print(round(score_a, 6), round(score_b, 6))
Output
10.040884 0.040884

Running this shows that when the unrotated query and key are held fixed, the RoPE score stays the same after shifting both positions together. The positional transform depends on relative offset, exactly as the math predicts. This property is useful, but alone provides no proof that a model works beyond its trained context window.

Why this matters

Holding the unrotated query and key fixed, RoPE's contribution to their attention score depends on the signed relative offset (n−m)(n - m)(n−m) between them, not on their absolute positions. Token 5 attending to token 3 produces the same positional geometry as token 1005 attending to token 1003. Actual attention scores remain content-dependent because the query and key vectors can differ across tokens and layers.

Worked example: the same fixed vectors and offset give the same score

Picture a single 2D pair where both the query and the key start as the simple unit vector [1,0][1, 0][1,0]. Let the rotation frequency for this pair be θ=0.5\theta = 0.5θ=0.5 radians.

  • Query at position m=2m = 2m=2, key at position n=1n = 1n=1: relative distance d=n−m=−1d = n - m = -1d=n−m=−1. After rotation, the dot product equals cos⁡(d⋅θ)=cos⁡(−0.5)≈0.878\cos(d \cdot \theta) = \cos(-0.5) \approx 0.878cos(d⋅θ)=cos(−0.5)≈0.878.

  • Query at position m=102m = 102m=102, key at position n=101n = 101n=101: relative distance is still d=−1d = -1d=−1. After rotation, the dot product is again cos⁡(−0.5)≈0.878\cos(-0.5) \approx 0.878cos(−0.5)≈0.878.

The absolute positions changed by 100, but the positional part of the attention score stayed identical because the starting vectors were held fixed and only their relative offset enters the rotation product. If the distance were d=−2d = -2d=−2, this particular pair would score cos⁡(−1.0)≈0.540\cos(-1.0) \approx 0.540cos(−1.0)≈0.540, which is smaller. Avoid generalizing that single comparison into a monotonic distance penalty: cosine phases can rise again at larger offsets, and a real head sums many frequency pairs.

RoPE tensor mechanics for an eight-channel rotary dimension, splitting query and key vectors into four 2D pairs with frequencies 1, 0.1, 0.01, and 0.001, rotating each pair at query position 4 and key position 2, then summing four pairwise scores into one attention logit RoPE tensor mechanics for an eight-channel rotary dimension, splitting query and key vectors into four 2D pairs with frequencies 1, 0.1, 0.01, and 0.001, rotating each pair at query position 4 and key position 2, then summing four pairwise scores into one attention logit
RoPE applies one reusable pairwise recipe across the head. Each pair gets its own frequency, but every pair collapses absolute rotation into relative offset.

Implementation

This example applies RoPE rotations in practice. It takes the query and key tensors as inputs, along with precomputed rotation frequencies based on the sequence length. The function reshapes the vectors into 2D pairs, applies the complex rotations, and returns the rotated query and key tensors.

implementation.py
1import torch 2 3def precompute_freqs_cis( 4 dim: int, 5 max_seq_len: int, 6 theta: float = 10000.0, 7) -> torch.Tensor: 8 """Precompute rotation frequencies (complex exponentials).""" 9 freqs = 1.0 / (theta ** (torch.arange(0, dim, 2).float() / dim)) 10 t = torch.arange(max_seq_len, dtype=torch.float) 11 freqs = torch.outer(t, freqs) # (seq_len, dim/2) 12 return torch.polar(torch.ones_like(freqs), freqs) # complex64 13 14def apply_rotary_emb( 15 xq: torch.Tensor, # (batch, seq_len, n_heads, d_k) 16 xk: torch.Tensor, # (batch, seq_len, n_heads, d_k) 17 freqs_cis: torch.Tensor, # (seq_len, d_k/2) 18) -> tuple[torch.Tensor, torch.Tensor]: 19 """Apply RoPE to queries and keys.""" 20 # View as complex numbers: pairs (x_2i, x_{2i+1}) -> x_2i + j·x_{2i+1} 21 xq_complex = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2)) 22 xk_complex = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2)) 23 24 # Multiply by rotation (complex multiplication = 2D rotation) 25 freqs_cis = freqs_cis.unsqueeze(0).unsqueeze(2) # broadcast 26 xq_out = torch.view_as_real(xq_complex * freqs_cis).flatten(-2) 27 xk_out = torch.view_as_real(xk_complex * freqs_cis).flatten(-2) 28 29 return xq_out.type_as(xq), xk_out.type_as(xk) 30 31# --- Verify the relative-distance property on tiny tensors --- 32d_k = 4 33freqs = precompute_freqs_cis(dim=d_k, max_seq_len=4) 34# Both q and k are unit vectors [1,0,1,0] at different positions 35q = torch.tensor([[[[1.0, 0.0, 1.0, 0.0]]]]) # (1, 1, 1, 4) at pos 0 36k_far = torch.tensor([[[[1.0, 0.0, 1.0, 0.0]]]]) # same vector at pos 2 37q_rot, _ = apply_rotary_emb(q, k_far, freqs[0:1]) 38_, k_rot = apply_rotary_emb(q, k_far, freqs[2:3]) 39print("Dot product at distance 2:", (q_rot * k_rot).sum().item()) 40 41# Now shift both by +1: q at pos 1, k at pos 3 42q2 = torch.tensor([[[[1.0, 0.0, 1.0, 0.0]]]]) 43k2 = torch.tensor([[[[1.0, 0.0, 1.0, 0.0]]]]) 44q_rot2, _ = apply_rotary_emb(q2, k2, freqs[1:2]) 45_, k_rot2 = apply_rotary_emb(q2, k2, freqs[3:4]) 46print("Dot product at distance 2 (shifted):", (q_rot2 * k_rot2).sum().item()) 47# Both prints match because q and k stay fixed while relative distance stays the same.
Output
1Dot product at distance 2: 0.5836532115936279 2Dot product at distance 2 (shifted): 0.5836531519889832

What RoPE changes

PropertySinusoidalLearnedRoPE
Position infoAdded to embeddingsAdded to embeddingsApplied to Q, K only
Relative positionImplicit (model must learn)ImplicitExplicit in dot product
Where position entersInput embedding sumInput embedding sumQ/K rotation
Direct RoPE transform on VNot applicableNot applicableNone
Extra parameters0Lmax⁡×dL_{\max} \times dLmax​×d0

RoPE directly rotates Q and K, not V. This places its relative-position operation in attention routing rather than applying the same rotation to aggregated values. In deeper layers, V still comes from hidden states that already include context mixed by earlier position-aware attention.

Relative offset isn't a monotonic penalty

RoPE gives attention a structured function of relative offset. Farther tokens aren't guaranteed to receive smaller positional contributions. For a single pair of identical unit vectors, the positional score is:

SΔ=cos⁡(Δθ)S_{\Delta} = \cos(\Delta\theta)SΔ​=cos(Δθ)

This quantity oscillates as distance Δ\DeltaΔ changes. A full head combines multiple frequencies and content-dependent coefficients, so its score can also rise or fall across offsets.

rope-offset-is-not-monotonic.py
1import math 2 3theta = 0.5 4distances = [1, 2, 4, 6, 8] 5scores = [math.cos(distance * theta) for distance in distances] 6print(distances) 7print([round(score, 3) for score in scores]) 8print(scores[-1] > scores[-2])
Output
1[1, 2, 4, 6, 8] 2[0.878, 0.54, -0.416, -0.99, -0.654] 3True

The RoFormer paper analyzes a long-term decay bound aggregated over RoPE frequencies, and Men et al. (2024) study how the RoPE base affects long-context retrieval behavior.[5]Reference 5RoFormer: Enhanced Transformer with Rotary Position Embedding.https://arxiv.org/abs/2104.09864[8]Reference 8Base of RoPE Bounds Context Length.https://arxiv.org/abs/2405.14591 Those analyses motivate careful base selection and evaluation. They remain distinct from ALiBi's explicit linear distance penalty.

Side-by-side exact curves showing a single RoPE pair contribution cos of 0.5 times distance oscillating from distance 0 to 16, while an ALiBi bias with slope 0.1 decreases linearly, including the RoPE rise from negative 0.990 at distance 6 to negative 0.654 at distance 8 Side-by-side exact curves showing a single RoPE pair contribution cos of 0.5 times distance oscillating from distance 0 to 16, while an ALiBi bias with slope 0.1 decreases linearly, including the RoPE rise from negative 0.990 at distance 6 to negative 0.654 at distance 8
A toy RoPE frequency contribution oscillates, while ALiBi explicitly subtracts more as distance grows. Aggregate RoPE behavior still requires measurement.

Caution: increasing the base frequency alone can give "superficial" long-context capability in the evaluations reported by Men et al.: perplexity may look good while retrieval accuracy degrades.[8]Reference 8Base of RoPE Bounds Context Length.https://arxiv.org/abs/2405.14591 A changed RoPE configuration therefore needs retrieval and task evaluation at its deployed length.


Method 3: Attention with Linear Biases (ALiBi)

The simplest approach[7]Reference 7Train Short, Test Long: Attention with Linear Biases Enables Input Length Generalization.https://arxiv.org/abs/2108.12409

ALiBi (Attention with Linear Biases) doesn't modify embeddings at all. Instead, it adds a head-specific linear bias directly to attention scores:

ALiBi behaves like a crowded room where nearby speakers are loud and distant speakers are quieter. It applies a simple distance penalty to attention scores, so nearby tokens "speak loudly" and distant tokens are naturally muffled. Different attention heads act like listeners with different hearing ranges: some focus on nearby whispers, others can hear across the room.

Attention(Q,K,V)=softmax(QKTdk+B(h))V,Bij(h)=−mh(i−j) for j≤i\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}} + B^{(h)}\right) V,\quad B^{(h)}_{ij} = -m_h(i-j)\ \text{for}\ j \le iAttention(Q,K,V)=softmax(dk​​QKT​+B(h))V,Bij(h)​=−mh​(i−j) for j≤i

What the ALiBi formula does

This is the normal attention formula with one modification: before applying softmax, we add a negative bias that gets more negative the farther back a key token sits from the current query. In a causal decoder, the current token gets zero penalty, one token back gets −mh-m_h−mh​, two tokens back gets −2mh-2m_h−2mh​, and so on. A steep slope makes the head short-sighted. A gentle slope lets it see further.

Here, mhm_hmh​ is the slope for head hhh. Future positions still get removed by the causal mask.

Head slopes

For nnn heads, the paper uses a fixed geometric schedule. For power-of-two head counts, this reduces to a clean sequence like mk=2−8k/nm_k = 2^{-8k/n}mk​=2−8k/n.

For 8 heads (n=8): m=12,14,18,116,132,164,1128,1256m = \frac{1}{2}, \frac{1}{4}, \frac{1}{8}, \frac{1}{16}, \frac{1}{32}, \frac{1}{64}, \frac{1}{128}, \frac{1}{256}m=21​,41​,81​,161​,321​,641​,1281​,2561​.

ALiBi mechanism with eight head slopes, two causal bias matrices, and one worked softmax row showing finite past-token penalties and hard future masking. ALiBi mechanism with eight head slopes, two causal bias matrices, and one worked softmax row showing finite past-token penalties and hard future masking.
ALiBi adds distance-dependent penalties before softmax. Different heads get different slopes, so some stay local while others remain long-range.
HeadSlope mmmEffect
Head 11/21/21/2Strong local attention
Head 41/161/161/16Moderate range
Head 81/2561/2561/256Very long-range

Different heads get different slopes through a fixed schedule, giving the model a spectrum of attention ranges, from very local (steep slope) to nearly global (gentle slope). For non-power-of-two head counts, the reference implementation uses a recursive workaround so slopes remain well spread.[7]Reference 7Train Short, Test Long: Attention with Linear Biases Enables Input Length Generalization.https://arxiv.org/abs/2108.12409

Worked example: a concrete distance penalty

Picture the token "loaded" at position 3 attending back to earlier words in "The model loaded the checkpoint." The raw dot-product score for "model" at position 1 is 2.5. Head 4 has slope m=1/16≈0.0625m = 1/16 \approx 0.0625m=1/16≈0.0625.

  • Distance from "loaded" to "model" = 3−1=23 - 1 = 23−1=2
  • Penalty = −0.0625×2=−0.125-0.0625 \times 2 = -0.125−0.0625×2=−0.125
  • Score entering softmax = 2.5−0.125=2.3752.5 - 0.125 = 2.3752.5−0.125=2.375

For "The" at position 0, the distance is 3, so the penalty is −0.0625×3=−0.1875-0.0625 \times 3 = -0.1875−0.0625×3=−0.1875, and the score entering softmax is 2.31252.31252.3125. The farther token is slightly quieter, but not silenced. With Head 1 (m=0.5m = 0.5m=0.5), the same distances would produce penalties of −1.0-1.0−1.0 and −1.5-1.5−1.5, making the head far more myopic.

worked-example-a-concrete-distance-penalty.py
1def alibi_score(raw_score: float, query_pos: int, key_pos: int, slope: float) -> float: 2 distance = max(query_pos - key_pos, 0) 3 return raw_score - slope * distance 4 5raw = 4.0 6query_pos = 10 7key_pos = 6 8 9head_1 = alibi_score(raw, query_pos, key_pos, slope=1 / 2) 10head_8 = alibi_score(raw, query_pos, key_pos, slope=1 / 256) 11 12print(head_1, round(head_8, 3))
Output
12.0 3.984

This snippet constructs the ALiBi bias tensor for a causal decoder. It follows the reference slope helper, including non-power-of-two head counts, and bakes the causal mask into the returned bias matrix.

worked-example-a-concrete-distance-penalty-2.py
1import math 2import torch 3 4def get_alibi_slopes_power_of_two(n_heads: int) -> torch.Tensor: 5 start = 2 ** (-2 ** -(math.log2(n_heads) - 3)) 6 ratio = start 7 return torch.tensor( 8 [start * (ratio ** head) for head in range(n_heads)], 9 dtype=torch.float32, 10 ) 11 12def get_alibi_slopes(n_heads: int) -> torch.Tensor: 13 assert n_heads > 0 14 if math.log2(n_heads).is_integer(): 15 return get_alibi_slopes_power_of_two(n_heads) 16 17 closest_power_of_two = 2 ** math.floor(math.log2(n_heads)) 18 return torch.cat( 19 [ 20 get_alibi_slopes_power_of_two(closest_power_of_two), 21 get_alibi_slopes(2 * closest_power_of_two)[0::2][ 22 : n_heads - closest_power_of_two 23 ], 24 ] 25 ) 26 27def build_alibi_bias( 28 n_heads: int, 29 seq_len: int, 30) -> torch.Tensor: 31 """Build ALiBi logits bias for a causal decoder.""" 32 slopes = get_alibi_slopes(n_heads) 33 34 q_pos = torch.arange(seq_len)[:, None] 35 k_pos = torch.arange(seq_len)[None, :] 36 37 # Causal distance: current token = 0, one step back = 1, etc. 38 relative = (q_pos - k_pos).clamp(min=0).to(torch.float32) 39 bias = -slopes[:, None, None] * relative 40 41 causal_mask = k_pos > q_pos 42 bias = bias.masked_fill(causal_mask.unsqueeze(0), float("-inf")) 43 44 return bias # Add directly to attention logits before softmax 45 46# --- Inspect a tiny bias matrix for 4 heads and 4 tokens --- 47bias = build_alibi_bias(n_heads=4, seq_len=4) 48print(bias.shape) 49print(bias[0, 3, :]) 50print(bias[-1, 3, :]) 51# Distant tokens get more negative values, and the last head is the most forgiving.
Output
1torch.Size([4, 4, 4]) 2tensor([-0.7500, -0.5000, -0.2500, -0.0000]) 3tensor([-0.0117, -0.0078, -0.0039, -0.0000])

What ALiBi demonstrated

In one original-paper experiment, a 1.3 billion parameter ALiBi model is trained at length 1024 and evaluated at length 2048, matching the perplexity of a sinusoidal model trained at length 2048 while using less training time and memory in that setup.[7]Reference 7Train Short, Test Long: Attention with Linear Biases Enables Input Length Generalization.https://arxiv.org/abs/2108.12409 The mechanism has several useful properties:

  • Linear biases are monotonic: distant tokens always get penalized more
  • The bias rule is defined for any distance, so there's no learned position table to run out
  • No learned position parameters -> nothing needs to be interpolated
  • The fixed slopes create a natural spectrum from local heads to longer-range heads

Softmax numerical stability with ALiBi

ALiBi interacts elegantly with standard softmax optimizations. ALiBi biases can produce very negative values for distant tokens. In practice, softmax is computed using the max-shift trick to prevent numerical overflow:

softmax(si+bi)=esi+bi−max⁡(s+b)∑jesj+bj−max⁡(s+b)\text{softmax}(s_i + b_i) = \frac{e^{s_i + b_i - \max(s + b)}}{\sum_j e^{s_j + b_j - \max(s + b)}}softmax(si​+bi​)=∑j​esj​+bj​−max(s+b)esi​+bi​−max(s+b)​

Where sis_isi​ is the raw attention score and bib_ibi​ is the ALiBi distance bias for token iii.

When computing this in finite precision, very negative ALiBi biases can make distant tokens' shifted exponent values extremely small or round them to zero. Mathematically, ALiBi is still a soft distance-dependent recency bias, not a hard window. The causal mask remains separate.

alibi-bias-is-not-a-mask.py
1import math 2 3def softmax(logits: list[float]) -> list[float]: 4 maximum = max(logits) 5 shifted = [math.exp(value - maximum) for value in logits] 6 total = sum(shifted) 7 return [value / total for value in shifted] 8 9raw_scores = [2.0, 2.0, 2.0] 10distances = [2, 1, 0] 11slope = 0.5 12biased_scores = [ 13 score - slope * distance 14 for score, distance in zip(raw_scores, distances) 15] 16weights = softmax(biased_scores) 17 18print([round(weight, 3) for weight in weights]) 19print(weights[0] > 0) 20print("future token uses causal mask separately")
Output
1[0.186, 0.307, 0.506] 2True 3future token uses causal mask separately

The extrapolation challenge

This is a practical challenge in production systems:

"Your model was trained on 4K tokens. How does it perform at 32K?"

Long-context methods require separate evidence lanes and a target-workload deployment gate. Long-context methods require separate evidence lanes and a target-workload deployment gate.
Being defined beyond the training window isn't enough. Long-context quality must be checked at the target context length.
MethodMechanism beyond training lengthReported evidence and required check
SinusoidalFormula can compute unseen positionsPress et al. report sharp perplexity degradation for their WikiText-103 setup; evaluate your task.
Learned absoluteNo row exists past configured Lmax⁡L_{\max}Lmax​ without changing the tableExtend or replace the table, then train and evaluate.
RoPE (unchanged)Relative rotations continue at unseen offsetsChen et al. report poor direct extension for their Llama experiments; evaluate retrieval and task quality.
ALiBiSame linear logit-bias rule applies at new distancesPress et al. report 1024 to 2048 extrapolation in their setup.
RoPE with PI or YaRNModify the rotary geometry, typically with adaptationChen et al. report PI up to 32K; Peng et al. report YaRN up to 128K in their evaluated models.

These are results from different experiments, not a universal ranking. Context length is a model-and-evaluation claim, not a property proved by selecting a positional formula.[7]Reference 7Train Short, Test Long: Attention with Linear Biases Enables Input Length Generalization.https://arxiv.org/abs/2108.12409[9]Reference 9Extending Context Window of Large Language Models via Positional Interpolation.https://arxiv.org/abs/2306.15595[10]Reference 10YaRN: Efficient Context Window Extension of Large Language Models.https://arxiv.org/abs/2309.00071

RoPE context extension techniques

When adapting a RoPE-based model for longer contexts, these methods illustrate different interventions:

1. Position Interpolation (PI)

Scale position indices down to fit within training range[9]Reference 9Extending Context Window of Large Language Models via Positional Interpolation.https://arxiv.org/abs/2306.15595

Let L=train length, L′=target length\text{Let } L = \text{train length},\ L' = \text{target length}Let L=train length, L′=target length f′(x,m)=f(x,m⋅L/L′)f'(x, m) = f(x, m \cdot L / L')f′(x,m)=f(x,m⋅L/L′)

What rescaling the position means

If a model was trained on 4K tokens and you want it to handle 16K, position interpolation shrinks indices by 4x so they stay inside the range the model has seen. Position 16,000 maps to effective position 4,000, while the RoPE frequencies themselves stay unchanged; only the position index that multiplies theta is rescaled. Chen et al. report extensions to 32K with up to 1,000 fine-tuning steps in their Llama experiments.[9]Reference 9Extending Context Window of Large Language Models via Positional Interpolation.https://arxiv.org/abs/2306.15595

position-interpolation-map.py
1train_length = 4096 2target_length = 16384 3scale = train_length / target_length 4 5for target_position in [0, 4096, 8192, 16383]: 6 effective_position = target_position * scale 7 print(target_position, round(effective_position, 2))
Output
10 0.0 24096 1024.0 38192 2048.0 416383 4095.75

2. NTK (Neural Tangent Kernel)-aware Scaling

Scale the frequency base instead of positions, trading off between low and high frequency components[10]Reference 10YaRN: Efficient Context Window Extension of Large Language Models.https://arxiv.org/abs/2309.00071

θbase′=θbase⋅sd/(d−2)\theta'_{\text{base}} = \theta_{\text{base}} \cdot s^{d/(d-2)}θbase′​=θbase​⋅sd/(d−2)

where s=Ltarget/Ltrains = L_{\text{target}} / L_{\text{train}}s=Ltarget​/Ltrain​ is the scale factor and ddd is the per-head RoPE dimension (the head dimension, not the full hidden size).

What scaling the base changes

Instead of compressing every position, this formulation changes the base so lower-frequency bands are stretched more than high-frequency bands. Peng et al. document this as earlier NTK-aware work while developing YaRN; any quality claim remains dependent on model, target length, adaptation data, and evaluation.[10]Reference 10YaRN: Efficient Context Window Extension of Large Language Models.https://arxiv.org/abs/2309.00071

3. YaRN (Yet another RoPE extensioN)

Combines NTK-by-parts interpolation with attention temperature adjustment.[10]Reference 10YaRN: Efficient Context Window Extension of Large Language Models.https://arxiv.org/abs/2309.00071 Peng et al. report RoPE-based Llama-family variants evaluated at contexts up to 128K.

The paper's recommended temperature rule for its Llama experiments is 1/t=0.1ln⁡(s)+1\sqrt{1/t} = 0.1 \ln(s) + 11/t​=0.1ln(s)+1, where s=Ltarget/Ltrains = L_{\text{target}} / L_{\text{train}}s=Ltarget​/Ltrain​. NTK-by-parts interpolates frequency bands differently; temperature adjustment changes attention scale. Both choices remain hyperparameters to validate on the deployed model.

Three mathematical views of RoPE context extension for a 4K to 16K target: Position Interpolation compressing target indices into 0 to 4K, NTK-aware scaling changing a 10,000 base to about 40,890 and reducing low-frequency rotation rates, and YaRN combining frequency-band treatment with a 1.139 attention factor Three mathematical views of RoPE context extension for a 4K to 16K target: Position Interpolation compressing target indices into 0 to 4K, NTK-aware scaling changing a 10,000 base to about 40,890 and reducing low-frequency rotation rates, and YaRN combining frequency-band treatment with a 1.139 attention factor
RoPE extension methods change different parts of the positional geometry: position index, frequency base, and attention temperature.

Choosing a positional method

GoalCandidate mechanismValidation obligation
Reproduce original Transformer behaviorSinusoidal absolute encodingConfirm quality at trained lengths and any extrapolated lengths used.
Use learned finite position slotsLearned absolute embeddingsDefine how new positions are initialized and adapted.
Encode relative offset inside query-key scoresRoPEMeasure target-length retrieval and generation quality, especially after any scaling.
Add an explicit monotonic distance biasALiBiMeasure whether its recency bias retains evidence needed by long tasks.
Extend an existing RoPE checkpointPI or YaRN-style adaptationValidate short-context regression and target-context behavior after adaptation.

The implementation choice decides where position enters attention. It still leaves the trained checkpoint to be evaluated on the exact lengths and tasks being served.


What to check before moving on

  • Prove permutation equivariance for unmasked self-attention by tracing X→PXX \rightarrow PXX→PX, A→PAPTA \rightarrow PAP^TA→PAPT, and Y→PYY \rightarrow PYY→PY.
  • Calculate sinusoidal frequencies and wavelengths, then explain how sine-cosine pairs form a multi-scale position fingerprint.
  • Derive R(mθ)TR(nθ)=R((n−m)θ)R(m\theta)^T R(n\theta) = R((n-m)\theta)R(mθ)TR(nθ)=R((n−m)θ) and explain why RoPE rotates Q and K without directly rotating V.
  • Construct a causal ALiBi bias matrix, distinguish finite distance penalties from the −∞-\infty−∞ future mask, and compare steep versus gentle head slopes.
  • Identify the variable changed by PI, NTK-aware scaling, and YaRN instead of treating them as interchangeable "long context" switches.
  • Design a deployment gate that checks retrieval across positions, target tasks, short-context regressions, latency, memory, and cost.

Practice checkpoints


What to remember

For unmasked self-attention without a position signal, swapping input rows swaps output rows. Sinusoidal encodings add multi-frequency position fingerprints to token embeddings. RoPE rotates Q and K so the attention dot product can represent relative offset without directly rotating V. ALiBi adds distance penalties directly to attention logits. Long-context claims need validation at the target length, because a method can be mathematically defined for a longer sequence and still fail retrieval behavior.

Common failures and fixes

  • Order seems implicit: Symptom: you say unmasked attention already knows sequence order. Cause: you skipped the permutation-equivariance step. Fix: start from the content-only attention identity, then account separately for position signals and masking.
  • All methods sound same: Symptom: sinusoidal, learned, RoPE, and ALiBi blur into one idea. Cause: you aren't tracking where position enters. Fix: separate embeddings, Q/K geometry, and attention-logit bias explicitly.
  • RoPE rotates wrong tensor: Symptom: you describe applying RoPE rotation to embeddings or V. Cause: you lost the routing-versus-aggregation distinction. Fix: rotate Q and K after projection; leave V without direct RoPE rotation.
  • Long context looks solved on paper: Symptom: perplexity improves but retrieval still fails. Cause: you treated mathematical validity as behavioral proof. Fix: run passkey, retrieval, summarization, and target-task evals at deployed length.
  • Bigger base must be enough: Symptom: config advertises a larger window but distant facts still disappear. Cause: base change alone doesn't teach the model to use long-range evidence. Fix: pair geometry changes with rescaling method, long-context data, and task-level checks.
  • Concatenate by default: Symptom: width and projection cost balloon without a clear gain. Cause: you tried to preserve content and position separately at all costs. Fix: add position vectors unless you have a strong reason and budget for a wider architecture.

Going deeper

Why not concatenate positional encodings?

Concatenation would either force the transformer to run at width 2d2d2d or require an extra projection layer to get back to ddd. If you keep the model width at 2d2d2d, square projection matrices like WQW_QWQ​, WKW_KWK​, and WVW_VWV​ become roughly 4x larger. Addition keeps the width constant while learned projections operate on the resulting combined representation.

RoPE relative derivation

At position mmm, q(m)=R(mθ)⋅qq^{(m)} = R(m\theta) \cdot qq(m)=R(mθ)⋅q. At position nnn, k(n)=R(nθ)⋅kk^{(n)} = R(n\theta) \cdot kk(n)=R(nθ)⋅k. q(m)Tk(n)=qTR(mθ)TR(nθ)k=qTR((n−m)θ)kq^{(m)T} k^{(n)} = q^T R(m\theta)^T R(n\theta) k = q^T R((n-m)\theta) kq(m)Tk(n)=qTR(mθ)TR(nθ)k=qTR((n−m)θ)k

Holding unrotated qqq and kkk fixed, the rotation product depends only on relative offset (n−m)(n-m)(n−m), not on absolute positions. RoPE exposes relative position information inside the query-key score. Actual scores remain content-dependent because qqq and kkk come from token representations.

Why is RoPE base size part of a long-context design?

Men et al. derive and evaluate a relationship between RoPE base and effective long-context retrieval, while also showing that perplexity alone can hide retrieval failures.[8]Reference 8Base of RoPE Bounds Context Length.https://arxiv.org/abs/2405.14591 Base size is therefore a parameter to choose and validate alongside adaptation data and task-level long-context evaluations, not a standalone certificate of usable context length.

Complete the lesson

Mastery Check

Answer every question, then check your score. Score above 75% to mark this lesson complete.

1.An unmasked self-attention block receives token embeddings with no positional signal. If the input rows are permuted before computing Q, K, and V, what should happen to the block output?
2.An engineer wants to combine a d-dimensional token embedding with a d-dimensional absolute position vector. If the model concatenates them and keeps the transformer at width 2d instead of adding them, what is the main cost?
3.In sinusoidal positional encoding with d_model = 8, dimensions 0 and 1 use angle equal to the position. At position 2, what are those two values, and why are sine and cosine paired at each frequency?
4.A RoPE attention head rotates only Q and K. In one 2D pair, fixed q = k = [1, 0] and theta = 0.5. What happens to the query-key dot product for positions (m=5, n=3) versus (m=105, n=103), and what role does V play in this RoPE step?
5.A developer says RoPE behaves like ALiBi because larger offsets always reduce the positional term. In one 2D RoPE pair with fixed q = k = [1, 0] and theta = 1.0, what do offsets Delta = 3 and Delta = 6 show?
6.In an 8-head causal decoder using ALiBi slopes 1/2 through 1/256, a query at position 10 has raw logit 4.0 for a visible key at position 6. What logits enter softmax for Head 1 and Head 8?
7.One model uses a learned absolute position table with L_max = 4096. Another uses ALiBi biases. You want to run 8192-token inputs without changing the position mechanism. What is the key difference, and what caveat remains?
8.Your 4096-token RoPE checkpoint is being adapted for 16384-token inputs. Which option correctly pairs each extension method with the part of RoPE or attention it changes?
9.A 4K-trained RoPE model is configured for 64K by increasing the RoPE base. Long-document perplexity barely changes, but passkey retrieval at 64K gets worse. What should you conclude?

9 questions remaining.

Next Step
Continue to Layer Normalization: Pre-LN vs Post-LN

Positional methods decide where attention can look; normalization decides whether deep attention blocks train stably as depth grows.

PreviousVision Transformers and Image Encoders
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

Attention Is All You Need.

Vaswani, A., et al. · 2017

Transformer Language Models without Positional Encodings Still Learn Positional Information.

Haviv, A., Ram, O., Press, O., Izsak, P., & Levy, O. · 2022 · Findings of EMNLP 2022

BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding.

Devlin, J., et al. · 2019 · NAACL 2019

GPT-2 Source Implementation.

OpenAI · 2019

RoFormer: Enhanced Transformer with Rotary Position Embedding.

Su, J., et al. · 2021

The Llama 3 Herd of Models.

Dubey, A., et al. · 2024 · arXiv preprint

Train Short, Test Long: Attention with Linear Biases Enables Input Length Generalization.

Press, O., Smith, N. A., & Lewis, M. · 2022 · ICLR 2022

Base of RoPE Bounds Context Length.

Men, X., et al. · 2024 · NeurIPS 2024

Extending Context Window of Large Language Models via Positional Interpolation.

Chen, S., et al. · 2023

YaRN: Efficient Context Window Extension of Large Language Models.

Peng, B., et al. · 2023

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.