DFlash: Block Diffusion for Flash Speculative Decoding

repository·main·Indexed 26 days ago

https://github.com/z-lab/dflash

A lightweight block diffusion model designed for flash speculative decoding to enable efficient, high-quality parallel drafting for large language models. DFlash supports multiple backends including vLLM, SGLang, Transformers (specifically Qwen3 and LLaMA-3.1), and MLX for Apple Silicon. It provides the DFlashDraftModel interface for speculative decoding, utilities for context feature extraction, and benchmarking tools for evaluating performance across various datasets.

Tokens
3.5K
Snippets
9
Records
22
Agent score
91%

What's inside dflash

  1. Run DFlash with vLLM

    main

    To use DFlash with vLLM, pass a JSON string to the --speculative-config flag.

    Gemma4 with Docker:

    docker run --rm -it \
      --gpus all \
      --ipc=host \
      --shm-size=16g \
      -p 8000:8000 \
      -v ~/.cache/huggingface:/root/.cache/huggingface \
      ghcr.io/z-lab/vllm-openai:gemma4-dflash-cu130 \
      google/gemma-4-26B-A4B-it \
      --host 0.0.0.0 \
      --port 8000 \
      --speculative-config '{"method": "dflash", "model": "z-lab/gemma-4-26B-A4B-it-DFlash", "num_speculative_tokens": 15, "attention_backend": "flash_attn"}' \
      --attention-backend triton_attn \
      --max-num-batched-tokens 32768 \
      --trust-remote-code

    Non-Gemma4 models:

    vllm serve Qwen/Qwen3.5-27B \
      --speculative-config '{"method": "dflash", "model": "z-lab/Qwen3.5-27B-DFlash", "num_speculative_tokens": 15}' \
      --attention-backend flash_attn \
      --max-num-batched-tokens 32768
  2. Install specialized vLLM builds for Gemma4 or SWA models

    main

    Standard vLLM installation works for most models, but specific builds are required for Gemma4 or newer non-Gemma4 SWA draft models.

    Gemma4 (via Docker):

    docker pull ghcr.io/z-lab/vllm-openai:gemma4-dflash-cu130

    Gemma4 (Source fallback):

    uv pip install -U --torch-backend=auto "vllm @ git+https://github.com/vllm-project/vllm.git@refs/pull/41703/head"

    Non-Gemma4 SWA draft models:

    uv pip install -U --torch-backend=auto "vllm @ git+https://github.com/vllm-project/vllm.git@refs/pull/40898/head"
  3. Run DFlash with SGLang

    main

    Set SGLANG_ALLOW_OVERWRITE_LONGER_CONTEXT_LEN=1 and use the sglang.launch_server module. You can optionally enable experimental schedule overlapping by exporting SGLANG_ENABLE_SPEC_V2=1, SGLANG_ENABLE_DFLASH_SPEC_V2=1, or SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1.

    export SGLANG_ALLOW_OVERWRITE_LONGER_CONTEXT_LEN=1
    
    python -m sglang.launch_server \
        --model-path Qwen/Qwen3.5-35B-A3B \
        --speculative-algorithm DFLASH \
        --speculative-draft-model-path z-lab/Qwen3.5-35B-A3B-DFlash \
        --speculative-num-draft-tokens 16 \
        --tp-size 1 \
        --attention-backend trtllm_mha \
        --speculative-draft-attention-backend fa4 \
        --mem-fraction-static 0.75 \
        --mamba-scheduler-strategy extra_buffer \
        --trust-remote-code
  4. Install DFlash for different backends

    main

    Install DFlash using uv or pip depending on your target backend. It is recommended to use a separate virtual environment for each backend to avoid conflicts.

    • Transformers: uv pip install -e ".[transformers]" (Supports Qwen3 and LLaMA-3.1 only)
    • SGLang: uv pip install -e ".[sglang]"
    • vLLM: uv pip install -e ".[vllm]" (v0.20.1+ includes core support)
    • MLX (Apple Silicon): pip install -e ".[mlx]"
    # Transformers
    uv pip install -e ".[transformers]"
    
    # SGLang
    uv pip install -e ".[sglang]"
    
    # vLLM
    uv pip install -e ".[vllm]"
    
    # MLX
    pip install -e ".[mlx]"
  5. Use DFlash with MLX (Apple Silicon)

    main

    For Apple Silicon, use the dflash.model_mlx module to load models and generate text via streaming.

    from dflash.model_mlx import load, load_draft, stream_generate
    
    model, tokenizer = load("Qwen/Qwen3.5-4B")
    draft = load_draft("z-lab/Qwen3.5-4B-DFlash")
    
    messages = [{"role": "user", "content": "How many positive whole-number divisors does 196 have?"}]
    prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True, enable_thinking=True)
    tps = 0.0
    for r in stream_generate(model, draft, tokenizer, prompt, block_size=16, max_tokens=2048, temperature=0.6):
        print(r.text, end="", flush=True)
        tps = r.generation_tps
    print(f"\nThroughput: {tps:.2f} tok/s")
  6. Use DFlash with Transformers (Python API)

    main

    The Transformers backend is only supported for Qwen3 and LLaMA-3.1 models. Use the spec_generate method on the draft model.

    from transformers import AutoModel, AutoModelForCausalLM, AutoTokenizer
    
    draft = AutoModel.from_pretrained("z-lab/Qwen3-8B-DFlash-b16", trust_remote_code=True, dtype="auto", device_map="cuda:0").eval()
    target = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-8B", dtype="auto", device_map="cuda:0").eval()
    tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-8B")
    
    messages = [{"role": "user", "content": "How many positive whole-number divisors does 196 have?"}]
    input_ids = tokenizer.apply_chat_template(messages, return_tensors="pt", add_generation_prompt=True, enable_thinking=False).to(draft.device)
    
    output = draft.spec_generate(input_ids=input_ids, max_new_tokens=2048, temperature=0.0, target=target, stop_token_ids=[tokenizer.eos_token_id])
    print(tokenizer.decode(output[0], skip_special_tokens=False))
  7. Evaluate DFlash performance

    main

    Benchmarks can be run using the dflash.benchmark module for different backends. Datasets (gsm8k, math500, humaneval, mbpp, mt-bench) are automatically downloaded and cached in cache/.

    vLLM:

    python -m dflash.benchmark --backend vllm \
        --base-url http://127.0.0.1:8000 --model Qwen/Qwen3.5-27B \
        --dataset gsm8k --num-prompts 128 --concurrency 1 --enable-thinking

    SGLang:

    python -m dflash.benchmark --backend sglang \
        --base-url http://127.0.0.1:30000 --model Qwen/Qwen3.5-35B-A3B \
        --dataset gsm8k --num-prompts 128 --concurrency 1 --enable-thinking

    Transformers (Qwen3 and LLaMA only):

    torchrun --nproc_per_node=8 -m dflash.benchmark --backend transformers \
        --model Qwen/Qwen3-8B --draft-model z-lab/Qwen3-8B-DFlash-b16 \
        --dataset gsm8k --max-samples 128

    MLX:

    python -m dflash.benchmark --backend mlx \
        --model mlx-community/gemma-4-31b-it-4bit --draft-model z-lab/gemma-4-31B-it-DFlash \
        --dataset gsm8k --max-samples 128 --enable-thinking
  8. Generate text using dflash_generate()

    main

    The dflash_generate function performs speculative decoding using a DFlashDraftModel and a target model. It supports block-based generation and can return performance statistics if return_stats is set to True.

    @torch.inference_mode()
    def dflash_generate(
        model: "DFlashDraftModel",
        target: nn.Module,
        input_ids: torch.LongTensor,
        max_new_tokens: int,
        stop_token_ids: Optional[list[int]],
        temperature: float,
        block_size: Optional[int] = None,
        mask_token_id: Optional[int] = None,
        return_stats: bool = False,
    )
  9. Stream generation with DFlash on MLX

    main
    The stream_generate function implements speculative decoding using a target model and a DFlash draft model. It yields GenerationResponse objects containing text segments and performance metrics. It handles automatic model patching for hidden state capture and supports both standard and GatedDeltaNet (GDN) models via rollback mechanisms.
  10. Load a DFlash draft model for MLX

    main
    Use load_draft(draft_id) to download and initialize a DFlashDraftModel from a Hugging Face repository. The function automatically handles downloading the necessary .safetensors and config.json files and parses the DFlash-specific configuration.
  11. Perform sampling with sample()

    main
    The sample function converts logits into token IDs. If temperature is less than 1e-5, it performs greedy decoding using argmax. Otherwise, it performs multinomial sampling based on the softmax of the temperature-scaled logits.