Autoregressive Decoding: One Token at a Time
A transformer processes all input tokens in parallel during the forward pass. But generating output is different. Output is produced autoregressively: the model generates one token, appends that token to the input, and then runs the forward pass again to generate the next token. This continues until the model produces an end-of-sequence token or reaches the maximum length.
The consequence: generating a 100-token response requires 100 sequential forward passes. Unlike the pretraining forward pass which can process many documents in a batch simultaneously, generation is inherently sequential in the output dimension. This is the fundamental constraint on latency. You cannot parallelize across output tokens because each output token depends on all previous output tokens.
You can, however, batch multiple users' requests together. If 32 users each need a response and you run their inputs through the model simultaneously, you perform one forward pass that serves 32 requests in parallel. Batching is the primary tool for throughput optimization: at the cost of slightly higher latency per request, you dramatically increase the number of tokens generated per second per GPU.
The KV Cache: Avoiding Redundant Computation
In autoregressive decoding, the prompt tokens are identical across all decoding steps. When generating token 50, the model still needs the Key and Value representations of all the prompt tokens, and of output tokens 1 through 49. Without optimization, it would recompute these representations at every decoding step.
The KV cache solves this. The Key and Value matrices computed in each attention layer for each token are stored in GPU memory after the first time they are computed. On subsequent decoding steps, only the new token's K and V are computed and appended. The full attention computation can then use the cached K and V without recomputation.
The memory cost of the KV cache is significant. For a model with L layers, H attention heads, and d_k head dimension, the cache for one token uses 2 * L * H * d_k floating point numbers (factor of 2 for K and V). For a 70B parameter model with 80 layers and 64 heads of dimension 128, caching 2,000 tokens requires several GB of GPU memory. The maximum sequence length is therefore not just a model capability: it is also a GPU memory budget question.
Quantization: Running Large Models in Less Memory
Neural network weights are typically stored as 32-bit or 16-bit floating point numbers. Quantization reduces the precision of these representations to lower bit widths: 8-bit integers (INT8) or 4-bit integers (INT4). This reduces memory usage by a factor of 2 or 4 respectively, which allows larger models to fit on a given set of GPUs and increases the number of model copies that can be served in parallel.
INT8 quantization maps the continuous distribution of weight values to 256 discrete levels. The key challenge is calibration: choosing the mapping from float to int carefully so that the distribution of weight values is well-covered by the 256 levels. With good calibration, INT8 quantization produces models with accuracy very close to the full-precision original, at half the memory footprint.
INT4 quantization (using only 16 discrete levels) is more aggressive. Accuracy degrades more noticeably, particularly for smaller models. Techniques like GPTQ (Frantar et al., arXiv:2210.17323) and AWQ (Lin et al., arXiv:2306.00978) address this with careful layer-wise quantization that minimizes accuracy loss. In practice, a 70B model quantized to INT4 can often match or exceed the accuracy of a 30B model in full precision, while fitting in significantly less GPU memory.
Speculative Decoding: Parallel Verification
Speculative decoding uses a smaller, faster draft model to propose multiple tokens at once, then uses the large target model to verify all proposed tokens in a single parallel forward pass. If the large model agrees with the draft tokens, all of them are accepted. If it disagrees at some position, the draft tokens from that position onward are rejected and generation continues normally.
The key insight: the large model's forward pass processes multiple tokens in parallel (as it does during training) rather than one at a time. If the draft model's proposals are accepted even 70-80% of the time, the effective token generation rate can increase by 2-3x without changing the output distribution of the large model. This is not an approximation: rejected draft tokens are discarded and the large model's own distribution is used, so the output is exactly equivalent to autoregressive decoding from the large model.
FrugalGPT: Routing Requests by Difficulty
Not every query requires the most capable model. Chen, Zaharia, and Zou, "FrugalGPT: How to Use Large Language Models While Reducing Cost and Improving Performance" (arXiv:2310.11409), showed that a routing strategy that sends easy queries to cheaper models and hard queries to expensive ones can reduce LLM API costs substantially while maintaining overall quality.
The FrugalGPT approach maintains a cascade of models ordered by cost. A router classifies each query by estimated difficulty and routes it to the cheapest model likely to answer it correctly. A quality verifier checks the response; if it fails a confidence threshold, the query is escalated to the next model in the cascade. The cascade continues until a satisfactory response is produced or the most capable model is reached.
This is not just about cost. Chen et al. found that the LLM cascade can also exceed the quality of the most expensive single model alone, because different models have different strengths. A routing strategy that directs queries to the model most likely to answer each query type correctly outperforms any single model on quality metrics. This is why FrugalGPT's framing includes both "reducing cost" and "improving performance" in its title.