Iteration-Dependent Activation Scales
What It Does
In a looped transformer, the same weights are applied L times — but the activations change at each iteration. Early iterations have large activation magnitudes (building context), later iterations have smaller magnitudes (refining). Measuring these per-iteration scales enables better quantization decisions.
The activation magnitude drops ~50% from iteration 1 to iteration 4, then stabilizes.
Why This Matters
Fixed quantization (same scale/zero for all iterations) is suboptimal because:
- Early iterations: large activations → quantization error is a small fraction of the signal
- Late iterations: small activations → same absolute quantization error is a larger fraction
Per-iteration scales let you adjust the effective dynamic range without re-quantizing weights.
How To Measure
python tools/measure_iter_scales.py \
--model model.tinyloop --L 8 --n-calib 20
Output:
Per-iteration activation scales (relative to iter 0):
iter 1: 1.000 ████████████████████
iter 2: 0.649 ████████████
iter 3: 0.498 █████████
iter 4: 0.449 ████████
iter 5: 0.459 █████████
iter 6: 0.486 █████████
iter 7: 0.502 ██████████
iter 8: 0.509 ██████████
Saves a JSON file with per-iteration scale factors for runtime use.
How It Connects To Other Features
- Dual-bit swap: the scale data shows early iterations can tolerate INT2 (activations are large enough to mask quantization noise)
- Error cancellation: scale-aware rounding could weight the correction by activation magnitude
- L scheduling: early iterations are not just cheaper (fewer FLOPs) but also less precision-sensitive
Why Only Looped
Standard transformers have different weights AND different activations at each layer — you can't separate the two effects. In a looped transformer, weights are constant across iterations, so any change in activation magnitude is purely from the iterative refinement process. This makes per-iteration scaling a clean, interpretable intervention.