formula generator

Building a GPT-2 KV Cache to Measure Real AI Performance Gains

Building a GPT-2 KV cache in PyTorch as a learning project is exactly the kind of hands-on work that reveals where the math meets reality.

3 min readMachine Learning

The gap between theoretical efficiency and real-world performance in AI systems is often treated as a minor footnote, but the work behind this GPT-2 KV cache implementation proves it deserves center stage. When a 1,000x reduction in FLOPs translates to only a 6x speedup in practice, that discrepancy isn't noise, it's the actual problem engineers need to solve. This kind of hands-on analysis, where someone builds the infrastructure from scratch and measures what actually happens, is exactly what the field needs more of. It echoes the practical rigor we've seen in recent comparisons of Linear Recurrence Matches Transformer Accuracy at a Fraction of the Cost and the latency-focused benchmarks in Seven Decision Models Put to the Test Against a Generative LLM.

What makes this project stand out is its honesty about the gap between math and measurement. The FLOP estimate for a cached generation at context length 1,000 is roughly 1,000x smaller than the uncached version, but the actual per-token latency drops from 29.69 ms to only 4.95 ms. That sixfold improvement is still meaningful, but it reveals how much overhead lives outside the attention computation itself. CPU kernel launch costs, PyTorch's dispatch mechanism, and the CUDA runtime all eat into the theoretical savings. The author correctly resists calling this a conclusion without a profiler, but the data already points a clear finger at infrastructure overhead rather than algorithmic shortcomings. This is a concrete lesson for anyone building or deploying transformer-based systems: optimizing the forward pass is only half the battle.

The memory analysis is equally instructive. The formula predicts 72 KiB per token, and after accounting for a lazily allocated cuBLAS workspace and a constant tensor offset, the measurements match perfectly across all 16 checkpoints. That precision is rare in published benchmarks, and it demonstrates that careful instrumentation can isolate exactly where bytes go. The allocator's block-size overhead remains visible separately, which is a reminder that even when you nail the big picture, the allocator's granularity still introduces small inefficiencies. For practitioners, this means that memory optimization is often a game of understanding your allocator's behavior as much as your model's architecture.

The most valuable part of this work may be the failure case the author discovered: reversing the cache concatenation order passed a single-token attention test but failed when decoding multiple new tokens together. This is a sharp warning that unit tests for individual components are necessary but not sufficient. Integration tests that exercise the full decode loop are the only way to catch subtle state-management bugs. For anyone building their own inference stack, this single observation is worth the price of admission. The open question worth watching is whether the remaining latency floor can be pushed lower with kernel fusion or better batching of the cache operations, or whether it is fundamentally bounded by PyTorch's Python overhead. The answer will tell us how much further software engineering can squeeze out of existing hardware before we need a different approach to attention entirely.

From Machine Learning

I built GPT-2 small and a KV cache in PyTorch as a learning project, then compared the mathematical savings with measured latency and memory. I have published the implementation and a detailed write-up, and would appreciate feedback on the methodology.

Setup: pretrained GPT-2 small (124M), NVIDIA A40, fp32 with TF32 off, batch size 1, greedy decoding. Timings are bracketed by torch.cuda.synchronize(), after warmup, using the median of five runs per context length.

Read the original at Machine Learning