大模型推理加速指南

2 阅读12分钟

目录


一、推理性能基础

1.1 关键指标

指标含义关注场景
TTFT (Time To First Token)首 token 延迟交互式对话
TPOT (Time Per Output Token)单 token 生成时间流式输出体验
Throughput总吞吐(tokens/s)批处理/服务化
GoodputSLA 内有效吞吐生产服务
QPS每秒请求数容量规划

1.2 推理两阶段

┌────────────┐         ┌────────────────┐
│  Prefill   │ ──────> │    Decode      │
│ (并行处理  │         │  (逐 token     │
│  prompt)   │         │   生成)        │
└────────────┘         └────────────────┘
   compute-bound          memory-bound
   GPU 利用率高           GPU 利用率低
  • Prefill:一次处理整个 prompt,矩阵乘充分并行 → 计算密集
  • Decode:每次只生成 1 token,瓶颈在显存带宽 → 内存密集

这是为什么 decode 阶段 GPU 利用率常常只有 20-30%。

1.3 显存占用估算

7B 模型 FP16 推理:

部分大小
权重7B × 2 bytes = 14 GB
KV Cache (per token)约 0.5 MB
激活值~1-2 GB
总计 (空载)~16 GB

KV Cache 公式:

2 × num_layers × num_kv_heads × head_dim × seq_len × dtype_bytes

8K 上下文的 7B 模型 KV Cache 约 4 GB。


二、性能瓶颈分析

2.1 Roofline 模型

吞吐 = min(
    计算上限 (FLOPS),
    访存上限 (BW × 算术强度)
)
阶段主要瓶颈优化方向
Prefill算力FlashAttention、并行度、量化
Decode显存带宽KV Cache 复用、量化、batching

2.2 工具

# 实时 GPU 监控
nvidia-smi dmon -s pucvmet

# Nsight Systems 性能分析
nsys profile -o report python infer.py

# PyTorch profiler
torch.profiler.profile(activities=[ProfilerActivity.CUDA])

2.3 瓶颈定位 checklist

  • GPU 利用率 < 80%?→ batching 不够 / I/O 瓶颈
  • 显存带宽接近峰值?→ decode 受限,考虑量化
  • TTFT 高 / TPOT 低?→ prefill 慢,prompt 太长,加 chunked prefill
  • 内存碎片严重?→ 启用 PagedAttention

三、KV Cache 优化

3.1 PagedAttention(vLLM 核心)

类比操作系统虚拟内存分页,把 KV Cache 切成固定大小的 block,按需分配:

传统:连续显存分配 → 碎片严重,浪费 60-80%
分页:固定 block → 几乎零碎片,2-4× 吞吐

3.2 Prefix Caching(前缀缓存)

相同 system prompt / few-shot 前缀复用 KV Cache:

# vLLM
from vllm import LLM
llm = LLM(model="...", enable_prefix_caching=True)

收益:长 system prompt 场景下 TTFT 降低 80%+。

3.3 KV Cache 量化

将 KV cache 从 FP16 量化到 FP8/INT4:

llm = LLM(model="...", kv_cache_dtype="fp8")
  • FP8:精度损失小,显存减半
  • INT4:再减半,精度损失可控(用 scale)

3.4 跨请求共享(RadixAttention)

SGLang 的 RadixTree 索引相同前缀,多用户多轮场景效果显著。


四、连续批处理(Continuous Batching)

4.1 静态批处理 vs 连续批处理

静态批处理(GPU 利用率低):
[req1: ████████████░░░░░░]  ← req2 完成后必须等待 req1
[req2: ████░░░░░░░░░░░░░░]
[req3: ░░░░░░░░░░░░░░░░░░]  ← 必须等本批结束才能加入

连续批处理(vLLM):
[req1: ████████████]
[req2: ████]   [req4: █████]   ← 完成立即被替换
[req3: ████████]

4.2 In-Flight Batching(TensorRT-LLM)

每一步迭代动态调整 batch 成员,已完成请求立即释放,新请求即时加入。

4.3 调度参数

LLM(
    max_num_seqs=256,           # 最大并发序列数
    max_num_batched_tokens=8192, # 每步最多 token 数
    max_model_len=4096,
)

调优经验:

  • max_num_batched_tokens 太小 → prefill 慢
  • 太大 → OOM
  • 通常设为 2× max_model_len

