<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Yuvraj singh Bhadoria</title>
    <description>The latest articles on DEV Community by Yuvraj singh Bhadoria (@yuvraj_llminference).</description>
    <link>https://dev.to/yuvraj_llminference</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4100416%2Fa4e43dea-cc2d-4982-9380-3eae23a1fb12.jpg</url>
      <title>DEV Community: Yuvraj singh Bhadoria</title>
      <link>https://dev.to/yuvraj_llminference</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/yuvraj_llminference"/>
    <language>en</language>
    <item>
      <title>Demystifying Speculative Decoding: From Architecture to Production Bottlenecks</title>
      <dc:creator>Yuvraj singh Bhadoria</dc:creator>
      <pubDate>Sun, 30 Aug 2026 08:48:51 +0000</pubDate>
      <link>https://dev.to/yuvraj_llminference/demystifying-speculative-decoding-from-architecture-to-production-bottlenecks-3hkm</link>
      <guid>https://dev.to/yuvraj_llminference/demystifying-speculative-decoding-from-architecture-to-production-bottlenecks-3hkm</guid>
      <description>&lt;h1&gt;
  
  
  Demystifying Speculative Decoding: From Architecture to Production Bottlenecks
&lt;/h1&gt;

&lt;p&gt;Speculative decoding is one of the most widely discussed inference optimizations in recent LLM engineering, and frequently one of the most misunderstood. The core proposition sounds ideal: achieving a 2–3× boost in decoding throughput with &lt;strong&gt;mathematically identical&lt;/strong&gt; output distributions—yielding performance gains via a lightweight secondary model.&lt;/p&gt;

&lt;p&gt;In practice, speculative decoding functions as a trade-off rather than a guaranteed acceleration: you pay the computational overhead of running a smaller draft model with the expectation that its outputs align sufficiently with the target model to yield a net speedup.&lt;/p&gt;

&lt;p&gt;This post details the complete system stack—covering core transformer architecture, memory bandwidth constraints, the draft-then-verify loop, state-of-the-art methodology taxonomies, and empirical benchmark evaluations on GPT-2 weights—to highlight where performance gains originate and where they risk regressing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Executive Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Autoregressive Decoding is Serial &amp;amp; Memory-Bound:&lt;/strong&gt; Single-token autoregressive generation is limited by memory bandwidth during low-batch inference. Speculative decoding directly targets this single-stream latency bottleneck.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Core Mechanism is Draft-Then-Verify:&lt;/strong&gt; A fast draft model proposes $k$ candidate tokens sequentially. The target model then verifies all $k+1$ positions in a single parallel forward pass. Rejection sampling preserves the exact target output distribution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Speedup Has a Hard Inequality Constraint ($\alpha &amp;gt; c$):&lt;/strong&gt; Net performance gains require the draft model's token acceptance rate ($\alpha$) to strictly exceed its relative computational cost fraction ($c$). Failing this condition increases overall latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architectural Taxonomy:&lt;/strong&gt; Current approaches (Speculative Sampling, Medusa, EAGLE, Self-Speculative, Lookahead) vary primarily in their draft generation mechanism. End-to-end performance depends directly on draft–target distribution alignment rather than the verification loop itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empirical Findings:&lt;/strong&gt; Evaluations on un-aligned weights yielded a speedup of &lt;strong&gt;0.2–0.9×&lt;/strong&gt; (a net performance penalty). This negative result highlights the operational necessity of validating draft alignment prior to deployment.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Visual Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbiulln0v5bhg06sxj0s9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbiulln0v5bhg06sxj0s9.png" alt="Figure 0: High-level visual summary showing serial memory constraints, drafting execution, taxonomy, framework integration, and performance benchmarking."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 0: High-level visual summary showing serial memory constraints, drafting execution, taxonomy, framework integration, and performance benchmarking.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Model Setup &amp;amp; Architecture
&lt;/h2&gt;

&lt;p&gt;To evaluate speculative decoding, we must analyze the hardware execution costs of a single forward pass. A causal language model generates next-token probability distributions by executing tensor operations across its transformer stack. This pipeline is bounded by two distinct factors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Matrix multiplication operations (GEMM FLOPS across transformer layers).&lt;/li&gt;
&lt;li&gt;Memory bus transfers (fetching model weights and KV-cache states from DRAM to SRAM/registers).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For small batch sizes ($B=1$) on single-stream inference, memory transfers dominate total step latency: compute units execute quickly and subsequently stall while waiting for weight loading. Speculative decoding specifically targets this architectural bottleneck.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Target Model (Ground Truth): GPT-2 124M]
d_model=768, depth=12, heads=12, Vocab=50k
                       ▲
                       │ (pt)
             ┌───────────────────┐
             │ Target Final Head │
             └─────────▲─────────┘
                       │
             ┌───────────────────┐
             │  GPT-2 (12 Layers)│
             └─────────▲─────────┘
                       │
             ┌───────────────────┐
             │  Input Embeddings │
             └───────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Takeaway:&lt;/strong&gt; A draft mechanism provides net throughput benefits only when it is computationally inexpensive (low layer count/parameter footprint) &lt;strong&gt;and&lt;/strong&gt; statistically aligned with the target distribution.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy37ilao6m7rsanotbw9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy37ilao6m7rsanotbw9e.png" alt="Figure 1: Structural comparison between the primary target model (GPT-2 124M), an independent draft model (tiny-GPT2 10M), and self-speculative early-exit configurations."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1: Structural comparison between the primary target model (GPT-2 124M), an independent draft model (tiny-GPT2 10M), and self-speculative early-exit configurations.&lt;/em&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  2. The Serial Memory Bottleneck
&lt;/h2&gt;

&lt;p&gt;Transformer architectures process input sequences in parallel during context encoding (prefill phase), but execute sequentially across step iterations during auto-regressive decoding (decoding phase). Token $t_i$ cannot be evaluated until token $t_{i-1}$ is generated, due to causal self-attention dependencies across historic Key-Value (KV) states.&lt;/p&gt;

&lt;p&gt;$$\text{Latency}&lt;em&gt;{\text{autoregressive}} = N&lt;/em&gt;{\text{tokens}} \times t_{\text{per-token}}$$&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Panel A: Autoregressive Bottleneck (Serial)
[Step t]  ──(Fetch Weights &amp;amp; KV)──► [Token 1] ──┐
[Step t+1] ──(Fetch Weights &amp;amp; KV)──► [Token 2] ──┼─► High Memory Stall / Idle Compute
[Step t+2] ──(Fetch Weights &amp;amp; KV)──► [Token 3] ──┘

Panel B: Speculative Verification (Parallel)
[Single Forward Pass] ──(Fetch Weights Once)──► [Verify Tokens 1, 2, 3, 4 Simultaneously]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At low batch sizes, single-token generation iterations fail to fully saturate GPU compute pipelines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0tcnu31umlg1rh8e1iy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0tcnu31umlg1rh8e1iy0.png" alt="Figure 2: Comparison of memory-bandwidth-bound serial autoregressive generation (Panel A) against batch-parallel target verification across k+1 token positions (Panel B)."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2: Comparison of memory-bandwidth-bound serial autoregressive generation (Panel A) against batch-parallel target verification across k+1 token positions (Panel B).&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The Speculative Sampling Mechanism
&lt;/h2&gt;

&lt;p&gt;The speculative sampling execution pipeline follows a three-step cycle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Draft Phase:&lt;/strong&gt; The lightweight draft model generates $k$ candidate tokens sequentially: $$\hat{x}&lt;em&gt;{1}, \hat{x}&lt;/em&gt;{2}, \dots, \hat{x}&lt;em&gt;{k} \sim p&lt;/em&gt;{d}(x \mid \text{context})$$&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification Phase:&lt;/strong&gt; The target model processes the concatenated sequence $\text{context} \cup {\hat{x}&lt;em&gt;{1} \dots \hat{x}&lt;/em&gt;{k}}$ in &lt;strong&gt;one&lt;/strong&gt; forward pass, computing target logits for all $k+1$ token positions in parallel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Correction Phase:&lt;/strong&gt; Rejection sampling is applied sequentially across candidate tokens. The first rejected token $\hat{x}&lt;em&gt;i$ is resampled from the corrected residual distribution: $$p&lt;/em&gt;{\text{adjusted}}(x) = \text{relu}\left(p_{t}(x) - p_{d}(x)\right)$$&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This mathematical formulation guarantees that the final output distribution remains provably identical to sampling directly from the target model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F63ejpgqvxipy1kpfecpg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F63ejpgqvxipy1kpfecpg.png" alt="Figure 3: Detailed control-flow loop showing sequential draft generation, parallel target model scoring, and distribution-preserving rejection sampling."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3: Detailed control-flow loop showing sequential draft generation, parallel target model scoring, and distribution-preserving rejection sampling.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sampling &amp;amp; Rejection Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch.nn.functional&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;spec_sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft_fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Executes speculative decoding with exact target distribution preservation.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft_logits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;current_seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 1. Draft Step: Generate k candidates sequentially
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;logits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;draft_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;next_logit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;draft_logits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_logit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multinomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_logit&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;current_seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Verify Step: Parallel validation over k+1 positions
&lt;/span&gt;    &lt;span class="n"&gt;target_logits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;target_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prefix_offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;accepted_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. Correction Step: Rejection sampling loop
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefix_offset&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;draft_logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Accept condition
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
            &lt;span class="n"&gt;accepted_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Reject: Resample candidate from adjusted distribution (pt - pd)+
&lt;/span&gt;            &lt;span class="n"&gt;residual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;residual&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="n"&gt;residual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;resampled_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multinomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;residual&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;accepted_count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;resampled_token&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;accepted_count&lt;/span&gt;

    &lt;span class="c1"&gt;# Bonus token sampling if all k drafted tokens are accepted
&lt;/span&gt;    &lt;span class="n"&gt;bonus_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multinomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefix_offset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bonus_token&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. The Speculative-Decoding Family
&lt;/h2&gt;

&lt;p&gt;While all speculative decoding variants rely on the same fundamental parallel verification framework, they differ in their structural draft generation mechanisms:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Draft Generation Architecture&lt;/th&gt;
&lt;th&gt;Target Acceleration&lt;/th&gt;
&lt;th&gt;Primary Operational Trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speculative Sampling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Independent auxiliary Small LM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.0–3.0×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires hosting separate draft model &amp;amp; tokenizer alignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Medusa&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-head prediction heads on target&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.3–3.0×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires parameter fine-tuning of prediction heads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EAGLE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Feature-level drafting with tree attention&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.0–3.0×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High draft acceptance rate; higher system complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Self-Speculative&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Target model internal early-exiting&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.3–1.8×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero additional weight hosting; limited by layer alignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lookahead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Jacobi iteration / N-gram retrieval&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.8–2.3×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Parameter-free; highly sequence/task dependent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqxl6syvbnc3z2vnstiw5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqxl6syvbnc3z2vnstiw5.png" alt="Figure 4: Classification taxonomy of speculative decoding variants structured by draft generation method."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 4: Classification taxonomy of speculative decoding variants structured by draft generation method.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Production Framework Integrations
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Hugging Face Transformers (&lt;code&gt;assisted_generation&lt;/code&gt;)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;

