Het artikel legt uit dat speculative decoding niet sneller is door een vermindering van floating point operations (FLOPs)—het totale aantal operaties neemt zelfs toe—maar door de efficiëntie van de GPU-benutting te optimaliseren.
De kernpunten zijn:
- Memory bound vs. Compute bound: Traditionele LLM-decodering is vaak memory bound, waarbij de GPU moet wachten op het laden van parameters. Speculative decoding gebruikt deze wachttijd om extra berekeningen uit te voeren.
- Werking: Een klein draft model stelt een reeks tokens voor, die het grote model vervolgens in één parallelle forward pass verifieert.
- Breedte versus Diepte: In plaats van meerdere sequenties tegelijk te verwerken (breedte), wordt de rekenkracht gebruikt om één sequentie sneller te voltooien door meer tokens per stap te genereren (diepte).
- Beperkingen: De techniek is vooral effectief bij kleine batch sizes. Bij hoge doorvoer kan het juist inefficiënt worden, wat verklaart waarom tools zoals vLLM de optie bieden om het uit te schakelen.
Waarom is Speculative Decoding snel?
Er bestaat een veelvoorkomend misverstand dat speculative decoding snel is omdat er per token minder werk wordt verricht; dat het enkel "verifiëren" van een conceptversie (draft) minder FLOPs vereist dan het genereren van dezelfde tokens.
Dit is onjuist.
Een van de contra-intuïtieve aspecten van speculative decoding is dat je eigenlijk méér werk verricht. Het totale aantal floating point operations (FLOPs) dat je uitvoert voor dezelfde reeks tokens gaat juist OMHOOG.
Maar waarom is het dan toch snel? Wat levert een accuraat conceptmodel je precies op, als het niet gaat om rekenefficiëntie?
Het antwoord ligt in het type werk dat je GPU uitvoert.
Een korte opfrisser over Speculative Decoding
Speculative decoding is een techniek waarbij een klein conceptmodel (draft model) wordt gebruikt om een waarschijnlijke reeks tokens voor te stellen. Vervolgens wordt het grote model gebruikt om die reeks in parallel (in één enkele forward pass) te verifiëren.
Traditionele LLM-decodering gaat token voor token. Speculative decoding stelt je echter in staat om naar meerdere tokens tegelijk te kijken en die te accepteren die ook door het grote model gegenereerd zouden zijn.
Soorten werkzaamheden
Wanneer een model op een GPU draait, vinden er verschillende soorten werkzaamheden plaats.
De meest voor de hand liggende zijn het uitvoeren van matrixvermenigvuldigingen, dot products of andere tensoroperaties. Maar een minder voor de hand liggende, cruciale taak is: het laden van gegevens van het globale geheugen naar het lokale geheugen (en vice versa).
- Wanneer de GPU moet wachten op het laden van gegevens voor een operatie, spreken we van een memory bound operatie (geheugenbeperkt).
- Als alles is geladen, maar we wachten tot alle tensoroperaties zijn voltooid, spreken we van een compute bound operatie (rekenbeperkt).
(Voor een diepere analyse hiervan heb ik een eerder bericht geschreven: A Visual Guide to the Roofline Model).
Wanneer een LLM één token per keer decodeert, is het proces zeer memory bound. Voor elk token moeten we alle actieve parameters van het model streamen (bijvoorbeeld 27 miljard parameters voor Qwen3.5-27B).
Wanneer een LLM een batched decode uitvoert van duizenden tokens in één stap, is het proces compute bound.
Wanneer LLM-decodering memory bound is, verspil je rekenkracht. De GPU zou meer operaties kunnen uitvoeren, maar dat gebeurt niet. Als je bijvoorbeeld twee sequenties zou decoderen in plaats van één, zou dit per token niet meer tijd in beslag nemen.
Speculative decoding is een manier om die extra rekenkracht te gebruiken om de decodering te versnellen (bij lage batch sizes).
Breedte inruilen voor diepte
Om dit concreet te maken: stel dat het optimale aantal tokens om in een gegeven forward pass uit te voeren 5 is. Als we er minder zouden draaien, zouden we memory bound zijn; bij meer tokens zouden we compute bound worden.
We hebben dan twee opties:
- We kunnen een batch size van 5 sequenties draaien, waarbij elke sequentie één token per keer decodeert. We noemen dit "breedte" (over sequenties).
- Alternatief kunnen we speculative decoding gebruiken om 5 tokens in één enkele sequentie te draaien, waardoor we een grote "diepte" voor die specifieke sequentie bereiken.
In beide gevallen verricht de GPU ongeveer dezelfde hoeveelheid werk. In het eerste geval maken alle vijf de sequenties een kleine hoeveelheid progressie; in het tweede geval maakt één sequentie een grote hoeveelheid progressie.
Als je meer sequenties toevoegt en speculeert tot dezelfde diepte, vertraag je ze allemaal omdat je dan compute bound wordt. Maar bij kleine batch sizes (waarbij de batch size veel kleiner is dan het optimale aantal tokens) stelt speculative decoding je in staat om "gratis" rekenkracht te gebruiken om alle sequenties sneller te voltooien.
Waarom is dit belangrijk?
Dit klinkt wellicht wat pedant. Speculative decoding maakt zaken sneller bij kleine batch sizes, dus wie geeft er om of het meer of minder werk is?
Dit wordt echter belangrijk wanneer je echte workloads gaat bedienen of dieper in het onderzoek naar speculative decoding duikt.
Als de optimale batch size 5 is, maar we draaien met speculative decoding aan, verspillen we eigenlijk rekenkracht op momenten dat we die tijd zouden kunnen gebruiken om geheugen te verplaatsen. Vooral als onze acceptatiegraad niet 100% is: elk afgewezen token is extra verspild werk.
Dit is de reden waarom vLLM bij een hoge doorvoer de mogelijkheid biedt om speculative decoding volledig uit te schakelen met de parameter --speculative-disable-by-batch-size.
Onderzoekers die naar dit scenario keken, begonnen zich af te vragen: waarom zouden we bij elke tijdstap tot dezelfde diepte speculeren? Waarom niet diep speculeren wanneer we extra rekenkracht hebben (kleine batch size), en ondiep — of zelfs dynamisch per sequentie — wanneer we een grotere batch size hebben?
Dit is de kernintuïtie achter ideeën zoals dSpark.
Waarom is Speculative Decoding snel?
Er bestaat een veelvoorkomend misverstand dat speculative decoding snel is omdat er per token minder werk wordt verricht; dat het enkel "verifiëren" van een conceptversie (draft) minder FLOPs vereist dan het genereren van dezelfde tokens.
Dit is onjuist.
Een van de contra-intuïtieve aspecten van speculative decoding is dat je eigenlijk méér werk verricht. Het totale aantal floating point operations (FLOPs) dat je uitvoert voor dezelfde reeks tokens gaat juist OMHOOG.
Maar waarom is het dan toch snel? Wat levert een accuraat conceptmodel je precies op, als het niet gaat om rekenefficiëntie?
Het antwoord ligt in het type werk dat je GPU uitvoert.
Een korte opfrisser over Speculative Decoding
Speculative decoding is een techniek waarbij een klein conceptmodel (draft model) wordt gebruikt om een waarschijnlijke reeks tokens voor te stellen. Vervolgens wordt het grote model gebruikt om die reeks in parallel (in één enkele forward pass) te verifiëren.
Traditionele LLM-decodering gaat token voor token. Speculative decoding stelt je echter in staat om naar meerdere tokens tegelijk te kijken en die te accepteren die ook door het grote model gegenereerd zouden zijn.
Soorten werkzaamheden
Wanneer een model op een GPU draait, vinden er verschillende soorten werkzaamheden plaats.
De meest voor de hand liggende zijn het uitvoeren van matrixvermenigvuldigingen, dot products of andere tensoroperaties. Maar een minder voor de hand liggende, cruciale taak is: het laden van gegevens van het globale geheugen naar het lokale geheugen (en vice versa).
- Wanneer de GPU moet wachten op het laden van gegevens voor een operatie, spreken we van een memory bound operatie (geheugenbeperkt).
- Als alles is geladen, maar we wachten tot alle tensoroperaties zijn voltooid, spreken we van een compute bound operatie (rekenbeperkt).
(Voor een diepere analyse hiervan heb ik een eerder bericht geschreven: A Visual Guide to the Roofline Model).
Wanneer een LLM één token per keer decodeert, is het proces zeer memory bound. Voor elk token moeten we alle actieve parameters van het model streamen (bijvoorbeeld 27 miljard parameters voor Qwen3.5-27B).
Wanneer een LLM een batched decode uitvoert van duizenden tokens in één stap, is het proces compute bound.
Wanneer LLM-decodering memory bound is, verspil je rekenkracht. De GPU zou meer operaties kunnen uitvoeren, maar dat gebeurt niet. Als je bijvoorbeeld twee sequenties zou decoderen in plaats van één, zou dit per token niet meer tijd in beslag nemen.
Speculative decoding is een manier om die extra rekenkracht te gebruiken om de decodering te versnellen (bij lage batch sizes).
Breedte inruilen voor diepte
Om dit concreet te maken: stel dat het optimale aantal tokens om in een gegeven forward pass uit te voeren 5 is. Als we er minder zouden draaien, zouden we memory bound zijn; bij meer tokens zouden we compute bound worden.
We hebben dan twee opties:
- We kunnen een batch size van 5 sequenties draaien, waarbij elke sequentie één token per keer decodeert. We noemen dit "breedte" (over sequenties).
- Alternatief kunnen we speculative decoding gebruiken om 5 tokens in één enkele sequentie te draaien, waardoor we een grote "diepte" voor die specifieke sequentie bereiken.
In beide gevallen verricht de GPU ongeveer dezelfde hoeveelheid werk. In het eerste geval maken alle vijf de sequenties een kleine hoeveelheid progressie; in het tweede geval maakt één sequentie een grote hoeveelheid progressie.
Als je meer sequenties toevoegt en speculeert tot dezelfde diepte, vertraag je ze allemaal omdat je dan compute bound wordt. Maar bij kleine batch sizes (waarbij de batch size veel kleiner is dan het optimale aantal tokens) stelt speculative decoding je in staat om "gratis" rekenkracht te gebruiken om alle sequenties sneller te voltooien.
Waarom is dit belangrijk?
Dit klinkt wellicht wat pedant. Speculative decoding maakt zaken sneller bij kleine batch sizes, dus wie geeft er om of het meer of minder werk is?
Dit wordt echter belangrijk wanneer je echte workloads gaat bedienen of dieper in het onderzoek naar speculative decoding duikt.
Als de optimale batch size 5 is, maar we draaien met speculative decoding aan, verspillen we eigenlijk rekenkracht op momenten dat we die tijd zouden kunnen gebruiken om geheugen te verplaatsen. Vooral als onze acceptatiegraad niet 100% is: elk afgewezen token is extra verspild werk.
Dit is de reden waarom vLLM bij een hoge doorvoer de mogelijkheid biedt om speculative decoding volledig uit te schakelen met de parameter --speculative-disable-by-batch-size.
Onderzoekers die naar dit scenario keken, begonnen zich af te vragen: waarom zouden we bij elke tijdstap tot dezelfde diepte speculeren? Waarom niet diep speculeren wanneer we extra rekenkracht hebben (kleine batch size), en ondiep — of zelfs dynamisch per sequentie — wanneer we een grotere batch size hebben?
Dit is de kernintuïtie achter ideeën zoals dSpark.