五、量化技术

5.1 量化方法对比

方法精度速度训练成本适用
FP16/BF16100%-基线
FP8 (E4M3)~99%1.5-2×H100/H200
INT8~98%1.5-2×校准通用
GPTQ (W4)~97%2-3×校准离线压缩
AWQ (W4)~97%2-3×校准推荐
GGUF (Q4_K)~96%2-3×转换CPU/Mac
INT4~95%3-4×校准极致压缩

5.2 GPTQ 量化

pip install auto-gptq
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig

quant_config = BaseQuantizeConfig(
    bits=4, group_size=128,
    damp_percent=0.01, desc_act=False,
)

model = AutoGPTQForCausalLM.from_pretrained("meta-llama/Llama-3-8B", quant_config)
model.quantize(calibration_data)
model.save_quantized("./llama3-8b-gptq-w4")

5.3 AWQ 量化(推荐)

pip install autoawq
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer

model = AutoAWQForCausalLM.from_pretrained("meta-llama/Llama-3-8B")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3-8B")

quant_config = {"zero_point": True, "q_group_size": 128, "w_bit": 4, "version": "GEMM"}
model.quantize(tokenizer, quant_config=quant_config)
model.save_quantized("./llama3-8b-awq")

AWQ 在大多数任务上略优于 GPTQ。

5.4 FP8(H100/H200 专属)

# vLLM
llm = LLM(model="...", quantization="fp8")

# TensorRT-LLM
trtllm-build --quant_mode fp8 ...

5.5 GGUF(llama.cpp 生态)

# 转换
python convert.py model.bin --outtype f16 --outfile model.f16.gguf
./quantize model.f16.gguf model.q4_k.gguf q4_k_m

# 推理
./main -m model.q4_k.gguf -p "Hello"

六、推测解码(Speculative Decoding)

6.1 原理

用一个小模型 (draft) 先生成 N 个候选 token,再用大模型 (target) 一次性验证。被接受的部分免费,省去多次 decode。

Draft (1B):    生成 4 token → "the cat sat on"
Target (70B):  并行验证 → 接受 3 个 (前 3 正确)
最终:         一次 decode 步等于 3-4 个 token

6.2 加速比

  • 任务越"可预测"(代码、JSON)加速越大:2-4×
  • 创意写作较小:1.3-1.8×

6.3 vLLM 配置

llm = LLM(
    model="meta-llama/Llama-3-70B",
    speculative_config={
        "model": "meta-llama/Llama-3.2-1B",  # draft
        "num_speculative_tokens": 5,
    },
)

6.4 EAGLE / Medusa(无需独立 draft 模型)

  • EAGLE:训练一个小的特征预测 head,复用主模型隐状态
  • Medusa:多个 head 并行预测多 token

vLLM 支持:

speculative_config={"method": "eagle3", "model": "yuhuili/EAGLE3-LLaMA3.1-Instruct-8B"}

七、注意力优化

7.1 FlashAttention

  • v1:减少 HBM 读写
  • v2:更好并行度
  • v3:H100 上利用 TMA + WGMMA,Hopper 专属
# 大多数引擎默认启用,PyTorch 中:
import torch
torch.nn.functional.scaled_dot_product_attention(q, k, v)  # 自动用 flash

7.2 Grouped-Query Attention (GQA)

多个 Q head 共享 KV head:

模型KV head
Llama-3-8B8 (32 Q)
Llama-3-70B8 (64 Q)

KV Cache 减少 4-8×,几乎无精度损失。新模型设计标配

7.3 MLA(Multi-head Latent Attention)

DeepSeek 提出,把 KV 投影到低秩潜在空间,KV Cache 再缩 5-10×。

7.4 Sliding Window Attention

仅关注最近 N token(Mistral 4K 窗口):

config.sliding_window = 4096

适合长文本但不需全局注意的场景。

7.5 Chunked Prefill

将长 prompt 切块逐步 prefill,与 decode 交错调度,降低 TTFT 抖动:

LLM(model="...", enable_chunked_prefill=True, max_num_batched_tokens=2048)

八、推理引擎对比