&lt;span class="n"&gt;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;target_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;assistant_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sshleifer/tiny-gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The future of artificial intelligence is&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;assistant_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;assistant_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;do_sample&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_new_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  vLLM Native Scheduler Integration
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; vllm.entrypoints.openai.api_server &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model&lt;/span&gt; meta-llama/Llama-3-8B-Instruct &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--speculative-model&lt;/span&gt; meta-llama/Llama-3-1B-Instruct &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--num_speculative_tokens&lt;/span&gt; 5 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-model-len&lt;/span&gt; 4096
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Benchmarking &amp;amp; Empirical Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mathematical Speedup Condition ($\alpha &amp;gt; c$)
&lt;/h3&gt;

&lt;p&gt;Let $c$ represent the ratio of draft model execution cost relative to target model execution cost per token:&lt;/p&gt;

&lt;p&gt;$$c = \frac{\text{Cost}&lt;em&gt;{\text{draft}}}{\text{Cost}&lt;/em&gt;{\text{target}}}$$&lt;/p&gt;

&lt;p&gt;Let $\alpha$ represent the average token acceptance rate across speculative steps. The theoretical speedup factor $S$ relative to standard autoregressive execution is modeled as:&lt;/p&gt;

&lt;p&gt;$$S \approx \frac{1 + k \cdot \alpha}{1 + k \cdot c}$$&lt;/p&gt;

&lt;p&gt;To achieve a net speedup ($S &amp;gt; 1$), the pipeline must satisfy the inequality:&lt;/p&gt;

&lt;p&gt;$$\alpha &amp;gt; c$$&lt;/p&gt;

&lt;p&gt;If candidate acceptance falls below the cost threshold ($\alpha &amp;lt; c$), the computational overhead of draft generation and verification outpaces the benefits of sequence amortization, leading to increased latency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp3aixcpbseqzv7r634ev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp3aixcpbseqzv7r634ev.png" alt="Figure 5: Measured wall-clock performance curve showing speedup vs. acceptance rate ($\alpha$) relative to relative cost fraction ($c$). Misaligned drafts fail to clear the baseline threshold."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 5: Measured wall-clock performance curve showing speedup vs. acceptance rate ($\alpha$) relative to relative cost fraction ($c$). Misaligned drafts fail to clear the baseline threshold.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Measured Experimental Results
&lt;/h3&gt;

&lt;p&gt;Evaluating speculative decoding across unaligned draft configurations demonstrates the real-world operational impact of the $\alpha &amp;gt; c$ constraint:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Draft Configuration&lt;/th&gt;
&lt;th&gt;Relative Cost Fraction ($c$)&lt;/th&gt;
&lt;th&gt;Acceptance Rate ($\alpha$)&lt;/th&gt;
&lt;th&gt;Speedup ($k=1$)&lt;/th&gt;
&lt;th&gt;Speedup ($k=3$)&lt;/th&gt;
&lt;th&gt;Net Performance Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;tiny-gpt2&lt;/code&gt; (10M vs 124M)&lt;/td&gt;
&lt;td&gt;~0.08&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.68×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.44×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performance Penalty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gpt2&lt;/code&gt; Early-Exit (Layer 3/12)&lt;/td&gt;
&lt;td&gt;~0.25&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.68×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.38×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performance Penalty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gpt2&lt;/code&gt; Early-Exit (Layer 10/12)&lt;/td&gt;
&lt;td&gt;~0.83&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;29.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.38×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.35×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performance Penalty&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Speedup (x Baseline)
    1.2x ┼─────────────────────────────────────────────────── (Break-even: 1.0x)
    1.0x ┼───────────────────────────────────────────────────
    0.8x ┼───── Top Performance (k=1, alpha=4%..12%): ~0.68x
    0.6x ┼───────────────────────────────────────────────────
    0.4x ┼───────────────── Top Performance (k=3): ~0.35x..0.44x
    0.2x ┼───────────────────────────────────────────────────
         └───────┬───────────────┬───────────────┬───────────
                k=1             k=2             k=3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  System Failure Modes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Distributional Mismatch ($\alpha &amp;lt; c$):&lt;/strong&gt; Using an unaligned draft model causes frequent rejection steps, incurring severe draft-overhead penalties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High Batch Aggregation ($B \gg 1$):&lt;/strong&gt; At high query volumes, hardware compute pipelines shift from memory-bound to compute-bound states. Under these conditions, speculative verification offers diminishing latency returns while increasing total FLOP utilization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-Entropy Generation Tasks:&lt;/strong&gt; Tasks with high logical complexity (e.g., code generation or complex mathematical reasoning) exhibit lower acceptance rates ($\alpha$), reducing maximum attainable sequence extensions per step.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Speculative decoding is a powerful technique for accelerating single-stream LLM inference, but its benefits are fundamentally conditional. Achieving real-world speedups requires strict optimization of draft alignment ($\alpha$) relative to system cost ($c$). When deploying speculative pipelines in production systems, profile target-draft acceptance rates under actual workload distributions before enabling parallel verification logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Leviathan, Y., Kalman, M., &amp;amp; Matias, Y. (2023). Fast Inference from Transformers via Speculative Decoding. &lt;em&gt;International Conference on Machine Learning (ICML)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2211.17192" rel="noopener noreferrer"&gt;arXiv:2211.17192&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chen, C., Borgeaud, S., Zhou, G., Steiner, D., &amp;amp; Chen, Z. (2023). Accelerating Large Language Model Decoding with Speculative Sampling. &lt;em&gt;arXiv preprint&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2302.01318" rel="noopener noreferrer"&gt;arXiv:2302.01318&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cai, T., Li, Y., Geng, Z., Peng, L., Li, F., &amp;amp; Xiao, W. (2024). Medusa: Simple LLM Inference Acceleration Framework with Multiple Decoding Heads. &lt;em&gt;International Conference on Machine Learning (ICML)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2401.10774" rel="noopener noreferrer"&gt;arXiv:2401.10774&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Li, Y., Wei, F., Zhang, C., &amp;amp; Zhang, H. (2024). EAGLE: Speculative Sampling Requires Rethinking Feature Uncertainty. &lt;em&gt;International Conference on Machine Learning (ICML)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2401.15077" rel="noopener noreferrer"&gt;arXiv:2401.15077&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Zhang, J., Wang, J., Huang, H., Chen, Y., &amp;amp; Zhou, W. (2023). Self-Speculative Decoding with Self-Draft and Self-Verification. &lt;em&gt;Empirical Methods in Natural Language Processing (EMNLP)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2311.08466" rel="noopener noreferrer"&gt;arXiv:2311.08466&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fu, Y., Bailis, P., Stoica, I., &amp;amp; Zhang, H. (2024). Break the Sequential Dependency of LLM Inference Using Lookahead Decoding. &lt;em&gt;arXiv preprint&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2402.02057" rel="noopener noreferrer"&gt;arXiv:2402.02057&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Original blog: &lt;a href="https://YuvrajSinghBhadoria2.github.io/spec-decoding-blog/" rel="noopener noreferrer"&gt;https://YuvrajSinghBhadoria2.github.io/spec-decoding-blog/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tags: #llm #machinelearning #performance #inference&lt;/em&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>machinelearning</category>
      <category>performance</category>
      <category>inference</category>
    </item>
    <item>
      <title>Demystifying Speculative Decoding: From Architecture to Production Bottlenecks</title>
      <dc:creator>Yuvraj singh Bhadoria</dc:creator>
      <pubDate>Sun, 30 Aug 2026 08:41:43 +0000</pubDate>
      <link>https://dev.to/yuvraj_llminference/demystifying-speculative-decoding-from-architecture-to-production-bottlenecks-10g5</link>
      <guid>https://dev.to/yuvraj_llminference/demystifying-speculative-decoding-from-architecture-to-production-bottlenecks-10g5</guid>
      <description>&lt;h1&gt;
  
  
  Demystifying Speculative Decoding: From Architecture to Production Bottlenecks
&lt;/h1&gt;

&lt;p&gt;Speculative decoding is one of the most widely discussed inference optimizations in recent LLM engineering, and frequently one of the most misunderstood. The core proposition sounds ideal: achieving a 2–3× boost in decoding throughput with &lt;strong&gt;mathematically identical&lt;/strong&gt; output distributions—yielding performance gains via a lightweight secondary model.&lt;/p&gt;

&lt;p&gt;In practice, speculative decoding functions as a trade-off rather than a guaranteed acceleration: you pay the computational overhead of running a smaller draft model with the expectation that its outputs align sufficiently with the target model to yield a net speedup.&lt;/p&gt;

&lt;p&gt;This post details the complete system stack—covering core transformer architecture, memory bandwidth constraints, the draft-then-verify loop, state-of-the-art methodology taxonomies, and empirical benchmark evaluations on GPT-2 weights—to highlight where performance gains originate and where they risk regressing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Executive Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Autoregressive Decoding is Serial &amp;amp; Memory-Bound:&lt;/strong&gt; Single-token autoregressive generation is limited by memory bandwidth during low-batch inference. Speculative decoding directly targets this single-stream latency bottleneck.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Core Mechanism is Draft-Then-Verify:&lt;/strong&gt; A fast draft model proposes $k$ candidate tokens sequentially. The target model then verifies all $k+1$ positions in a single parallel forward pass. Rejection sampling preserves the exact target output distribution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Speedup Has a Hard Inequality Constraint ($\alpha &amp;gt; c$):&lt;/strong&gt; Net performance gains require the draft model's token acceptance rate ($\alpha$) to strictly exceed its relative computational cost fraction ($c$). Failing this condition increases overall latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architectural Taxonomy:&lt;/strong&gt; Current approaches (Speculative Sampling, Medusa, EAGLE, Self-Speculative, Lookahead) vary primarily in their draft generation mechanism. End-to-end performance depends directly on draft–target distribution alignment rather than the verification loop itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empirical Findings:&lt;/strong&gt; Evaluations on un-aligned weights yielded a speedup of &lt;strong&gt;0.2–0.9×&lt;/strong&gt; (a net performance penalty). This negative result highlights the operational necessity of validating draft alignment prior to deployment.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Visual Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpdp3uzdhuq423jecuchs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpdp3uzdhuq423jecuchs.png" alt="Figure 0: High-level visual summary showing serial memory constraints, drafting execution, taxonomy, framework integration, and performance benchmarking." width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 0: High-level visual summary showing serial memory constraints, drafting execution, taxonomy, framework integration, and performance benchmarking.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Model Setup &amp;amp; Architecture
&lt;/h2&gt;

