惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
罗磊的独立博客
量子位
Microsoft Azure Blog
Microsoft Azure Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
J
Java Code Geeks
M
MIT News - Artificial intelligence
月光博客
月光博客
IT之家
IT之家
D
DataBreaches.Net
A
About on SuperTechFans
博客园 - 三生石上(FineUI控件)
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Last Week in AI
Last Week in AI
D
Docker
The GitHub Blog
The GitHub Blog
B
Blog
V
Visual Studio Blog
博客园 - Franky
N
Netflix TechBlog - Medium
博客园 - 【当耐特】
Martin Fowler
Martin Fowler
博客园 - 聂微东
U
Unit 42

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Speculative Decoding on Mobile GPUs
SoftwareDevs mvpfactory.io · 2026-06-19 · via DEV Community

SoftwareDevs mvpfactory.io

---
title: "Speculative Decoding on Mobile GPUs: Draft-Verify LLM Pipelines with Vulkan Compute"
published: true
description: "Build a speculative decoding pipeline on Android using Vulkan compute shaders for draft models and NNAPI for verification, with adaptive batch scheduling."
tags: android, kotlin, architecture, performance
canonical_url: https://blog.mvpfactory.co/speculative-decoding-mobile-gpus-vulkan-compute
---

## What We Are Building

In this workshop, we are going to wire up a speculative decoding pipeline that runs entirely on-device on Android. A small ~150M parameter draft model will propose candidate tokens using Vulkan compute shaders, while a larger 3-7B verify model accepts or rejects them through NNAPI — all coordinated by a dynamic batch scheduler that adapts to thermal state and memory pressure.

The result: 2-3x lower per-token latency, pushing sub-200ms generation on flagship Android hardware. Let me show you how the pieces fit together.

## Prerequisites

- Android device with Vulkan 1.1+ compute support (2019 SoCs or newer)
- Android 12+ for `PowerManager.getThermalHeadroom()` API
- Familiarity with Kotlin and basic Vulkan concepts
- A quantized draft model (int4) and verify model (int8)

## Step 1: Understand the Split Architecture

Most teams get this wrong by running both models through the same accelerator. Split the pipeline instead.

| Component | Accelerator | Why |
|-----------|------------|-----|
| Draft model (~150M params) | Vulkan compute shaders | Direct GPU control, custom quantization kernels, no NNAPI overhead |
| Verify model (~3-7B params) | NNAPI (delegates to NPU/GPU) | Hardware-optimized int8/int4, vendor-tuned kernels |
| Batch scheduler | CPU | Lightweight coordinator, thermal/memory monitoring |
| KV-cache management | Shared GPU memory | Vulkan buffer exports via `VK_KHR_external_memory` |

A 7B model running autoregressively on a Snapdragon 8 Gen 3 generates roughly 8-12 tokens/second. With speculative decoding at K=5, server GPUs see 70-85% acceptance rates. The algorithm works. The engineering challenge is orchestrating two models across heterogeneous compute units without melting the phone.

## Step 2: Build the Vulkan Draft Pipeline

Here is the minimal setup to get this working. Custom GLSL compute shaders handle quantized matrix multiplications — 4-bit weights with fp16 accumulation hits the sweet spot for mobile GPU ALUs.


kotlin
class VulkanDraftModel(
private val device: VkDevice,
private val specDepth: Int = 5
) {
private val matmulPipeline: VkPipeline // int4 GEMV shader
private val kvCache: VkBuffer // exportable via external memory

fun proposeCandidates(inputTokenId: Int): IntArray {
    val candidates = IntArray(specDepth)
    var currentToken = inputTokenId

    for (i in 0 until specDepth) {
        bindDescriptorSets(currentToken, kvCache)
        vkCmdDispatch(commandBuffer, workgroupsX, 1, 1)
        candidates[i] = readArgmaxFromBuffer()
        currentToken = candidates[i]
    }
    return candidates
}

}


## Step 3: Wire Up the Adaptive Batch Scheduler

Here is a pattern I use in every project that involves on-device inference. You cannot run speculation depth K=8 when the device is thermal throttling at 45°C. The scheduler must adapt.


kotlin
class AdaptiveBatchScheduler(
private val thermalMonitor: ThermalMonitor,
private val memoryMonitor: GpuMemoryMonitor
) {
fun computeSpeculationDepth(): Int {
val thermalHeadroom = thermalMonitor.headroomFraction() // 0.0 - 1.0
val memoryAvailable = memoryMonitor.freeBufferMemoryMb()

    return when {
        thermalHeadroom < 0.15f -> 1  // near throttle: no speculation
        memoryAvailable < 64    -> 2  // memory-constrained
        thermalHeadroom < 0.40f -> 3  // warm but manageable
        else                    -> 6  // full speculation
    }
}

}


The scheduler polls `PowerManager.getThermalHeadroom()` on Android 12+ and reads `/sys/class/thermal/` zones as a fallback. GPU memory pressure comes from Vulkan's `vkGetPhysicalDeviceMemoryBudgetPropertiesEXT`.

On a Pixel 8 Pro, I measured the following thermal-adaptive behavior:

| Thermal State | Spec Depth | Tokens/sec | Acceptance Rate |
|---------------|-----------|------------|-----------------|
| Cool (<35°C) | 6 | 22-26 | 78% |
| Warm (35-42°C) | 3 | 16-19 | 74% |
| Hot (>42°C) | 1 | 9-11 | N/A (no speculation) |

## Step 4: Solve Zero-Copy KV-Cache Sharing

Both models need access to the key-value cache. The draft model builds speculative KV entries in Vulkan buffers. When the verify model accepts tokens, those entries become canonical. When it rejects, you roll back.

Use `VK_KHR_external_memory_fd` to export Vulkan buffers as file descriptors, then import them into NNAPI via `ANeuralNetworksMemory_createFromFd`. On a Snapdragon 8 Gen 3, a 512MB KV-cache copy costs ~8ms — that would erase most of your speculation benefit. In my benchmarks, this single zero-copy optimization was worth 15-20% throughput improvement.

## Gotchas

Here is the gotcha that will save you hours:

- **Pre-2019 SoCs** lack Vulkan 1.1 compute support entirely. The draft pipeline simply will not run. Check capabilities at startup and fall back gracefully.
- **NNAPI delegation is vendor-dependent.** Some NPU delegates reject model topologies silently. The docs do not mention this, but you will need logging at every delegation step to catch silent failures.
- **Memory budget is tighter than you think.** Devices with 6GB RAM leave roughly 1.5-2GB for both models after Android's runtime takes its share. You need aggressive quantization: int4 for the draft model, int8 for the verifier. There is no way around it.
- **Static speculation depth is a trap.** Build thermal-aware scheduling from day one. A fixed K will either waste thermals or leave performance on the table.

## Wrapping Up

The split-compute architecture — Vulkan for drafting, NNAPI for verification — is the only way to get parallel model execution on mobile. If you are doing on-device inference and have not explored this pattern yet, start with the Vulkan draft pipeline. It has the steepest learning curve, and everything else builds on top of it.

Build the scheduler early, invest in zero-copy KV-cache sharing, and respect the thermal envelope. That is how you get to 22+ tokens/second on a phone.