引擎主推强项弱项
vLLM通用PagedAttention、社区活跃TRT 不及在 NVIDIA 上的极致
TensorRT-LLMNVIDIA极致延迟、FP8编译复杂、依赖重
SGLang通用RadixAttention、structured output较新
LMDeploy国产中文模型友好、TurboMind 内核生态规模小于 vLLM
llama.cppCPU/Mac无 GPU、GGUF不适合大并发
HuggingFace TGI通用集成 HF 生态性能弱于 vLLM
MLC-LLM移动/Web跨设备、WebGPU调优门槛高

8.1 选择建议

是否要求极致延迟(金融/广告)?─→ TensorRT-LLM
                              │
                              否
                              │
是否需要 structured output?──→ SGLang
                              │
                              否
                              │
是否中文模型为主?───────────→ LMDeploy
                              │
                              否
                              │
                          → vLLM (默认推荐)

九、vLLM 实战

pip install vllm

9.1 离线推理

from vllm import LLM, SamplingParams

llm = LLM(
    model="meta-llama/Llama-3-8B-Instruct",
    tensor_parallel_size=2,
    dtype="bfloat16",
    gpu_memory_utilization=0.90,
    max_model_len=8192,
    enable_prefix_caching=True,
)

params = SamplingParams(temperature=0.7, max_tokens=512)
outputs = llm.generate(["你好,介绍一下你自己"], params)
print(outputs[0].outputs[0].text)

9.2 OpenAI 兼容 API

python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-3-8B-Instruct \
  --tensor-parallel-size 2 \
  --port 8000 \
  --max-model-len 8192 \
  --enable-prefix-caching \
  --gpu-memory-utilization 0.90

调用:

from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="EMPTY")
resp = client.chat.completions.create(
    model="meta-llama/Llama-3-8B-Instruct",
    messages=[{"role": "user", "content": "你好"}],
)

9.3 高吞吐配置

--max-num-batched-tokens 16384 \
--max-num-seqs 256 \
--enable-chunked-prefill \
--quantization fp8 \
--kv-cache-dtype fp8

9.4 LoRA 多租户

python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-3-8B \
  --enable-lora \
  --lora-modules sql=/lora/sql math=/lora/math

9.5 关键参数速查

参数含义默认
gpu_memory_utilization占用 GPU 显存比例0.9
max_num_seqs最大并发序列256
max_num_batched_tokens单步最大 tokenauto
tensor_parallel_sizeTP 并行度1
pipeline_parallel_sizePP 并行度1
enable_prefix_caching前缀缓存False
enable_chunked_prefill分块 prefillFalse
quantization量化None
kv_cache_dtypeKV 量化auto
swap_spaceCPU offload (GB)4

十、TensorRT-LLM 实战

10.1 安装

pip install tensorrt-llm
# 或使用 NGC 镜像
docker pull nvcr.io/nvidia/tensorrt-llm/release:latest

10.2 编译模型

# 1. 转换 HF 模型 → TRT-LLM 中间格式
python convert_checkpoint.py \
  --model_dir ./Llama-3-8B \
  --output_dir ./trtllm_ckpt \
  --dtype bfloat16 \
  --tp_size 2

# 2. 构建引擎
trtllm-build \
  --checkpoint_dir ./trtllm_ckpt \
  --output_dir ./trtllm_engines \
  --gemm_plugin bfloat16 \
  --max_batch_size 64 \
  --max_input_len 4096 \
  --max_output_len 1024 \
  --use_paged_context_fmha enable \
  --use_fp8_context_fmha enable

10.3 推理

from tensorrt_llm import LLM, SamplingParams

llm = LLM(model="./trtllm_engines")
out = llm.generate(["Hello"], SamplingParams(max_tokens=100))

10.4 关键优化

  • --use_paged_context_fmha:分页上下文 attention
  • --use_fp8_context_fmha:FP8 attention(H100)
  • --multi_block_mode:长序列优化
  • --use_custom_all_reduce:自定义 NCCL all-reduce

10.5 Triton 部署

# 拉取 Triton 镜像
docker pull nvcr.io/nvidia/tritonserver:24.09-trtllm-python-py3

# 启动
tritonserver --model-repository=/models

十一、SGLang 与 LMDeploy

11.1 SGLang

pip install "sglang[all]"
python -m sglang.launch_server \
  --model meta-llama/Llama-3-8B-Instruct \
  --tp 2 \
  --enable-radix-cache \
  --port 30000