&lt;p&gt;To evaluate speculative decoding, we must analyze the hardware execution costs of a single forward pass. A causal language model generates next-token probability distributions by executing tensor operations across its transformer stack. This pipeline is bounded by two distinct factors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Matrix multiplication operations (GEMM FLOPS across transformer layers).&lt;/li&gt;
&lt;li&gt;Memory bus transfers (fetching model weights and KV-cache states from DRAM to SRAM/registers).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For small batch sizes ($B=1$) on single-stream inference, memory transfers dominate total step latency: compute units execute quickly and subsequently stall while waiting for weight loading. Speculative decoding specifically targets this architectural bottleneck.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Target Model (Ground Truth): GPT-2 124M]
d_model=768, depth=12, heads=12, Vocab=50k
                       ▲
                       │ (pt)
             ┌───────────────────┐
             │ Target Final Head │
             └─────────▲─────────┘
                       │
             ┌───────────────────┐
             │  GPT-2 (12 Layers)│
             └─────────▲─────────┘
                       │
             ┌───────────────────┐
             │  Input Embeddings │
             └───────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Takeaway:&lt;/strong&gt; A draft mechanism provides net throughput benefits only when it is computationally inexpensive (low layer count/parameter footprint) &lt;strong&gt;and&lt;/strong&gt; statistically aligned with the target distribution.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Serial Memory Bottleneck
&lt;/h2&gt;

&lt;p&gt;Transformer architectures process input sequences in parallel during context encoding (prefill phase), but execute sequentially across step iterations during auto-regressive decoding (decoding phase). Token $t_i$ cannot be evaluated until token $t_{i-1}$ is generated, due to causal self-attention dependencies across historic Key-Value (KV) states.&lt;/p&gt;

&lt;p&gt;$$\text{Latency}&lt;em&gt;{\text{autoregressive}} = N&lt;/em&gt;{\text{tokens}} \times t_{\text{per-token}}$$&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Panel A: Autoregressive Bottleneck (Serial)
[Step t]  ──(Fetch Weights &amp;amp; KV)──► [Token 1] ──┐
[Step t+1] ──(Fetch Weights &amp;amp; KV)──► [Token 2] ──┼─► High Memory Stall / Idle Compute
[Step t+2] ──(Fetch Weights &amp;amp; KV)──► [Token 3] ──┘

Panel B: Speculative Verification (Parallel)
[Single Forward Pass] ──(Fetch Weights Once)──► [Verify Tokens 1, 2, 3, 4 Simultaneously]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At low batch sizes, single-token generation iterations fail to fully saturate GPU compute pipelines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk01nnpahwa1yki8nbsho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk01nnpahwa1yki8nbsho.png" alt="Figure 2: Comparison of memory-bandwidth-bound serial autoregressive generation (Panel A) against batch-parallel target verification across k+1 token positions (Panel B)." width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2: Comparison of memory-bandwidth-bound serial autoregressive generation (Panel A) against batch-parallel target verification across k+1 token positions (Panel B).&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The Speculative Sampling Mechanism
&lt;/h2&gt;

&lt;p&gt;The speculative sampling execution pipeline follows a three-step cycle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Draft Phase:&lt;/strong&gt; The lightweight draft model generates $k$ candidate tokens sequentially: $$\hat{x}&lt;em&gt;{1}, \hat{x}&lt;/em&gt;{2}, \dots, \hat{x}&lt;em&gt;{k} \sim p&lt;/em&gt;{d}(x \mid \text{context})$$&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification Phase:&lt;/strong&gt; The target model processes the concatenated sequence $\text{context} \cup {\hat{x}&lt;em&gt;{1} \dots \hat{x}&lt;/em&gt;{k}}$ in &lt;strong&gt;one&lt;/strong&gt; forward pass, computing target logits for all $k+1$ token positions in parallel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Correction Phase:&lt;/strong&gt; Rejection sampling is applied sequentially across candidate tokens. The first rejected token $\hat{x}&lt;em&gt;i$ is resampled from the corrected residual distribution: $$p&lt;/em&gt;{\text{adjusted}}(x) = \text{relu}\left(p_{t}(x) - p_{d}(x)\right)$$&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This mathematical formulation guarantees that the final output distribution remains provably identical to sampling directly from the target model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxbs8tp7msjfd2kccs3bq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxbs8tp7msjfd2kccs3bq.png" alt="Figure 3: Detailed control-flow loop showing sequential draft generation, parallel target model scoring, and distribution-preserving rejection sampling." width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3: Detailed control-flow loop showing sequential draft generation, parallel target model scoring, and distribution-preserving rejection sampling.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sampling &amp;amp; Rejection Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch.nn.functional&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;spec_sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft_fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Executes speculative decoding with exact target distribution preservation.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft_logits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;current_seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 1. Draft Step: Generate k candidates sequentially
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;logits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;draft_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;next_logit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;draft_logits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_logit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multinomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_logit&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;current_seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Verify Step: Parallel validation over k+1 positions
&lt;/span&gt;    &lt;span class="n"&gt;target_logits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;target_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prefix_offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;accepted_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. Correction Step: Rejection sampling loop
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefix_offset&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;draft_logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Accept condition
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
            &lt;span class="n"&gt;accepted_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Reject: Resample candidate from adjusted distribution (pt - pd)+
&lt;/span&gt;            &lt;span class="n"&gt;residual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;residual&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="n"&gt;residual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;resampled_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multinomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;residual&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;accepted_count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;resampled_token&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;accepted_count&lt;/span&gt;

    &lt;span class="c1"&gt;# Bonus token sampling if all k drafted tokens are accepted
&lt;/span&gt;    &lt;span class="n"&gt;bonus_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multinomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefix_offset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bonus_token&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. The Speculative-Decoding Family
&lt;/h2&gt;

&lt;p&gt;While all speculative decoding variants rely on the same fundamental parallel verification framework, they differ in their structural draft generation mechanisms:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Draft Generation Architecture&lt;/th&gt;
&lt;th&gt;Target Acceleration&lt;/th&gt;
&lt;th&gt;Primary Operational Trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speculative Sampling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Independent auxiliary Small LM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.0–3.0×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires hosting separate draft model &amp;amp; tokenizer alignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Medusa&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-head prediction heads on target&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.3–3.0×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires parameter fine-tuning of prediction heads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EAGLE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Feature-level drafting with tree attention&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.0–3.0×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High draft acceptance rate; higher system complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Self-Speculative&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Target model internal early-exiting&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.3–1.8×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero additional weight hosting; limited by layer alignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lookahead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Jacobi iteration / N-gram retrieval&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.8–2.3×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Parameter-free; highly sequence/task dependent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Production Framework Integrations
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Hugging Face Transformers (&lt;code&gt;assisted_generation&lt;/code&gt;)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;

&lt;span class="n"&gt;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;target_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;assistant_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sshleifer/tiny-gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The future of artificial intelligence is&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;assistant_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;assistant_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;do_sample&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_new_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  vLLM Native Scheduler Integration
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; vllm.entrypoints.openai.api_server &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model&lt;/span&gt; meta-llama/Llama-3-8B-Instruct &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--speculative-model&lt;/span&gt; meta-llama/Llama-3-1B-Instruct &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--num_speculative_tokens&lt;/span&gt; 5 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-model-len&lt;/span&gt; 4096
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Benchmarking &amp;amp; Empirical Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mathematical Speedup Condition ($\alpha &amp;gt; c$)
&lt;/h3&gt;

&lt;p&gt;Let $c$ represent the ratio of draft model execution cost relative to target model execution cost per token:&lt;/p&gt;

&lt;p&gt;$$c = \frac{\text{Cost}&lt;em&gt;{\text{draft}}}{\text{Cost}&lt;/em&gt;{\text{target}}}$$&lt;/p&gt;

&lt;p&gt;Let $\alpha$ represent the average token acceptance rate across speculative steps. The theoretical speedup factor $S$ relative to standard autoregressive execution is modeled as:&lt;/p&gt;

&lt;p&gt;$$S \approx \frac{1 + k \cdot \alpha}{1 + k \cdot c}$$&lt;/p&gt;

&lt;p&gt;To achieve a net speedup ($S &amp;gt; 1$), the pipeline must satisfy the inequality:&lt;/p&gt;

&lt;p&gt;$$\alpha &amp;gt; c$$&lt;/p&gt;

&lt;p&gt;If candidate acceptance falls below the cost threshold ($\alpha &amp;lt; c$), the computational overhead of draft generation and verification outpaces the benefits of sequence amortization, leading to increased latency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyckukr9oe5xdc419tgpk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyckukr9oe5xdc419tgpk.png" alt="Figure 5: Measured wall-clock performance curve showing speedup vs. acceptance rate ($\alpha$) relative to relative cost fraction ($c$). Misaligned drafts fail to clear the baseline threshold." width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 5: Measured wall-clock performance curve showing speedup vs. acceptance rate ($\alpha$) relative to relative cost fraction ($c$). Misaligned drafts fail to clear the baseline threshold.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Measured Experimental Results
&lt;/h3&gt;

