{"article":{"slug":"why-is-speculative-decoding-fast","title":"Why Is Speculative Decoding Fast?","subtitle":null,"summary":"Joe Barrow explains that speculative decoding does not save work: verifying a draft actually costs more FLOPs. It is fast because single-token decoding is memory bound, so drafted tokens use idle GPU compute at small batch sizes. That is why it can waste compute at high throughput, and why dynamic per-sequence speculation depth helps.","content_type":"tutorial","language":"en","canonical_url":"https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/","author":{"name":"Joe Barrow","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"Joe Barrow","url":"https://jbarrow.ai/","listing_slug":null,"listing":null},"topics":[{"name":"Machine Learning","slug":"machine-learning","url":"https://listedarticles.com/topics/machine-learning"},{"name":"LLM Inference","slug":"llm-inference","url":"https://listedarticles.com/topics/llm-inference"},{"name":"GPUs","slug":"gpus","url":"https://listedarticles.com/topics/gpus"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":897,"reading_minutes":4,"published_at":"2026-10-08T00:00:00.000Z","added_at":"2026-10-20T11:18:24.084Z","updated_at":"2026-10-20T11:18:24.084Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/why-is-speculative-decoding-fast","markdown_url":"https://listedarticles.com/articles/why-is-speculative-decoding-fast.md","example":false,"citation":"Joe Barrow, Joe Barrow. \"Why Is Speculative Decoding Fast?.\" 8 Oct 2026. https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/"},"body_markdown":"# Why is Speculative Decoding Fast?\n\nIt's not because you do less work. It's because you change the kind of work the GPU is doing.\n\nBy **Joe Barrow** | October 8, 2026\n\nThere is a common misconception that speculative decoding is fast because you do *less* work per token.\nThat just “verifying” a draft requires fewer FLOPs than *generating* the same tokens.\n\nThis is untrue.\n\nOne of the counterintuitive things about speculative decoding is that you actually do *more* work!\nThe total number of floating point operations (FLOPs) you execute goes UP for the same sequence.\n\nBut then why is it fast? What exactly does an accurate draft model buy you, if it’s not compute efficiency?\n\nThe answer lies in the *type* of work your GPU is doing.\n\n## Quick SpecDec Refresher\n\nSpeculative Decoding is a technique where you use a small draft model to propose a likely draft sequence, and then you use your big model to verify that sequence in parallel (in a single forward pass).\n\nTraditional LLM decoding goes one token at a time:\n\n![a decoder LLM taking the prompt tokens \"The quick\" and emitting a single next token, \"brown\"](https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/decode_one_token.png)\n\nBut speculative decoding allows you to look at many tokens at once, and accept the ones that would have been generated by the big model:\n\n![the decoder LLM verifying three draft tokens alongside the prompt in one pass, accepting \"brown\" and \"fox\" and rejecting \"hopped\" in favor of \"jumped\"](https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/speculative_decode.png)\n\n## Types of Work\n\nWhen a model runs on a GPU, there are different types of work going on.\nThe obvious one is running the matrix multiplies, dot products, or other tensor operations.\nBut an important less obvious one is: **loading data from global memory to local memory (and vice versa)**.\n\nWhen the GPU is waiting on data to load for an operation, we call that a *memory bound operation*.\nIf everything is loaded but we’re waiting on all the tensor operations to finish, we call that a *compute bound operation*.\n\n(For a more in-depth exploration of this, I have a prior post: [A Visual Guide to the Roofline Model](https://jbarrow.ai/2026-07-13-roofline-model/))\n\nWhen an LLM is decoding one token at a time (as in the first figure), it is *very* **memory bound**.\nFor every token we have to stream all the active parameters of the model (e.g. 27B parameters for Qwen3.5-27B).\nWhen an LLM is doing a **batched decode** (as in the second figure) of thousands of tokens in a single step, it’s **compute bound**.\n\n![five sequences decoding in parallel, T = 5 tokens entering the decoder LLM in a single step and five tokens coming out](https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/batched_decode.png)\n\nWhen LLM decoding is memory bound, you’re **wasting compute**.\nThe GPU *could* be doing more operations, but it’s not.\n**For instance, if you were decoding 2 sequences instead of 1, it wouldn’t take any more time per token.**\n\n**Speculative decoding is a way of using that extra compute to make decoding faster (at low batch sizes)**.\n\n## Trading Breadth for Depth\n\nTo make this concrete, let’s say the optimal number of tokens to run is 5 in a given forward pass.\nIf we ran any fewer, we’d be memory bound, any more and we’d be compute bound.\n\nWe have two options.\n\nFirst, we can run a batch size of 5 sequences, each decoding one at a time.\nWe’ll say this is “breadth” (across sequences):\n\n![the same T = 5 batch, read as breadth: five separate sequences each advancing by one token](https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/batched_decode.png)\n\nAlternatively, we can use speculative decoding to run 5 tokens in one sequence, achieving high “depth” for that sequence:\n\n![T = 5 tokens from a single sequence entering the decoder LLM, with four of the five tokens accepted](https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/depth_speculation.png)\n\nIn both cases, the GPU is doing roughly the same amount of work.\nIn the first case, all 5 sequences make a little bit of progress, in the second, our one sequence makes a lot of progress.\n\nIf you add more sequences and speculate to the same depth, you’ll just be **slowing them all down as you’re compute bound**.\n\n**But at small batch sizes (where batch size << optimal number of tokens), speculative decoding allows you to use “free” compute to complete all the sequences faster!**\n\n## Why Does This Matter?\n\nThis might all sound a little pedantic.\nSpeculative decoding *does* make things faster at small batch sizes, so who cares if it’s as much or more work?\n\nThis becomes important when you start to serve real-world loads or digging into speculative decoding research.\nIf the optimal batch size is 5 but we’re running with speculative decoding on, as in the following figure, we’re actually **wasting compute** when we could be using that time to move memory!\n\n![five sequences each speculating four tokens deep, T = 20 tokens in one step, with many of the verified tokens rejected](https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/compute_bound_speculation.png)\n\nEspecially if our acceptance rate isn’t 100%, every rejected token is *extra* wasted work.\n\nThis is why, at high throughput, vLLM gives you the configurability to [totally turn off speculative decoding](https://docs.vllm.ai/en/v0.6.0/models/engine_args.html) with the `--speculative-disable-by-batch-size` param.\n\nAnd researchers looking at this picture started to wonder: why would we speculate to the same depth at every timestep?\nWhy not speculate deep when we have extra compute (small batch size), and shallow, or even dynamically per sequence, when we have a larger batch size:\n\n![five sequences speculating to different depths in the same step, totaling T = 13 tokens](https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/dynamic_speculation.png)\n\n[This is the core intuition behind ideas like dSpark](https://jbarrow.ai/field_notes/dspark/)!\n","body_html":"<h1 id=\"why-is-speculative-decoding-fast\">Why is Speculative Decoding Fast?</h1>\n<p>It&#39;s not because you do less work. It&#39;s because you change the kind of work the GPU is doing.</p>\n<p>By <strong>Joe Barrow</strong> | October 8, 2026</p>\n<p>There is a common misconception that speculative decoding is fast because you do <em>less</em> work per token.\nThat just “verifying” a draft requires fewer FLOPs than <em>generating</em> the same tokens.</p>\n<p>This is untrue.</p>\n<p>One of the counterintuitive things about speculative decoding is that you actually do <em>more</em> work!\nThe total number of floating point operations (FLOPs) you execute goes UP for the same sequence.</p>\n<p>But then why is it fast? What exactly does an accurate draft model buy you, if it’s not compute efficiency?</p>\n<p>The answer lies in the <em>type</em> of work your GPU is doing.</p>\n<h2 id=\"quick-specdec-refresher\">Quick SpecDec Refresher</h2>\n<p>Speculative Decoding is a technique where you use a small draft model to propose a likely draft sequence, and then you use your big model to verify that sequence in parallel (in a single forward pass).</p>\n<p>Traditional LLM decoding goes one token at a time:</p>\n<figure><img src=\"https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/decode_one_token.png\" alt=\"a decoder LLM taking the prompt tokens &quot;The quick&quot; and emitting a single next token, &quot;brown&quot;\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></figure>\n<p>But speculative decoding allows you to look at many tokens at once, and accept the ones that would have been generated by the big model:</p>\n<figure><img src=\"https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/speculative_decode.png\" alt=\"the decoder LLM verifying three draft tokens alongside the prompt in one pass, accepting &quot;brown&quot; and &quot;fox&quot; and rejecting &quot;hopped&quot; in favor of &quot;jumped&quot;\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></figure>\n<h2 id=\"types-of-work\">Types of Work</h2>\n<p>When a model runs on a GPU, there are different types of work going on.\nThe obvious one is running the matrix multiplies, dot products, or other tensor operations.\nBut an important less obvious one is: <strong>loading data from global memory to local memory (and vice versa)</strong>.</p>\n<p>When the GPU is waiting on data to load for an operation, we call that a <em>memory bound operation</em>.\nIf everything is loaded but we’re waiting on all the tensor operations to finish, we call that a <em>compute bound operation</em>.</p>\n<p>(For a more in-depth exploration of this, I have a prior post: <a href=\"https://jbarrow.ai/2026-07-13-roofline-model/\" rel=\"nofollow ugc noopener\">A Visual Guide to the Roofline Model</a>)</p>\n<p>When an LLM is decoding one token at a time (as in the first figure), it is <em>very</em> <strong>memory bound</strong>.\nFor every token we have to stream all the active parameters of the model (e.g. 27B parameters for Qwen3.5-27B).\nWhen an LLM is doing a <strong>batched decode</strong> (as in the second figure) of thousands of tokens in a single step, it’s <strong>compute bound</strong>.</p>\n<figure><img src=\"https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/batched_decode.png\" alt=\"five sequences decoding in parallel, T = 5 tokens entering the decoder LLM in a single step and five tokens coming out\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></figure>\n<p>When LLM decoding is memory bound, you’re <strong>wasting compute</strong>.\nThe GPU <em>could</em> be doing more operations, but it’s not.\n<strong>For instance, if you were decoding 2 sequences instead of 1, it wouldn’t take any more time per token.</strong></p>\n<p><strong>Speculative decoding is a way of using that extra compute to make decoding faster (at low batch sizes)</strong>.</p>\n<h2 id=\"trading-breadth-for-depth\">Trading Breadth for Depth</h2>\n<p>To make this concrete, let’s say the optimal number of tokens to run is 5 in a given forward pass.\nIf we ran any fewer, we’d be memory bound, any more and we’d be compute bound.</p>\n<p>We have two options.</p>\n<p>First, we can run a batch size of 5 sequences, each decoding one at a time.\nWe’ll say this is “breadth” (across sequences):</p>\n<figure><img src=\"https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/batched_decode.png\" alt=\"the same T = 5 batch, read as breadth: five separate sequences each advancing by one token\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></figure>\n<p>Alternatively, we can use speculative decoding to run 5 tokens in one sequence, achieving high “depth” for that sequence:</p>\n<figure><img src=\"https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/depth_speculation.png\" alt=\"T = 5 tokens from a single sequence entering the decoder LLM, with four of the five tokens accepted\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></figure>\n<p>In both cases, the GPU is doing roughly the same amount of work.\nIn the first case, all 5 sequences make a little bit of progress, in the second, our one sequence makes a lot of progress.</p>\n<p>If you add more sequences and speculate to the same depth, you’ll just be <strong>slowing them all down as you’re compute bound</strong>.</p>\n<p><strong>But at small batch sizes (where batch size &lt;&lt; optimal number of tokens), speculative decoding allows you to use “free” compute to complete all the sequences faster!</strong></p>\n<h2 id=\"why-does-this-matter\">Why Does This Matter?</h2>\n<p>This might all sound a little pedantic.\nSpeculative decoding <em>does</em> make things faster at small batch sizes, so who cares if it’s as much or more work?</p>\n<p>This becomes important when you start to serve real-world loads or digging into speculative decoding research.\nIf the optimal batch size is 5 but we’re running with speculative decoding on, as in the following figure, we’re actually <strong>wasting compute</strong> when we could be using that time to move memory!</p>\n<figure><img src=\"https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/compute_bound_speculation.png\" alt=\"five sequences each speculating four tokens deep, T = 20 tokens in one step, with many of the verified tokens rejected\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></figure>\n<p>Especially if our acceptance rate isn’t 100%, every rejected token is <em>extra</em> wasted work.</p>\n<p>This is why, at high throughput, vLLM gives you the configurability to <a href=\"https://docs.vllm.ai/en/v0.6.0/models/engine_args.html\" rel=\"nofollow ugc noopener\">totally turn off speculative decoding</a> with the <code>--speculative-disable-by-batch-size</code> param.</p>\n<p>And researchers looking at this picture started to wonder: why would we speculate to the same depth at every timestep?\nWhy not speculate deep when we have extra compute (small batch size), and shallow, or even dynamically per sequence, when we have a larger batch size:</p>\n<figure><img src=\"https://jbarrow.ai/2026-10-08-why-is-speculative-decoding-fast/dynamic_speculation.png\" alt=\"five sequences speculating to different depths in the same step, totaling T = 13 tokens\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></figure>\n<p><a href=\"https://jbarrow.ai/field_notes/dspark/\" rel=\"nofollow ugc noopener\">This is the core intuition behind ideas like dSpark</a>!</p>","headings":[{"level":1,"text":"Why is Speculative Decoding Fast?","id":"why-is-speculative-decoding-fast"},{"level":2,"text":"Quick SpecDec Refresher","id":"quick-specdec-refresher"},{"level":2,"text":"Types of Work","id":"types-of-work"},{"level":2,"text":"Trading Breadth for Depth","id":"trading-breadth-for-depth"},{"level":2,"text":"Why Does This Matter?","id":"why-does-this-matter"}]}}