特色:

  • RadixAttention:跨请求共享前缀 KV
  • Structured output:内置 grammar/regex/json schema 约束
  • Constrained decoding 性能优于其他引擎
from openai import OpenAI
client = OpenAI(base_url="http://localhost:30000/v1", api_key="x")

# JSON Schema 约束
client.chat.completions.create(
    model="...",
    messages=[...],
    extra_body={"response_format": {
        "type": "json_schema",
        "json_schema": {"schema": {...}}
    }},
)

11.2 LMDeploy

pip install lmdeploy
lmdeploy serve api_server \
  internlm/internlm2-chat-7b \
  --backend turbomind \
  --tp 2 \
  --quant-policy 8 \
  --server-port 23333

特色:

  • TurboMind 内核:中文模型 (InternLM/Qwen) 性能优秀
  • W4A16 量化:精度+速度平衡好
  • PyTorch backend:兼容性好

十二、分布式推理

12.1 并行策略

策略切分通信适用
TP(Tensor Parallel)层内权重All-Reduce 频繁单机多卡
PP(Pipeline Parallel)层间阶段流水跨机
EP(Expert Parallel)MoE 专家All-to-AllMoE 模型
DP(Data Parallel)请求维度横向扩展
SP(Sequence Parallel)序列维度长序列长上下文

12.2 选择策略

单机 8×H100,70B 模型 → TP=8
多机 70B 模型         → TP=8 + PP=2
MoE 模型             → TP + EP
吞吐扩展             → DP 多副本

12.3 vLLM 多机部署

# 节点 0
ray start --head --port=6379

# 节点 1+
ray start --address='HEAD_IP:6379'

# 启动
python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-3-70B \
  --tensor-parallel-size 8 \
  --pipeline-parallel-size 2

12.4 NCCL 调优

export NCCL_IB_DISABLE=0          # 启用 InfiniBand
export NCCL_NET_GDR_LEVEL=2       # GPUDirect RDMA
export NCCL_P2P_DISABLE=0         # 启用 P2P
export NCCL_DEBUG=INFO            # 排错时

十三、性能基准测试

13.1 vLLM benchmark

python benchmarks/benchmark_serving.py \
  --backend vllm \
  --model meta-llama/Llama-3-8B-Instruct \
  --dataset-name sharegpt \
  --dataset-path ShareGPT_V3.json \
  --num-prompts 1000 \
  --request-rate 16

13.2 自定义 benchmark

import asyncio, time, statistics, httpx

async def bench(url, prompt, n_concurrent=32, n_requests=200):
    sem = asyncio.Semaphore(n_concurrent)
    latencies = []

    async def one():
        async with sem:
            t0 = time.perf_counter()
            async with httpx.AsyncClient(timeout=120) as c:
                r = await c.post(url, json={
                    "model": "...", "messages": [{"role": "user", "content": prompt}],
                    "max_tokens": 256, "stream": False,
                })
            latencies.append(time.perf_counter() - t0)

    t0 = time.perf_counter()
    await asyncio.gather(*[one() for _ in range(n_requests)])
    total = time.perf_counter() - t0

    print(f"QPS: {n_requests/total:.2f}")
    print(f"Latency p50/p95/p99: "
          f"{statistics.median(latencies):.2f}/"
          f"{statistics.quantiles(latencies, n=20)[18]:.2f}/"
          f"{statistics.quantiles(latencies, n=100)[98]:.2f}s")

asyncio.run(bench("http://localhost:8000/v1/chat/completions", "你好"))

13.3 关键测试维度

  • 并发:1, 8, 32, 128, 256
  • prompt 长度:128, 1k, 4k tokens
  • 生成长度:128, 512, 2048 tokens
  • 混合负载:模拟真实分布(ShareGPT/long-tail)

13.4 SLA 指标

TTFT p99 < 500ms
TPOT p99 < 50ms (即 20 tok/s/请求)
Throughput > 1000 tok/s/GPU

十四、生产部署

14.1 Dockerfile

FROM nvcr.io/nvidia/pytorch:24.09-py3
RUN pip install vllm==0.6.3
COPY entrypoint.sh /
EXPOSE 8000
CMD ["/entrypoint.sh"]
#!/bin/bash
exec python -m vllm.entrypoints.openai.api_server \
  --model "$MODEL_PATH" \
  --tensor-parallel-size "${TP:-2}" \
  --max-model-len "${MAX_LEN:-8192}" \
  --gpu-memory-utilization 0.90 \
  --enable-prefix-caching