&lt;p&gt;Evaluating speculative decoding across unaligned draft configurations demonstrates the real-world operational impact of the $\alpha &amp;gt; c$ constraint:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Draft Configuration&lt;/th&gt;
&lt;th&gt;Relative Cost Fraction ($c$)&lt;/th&gt;
&lt;th&gt;Acceptance Rate ($\alpha$)&lt;/th&gt;
&lt;th&gt;Speedup ($k=1$)&lt;/th&gt;
&lt;th&gt;Speedup ($k=3$)&lt;/th&gt;
&lt;th&gt;Net Performance Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;tiny-gpt2&lt;/code&gt; (10M vs 124M)&lt;/td&gt;
&lt;td&gt;~0.08&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.68×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.44×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performance Penalty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gpt2&lt;/code&gt; Early-Exit (Layer 3/12)&lt;/td&gt;
&lt;td&gt;~0.25&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.68×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.38×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performance Penalty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gpt2&lt;/code&gt; Early-Exit (Layer 10/12)&lt;/td&gt;
&lt;td&gt;~0.83&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;29.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.38×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.35×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performance Penalty&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Speedup (x Baseline)
    1.2x ┼─────────────────────────────────────────────────── (Break-even: 1.0x)
    1.0x ┼───────────────────────────────────────────────────
    0.8x ┼───── Top Performance (k=1, alpha=4%..12%): ~0.68x
    0.6x ┼───────────────────────────────────────────────────
    0.4x ┼───────────────── Top Performance (k=3): ~0.35x..0.44x
    0.2x ┼───────────────────────────────────────────────────
         └───────┬───────────────┬───────────────┬───────────
                k=1             k=2             k=3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  System Failure Modes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Distributional Mismatch ($\alpha &amp;lt; c$):&lt;/strong&gt; Using an unaligned draft model causes frequent rejection steps, incurring severe draft-overhead penalties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High Batch Aggregation ($B \gg 1$):&lt;/strong&gt; At high query volumes, hardware compute pipelines shift from memory-bound to compute-bound states. Under these conditions, speculative verification offers diminishing latency returns while increasing total FLOP utilization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-Entropy Generation Tasks:&lt;/strong&gt; Tasks with high logical complexity (e.g., code generation or complex mathematical reasoning) exhibit lower acceptance rates ($\alpha$), reducing maximum attainable sequence extensions per step.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Speculative decoding is a powerful technique for accelerating single-stream LLM inference, but its benefits are fundamentally conditional. Achieving real-world speedups requires strict optimization of draft alignment ($\alpha$) relative to system cost ($c$). When deploying speculative pipelines in production systems, profile target-draft acceptance rates under actual workload distributions before enabling parallel verification logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Leviathan, Y., Kalman, M., &amp;amp; Matias, Y. (2023). Fast Inference from Transformers via Speculative Decoding. &lt;em&gt;International Conference on Machine Learning (ICML)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2211.17192" rel="noopener noreferrer"&gt;arXiv:2211.17192&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chen, C., Borgeaud, S., Zhou, G., Steiner, D., &amp;amp; Chen, Z. (2023). Accelerating Large Language Model Decoding with Speculative Sampling. &lt;em&gt;arXiv preprint&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2302.01318" rel="noopener noreferrer"&gt;arXiv:2302.01318&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cai, T., Li, Y., Geng, Z., Peng, L., Li, F., &amp;amp; Xiao, W. (2024). Medusa: Simple LLM Inference Acceleration Framework with Multiple Decoding Heads. &lt;em&gt;International Conference on Machine Learning (ICML)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2401.10774" rel="noopener noreferrer"&gt;arXiv:2401.10774&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Li, Y., Wei, F., Zhang, C., &amp;amp; Zhang, H. (2024). EAGLE: Speculative Sampling Requires Rethinking Feature Uncertainty. &lt;em&gt;International Conference on Machine Learning (ICML)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2401.15077" rel="noopener noreferrer"&gt;arXiv:2401.15077&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Zhang, J., Wang, J., Huang, H., Chen, Y., &amp;amp; Zhou, W. (2023). Self-Speculative Decoding with Self-Draft and Self-Verification. &lt;em&gt;Empirical Methods in Natural Language Processing (EMNLP)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2311.08466" rel="noopener noreferrer"&gt;arXiv:2311.08466&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fu, Y., Bailis, P., Stoica, I., &amp;amp; Zhang, H. (2024). Break the Sequential Dependency of LLM Inference Using Lookahead Decoding. &lt;em&gt;arXiv preprint&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2402.02057" rel="noopener noreferrer"&gt;arXiv:2402.02057&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Original blog: &lt;a href="https://YuvrajSinghBhadoria2.github.io/spec-decoding-blog/" rel="noopener noreferrer"&gt;https://YuvrajSinghBhadoria2.github.io/spec-decoding-blog/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Tags: #llm #machinelearning #performance #inference&lt;/em&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>machinelearning</category>
      <category>performance</category>
      <category>inference</category>
    </item>
    <item>
      <title>Demystifying Speculative Decoding: From Architecture to Production Bottlenecks</title>
      <dc:creator>Yuvraj singh Bhadoria</dc:creator>
      <pubDate>Sun, 30 Aug 2026 03:35:19 +0000</pubDate>
      <link>https://dev.to/yuvraj_llminference/speculative-decoding-i-ran-it-on-real-models-and-it-was-slower-10hk</link>
      <guid>https://dev.to/yuvraj_llminference/speculative-decoding-i-ran-it-on-real-models-and-it-was-slower-10hk</guid>
      <description>&lt;h1&gt;
  
  
  Demystifying Speculative Decoding: From Architecture to Production Bottlenecks
&lt;/h1&gt;

&lt;p&gt;Speculative decoding is one of the most widely discussed inference optimizations in recent LLM engineering, and frequently one of the most misunderstood. The core proposition sounds ideal: achieving a 2–3× boost in decoding throughput with &lt;strong&gt;mathematically identical&lt;/strong&gt; output distributions—yielding performance gains via a lightweight secondary model.&lt;/p&gt;

&lt;p&gt;In practice, speculative decoding functions as a trade-off rather than a guaranteed acceleration: you pay the computational overhead of running a smaller draft model with the expectation that its outputs align sufficiently with the target model to yield a net speedup.&lt;/p&gt;

&lt;p&gt;This post details the complete system stack—covering core transformer architecture, memory bandwidth constraints, the draft-then-verify loop, state-of-the-art methodology taxonomies, and empirical benchmark evaluations on GPT-2 weights—to highlight where performance gains originate and where they risk regressing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Executive Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Autoregressive Decoding is Serial &amp;amp; Memory-Bound:&lt;/strong&gt; Single-token autoregressive generation is limited by memory bandwidth during low-batch inference. Speculative decoding directly targets this single-stream latency bottleneck.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Core Mechanism is Draft-Then-Verify:&lt;/strong&gt; A fast draft model proposes $k$ candidate tokens sequentially. The target model then verifies all $k+1$ positions in a single parallel forward pass. Rejection sampling preserves the exact target output distribution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Speedup Has a Hard Inequality Constraint ($\alpha &amp;gt; c$):&lt;/strong&gt; Net performance gains require the draft model's token acceptance rate ($\alpha$) to strictly exceed its relative computational cost fraction ($c$). Failing this condition increases overall latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Architectural Taxonomy:&lt;/strong&gt; Current approaches (Speculative Sampling, Medusa, EAGLE, Self-Speculative, Lookahead) vary primarily in their draft generation mechanism. End-to-end performance depends directly on draft–target distribution alignment rather than the verification loop itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empirical Findings:&lt;/strong&gt; Evaluations on un-aligned weights yielded a speedup of &lt;strong&gt;0.2–0.9×&lt;/strong&gt; (a net performance penalty). This negative result highlights the operational necessity of validating draft alignment prior to deployment.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Visual Overview
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbiulln0v5bhg06sxj0s9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbiulln0v5bhg06sxj0s9.png" alt="Figure 0: High-level visual summary showing serial memory constraints, drafting execution, taxonomy, framework integration, and performance benchmarking." width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Model Setup &amp;amp; Architecture
&lt;/h2&gt;

&lt;p&gt;To evaluate speculative decoding, we must analyze the hardware execution costs of a single forward pass. A causal language model generates next-token probability distributions by executing tensor operations across its transformer stack. This pipeline is bounded by two distinct factors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Matrix multiplication operations (GEMM FLOPS across transformer layers).&lt;/li&gt;
&lt;li&gt;Memory bus transfers (fetching model weights and KV-cache states from DRAM to SRAM/registers).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For small batch sizes ($B=1$) on single-stream inference, memory transfers dominate total step latency: compute units execute quickly and subsequently stall while waiting for weight loading. Speculative decoding specifically targets this architectural bottleneck.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Target Model (Ground Truth): GPT-2 124M]
d_model=768, depth=12, heads=12, Vocab=50k
                       ▲
                       │ (pt)
             ┌───────────────────┐
             │ Target Final Head │
             └─────────▲─────────┘
                       │
             ┌───────────────────┐
             │  GPT-2 (12 Layers)│
             └─────────▲─────────┘
                       │
             ┌───────────────────┐
             │  Input Embeddings │
             └───────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Experimental Setup Parameters
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Target Model:&lt;/strong&gt; &lt;code&gt;gpt2&lt;/code&gt; (124M parameters, 12 layers).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Draft Models:&lt;/strong&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;sshleifer/tiny-gpt2&lt;/code&gt; (10M parameters, 2 layers) serving as an independent small LM draft.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gpt2&lt;/code&gt; early-exit heads at intermediate layers $m \in {3, 10}$ serving as a self-speculative draft.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decoding Strategy:&lt;/strong&gt; Rejection sampling (Chen et al., 2023) at temperature $T = 0.8$.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluation Metric:&lt;/strong&gt; Wall-clock output generation rate (tokens/sec) evaluated across benchmark prompts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reproducibility:&lt;/strong&gt; Benchmarks are programmatically generated via &lt;code&gt;spec_experiment.py&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy37ilao6m7rsanotbw9e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy37ilao6m7rsanotbw9e.png" alt="Figure 1: Structural comparison between the primary target model (GPT-2 124M), an independent draft model (tiny-GPT2 10M), and self-speculative early-exit configurations." width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key Takeaway:&lt;/strong&gt; A draft mechanism provides net throughput benefits only when it is computationally inexpensive (low layer count/parameter footprint) &lt;strong&gt;and&lt;/strong&gt; statistically aligned with the target distribution.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. The Serial Memory Bottleneck
&lt;/h2&gt;

&lt;p&gt;Transformer architectures process input sequences in parallel during context encoding (prefill phase), but execute sequentially across step iterations during auto-regressive decoding (decoding phase). Token $t_i$ cannot be evaluated until token $t_{i-1}$ is generated, due to causal self-attention dependencies across historic Key-Value (KV) states.&lt;/p&gt;

&lt;p&gt;$$\text{Latency}&lt;em&gt;{\text{autoregressive}} = N&lt;/em&gt;{\text{tokens}} \times t_{\text{per-token}}$$&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Panel A: Autoregressive Bottleneck (Serial)
[Step t]  ──(Fetch Weights &amp;amp; KV)──&amp;gt; [Token 1] ──┐
[Step t+1] ──(Fetch Weights &amp;amp; KV)──&amp;gt; [Token 2] ──┼─&amp;gt; High Memory Stall / Idle Compute
[Step t+2] ──(Fetch Weights &amp;amp; KV)──&amp;gt; [Token 3] ──┘

Panel B: Speculative Verification (Parallel)
[Single Forward Pass] ──(Fetch Weights Once)──&amp;gt; [Verify Tokens 1, 2, 3, 4 Simultaneously]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At low batch sizes, single-token generation iterations fail to fully saturate GPU compute pipelines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0tcnu31umlg1rh8e1iy0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0tcnu31umlg1rh8e1iy0.png" alt="Figure 2: Comparison of memory-bandwidth-bound serial autoregressive generation (Panel A) against batch-parallel target verification across k+1 token positions (Panel B)." width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Executing a single target forward pass over a sequence of length $L+k$ requires nearly the same memory bandwidth overhead as executing a forward pass over sequence length $L$. Speculative decoding leverages this invariant by amortizing weight transfer costs across $k+1$ candidate tokens simultaneously.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The Speculative Sampling Mechanism
&lt;/h2&gt;

