Incredibly Fast BLOOM Inference with DeepSpeed and Accelerate

TL;DR

Hugging Face shows that the 176‑billion‑parameter BLOOM model can generate tokens in under 1 ms when run with DeepSpeed‑Inference tensor parallelism (or achieve comparable speeds with Accelerate pipeline parallelism) on a single node of eight 80 GB A100 GPUs, and also provides quantized 8‑bit alternatives that halve memory usage.


Hardware Requirements and Setup

  • Optimal configuration: 8 × 80 GB A100 GPUs (352 GB bf16 weights). Alternatives include 2 × 8 × 40 GB A100s, 2 × 8 × 48 GB A6000s, or 24 × 32 GB V100s.
  • Single‑node advantage: Intra‑node GPU interconnects are faster than inter‑node links, typically yielding higher throughput.
  • Lower‑end options: CPU or NVMe off‑load can run BLOOM on smaller GPUs, but generation latency increases substantially.
  • Quantized inference: 8‑bit models (via BitsAndBytes) require roughly half the GPU memory at a modest throughput penalty.

Benchmark Environment

  • Node: Jean Zay HPC, 8 × 80 GB A100, 512 GB CPU RAM, GPFS storage (~3 GB/s read speed).
  • Task: Greedy generation of 100 tokens (max_length=100, do_sample=False) with a short prompt and KV‑cache enabled.
  • Metrics: Model loading time (seconds) and per‑token throughput (ms per token = wall‑time ÷ (batch × tokens)).

Model Loading Times

Solution Load Time (s)
Accelerate 121
DeepSpeed‑Inference (shard‑int8) 61
DeepSpeed‑Inference (shard‑fp16) 60
DeepSpeed‑Inference (unsharded) 662
DeepSpeed‑ZeRO 462

Pre‑sharded DeepSpeed checkpoints load in ~1 minute, while unsharded checkpoints can take >10 minutes.


Token‑Generation Throughput (8 × 80 GB A100)

Solution (dtype) Batch 1 Batch 8 Batch 16 Batch 32 Batch 64 Batch 128 Batch 256 Batch 512
Accelerate bf16 230.38 ms 31.78 ms 17.84 ms 10.89 ms OOM – – –
Accelerate int8 286.56 ms 40.92 ms 22.65 ms 13.27 ms OOM – – –
DeepSpeed‑Inference fp16 44.02 ms 5.70 ms 3.01 ms 1.68 ms 1.00 ms 0.69 ms OOM –
DeepSpeed‑Inference int8 89.09 ms 11.44 ms 5.88 ms 3.09 ms 1.71 ms 1.02 ms 0.71 ms OOM
DeepSpeed‑ZeRO bf16 283 ms 34.88 ms OOM – – – – –

Key observations

  • DeepSpeed‑Inference achieves sub‑1 ms per token at batch 128 thanks to tensor parallelism (TP) and custom fused CUDA kernels.
  • Accelerate, using naive pipeline parallelism (PP), reaches ~10 ms per token at batch 32 but cannot exceed GPU memory limits beyond batch 64.
  • Quantized int8 runs halve memory consumption; DeepSpeed‑Inference int8 still reaches ~1 ms per token at batch 128, while Accelerate int8 runs out of memory earlier.

Quantized 8‑bit Throughput (4 × 80 GB A100)

Solution Batch 1 Batch 8 Batch 16 Batch 32 Batch 64 Batch 128
Accelerate int8 284.15 ms 40.14 ms 21.97 ms OOM – –
DeepSpeed‑Inference int8 156.51 ms 20.11 ms 10.38 ms 5.50 ms 2.96 ms OOM

Solution Details

HuggingFace Accelerate

  • Approach: Loads model weights lazily onto devices based on layer size and available memory; uses simple pipeline parallelism where only one GPU is active per layer.
  • Pros: Works out‑of‑the‑box on any hardware configuration; can offload to CPU or disk when GPU memory is insufficient.
  • Cons: GPUs idle during most of the forward pass, limiting peak throughput; larger batch sizes quickly hit OOM.
  • Usage:
    pip install transformers>=4.21.3 accelerate>=0.12.0
    python bloom-inference-scripts/bloom-accelerate-inference.py \
      --name bigscience/bloom --batch_size 1 --benchmark
    # 8‑bit quantized run
    pip install bitsandbytes
    python bloom-inference-scripts/bloom-accelerate-inference.py \
      --name bigscience/bloom --dtype int8 --batch_size 1 --benchmark
    