14.2 K8s 部署

apiVersion: apps/v1
kind: Deployment
metadata: { name: vllm }
spec:
  replicas: 2
  selector: { matchLabels: { app: vllm } }
  template:
    metadata: { labels: { app: vllm } }
    spec:
      containers:
        - name: vllm
          image: registry/vllm:latest
          resources:
            limits:
              nvidia.com/gpu: "2"
              memory: 64Gi
          env:
            - { name: MODEL_PATH, value: /models/llama3-8b }
            - { name: TP, value: "2" }
          volumeMounts:
            - { name: models, mountPath: /models }
            - { name: shm, mountPath: /dev/shm }
          readinessProbe:
            httpGet: { path: /health, port: 8000 }
            initialDelaySeconds: 120
      volumes:
        - { name: models, persistentVolumeClaim: { claimName: model-pvc } }
        - { name: shm, emptyDir: { medium: Memory, sizeLimit: 16Gi } }

14.3 自动扩缩容

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: vllm }
spec:
  scaleTargetRef: { kind: Deployment, name: vllm }
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Pods
      pods:
        metric: { name: vllm:num_requests_running }
        target: { type: AverageValue, averageValue: "200" }

14.4 灰度发布

  • 蓝绿:新旧模型并行,流量切换
  • A/B:基于 user-id 哈希分流
  • 金丝雀:1% → 10% → 100%

14.5 模型加载加速

# safetensors 加载比 .bin 快 3-5×
# 用 NVMe 本地盘缓存 HF 模型
HF_HOME=/local-nvme/hf-cache vllm serve ...

# Tensorizer 进一步加速
from tensorizer import TensorSerializer, TensorDeserializer

十五、常见问题

15.1 OOM

  • 降低 gpu_memory_utilization 到 0.85
  • 减小 max_model_len
  • 启用 KV cache 量化(kv_cache_dtype=fp8
  • 减小 max_num_seqs

15.2 TTFT 太高

  • 启用 enable_chunked_prefill
  • 启用 enable_prefix_caching(system prompt 较长时)
  • 减少 max_num_batched_tokens(避免 prefill 排队过久)

15.3 吞吐上不去

  • GPU 利用率 < 70% → 加大 batch
  • 利用率 > 95% → 上 TP / 加卡 / 量化
  • I/O 瓶颈 → tokenizer 进程化、HTTP 连接池

15.4 长尾延迟(p99 高)

  • 启用 chunked prefill
  • 隔离长请求(独立 endpoint)
  • 限制 max_tokens

15.5 输出质量下降

量化/draft 模型可能引入精度损失:

  • 跑 lm-eval-harness 验证
  • AWQ 一般优于 GPTQ
  • speculative 仅影响速度,不影响输出(数学等价)

15.6 多机 NCCL 卡死

  • 检查所有节点 IB 网络互通
  • NCCL_DEBUG=INFO 看具体卡在哪步
  • 防火墙是否阻断

15.7 显存碎片导致逐渐变慢

  • 用 PagedAttention 引擎(vLLM/TRT-LLM)
  • 定期重启 worker

附录:速查

A.1 加速手段优先级

  1. 量化(FP8/AWQ)→ 显存减半,速度 1.5-2×
  2. prefix caching → system prompt 重的场景,TTFT 大降
  3. continuous batching → 默认开(vLLM/TRT-LLM)
  4. chunked prefill → 长 prompt 平滑 TTFT
  5. speculative decoding → 进一步 1.5-3× 解码加速
  6. TP/PP → 模型放不下时再考虑

A.2 不同规模选型

规模推荐
7-13BvLLM + AWQ + 1×A10/A100
30-70BvLLM TP=4 + FP8 + 4×A100/H100
100B+TRT-LLM TP=8 + PP,多机
MoESGLang/vLLM + EP

A.3 关键环境变量

CUDA_VISIBLE_DEVICES=0,1
NCCL_IB_DISABLE=0
VLLM_WORKER_MULTIPROC_METHOD=spawn
HF_HUB_OFFLINE=1   # 避免每次启动联网

A.4 资源链接