&lt;p&gt;The speculative sampling execution pipeline follows a three-step cycle:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Draft Phase:&lt;/strong&gt; The lightweight draft model generates $k$ candidate tokens sequentially: $$\hat{x}&lt;em&gt;{1}, \hat{x}&lt;/em&gt;{2}, \dots, \hat{x}&lt;em&gt;{k} \sim p&lt;/em&gt;{d}(x \mid \text{context})$$&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification Phase:&lt;/strong&gt; The target model processes the concatenated sequence $\text{context} \cup {\hat{x}&lt;em&gt;{1} \dots \hat{x}&lt;/em&gt;{k}}$ in &lt;strong&gt;one&lt;/strong&gt; forward pass, computing target logits for all $k+1$ token positions in parallel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Correction Phase:&lt;/strong&gt; Rejection sampling is applied sequentially across candidate tokens. The first rejected token $\hat{x}&lt;em&gt;i$ is resampled from the corrected residual distribution: $$p&lt;/em&gt;{\text{adjusted}}(x) = \text{relu}\left(p_{t}(x) - p_{d}(x)\right)$$&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This mathematical formulation guarantees that the final output distribution remains provably identical to sampling directly from the target model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F63ejpgqvxipy1kpfecpg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F63ejpgqvxipy1kpfecpg.png" alt="Figure 3: Detailed control-flow loop showing sequential draft generation, parallel target model scoring, and distribution-preserving rejection sampling." width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sampling &amp;amp; Rejection Implementation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch.nn.functional&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;spec_sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft_fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Executes speculative decoding with exact target distribution preservation.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;draft_logits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;current_seq&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 1. Draft Step: Generate k candidates sequentially
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;logits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;draft_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;next_logit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;draft_logits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_logit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multinomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;next_logit&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;current_seq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Verify Step: Parallel validation over k+1 positions
&lt;/span&gt;    &lt;span class="n"&gt;target_logits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;target_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;prefix_offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;accepted_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. Correction Step: Rejection sampling loop
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefix_offset&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;pd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;draft_logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c1"&gt;# Accept condition
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
            &lt;span class="n"&gt;accepted_count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Reject: Resample candidate from adjusted distribution (pt - pd)+
&lt;/span&gt;            &lt;span class="n"&gt;residual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pt&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;residual&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="n"&gt;residual&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;resampled_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multinomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;residual&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;accepted_count&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;resampled_token&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;accepted_count&lt;/span&gt;

    &lt;span class="c1"&gt;# Bonus token sampling if all k drafted tokens are accepted
&lt;/span&gt;    &lt;span class="n"&gt;bonus_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multinomial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;F&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;softmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_logits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;prefix_offset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;item&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seq&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;draft_tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bonus_token&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. The Speculative-Decoding Family
&lt;/h2&gt;

&lt;p&gt;While all speculative decoding variants rely on the same fundamental parallel verification framework, they differ in their structural draft generation mechanisms:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqxl6syvbnc3z2vnstiw5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqxl6syvbnc3z2vnstiw5.png" alt="Figure 4: Classification taxonomy of speculative decoding variants structured by draft generation method." width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Approach&lt;/th&gt;
&lt;th&gt;Draft Generation Architecture&lt;/th&gt;
&lt;th&gt;Target Acceleration&lt;/th&gt;
&lt;th&gt;Primary Operational Trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speculative Sampling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Independent auxiliary Small LM&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.0–3.0×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires hosting separate draft model &amp;amp; tokenizer alignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Medusa&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Multi-head prediction heads on target&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.3–3.0×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Requires parameter fine-tuning of prediction heads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EAGLE&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Feature-level drafting with tree attention&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;2.0–3.0×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;High draft acceptance rate; higher system complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Self-Speculative&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Target model internal early-exiting&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.3–1.8×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Zero additional weight hosting; limited by layer alignment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lookahead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Jacobi iteration / N-gram retrieval&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.8–2.3×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Parameter-free; highly sequence/task dependent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Production Framework Integrations
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Hugging Face Transformers (&lt;code&gt;assisted_generation&lt;/code&gt;)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;

&lt;span class="n"&gt;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;target_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;assistant_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AutoModelForCausalLM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sshleifer/tiny-gpt2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The future of artificial intelligence is&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_tensors&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;input_ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;assistant_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;assistant_model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;do_sample&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;max_new_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  vLLM Native Scheduler Integration
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; vllm.entrypoints.openai.api_server &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model&lt;/span&gt; meta-llama/Llama-3-8B-Instruct &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--speculative-model&lt;/span&gt; meta-llama/Llama-3-1B-Instruct &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--num_speculative_tokens&lt;/span&gt; 5 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--max-model-len&lt;/span&gt; 4096
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Benchmarking &amp;amp; Empirical Performance
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mathematical Speedup Condition ($\alpha &amp;gt; c$)
&lt;/h3&gt;

&lt;p&gt;Let $c$ represent the ratio of draft model execution cost relative to target model execution cost per token:&lt;/p&gt;

&lt;p&gt;$$c = \frac{\text{Cost}&lt;em&gt;{\text{draft}}}{\text{Cost}&lt;/em&gt;{\text{target}}}$$&lt;/p&gt;

&lt;p&gt;Let $\alpha$ represent the average token acceptance rate across speculative steps. The theoretical speedup factor $S$ relative to standard autoregressive execution is modeled as:&lt;/p&gt;

&lt;p&gt;$$S \approx \frac{1 + k \cdot \alpha}{1 + k \cdot c}$$&lt;/p&gt;

&lt;p&gt;To achieve a net speedup ($S &amp;gt; 1$), the pipeline must satisfy the inequality:&lt;/p&gt;

&lt;p&gt;$$\alpha &amp;gt; c$$&lt;/p&gt;

&lt;p&gt;If candidate acceptance falls below the cost threshold ($\alpha &amp;lt; c$), the computational overhead of draft generation and verification outpaces the benefits of sequence amortization, leading to increased latency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp3aixcpbseqzv7r634ev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp3aixcpbseqzv7r634ev.png" alt="Figure 5: Measured wall-clock performance curve showing speedup vs. acceptance rate (α) relative to relative cost fraction (c). Misaligned drafts fail to clear the baseline threshold." width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Measured Experimental Results
&lt;/h3&gt;

&lt;p&gt;Evaluating speculative decoding across unaligned draft configurations demonstrates the real-world operational impact of the $\alpha &amp;gt; c$ constraint:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Draft Configuration&lt;/th&gt;
&lt;th&gt;Relative Cost Fraction ($c$)&lt;/th&gt;
&lt;th&gt;Acceptance Rate ($\alpha$)&lt;/th&gt;
&lt;th&gt;Speedup ($k=1$)&lt;/th&gt;
&lt;th&gt;Speedup ($k=3$)&lt;/th&gt;
&lt;th&gt;Net Performance Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;tiny-gpt2&lt;/code&gt; (10M vs 124M)&lt;/td&gt;
&lt;td&gt;~0.08&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.68×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.44×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performance Penalty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gpt2&lt;/code&gt; Early-Exit (Layer 3/12)&lt;/td&gt;
&lt;td&gt;~0.25&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;12.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.68×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.38×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performance Penalty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;gpt2&lt;/code&gt; Early-Exit (Layer 10/12)&lt;/td&gt;
&lt;td&gt;~0.83&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;29.0%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.38×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.35×&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Performance Penalty&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Speedup (x Baseline)
    1.2x ┼─────────────────────────────────────────────────── (Break-even: 1.0x)
    1.0x ┼───────────────────────────────────────────────────
    0.8x ┼───── Top Performance (k=1, alpha=4%..12%): ~0.68x
    0.6x ┼───────────────────────────────────────────────────
    0.4x ┼───────────────── Top Performance (k=3): ~0.35x..0.44x
    0.2x ┼───────────────────────────────────────────────────
         └───────┬───────────────┬───────────────┬───────────
               k=1             k=2             k=3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  System Failure Modes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Distributional Mismatch ($\alpha &amp;lt; c$):&lt;/strong&gt; Using an unaligned draft model causes frequent rejection steps, incurring severe draft-overhead penalties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High Batch Aggregation ($B \gg 1$):&lt;/strong&gt; At high query volumes, hardware compute pipelines shift from memory-bound to compute-bound states. Under these conditions, speculative verification offers diminishing latency returns while increasing total FLOP utilization.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-Entropy Generation Tasks:&lt;/strong&gt; Tasks with high logical complexity (e.g., code generation or complex mathematical reasoning) exhibit lower acceptance rates ($\alpha$), reducing maximum attainable sequence extensions per step.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Speculative decoding is a powerful technique for accelerating single-stream LLM inference, but its benefits are fundamentally conditional. Achieving real-world speedups requires strict optimization of draft alignment ($\alpha$) relative to system cost ($c$). When deploying speculative pipelines in production systems, profile target-draft acceptance rates under actual workload distributions before enabling parallel verification logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Leviathan, Y., Kalman, M., &amp;amp; Matias, Y. (2023). Fast Inference from Transformers via Speculative Decoding. &lt;em&gt;International Conference on Machine Learning (ICML)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2211.17192" rel="noopener noreferrer"&gt;arXiv:2211.17192&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Chen, C., Borgeaud, S., Zhou, G., Steiner, D., &amp;amp; Chen, Z. (2023). Accelerating Large Language Model Decoding with Speculative Sampling. &lt;em&gt;arXiv preprint&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2302.01318" rel="noopener noreferrer"&gt;arXiv:2302.01318&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cai, T., Li, Y., Geng, Z., Peng, L., Li, F., &amp;amp; Xiao, W. (2024). Medusa: Simple LLM Inference Acceleration Framework with Multiple Decoding Heads. &lt;em&gt;International Conference on Machine Learning (ICML)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2401.10774" rel="noopener noreferrer"&gt;arXiv:2401.10774&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Li, Y., Wei, F., Zhang, C., &amp;amp; Zhang, H. (2024). EAGLE: Speculative Sampling Requires Rethinking Feature Uncertainty. &lt;em&gt;International Conference on Machine Learning (ICML)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2401.15077" rel="noopener noreferrer"&gt;arXiv:2401.15077&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Zhang, J., Wang, J., Huang, H., Chen, Y., &amp;amp; Zhou, W. (2023). Self-Speculative Decoding with Self-Draft and Self-Verification. &lt;em&gt;Empirical Methods in Natural Language Processing (EMNLP)&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2311.08466" rel="noopener noreferrer"&gt;arXiv:2311.08466&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Fu, Y., Bailis, P., Stoica, I., &amp;amp; Zhang, H. (2024). Break the Sequential Dependency of LLM Inference Using Lookahead Decoding. &lt;em&gt;arXiv preprint&lt;/em&gt;. &lt;a href="https://arxiv.org/abs/2402.02057" rel="noopener noreferrer"&gt;arXiv:2402.02057&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>llm</category>
      <category>inference</category>
      <category>machinelearning</category>
      <category>performance</category>
    </item>
    <item>
      <title>KV-Cache Quantization: How 2–4 Bits Cut LLM Memory by 4–8 Without Killing Quality</title>
      <dc:creator>Yuvraj singh Bhadoria</dc:creator>
      <pubDate>Sat, 29 Aug 2026 15:24:17 +0000</pubDate>
      <link>https://dev.to/yuvraj_llminference/kv-cache-quantization-how-2-4-bits-cut-llm-memory-by-4-8-without-killing-quality-15lh</link>
      <guid>https://dev.to/yuvraj_llminference/kv-cache-quantization-how-2-4-bits-cut-llm-memory-by-4-8-without-killing-quality-15lh</guid>
      <description>&lt;h1&gt;
  
  
  KV-Cache Quantization: I Ran the Experiments So You Don't Have To
&lt;/h1&gt;

