Skip to content
Back to skills

Apd Adaptive Parallel Decoding

ASecurity

Accelerate diffusion language model inference by dynamically adjusting parallel tokens per step using a small auxiliary autoregressive model, achieving substantial throughput gains.

  • 6 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 9, 2026
ai-agentspythongogitperformance

Security analysis

A100/100

Scanned September 9, 2026

npx -y skills add ADu2021/skillXiv --skill apd-adaptive-parallel-decoding --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Apd Adaptive Parallel Decoding?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Apd Adaptive Parallel Decoding
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/adu2021-apd-adaptive-parallel-decoding/badge)](https://www.skillsdirectory.com/skills/adu2021-apd-adaptive-parallel-decoding)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: apd-adaptive-parallel-decoding
title: "Accelerating Diffusion LLMs via Adaptive Parallel Decoding"
version: 0.0.2
engine: skillxiv-v0.0.2-claude-opus-4.6
license: MIT
url: "https://arxiv.org/abs/2506.00413"
keywords: [diffusion-llm, parallel-decoding, speculative-decoding, inference-acceleration, adaptive-sampling]
description: "Accelerate diffusion language model inference by dynamically adjusting parallel tokens per step using a small auxiliary autoregressive model, achieving substantial throughput gains."
---

# Accelerating Diffusion LLMs via Adaptive Parallel Decoding

## Core Concept

Diffusion language models (dLLMs) theoretically enable parallel token generation but struggle to match autoregressive models' speed-quality tradeoffs. APD (Adaptive Parallel Decoding) bridges this gap by dynamically adjusting how many tokens are sampled in parallel based on quality assessment from a lightweight auxiliary model. The key innovation: use multiplicative mixture of dLLM marginals with autoregressive joint probabilities, accepting tokens only while both distributions agree. This converts diffusion into left-to-right generation while preserving parallelism where distributions align.

Results show substantial throughput gains (5-8 parallel tokens per step) while maintaining ~80% accuracy on mathematical reasoning tasks, surpassing autoregressive Qwen 7B in speed.

## Architecture Overview

- **Dual Distribution Mixture**: Combines dLLM marginal probabilities with autoregressive joint probabilities
- **Universal Coupling**: Gumbel-Softmax samples ensure principled token acceptance across distributions
- **Adaptive Parallelization**: Number of parallel tokens varies per step based on distribution agreement
- **KV Caching Optimization**: Efficient caching for both diffusion and autoregressive branches
- **Three Tunable Parameters**: Mixture weight R, KV cache window W, maximum masked lookahead M

## Implementation

1. **Mixture Distribution Definition**: Balance diffusion and autoregressive predictions

```python
def compute_mixture_distribution(diffusion_logits, ar_logits, mixture_weight_R):
    """
    Combine diffusion model's marginal distribution with autoregressive
    joint distribution. Higher R favors diffusion, lower favors AR.
    """
    # Diffusion: marginal probability of each token at current position
    p_diffusion = torch.softmax(diffusion_logits, dim=-1)

    # Autoregressive: joint probability given context
    p_ar = torch.softmax(ar_logits, dim=-1)

    # Multiplicative mixture: pT(x) ∝ p_D(x)^R * p_AR(x)^(1-R)
    # Take log to avoid numerical underflow
    log_mixture = R * torch.log(p_diffusion + 1e-10) + (1 - R) * torch.log(p_ar + 1e-10)

    # Normalize to valid probability distribution
    p_mixture = torch.softmax(log_mixture, dim=-1)

    return p_mixture
```

2. **Universal Coupling Token Acceptance**: Use Gumbel-Softmax for principled acceptance

```python
def universal_coupling_acceptance(mixture_dist, ar_dist, num_parallel_tokens=5):
    """
    Sample tokens from mixture distribution. Accept tokens only where
    mixture and autoregressive distributions agree (within threshold).
    Determines parallelization factor adaptively.
    """
    # Gumbel-max trick: sample from categorical using Gumbel noise
    gumbel_noise = -torch.log(-torch.log(torch.rand_like(mixture_dist) + 1e-10) + 1e-10)

    # Mixture samples
    mixture_samples = torch.argmax(
        torch.log(mixture_dist) + gumbel_noise, dim=-1
    )

    # AR samples (for comparison)
    ar_samples = torch.argmax(
        torch.log(ar_dist) + gumbel_noise, dim=-1
    )

    # Acceptance criterion: mixture and AR agree
    agreement = (mixture_samples == ar_samples)

    # Accept tokens while both distributions agree
    accepted_tokens = []
    disagreement_index = None

    for i in range(min(num_parallel_tokens, len(mixture_samples))):
        if agreement[i]:
            accepted_tokens.append(mixture_samples[i])
        else:
            disagreement_index = i
            break

    # Adaptive parallelization: return accepted tokens count
    return torch.stack(accepted_tokens), len(accepted_tokens)
```

3. **Efficient KV Caching**: Maintain cache for both branches

```python
def adaptive_kv_cache_update(kv_cache_diffusion, kv_cache_ar,
                             new_tokens, window_size_W, lookahead_M):
    """
    Update KV caches for both diffusion and AR models.
    Limit cache size to window_size_W for efficiency.
    Lookahead_M determines masked prediction window for diffusion.
    """
    # Append new tokens to both caches
    kv_cache_diffusion['keys'] = torch.cat([kv_cache_diffusion['keys'], new_tokens], dim=1)
    kv_cache_diffusion['values'] = torch.cat([kv_cache_diffusion['values'], new_tokens], dim=1)

    kv_cache_ar['keys'] = torch.cat([kv_cache_ar['keys'], new_tokens], dim=1)
    kv_cache_ar['values'] = torch.cat([kv_cache_ar['values'], new_tokens], dim=1)

    # Maintain sliding window for diffusion (processes in parallel)
    if len(kv_cache_diffusion['keys']) > window_size_W:
        # Keep most recent window_size_W tokens
        start_idx = len(kv_cache_diffusion['keys']) - window_size_W
        kv_cache_diffusion['keys'] = kv_cache_diffusion['keys'][:, start_idx:, :]
        kv_cache_diffusion['values'] = kv_cache_diffusion['values'][:, start_idx:, :]

    # Limit lookahead for masked diffusion prediction
    if lookahead_M > 0:
        # Only allow attending to next M positions ahead
        max_future = len(kv_cache_diffusion['keys']) + lookahead_M
        # Create attention mask for lookahead

    return kv_cache_diffusion, kv_cache_ar
```

4. **Generation Loop**: Integrate adaptive parallelization

```python
def generate_with_apd(diffusion_model, ar_model, prompt_ids, max_length,
                      mixture_weight_R=0.5, window_W=128, lookahead_M=32):
    """
    Generate tokens using adaptive parallel decoding.
    Dynamically determines parallelization per step.
    """
    generated = prompt_ids.clone()
    kv_diffusion = {'keys': None, 'values': None}
    kv_ar = {'keys': None, 'values': None}

    parallel_token_counts = []

    while len(generated) < max_length:
        # Encode current context
        context = generated[-window_W:]  # Use sliding window

        # Get diffusion predictions (multiple masked positions)
        diffusion_output = diffusion_model(
            context,
            num_steps=5,
            kv_cache=kv_diffusion,
            lookahead=lookahead_M
        )
        diffusion_logits = diffusion_output.logits[:, -1, :]

        # Get AR predictions (single position)
        ar_output = ar_model(context, kv_cache=kv_ar)
        ar_logits = ar_output.logits[:, -1, :]

        # Compute mixture and sample
        mixture_dist = compute_mixture_distribution(
            diffusion_logits, ar_logits, mixture_weight_R
        )

        # Accept tokens while distributions agree
        new_tokens, num_accepted = universal_coupling_acceptance(
            mixture_dist, torch.softmax(ar_logits, dim=-1), num_parallel_tokens=10
        )

        # Append accepted tokens
        generated = torch.cat([generated, new_tokens], dim=1)
        parallel_token_counts.append(num_accepted)

        # Update KV caches
        kv_diffusion, kv_ar = adaptive_kv_cache_update(
            kv_diffusion, kv_ar, new_tokens, window_W, lookahead_M
        )

    avg_parallel = sum(parallel_token_counts) / len(parallel_token_counts)
    return generated, avg_parallel
```

5. **Tuning Parameters**: Three key hyperparameters control tradeoff

```python
# Configuration for speed-quality balance
APD_CONFIG = {
    'mixture_weight_R': {
        'description': 'Balance between diffusion (R=1.0) and AR (R=0.0)',
        'default': 0.5,
        'range': (0.3, 0.8),
        'effect': 'Higher R → more parallelism, lower quality'
    },
    'kv_cache_window_W': {
        'description': 'Context window for KV caching',
        'default': 128,
        'range': (64, 256),
        'effect': 'Larger window → more context but slower'
    },
    'max_lookahead_M': {
        'description': 'Maximum lookahead for masked diffusion prediction',
        'default': 32,
        'range': (16, 64),
        'effect': 'Larger M → more parallelism, less accurate predictions'
    }
}
```

## Practical Guidance

**When to Apply:**
- Deploying diffusion language models where latency is critical
- Need speed improvements while maintaining reasoning accuracy
- Have auxiliary small autoregressive model available

**Implementation Prerequisites:**
- Pre-trained diffusion language model (Dream 7B or similar)
- Small autoregressive verifier model (0.5B-1B range, e.g., Qwen2.5-0.5B)
- Sufficient GPU memory for dual model inference

**Performance Expectations:**
- Parallel tokens per step: 5-8 on average
- Throughput: Substantially higher than baseline dLLM
- Accuracy: ~80% on mathematical reasoning (GSM8K, GPQA, MATH)
- Speed-quality tradeoff: Tunable via R parameter

**Key Configuration Strategies:**
- Conservative (high quality, moderate speed): R=0.3, W=128, M=16
- Balanced: R=0.5, W=128, M=32 (default)
- Aggressive (high speed, slightly lower quality): R=0.7, W=64, M=48

**Evaluation Metrics to Track:**
- Average parallel tokens per generation step
- Total latency vs. baseline autoregressive models
- Accuracy on reasoning benchmarks (maintain >90% of baseline)
- Throughput (tokens/sec) on hardware target

**Common Issues:**
- Distribution disagreement too frequent: Decrease R towards 0.5
- Quality degradation: Increase W or decrease M for better context
- OOM errors: Reduce W or use smaller AR verifier
- Slow generation: Increase R or decrease lookahead M

## Reference

Demonstrated on Dream 7B Instruct (diffusion) with Qwen2.5 0.5B (auxiliary AR) on NVIDIA A5000. Achieves 5-8 parallel tokens with negligible performance impact. Evaluated on GSM8K, GPQA, MATH, HumanEval benchmarks. Shows competitive or superior throughput vs. autoregressive Qwen 7B.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…