DeepSpeed‑Inference

  • Approach: Tensor‑parallelism splits each layer across GPUs; custom fused kernels reduce memory copies and kernel launches.
  • Performance drivers:
    1. TP vs PP – all GPUs compute simultaneously, increasing utilization.
    2. Fused kernels – lower memory overhead and fewer kernel launches.
  • Pre‑sharded checkpoints (microsoft/bloom-deepspeed-inference-fp16) load in ~1 minute; non‑sharded checkpoints load in 10‑20 minutes but run at the same speed after loading.
  • Quantized int8 (microsoft/bloom-deepspeed-inference-int8) halves memory needs and still attains sub‑1 ms per token at batch 128 on 8 × 80 GB A100s, or works on 4 × 80 GB A100s.
  • Usage:
    pip install deepspeed>=0.7.3
    # Fast TP‑pre‑sharded fp16
    deepspeed --num_gpus 8 bloom-inference-scripts/bloom-ds-inference.py \
      --name microsoft/bloom-deepspeed-inference-fp16
    # Original checkpoint (slower load)
    deepspeed --num_gpus 8 bloom-inference-scripts/bloom-ds-inference.py \
      --name bigscience/bloom
    # 8‑bit version (half memory)
    deepspeed --num_gpus 8 bloom-inference-scripts/bloom-ds-inference.py \
      --name microsoft/bloom-deepspeed-inference-int8 --dtype int8
    

DeepSpeed‑ZeRO Inference

  • Approach: Shards model states across GPUs (ZeRO‑3 style) and can run multiple independent generation streams in parallel, yielding an effective speedup proportional to the number of GPUs.
  • Limitations: The provided script runs the same input on all GPUs; achieving the theoretical 8‑× or 16‑× speedup requires custom per‑GPU streams.
  • Off‑loading options: CPU‑offload or NVMe‑offload enable inference on a single GPU at the cost of large latency.
  • Usage:
    pip install deepspeed
    # Multi‑GPU ZeRO inference
    deepspeed --num_gpus 8 bloom-inference-scripts/bloom-ds-zero-inference.py \
      --name bigscience/bloom --batch_size 1 --benchmark
    # CPU off‑load (single GPU)
    deepspeed --num_gpus 1 bloom-inference-scripts/bloom-ds-zero-inference.py \
      --name bigscience/bloom --batch_size 8 --cpu_offload --benchmark
    # NVMe off‑load (single GPU)
    deepspeed --num_gpus 1 bloom-inference-scripts/bloom-ds-zero-inference.py \
      --name bigscience/bloom --batch_size 8 \
      --nvme_offload_path=/path/to/nvme_offload --benchmark
    

Community Server and Client Extensions

  • Server implementations:
    • Mayank Mishra packaged the demo scripts into a ready‑to‑run web server.
    • Nicolas Patry created a high‑performance Rust‑based server.
  • Client‑side projects:
    • Thomas Wang is developing a custom CUDA‑kernel‑accelerated BLOOM model.
    • The HuggingFace JAX team released a JAX inference backend for BLOOM.
  • Keeping up‑to‑date: The transformers-bloom-inference repository aggregates the latest scripts and server implementations.

Practical Takeaways

  • For maximum raw throughput on a single node, use DeepSpeed‑Inference with a pre‑sharded fp16 checkpoint; expect sub‑1 ms per token at batch 128.
  • When GPU memory is limited, switch to 8‑bit quantization via BitsAndBytes (DeepSpeed or Accelerate) to halve memory requirements with a modest speed loss.
  • Accelerate remains the most flexible solution for heterogeneous hardware, but its pipeline parallelism yields higher latency than DeepSpeed’s tensor parallelism.
  • ZeRO inference offers a path to scale across many GPUs or to run on a single GPU with off‑loading, useful when large GPU clusters are unavailable.

“The highest batch size we were able to run without OOM was 128 in this case.” – Hugging Face blog, describing DeepSpeed‑Inference int8 on 8 × 80 GB A100s.


This post reflects the state of BLOOM inference performance as of September 2022. For newer optimizations, consult the transformers-bloom-inference GitHub repository.

Sources

Related

  • Dispatch
  • Dispatch
  • Dispatch
  • Dispatch
  • Dispatch