&lt;p&gt;KV-cache quantization is one of the highest-leverage knobs in modern LLM inference. As context windows&lt;br&gt;
stretch past 128K tokens and batch sizes climb, the Key-Value cache — not the model weights — becomes the&lt;br&gt;
dominant memory consumer, quietly turning serving into a memory-bound problem. Storing that cache in 4-bit&lt;br&gt;
or 2-bit cuts its footprint 4–8× with minimal quality loss, but naive rounding collapses attention rather&lt;br&gt;
than compressing it.&lt;/p&gt;

&lt;p&gt;In this deep-dive I don't take that on faith. I load a real model (&lt;strong&gt;Qwen2.5-0.5B&lt;/strong&gt;), capture its actual&lt;br&gt;
KV-cache activations, quantize them four different ways, and measure exactly how each scheme distorts&lt;br&gt;
attention. Then I compare the three production schemes — &lt;strong&gt;KIVI&lt;/strong&gt;, &lt;strong&gt;KVQuant&lt;/strong&gt;, and &lt;strong&gt;GEAR&lt;/strong&gt; — and show&lt;br&gt;
how to wire quantization into a real serving stack (vLLM / HuggingFace).&lt;/p&gt;
&lt;h2&gt;
  
  
  The Goal
&lt;/h2&gt;

&lt;p&gt;By the end you should be able to answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why the KV cache — not the weights — is the memory wall on long context.&lt;/li&gt;
&lt;li&gt;The trap I measured: why naive &lt;code&gt;round()&lt;/code&gt; on the cache is a silent quality killer.&lt;/li&gt;
&lt;li&gt;Which scheme to reach for: &lt;strong&gt;KIVI&lt;/strong&gt;, &lt;strong&gt;KVQuant&lt;/strong&gt;, or &lt;strong&gt;GEAR&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;How to wire it into a real serving stack (vLLM / HuggingFace).&lt;/li&gt;
&lt;li&gt;How to compute the cache size for &lt;em&gt;your&lt;/em&gt; model in 30 lines of Python.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbswzre7amcsl86dncszm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbswzre7amcsl86dncszm.png" alt="End-to-end KV-cache quantization workflow" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Hardware &amp;amp; Experiment Setup
&lt;/h2&gt;

&lt;p&gt;Before the theory, the actual rig the numbers below come from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; &lt;code&gt;Qwen/Qwen2.5-0.5B-Instruct&lt;/code&gt; — 0.5B params, 24 layers, GQA (14 query / 2 KV heads), head_dim 64.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Machine:&lt;/strong&gt; a CPU-only laptop (no GPU) — the point is you can reproduce this without a cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt:&lt;/strong&gt; one 77-token real sentence, run through the model's forward pass.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What we captured:&lt;/strong&gt; the &lt;em&gt;actual&lt;/em&gt; Key and Value projections at every layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What we measured:&lt;/strong&gt; relative attention-score error &lt;code&gt;‖A − Â‖ / ‖A‖&lt;/code&gt; after quantizing the KV cache.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No synthetic tensors, no "trust me" — the activations are the model's own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo7ibihg1b36f3wkju90i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo7ibihg1b36f3wkju90i.png" alt="Complete architecture of the Qwen2.5-0.5B model used in this experiment" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Component 1 — The cache is a tax that scales with tokens
&lt;/h2&gt;

&lt;p&gt;Every transformer layer keeps the Key and Value vectors of every token it has seen, so attention doesn't&lt;br&gt;
have to recompute them. That storage is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KV_bytes = 2 · n_layers · n_kv_heads · head_dim · bytes_per_elem · seq_len · batch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;strong&gt;Llama-3-8B&lt;/strong&gt; (32 layers, 8 KV heads, head_dim 128) that's &lt;strong&gt;128 KiB per token at fp16&lt;/strong&gt;, and it&lt;br&gt;
grows linearly with both sequence length and batch. The picture below is the whole problem in one frame.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foyf2k0j38zf9u7c1yg8m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foyf2k0j38zf9u7c1yg8m.png" alt="Why context length causes OOM: weights vs KV-cache memory growth" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Context (tokens)&lt;/th&gt;
&lt;th&gt;fp16&lt;/th&gt;
&lt;th&gt;8-bit&lt;/th&gt;
&lt;th&gt;4-bit&lt;/th&gt;
&lt;th&gt;2-bit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4,096&lt;/td&gt;
&lt;td&gt;0.54 GB&lt;/td&gt;
&lt;td&gt;0.27 GB&lt;/td&gt;
&lt;td&gt;0.13 GB&lt;/td&gt;
&lt;td&gt;0.07 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8,192&lt;/td&gt;
&lt;td&gt;1.07 GB&lt;/td&gt;
&lt;td&gt;0.54 GB&lt;/td&gt;
&lt;td&gt;0.27 GB&lt;/td&gt;
&lt;td&gt;0.13 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;32,768&lt;/td&gt;
&lt;td&gt;4.29 GB&lt;/td&gt;
&lt;td&gt;2.15 GB&lt;/td&gt;
&lt;td&gt;1.07 GB&lt;/td&gt;
&lt;td&gt;0.54 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;131,072&lt;/td&gt;
&lt;td&gt;17.18 GB&lt;/td&gt;
&lt;td&gt;8.59 GB&lt;/td&gt;
&lt;td&gt;4.29 GB&lt;/td&gt;
&lt;td&gt;2.15 GB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Batch 64 requests at 32K: the fp16 cache alone is &lt;strong&gt;~275 GB&lt;/strong&gt; — past any single GPU. Even 4-bit leaves&lt;br&gt;
~69 GB. This is why long-context serving is &lt;strong&gt;memory-bound&lt;/strong&gt;: the GPU's compute cores sit idle while the&lt;br&gt;
KV cache is shuffled from main memory into SRAM for every generated token (KIVI, ICML 2024).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;br&gt;
A smaller cache ≠ automatic speedup. The win is &lt;em&gt;throughput via bigger batches&lt;/em&gt;, and only if your&lt;br&gt;
serving stack (paged memory, fused dequant-matmul, correct calibration) supports KV quantization end to&lt;br&gt;
end. Quantize the tensor but not the memory manager and you get neither.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Component 2 — I measured the trap myself
&lt;/h2&gt;

&lt;p&gt;The obvious move is uniform, per-token quantization. That's also the mistake. Here is the experiment, end&lt;br&gt;
to end:&lt;/p&gt;

&lt;p&gt;I fake-quantized the captured KV cache at &lt;strong&gt;2-bit and 4-bit&lt;/strong&gt; under four schemes, recomputed attention&lt;br&gt;
scores, and measured the error. The bar chart is the measured result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkpcdin52v3qlydaumqf1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkpcdin52v3qlydaumqf1.png" alt="Measured KV-cache quantization error on Qwen2.5-0.5B" width="799" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scheme (bits)&lt;/th&gt;
&lt;th&gt;2-bit attn error&lt;/th&gt;
&lt;th&gt;4-bit attn error&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;uniform (K,V per-token) — &lt;strong&gt;the naive one&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.786&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.401&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;uniform (K,V per-channel)&lt;/td&gt;
&lt;td&gt;0.623&lt;/td&gt;
&lt;td&gt;0.215&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;K per-channel, V per-token (KIVI)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.623&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.215&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;K per-token, V per-channel (wrong)&lt;/td&gt;
&lt;td&gt;0.786&lt;/td&gt;
&lt;td&gt;0.401&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things jump out, and they match the literature:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Naive per-token quantization is the worst&lt;/strong&gt; — highest attention error at both bit-widths. Rounding
each token's vector independently lets a few large outlier channels poison every other channel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quantizing keys per-channel fixes most of it.&lt;/strong&gt; Per-channel key (0.623) cuts the error vs per-token
key (0.786) — about &lt;strong&gt;1.3× lower&lt;/strong&gt; here, and KIVI reports a much larger &lt;strong&gt;~5× gap on Llama-2&lt;/strong&gt; because
its outlier channels are more aggressive. Direction is identical; magnitude scales with the model.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why? Look at the distribution. Keys have a few &lt;strong&gt;fixed outlier channels&lt;/strong&gt; (same channels, every token);&lt;br&gt;
values have no such pattern but are mixed by attention into the output. So keys want per-channel&lt;br&gt;
quantization, values want per-token. Uniform quantization ignores that and pays for it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwggybht0kr3apk8dt2c5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwggybht0kr3apk8dt2c5.png" alt="Asymmetric outlier structure: why per-token round() fails vs per-channel" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole asymmetric scheme in a dozen lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fake_quant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;qmax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;scale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;amax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keepdim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;clamp_min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1e-9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;qmax&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;qmax&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;qmax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;

&lt;span class="c1"&gt;# KIVI: keys per-channel (dim = sequence), values per-token (dim = head_dim)
&lt;/span&gt;&lt;span class="n"&gt;K_q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fake_quant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# per-channel over tokens
&lt;/span&gt;&lt;span class="n"&gt;V_q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fake_quant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# per-token over head_dim
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Component 3 — Three schemes that actually ship
&lt;/h2&gt;

