Sequences, geometric series, frequency ladders
Overview
Section titled “Overview”| Module | M00.3 · build · Python · Pass 2 · 2 to 3 h |
| You build | python/tinyllm/num/series.py: geometric, geometric_sum, rope_inv_freq, alibi_slopes |
| Contract | course/contracts/py/tinyllm/num/series.pyi |
| Tests | course/tests/M00.3/test_series.py (what they check: section 4) |
| Needs | nothing to call. Reading: M00.1 (powers, log1p and expm1), lang.01 |
| Used by | M02.2 the EMA’s weights and bias correction call geometric and geometric_sum · later L7.3 RoPE inv_freq and L7.4 ALiBi slopes and YaRN’s per-frequency ramps · M10.4 learning-rate schedules (reading) · later: L5.4 |
| Milestone | MS-P2 (the Pass 2 gate) |
| Optional depth | OpenStax, Precalculus 2e (free), ch. 11 (sequences and series); Press, Smith, and Lewis, “Train Short, Test Long: Attention with Linear Biases” (ALiBi, 2022), section 3; Su et al., “RoFormer” (2021), section 3.3 |
Key Takeaways
Section titled “Key Takeaways”- A geometric sequence multiplies by the same ratio at every step: (
test_geometric_terms). - Its first terms add up to , by subtracting times the sum from the sum (
test_hand_example_geometric_sum,test_sum_matches_exact_rationals). - Near that formula cancels: it subtracts two nearly equal numbers and loses half its digits. Rewriting it with and keeps them all; Adam’s bias correction lives exactly there (
test_sum_near_one_keeps_its_digits,test_ema_bias_correction_identity). - RoPE’s inverse frequencies form a geometric ladder from one radian per token down to about , so pairs of dimensions see position at every scale from a few tokens to tens of thousands (
test_rope_inv_freq_golden_hf). - ALiBi slopes are a geometric ladder of ; head counts that are not powers of two interleave a second ladder (
test_hand_example_alibi_six_heads,test_alibi_golden_hf).
How to work this chapter
Section titled “How to work this chapter”ol start M00.3 # stubs python/tinyllm/num/series.py into your repool tests M00.3 # read the test catalog first: rung R0, you write no tests hereol check M00.3 # exit code is the verdictol diff M00.3 # after passing: your code against the reference1. Why now
Section titled “1. Why now”M00.2 gave you rotations, and RoPE rotates each pair of a query by an angle proportional to the token’s position. The open question is how fast each pair should turn. If every pair turned by 1 radian per token, positions tokens apart would look identical; if every pair turned slowly, neighbours would be indistinguishable. RoPE answers with a ladder of speeds, a geometric sequence, and so does ALiBi, the other position scheme in L7.4. The same mathematics appears in training: the moving averages of Adam (M02.2, M10.3) weight past gradients by a geometric sequence, and correct for its partial sum. Your SmolLM2 loader (L7.9) will read rope_theta = 100000 from a config.json and must turn it into exactly the frequencies Hugging Face computes. This module builds the sequences, their sums (accurately, including the hard case), and both ladders.
2. Principles
Section titled “2. Principles”| Symbol | Meaning | Type / shape |
|---|---|---|
| the first term of a sequence | float | |
| the common ratio | float | |
| the number of terms | int | |
| term , counted from | float | |
| the sum of the first terms, | float | |
| the decay of an exponential moving average, | float | |
| the value seen at step and the moving average after it | float | |
the rotary dimension (d_rot): the number of coordinates RoPE rotates, even | int | |
the RoPE base (rope_theta in a config.json) | float | |
| inverse frequency of pair , , in radians per position | float[d/2] | |
| wavelength of pair , , in positions | float | |
| the number of attention heads | int | |
| the ALiBi slope of head | float[H] | |
| float64 unit roundoff, |
2.1 Sequences
Section titled “2.1 Sequences”A sequence is a list of numbers indexed by position: . Two families matter here. An arithmetic sequence adds the same step, (positions are one). A geometric sequence multiplies by the same ratio, : has , . With the terms shrink toward 0; with they grow without bound; with they alternate in sign. Compute term as a * r**j, not by multiplying the previous term by : a running product rounds once per step and its error grows with .
2.2 The geometric sum
Section titled “2.2 The geometric sum”Let . Multiply by : . Subtracting, every term but two cancels:
and when (every term is ). When , approaches 0 as grows, so the infinite sum converges: . That is why , and why a repeating decimal is a fraction: .
2.3 The exponential moving average is a geometric series
Section titled “2.3 The exponential moving average is a geometric series”An exponential moving average (EMA) with decay updates , starting from . Unrolling,
so the weights are a geometric sequence , newest first, and they add up to , not 1. Early on the average is biased toward its starting value 0: after one step with , . Adam divides by to undo exactly this (M02.2, M10.3). With the ratio is , close to 1, which is the hard case of section 2.6.
2.4 Frequency ladders: RoPE
Section titled “2.4 Frequency ladders: RoPE”RoPE rotates pair of a query or key at position by the angle (M00.2, section 2.5), with
This is a geometric sequence with first term and ratio . Pair 0 turns one radian per token and repeats every positions; the last pair turns radians per token, slightly faster than , and repeats only after about positions. Like the hands of a clock (seconds, minutes, hours), fast pairs resolve neighbouring tokens and slow pairs tell far-apart ones apart, and the geometric spacing gives every scale the same number of pairs. The exponent steps by because there are pairs spread over the exponents from 0 to almost 1. Models with partial rotary embeddings rotate only the first coordinates of each head; the formula is the same with that . The SmolLM2-135M config.json says hidden_size = 576 over num_attention_heads = 9 (a head size of 64) and rope_theta = 100000; your rope_inv_freq(64, 1e5) must match what Hugging Face computes from those, which is what the golden test checks.
2.5 Frequency ladders: ALiBi
Section titled “2.5 Frequency ladders: ALiBi”ALiBi (Press et al.) adds no rotation at all. Head subtracts times the distance between query and key from each attention score, so far tokens are penalized linearly, and each head has its own slope. For a power of two the slopes are the geometric sequence with first term and ratio :
from (steep: the head looks at the last few tokens) down to (flat: it looks hundreds of tokens back). For other , with the largest power of two below , the paper’s code takes the slopes for heads, then fills the remaining heads with every other slope of the -head ladder, , which fall between the existing ones. Find with integer arithmetic (1 << (H.bit_length() - 1)), never with a floating-point .
2.6 Floating point near
Section titled “2.6 Floating point near r=1r = 1r=1”For close to 1 the closed form divides one small difference by another. is computed exactly (subtracting nearby floats is exact), but is rounded to about relative error first, and then subtracts two numbers that agree in most of their digits, keeping the rounding error and losing the rest. With and , carries an absolute error near : about 5 correct digits out of 16.
The cure is to never form near 1. Since ,
where and are computed accurately for small arguments (math.log1p, math.expm1; M00.1). Every quantity in this form is small and accurate, and the result keeps nearly all 16 digits. For this form is used everywhere; for the closed form has no cancellation (). When the sum overflows (huge and ), the answer is , by the sign of the last term.
3. Worked example by hand
Section titled “3. Worked example by hand”A geometric sum. : , , .
which agrees with adding . With every term triples, so . These are test_hand_example_geometric_sum.
The RoPE ladder for , . Four pairs, exponents :
| exponent | wavelength | ||
|---|---|---|---|
| 0 | 0 | 1 | 6.28 positions |
| 1 | 62.8 | ||
| 2 | 628 | ||
| 3 | 6283 |
( because .) The ratio is : test_hand_example_rope_ladder.
ALiBi with 6 heads. is not a power of two, so . The 4-head ladder has first term and ratio : . The 8-head ladder is ; every other entry from the first is , and the two extra heads take the first two:
test_hand_example_alibi_six_heads. The extra slopes and sit between the existing ones, so the six heads still cover the range evenly.
4. The interface
Section titled “4. The interface”def geometric(a: float, r: float, n: int) -> NDArray: ... # [a, a r, ..., a r^(n-1)]def geometric_sum(a: float, r: float, n: int) -> float: ... # accurate near r = 1def rope_inv_freq(d_rot: int, base: float) -> NDArray: ... # base ** (-2 i / d_rot), [d_rot/2]def alibi_slopes(n_heads: int) -> NDArray: ... # Press et al., any head countEverything is float64. Bad counts (negative, fractional, or True), an odd or non-positive d_rot, a base that is not finite and above 1, and a head count below 1 raise ValueError.
What the tests check
Section titled “What the tests check”| Test | KIND | Checks | Why it matters downstream |
|---|---|---|---|
test_hand_example_geometric_sum | unit, smoke | section 3: , , and the four terms | you and the tests agree on what counts |
test_hand_example_rope_ladder | unit, smoke | , gives | the exponent is |
test_hand_example_alibi_six_heads | unit, smoke | the 6-head slopes of section 3 | the non-power-of-two rule |
test_geometric_terms | unit | negative and unit ratios, and (empty) | term 0 is |
test_sum_matches_exact_rationals | differential | 66 sums against exact Fraction arithmetic on the same inputs | any correct formula passes, any wrong count fails |
test_sum_near_one_keeps_its_digits | boundary | and : relative error below | pitfall 1 |
test_ema_bias_correction_identity | property | for up to | Adam’s bias correction (M02.2) |
test_sum_overflows_to_infinity | boundary | for sums beyond float64, by the sign of the last term | no OverflowError escapes |
test_bad_n_rejected | boundary | , , True raise ValueError | counts are whole numbers |
test_rope_inv_freq_golden_hf | golden | Hugging Face’s default RoPE for SmolLM2-135M, Llama 2, Llama 3, and a partial rotary size | exactly what L7.9 loads |
test_rope_ladder_is_geometric | property | first rung 1, constant ratio , last rung above | the ladder’s shape for any and |
test_rope_bad_arguments | boundary | odd or zero , bases or infinite raise ValueError | a flat or climbing ladder is a bug |
test_alibi_powers_of_two_exact | unit | 8 heads: ; 16 heads: ; 1 head: | the power-of-two rule |
test_alibi_golden_hf | golden | BLOOM’s build_alibi_tensor for 20 head counts from 1 to 128 | twelve of them are not powers of two |
test_alibi_bad_head_count | boundary | 0, , heads raise ValueError | a model has whole heads |
5. Pitfalls
Section titled “5. Pitfalls”| Pitfall | Symptom | Caught by |
|---|---|---|
| 1. the textbook closed form near | Adam’s bias correction with correct to 7 digits instead of 16; tests at fail | test_sum_near_one_keeps_its_digits (mutant s03) |
| 2. the RoPE exponent instead of | frequencies fall only to : long-range pairs turn far too fast and checkpoints from HF load with the wrong positions | test_hand_example_rope_ladder (mutant s04) |
| 3. starting the ladder at | every frequency shifted one rung; the 1-radian pair is missing | test_rope_inv_freq_golden_hf (mutant s05) |
| 4. ignoring the non-power-of-two rule, or taking the odd entries | 12-head and 40-head models get slopes no published model uses | test_hand_example_alibi_six_heads (mutants s08, s09, s10) |
| 5. one term too many | includes ; every bias correction is off | test_hand_example_geometric_sum (mutant s02) |
| 6. starting the sequence at | geometric returns ; ALiBi slopes shift by one rung | test_geometric_terms (mutant s01) |
6. Where it’s used next
Section titled “6. Where it’s used next”| Forward | L5.4 | Registered call site uses this module. |
| Direction | Module | How it uses this |
|---|---|---|
| Back | M00.1 | powers, , and log1p/expm1 (reading) |
| Back | lang.01 | numpy arange and power (reading) |
| Forward | L7.3 | rope_inv_freq(d_rot, rope_theta) builds RoPE’s angles, positions * inv_freq |
| Forward | L7.4 | ALiBi biases from alibi_slopes; YaRN and NTK scaling bend the same ladder per frequency |
| Forward | M02.2 | the EMA’s weights, geometric(1 - beta, beta, t), and its bias correction, geometric_sum(1 - beta, beta, t) |
| Forward | M10.4 | step-decay schedules are geometric sequences of learning rates (reading) |
| Forward | M00.2 | the ladder feeds the angles that rotate_pairs applies (reading) |
Going further
Section titled “Going further”| Your piece | Production equivalent | What it adds | Where to look |
|---|---|---|---|
rope_inv_freq | Hugging Face ROPE_INIT_FUNCTIONS and compute_default_rope_parameters | one function per scaling kind (linear, dynamic, yarn, llama3, longrope) that bends this ladder for longer contexts | transformers/modeling_rope_utils.py |
alibi_slopes | BLOOM and MPT attention biases | slopes built once per model, biases fused into the attention kernel | transformers/models/bloom/modeling_bloom.py (build_alibi_tensor) |
geometric_sum near | PyTorch torch.optim.Adam | the bias corrections 1 - beta1 ** step and 1 - beta2 ** step (in float32, where the cancellation is worse) | torch/optim/adam.py |
log1p and expm1 | C99 log1p, expm1 | the accurate small-argument functions every math library ships | man 3 expm1 |