&lt;p&gt;Three papers define the frontier. They agree on the outlier structure and diverge on how hard they push&lt;br&gt;
the bit-width.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Scheme&lt;/th&gt;
&lt;th&gt;Bits&lt;/th&gt;
&lt;th&gt;Quality&lt;/th&gt;
&lt;th&gt;Memory / throughput&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;KIVI&lt;/strong&gt; (ICML'24)&lt;/td&gt;
&lt;td&gt;per-channel K, per-token V; recent tokens kept fp16&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;~2% drop on Llama-2/Mistral (GSM8K); Falcon needs 4-bit&lt;/td&gt;
&lt;td&gt;2.6× peak mem, 4× larger batch, &lt;strong&gt;2.35–3.47× throughput&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;KVQuant&lt;/strong&gt; (NeurIPS'24)&lt;/td&gt;
&lt;td&gt;pre-RoPE per-channel K, non-uniform, dense-and-sparse (1% outliers)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;&amp;lt;0.1 perplexity drop&lt;/strong&gt; (WikiText-2, C4)&lt;/td&gt;
&lt;td&gt;4.8× compression; LLaMA-7B at &lt;strong&gt;1M ctx on 1× A100&lt;/strong&gt;, 10M on 8× GPU; ~1.7× matvec speedup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;GEAR&lt;/strong&gt; (ICML'24)&lt;/td&gt;
&lt;td&gt;quantization + low-rank error + sparse outliers&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;near-lossless; up to &lt;strong&gt;24.4% over SOTA&lt;/strong&gt; at 2-bit&lt;/td&gt;
&lt;td&gt;2.39× peak mem, &lt;strong&gt;2.1–5.07× throughput&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvwx8uwdmfrdc34fzgx8s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvwx8uwdmfrdc34fzgx8s.png" alt="Memory saved vs throughput at a glance" width="800" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2vpebnuo98fbof9bqsf0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2vpebnuo98fbof9bqsf0.png" alt="How KIVI, KVQuant, and GEAR decompose the KV tensor" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;KIVI is the pragmatic default.&lt;/strong&gt; Tuning-free, plug-and-play, ships as a HuggingFace wrapper. The
full-precision window for the most recent tokens rescues hard reasoning — without it, fake 2-bit on
GSM8K craters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KVQuant is the "go long" play.&lt;/strong&gt; Quantizing &lt;em&gt;before&lt;/em&gt; RoPE (which otherwise mixes outlier channels)
plus sensitivity-weighted non-uniform codebooks and a 1% sparse outlier store reaches 3-bit with
sub-0.1 perplexity loss and turns context length into a tunable dial.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GEAR is the "go low" play.&lt;/strong&gt; Instead of fighting residuals it models them: a low-rank matrix recovers
the coherent part of the quantization error, a sparse matrix catches the rest. It layers on top of any
base quantizer and is the only one of the three that stays near-lossless at 2-bit on complex generation.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;br&gt;
These numbers are method-specific. KIVI reports that &lt;strong&gt;Falcon-7B (multi-query attention, a single KV&lt;br&gt;
head) needs 4-bit, not 2-bit&lt;/strong&gt; — MQA is already so compressed there's no redundancy left to trade. If&lt;br&gt;
your model uses MQA, don't assume 2-bit works.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Component 4 — Serving architecture &amp;amp; manifests
&lt;/h2&gt;

&lt;p&gt;This isn't a research curiosity you bolt on by hand — it slots into the paged-memory path every modern&lt;br&gt;
server already runs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbj1x3ns5jkr65yq1091s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbj1x3ns5jkr65yq1091s.png" alt="Serving layer: quantized KV blocks mapped to paged memory in vLLM" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the long-context frontier, KVQuant and GEAR ship CUDA kernels that fuse dequant into the matmul —&lt;br&gt;
without that fusion, the quantization overhead eats the memory win. In practice you rarely write the kernel&lt;br&gt;
yourself; two drop-in paths:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;vLLM — fp8 KV cache (the safe default today):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# vllm serve config&lt;/span&gt;
&lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;meta-llama/Llama-3-8B-Instruct&lt;/span&gt;
&lt;span class="na"&gt;kv_cache_dtype&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fp8_e5m2&lt;/span&gt;        &lt;span class="c1"&gt;# 2x smaller KV, near-lossless&lt;/span&gt;
&lt;span class="na"&gt;max_model_len&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;131072&lt;/span&gt;
&lt;span class="na"&gt;gpu_memory_utilization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.85&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; vllm.entrypoints.openai.api_server &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--model&lt;/span&gt; meta-llama/Llama-3-8B-Instruct &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--kv-cache-dtype&lt;/span&gt; fp8_e5m2 &lt;span class="nt"&gt;--max-model-len&lt;/span&gt; 131072
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;HuggingFace + KIVI (research-grade 2-bit):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;models.llama_kivi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LlamaForCausalLM_KIVI&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;k_bits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v_bits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;          &lt;span class="c1"&gt;# 2-bit KV cache
&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;group_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;residual_length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;                    &lt;span class="c1"&gt;# recent tokens kept fp16
&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LlamaForCausalLM_KIVI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;meta-llama/Llama-2-7b-hf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where it still breaks
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Small model + long context = danger zone.&lt;/strong&gt; Perplexity degradation grows as you shrink the model
and lengthen the prompt; the headroom that hides quantization error in a 70B model doesn't exist in a
7B one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning tasks are unforgiving.&lt;/strong&gt; GSM8K-style math is where fake quantization fails hardest; the
recent-token window (KIVI) or low-rank residual (GEAR) is not optional.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput only follows if the kernel exists.&lt;/strong&gt; KVQuant and GEAR ship custom CUDA kernels; without
fused dequant-matmul the overhead eats the memory win. Production stacks now default to &lt;strong&gt;fp8 KV
cache&lt;/strong&gt; — 2× smaller, near-lossless, hardware-accelerated on Hopper/Ada. 4-bit and below still need the
research kernels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calibration matters at the low end.&lt;/strong&gt; KVQuant calibrates key scales offline; skip it and 3-bit
quality drops sharply.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The memory math (verified)
&lt;/h2&gt;

&lt;p&gt;The tables above aren't benchmark results — they're deterministic accounting that tells you whether the&lt;br&gt;
request fits at all. Here's the whole computation, in 30 lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;kv_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seq_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# 2 (K and V) * layers * kv_heads * head_dim * (bits/8) * seq * batch
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bits&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;seq_len&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;kv_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;131072&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# 17.18 GB  (fp16, 1 req, 128K)
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;kv_bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;131072&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1e9&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# 4.29 GB   (4-bit)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F09hfdtmmlt4khe5gn9cm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F09hfdtmmlt4khe5gn9cm.png" alt="KV cache memory vs context length for Llama-3-8B" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run it and you get the figures in this post. That's the question KV-cache quantization exists to answer:&lt;br&gt;
&lt;em&gt;does this request fit?&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;KV-cache quantization is the rare optimization that's both mathematically simple and empirically subtle.&lt;br&gt;
The win is real and large — &lt;strong&gt;4–8× memory, 2–5× throughput&lt;/strong&gt; — but it's earned by respecting the cache's&lt;br&gt;
outlier structure, not by rounding harder. I measured it directly on a real 0.5B model: naive per-token&lt;br&gt;
quantization distorts attention ~1.3× more than the per-channel key scheme, and the gap is wider on bigger&lt;br&gt;
models. For most teams the right move today is &lt;strong&gt;fp8 in the serving stack&lt;/strong&gt;; for the long-context&lt;br&gt;
frontier, &lt;strong&gt;KVQuant&lt;/strong&gt; and &lt;strong&gt;GEAR&lt;/strong&gt; show 2–3-bit caches are deployable, not research curiosities.&lt;/p&gt;

&lt;p&gt;I started this wanting to &lt;em&gt;understand&lt;/em&gt; why my 128K requests kept OOMing, and ended up rebuilding the cache&lt;br&gt;
path from the outlier math up. Next up: I'll break down &lt;strong&gt;speculative decoding&lt;/strong&gt; the same way — where the&lt;br&gt;
famous 2–3× claim actually holds, and where it quietly loses.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Liu et al., &lt;strong&gt;KIVI: A Tuning-Free Asymmetric 2bit Quantization for KV Cache&lt;/strong&gt; (ICML 2024).
&lt;a href="https://arxiv.org/abs/2402.02750" rel="noopener noreferrer"&gt;arXiv:2402.02750&lt;/a&gt; · &lt;a href="https://github.com/jy-yuan/KIVI" rel="noopener noreferrer"&gt;github.com/jy-yuan/KIVI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hooper et al., &lt;strong&gt;KVQuant: Towards 10 Million Context Length LLM Inference with KV Cache Quantization&lt;/strong&gt;
(NeurIPS 2024). &lt;a href="https://arxiv.org/abs/2401.18079" rel="noopener noreferrer"&gt;arXiv:2401.18079&lt;/a&gt; · &lt;a href="https://github.com/SqueezeAILab/KVQuant" rel="noopener noreferrer"&gt;github.com/SqueezeAILab/KVQuant&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Kang et al., &lt;strong&gt;GEAR: An Efficient Error Reduction Framework for KV Cache Compression in LLM Inference&lt;/strong&gt;
(ICML 2024). &lt;a href="https://arxiv.org/abs/2403.05527" rel="noopener noreferrer"&gt;arXiv:2403.05527&lt;/a&gt; · &lt;a href="https://github.com/opengear-project/GEAR" rel="noopener noreferrer"&gt;github.com/opengear-project/GEAR&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Kwon et al., &lt;strong&gt;vLLM / PagedAttention&lt;/strong&gt; (SOSP 2023) — the system layer KV quantization slots into.
&lt;a href="https://arxiv.org/abs/2309.06180" rel="noopener noreferrer"&gt;arXiv:2309.06180&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Experiment code &amp;amp; raw results: &lt;code&gt;real_experiment.py&lt;/code&gt;, &lt;code&gt;assets/real_results.json&lt;/code&gt; in this project.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>I Wrote the Three Attention Kernels That Run LLM Inference — in Portable Triton, on a Free Colab T4</title>
      <dc:creator>Yuvraj singh Bhadoria</dc:creator>
      <pubDate>Sat, 29 Aug 2026 15:05:17 +0000</pubDate>
      <link>https://dev.to/yuvraj_llminference/i-wrote-the-three-attention-kernels-that-run-llm-inference-in-portable-triton-on-a-free-colab-t4-a8d</link>
      <guid>https://dev.to/yuvraj_llminference/i-wrote-the-three-attention-kernels-that-run-llm-inference-in-portable-triton-on-a-free-colab-t4-a8d</guid>
      <description>&lt;h1&gt;
  
  
  I Wrote the Three Attention Kernels That Run LLM Inference — in Portable Triton, on a Free Colab T4
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl3oxo709d502fzdj9g9j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl3oxo709d502fzdj9g9j.png" alt="the three attention kernels = the full LLM serving path" width="800" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When people talk about LLM inference kernels, they usually go straight to the hardware-specific fireworks: Hopper TMA, FP8, warp-specialization, FlashAttention-3. But if you actually want to &lt;em&gt;understand&lt;/em&gt; why inference is fast or slow on ordinary hardware, you have to start with the foundation: the three attention kernels that every serving engine secretly runs — &lt;strong&gt;fused prefill, split-KV decode, and paged KV-cache attention&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I wrote all three from scratch in &lt;strong&gt;portable Triton&lt;/strong&gt; (no CUDA C++), ran them on a &lt;strong&gt;free Colab NVIDIA T4&lt;/strong&gt;, and validated every one against PyTorch SDPA. This is the engineering post: what each kernel does, why it matters, where it wins, and the traps I hit.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is attention, really?
&lt;/h2&gt;

&lt;p&gt;Inference attention computes &lt;code&gt;softmax(QKᵀ / √d) V&lt;/code&gt;. The catch is the middle matrix &lt;code&gt;QKᵀ&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At &lt;strong&gt;prefill&lt;/strong&gt; (processing a prompt), &lt;code&gt;Q&lt;/code&gt; is large, so this is &lt;strong&gt;compute-bound&lt;/strong&gt; — but the naive version materializes the full &lt;code&gt;[B, H, N, N]&lt;/code&gt; score matrix, which is &lt;code&gt;O(N²)&lt;/code&gt; in &lt;em&gt;memory&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;At &lt;strong&gt;decode&lt;/strong&gt; (generating one token), &lt;code&gt;Q&lt;/code&gt; is a single vector (&lt;code&gt;Q=1&lt;/code&gt;), so the matmul is tiny and the cost is dominated by &lt;strong&gt;streaming the KV cache from HBM&lt;/strong&gt; — it is &lt;strong&gt;memory-bound&lt;/strong&gt;, not compute-bound.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That single distinction — compute-bound prefill vs memory-bound decode — is the whole reason serving engines use &lt;em&gt;different&lt;/em&gt; kernels for each phase. Ignore it and your "optimization" optimizes the wrong thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The memory model (why naive attention dies)
&lt;/h2&gt;

&lt;p&gt;Your GPU has fast compute but it does not know how to stage your exact workload. With custom/Triton kernels you control data movement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Off-chip (HBM, 16 GB on T4):&lt;/strong&gt; where &lt;code&gt;Q, K, V&lt;/code&gt; and the KV cache live. Huge but slow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-chip (shared memory / registers):&lt;/strong&gt; tiny but fast. You want to pull &lt;code&gt;K, V&lt;/code&gt; once and reuse them across the &lt;code&gt;Q&lt;/code&gt; dimension.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For prefill, the naive implementation pulls this wrong: it builds the full &lt;code&gt;N×N&lt;/code&gt; score matrix in HBM. That is the trap.&lt;/p&gt;

&lt;h2&gt;
  
  
  My hardware: a free Colab T4
&lt;/h2&gt;

&lt;p&gt;I have no H100. This runs on an &lt;strong&gt;NVIDIA T4 (sm75, 16 GB)&lt;/strong&gt; — the free Colab tier. Ada/Hopper tricks (TMA, FP8) are intentionally out of scope; the point is a &lt;em&gt;portable&lt;/em&gt; kernel any laptop-class GPU can run. fp16 throughout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trap: naive attention OOMs at 8K
&lt;/h2&gt;

&lt;p&gt;I benchmarked prefill peak memory exactly (peak-memory is unaffected by Colab's compute throttling, so these numbers are trustworthy):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;N_CTX&lt;/th&gt;
&lt;th&gt;Naive attention&lt;/th&gt;
&lt;th&gt;Triton fused&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4K&lt;/td&gt;
&lt;td&gt;4.46 GB&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;0.44 GB&lt;/strong&gt; (10.2× less)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8K&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;OOM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;0.57 GB&lt;/strong&gt; (fits)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The naive materialized &lt;code&gt;[B,H,N,N]&lt;/code&gt; matrix is &lt;code&gt;O(N²)&lt;/code&gt;. At 8K it blows past 16 GB and dies. Triton's fused kernel is &lt;code&gt;O(N·D)&lt;/code&gt; — it never materializes the scores, it streams &lt;code&gt;K,V&lt;/code&gt; and reduces online (FlashAttention-2 style). Same math, 10× less memory, and it &lt;em&gt;keeps running&lt;/em&gt; where naive crashes.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[!WARNING]&lt;br&gt;
On a free T4, PyTorch SDPA dispatches to vendor-tuned FlashAttention-2 / cuDNN. Do &lt;strong&gt;not&lt;/strong&gt; expect a raw-speed win over SDPA. The honest, demonstrable win here is &lt;strong&gt;memory&lt;/strong&gt; and &lt;strong&gt;portability&lt;/strong&gt; — not latency. Measuring latency against SDPA and calling it a loss misses the point.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The three kernels (evolution, with why)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Fused prefill attention (&lt;code&gt;flash_attention.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;The baseline. Online softmax, autotuned, FA2-style. Processes the whole prompt in one pass. Its job is to prove the &lt;strong&gt;correctness methodology&lt;/strong&gt;: every output is checked against &lt;code&gt;F.scaled_dot_product_attention&lt;/code&gt; with &lt;code&gt;allclose(atol=1e-2, rtol=1e-2)&lt;/code&gt; in fp16, including non-power-of-two and GQA shapes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@triton.autotune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;configs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;triton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BLOCK_M&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BLOCK_N&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;num_warps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;num_stages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;triton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BLOCK_M&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BLOCK_N&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;num_warps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;num_stages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;triton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BLOCK_M&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BLOCK_N&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;num_warps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;num_stages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;N_CTX&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@triton.jit&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_flash_attention_fwd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;K&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;V&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sm_scale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...):&lt;/span&gt;
    &lt;span class="n"&gt;start_m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;program_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# one tile of query rows per program
&lt;/span&gt;    &lt;span class="c1"&gt;# online softmax: stream K,V, reduce in registers -- never materialize NxN
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Split-KV flash-decoding (&lt;code&gt;flash_decoding.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;The decode kernel. With &lt;code&gt;Q=1&lt;/code&gt; there is no query-dimension parallelism, so the &lt;em&gt;only&lt;/em&gt; way to parallelize decode is to split the &lt;strong&gt;KV dimension&lt;/strong&gt; across SMs — exactly what vLLM does for long-context decode. Each SM reduces its slice of &lt;code&gt;K,V&lt;/code&gt;, then a final cross-SM reduction gives the output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; the tiny &lt;code&gt;Q=1&lt;/code&gt; matmul is memory-bound, so you hide HBM latency by having many SMs pull different KV blocks at once.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;split&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;program_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                  &lt;span class="c1"&gt;# KV dimension split across SMs
&lt;/span&gt;&lt;span class="n"&gt;kv_per_split&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cdiv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cdiv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N_CTX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BLOCK_N&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;NUM_SPLITS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;BLOCK_N&lt;/span&gt;
&lt;span class="n"&gt;start_n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;split&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;kv_per_split&lt;/span&gt;            &lt;span class="c1"&gt;# this SM owns its slice of K,V
&lt;/span&gt;
&lt;span class="c1"&gt;# ... after each SM reduces its slice, a final cross-SM combine:
&lt;/span&gt;&lt;span class="n"&gt;lse_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;partial_lse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keepdim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;
&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;partial_lse&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lse_max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;partial_out&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsqueeze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keepdim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Paged KV-cache attention (&lt;code&gt;paged_attention.py&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;The inference-systems piece. Instead of one contiguous KV tensor, it reads through a &lt;strong&gt;block table&lt;/strong&gt; (GQA-aware) — the exact memory layout vLLM uses. This is a capability &lt;strong&gt;SDPA literally cannot express&lt;/strong&gt;: PyTorch's built-in attention assumes a dense KV tensor; real serving does not have one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# paged_attention.py -- read K,V through a block table, not one dense tensor
&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlockTable&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stride_bb&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;PAGE_SIZE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stride_bm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KV_Cache&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stride_kn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;off_in_page&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stride_kps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Benchmark method
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shapes:&lt;/strong&gt; &lt;code&gt;B=4, H=16, D=64, Q=1&lt;/code&gt;, fp16.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decode sweep:&lt;/strong&gt; &lt;code&gt;N_CTX ∈ {1024, 2048, 4096, 8192, 16384}&lt;/code&gt;, &lt;code&gt;num_splits ∈ {1, 8, 16, 32, 64, 128}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timing:&lt;/strong&gt; 20 warmup + 100 measured CUDA-event iterations (async events, like a real benchmark).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Correctness:&lt;/strong&gt; &lt;code&gt;allclose&lt;/code&gt; vs SDPA on every shape before any timing runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fybykmp02rc0dp9b7rmcs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fybykmp02rc0dp9b7rmcs.png" alt="decode latency vs context" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Best &lt;code&gt;num_splits&lt;/code&gt; per context (lowest kernel latency):&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;N_CTX&lt;/th&gt;
&lt;th&gt;best num_splits&lt;/th&gt;
&lt;th&gt;Triton (ms)&lt;/th&gt;
&lt;th&gt;SDPA (ms)&lt;/th&gt;
&lt;th&gt;Triton / SDPA&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1024&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;0.405&lt;/td&gt;
&lt;td&gt;0.249&lt;/td&gt;
&lt;td&gt;1.62×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2048&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;0.297&lt;/td&gt;
&lt;td&gt;0.379&lt;/td&gt;
&lt;td&gt;0.78×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4096&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;0.528&lt;/td&gt;
&lt;td&gt;0.393&lt;/td&gt;
&lt;td&gt;1.34×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8192&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;1.018&lt;/td&gt;
&lt;td&gt;0.845&lt;/td&gt;
&lt;td&gt;1.21×&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16384&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;2.012&lt;/td&gt;
&lt;td&gt;1.737&lt;/td&gt;
&lt;td&gt;1.16×&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwoh0yuyzx8uc8i7nbip6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwoh0yuyzx8uc8i7nbip6.png" alt="prefill memory vs naive" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-step optimization journey
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;From single-split to split-KV (the big one).&lt;/strong&gt; At &lt;code&gt;N=1024&lt;/code&gt;, &lt;code&gt;num_splits=1&lt;/code&gt; stalled at &lt;strong&gt;1.14 ms&lt;/strong&gt;; moving to &lt;code&gt;num_splits=32&lt;/code&gt; dropped it to &lt;strong&gt;0.40 ms&lt;/strong&gt; — because splitting the KV dimension is the only source of sequence parallelism when &lt;code&gt;Q=1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefill memory:&lt;/strong&gt; fused Triton went from 4.46 GB → 0.44 GB at 4K (&lt;strong&gt;10.2×&lt;/strong&gt;), and fit at 8K where naive &lt;strong&gt;OOMs&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Versus SDPA:&lt;/strong&gt; within ~1.2–1.6× at 4K–16K, and &lt;em&gt;faster&lt;/em&gt; at 2K (0.78×) in this run. SDPA stays the vendor-tuned reference; the benchmark characterizes split-KV scaling, not a speed claim.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Key Tradeoffs &amp;amp; Technical Takeaways
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. More splits is NOT monotonic — launch overhead beats memory reuse.&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;num_splits=128&lt;/code&gt; is the &lt;em&gt;worst&lt;/em&gt; configuration at every context length. The sweet spot (16–32) does not even grow steadily with &lt;code&gt;N&lt;/code&gt;. Past the sweet spot, cross-SM launch + reduction overhead dominates the HBM savings. Takeaway: split-KV helps until reduction bookkeeping costs more than the memory you saved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Memory win vs speed win are different wins.&lt;/strong&gt;&lt;br&gt;
On T4 we beat naive on memory 10×, and we match/beat SDPA on latency at scale — but SDPA still wins at small &lt;code&gt;N&lt;/code&gt; because it dispatches to cuDNN/FA2. Takeaway: on constrained hardware, optimize the metric that's actually broken (here, decode memory pressure), not the one the vendor already solved.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Portability is a deliberate tradeoff.&lt;/strong&gt;&lt;br&gt;
No TMA, no FP8, no warp-spec — those need Hopper+. By targeting sm75 Triton, the kernel runs on a free Colab T4 &lt;em&gt;and&lt;/em&gt; any datacenter GPU, at the cost of leaving Hopper bandwidth on the table. Takeaway: write the portable kernel first; specialize only when the hardware is guaranteed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Triton is a new thing I explored in this project, and it's a bit low-level — but watching three kernels go from "naive OOM" to "validated against SDPA on a free T4" made the inference path click in a way no framework toggle ever did. Building the paged kernel especially — the one SDPA &lt;em&gt;can't&lt;/em&gt; express — is what showed me why serving engines look the way they do.&lt;/p&gt;

&lt;p&gt;Benchmarking on shared Colab GPUs has been tough lately (numbers wander with contention), so I report medians across 2–3 runs. Still, the memory numbers and the split-KV shape are solid.&lt;/p&gt;

&lt;p&gt;Thanks for reading till here. Repo: &lt;a href="https://github.com/YuvrajSinghBhadoria2/triton-attention-kernels" rel="noopener noreferrer"&gt;triton-attention-kernels&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
