Chapter 10

DeepSpeed-Inference 与 DeepSpeed-MII

📌 源码引用基于 deepspeed/inference/ 、 deepspeed/inference/v2/ · commit 510ebe58e4e4 。 MII 在独立仓库 deepspeedai/DeepSpeed-MII ,本章只点入口。

10.1 DS 推理生态的三层

能力API
DeepSpeed-Inference v1tensor 并行推理、fused kerneldeepspeed.init_inference()
DeepSpeed-Inference v2 (FastGen)continuous batching、PagedAttention 风格 KV 管理deepspeed.inference.v2.*
DeepSpeed-MIIOpenAI 兼容服务、persistent/non-persistent 部署独立 pip 包 deepspeed-mii

实战中 vLLM / SGLang 后来居上,DS 推理生态的市场份额不如训练那么强势。但在两个场景下仍然有竞争力:

10.2 DeepSpeed-Inference v1:单卡 / 多卡 TP 推理

最小示例

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
import deepspeed

tok = AutoTokenizer.from_pretrained("Qwen/Qwen3-4B-Instruct-2507")
model = AutoModelForCausalLM.from_pretrained(
    "Qwen/Qwen3-4B-Instruct-2507", torch_dtype=torch.bfloat16
)

# ★ 注入推理引擎
engine = deepspeed.init_inference(
    model,
    tensor_parallel={"tp_size": 2},        # 用 2 张卡做 TP
    dtype=torch.bfloat16,
    replace_with_kernel_inject=True,       # 替换 fused kernel
    max_out_tokens=2048,
)

prompt = "你好,介绍一下 DeepSpeed"
inputs = tok(prompt, return_tensors="pt").to(engine.module.device)
out = engine.module.generate(**inputs, max_new_tokens=128)
print(tok.decode(out[0], skip_special_tokens=True))

启动方式:

deepspeed --num_gpus 2 infer.py

init_inference() 关键参数

参数说明
tensor_parallel.tp_size张量并行度,>1 时多卡 TP
dtype fp16 / bf16 / int8
replace_with_kernel_inject把模型里的 attention/MLP 替换成 DS fused kernel
max_out_tokens 预分配 KV cache 长度上限
quant { "enabled": True, "bits": 8 }
moe MoE 推理配置(expert parallel)

10.3 DeepSpeed-Inference v2 / FastGen

v1 偏静态批,v2(FastGen) 加入了:

用法:

from deepspeed.inference.v2 import build_hf_engine

engine = build_hf_engine(
    path="Qwen/Qwen3-4B-Instruct-2507",
    engine_config={
        "tensor_parallel": {"tp_size": 2},
        "max_ragged_sequence_count": 256,
        "max_ragged_batch_size": 8192,
    },
)
# 之后通过 generator API 提交请求

FastGen 在同样硬件上吞吐通常和 vLLM 相当,但调用 API 风格不同;选哪个看团队习惯。

10.4 DeepSpeed-MII:开箱即用的服务

MII = "Model Implementations for Inference"。它包了 v1/v2,让你一行命令起 OpenAI 兼容 API:

pip install deepspeed-mii

# 启动 RESTful 服务
python -c "
import mii
client = mii.serve('Qwen/Qwen3-4B-Instruct-2507', tensor_parallel=2)
"

# 客户端调用
curl http://localhost:28080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"default","messages":[{"role":"user","content":"你好"}]}'

MII 还支持 persistent 部署(不退出,挂着等请求)和 non-persistent(短任务进出)。在 LLaMA-Factory ch12 提到的"训完直接部署"流程,DS 用户的一条路就是 LLaMA-Factory 出 merged HF model → MII 部署。

10.5 训练 → 推理无缝衔接

flowchart LR Train["训练: deepspeed.initialize()
(ZeRO-3 + offload)"] Train --> Save["engine.save_checkpoint()
+ save_16bit_model() 得到 HF 格式"] Save --> Infer["推理: deepspeed.init_inference()
或 build_hf_engine() (v2)"] Save --> MII["部署: mii.serve()"] Save --> Other["或者 → vLLM / SGLang / TRT-LLM"]

关键链路:训练时的 ZeRO-3 切分 → 保存时通过 stage3_gather_16bit_weights_on_model_save 合回完整 fp16 → 推理时再用 DS-Inference / MII 加载。这就是 DS 一条龙生态的最大卖点。

10.6 选型对照表

场景推荐
开发期 / 单卡推理调试 transformers 直接 model.generate()
多卡 TP 推理(H100 集群) vLLM 或 DeepSpeed-Inference v2
已经全栈 DS 训练,想最小转换 DeepSpeed-Inference v2 / MII
OpenAI 兼容 API 服务 vLLM serve(最稳);DS-MII 或 LLaMA-Factory api
非 NVIDIA 硬件(AMD / Habana) DeepSpeed(生态较广)
MoE 推理 DeepSpeed-Inference 自带 EP 支持
追求 SOTA 吞吐 / 最长上下文 vLLM / SGLang 通常领先半个版本

10.7 重要注意

10.9 InferenceEngine 的三种 injection 路径

翻开 deepspeed/inference/engine.pyInferenceEngine.__init__(line 45–184)能看到一段判分支:到底用哪条 injection 路径,由三个 config 字段决定。

config 字段行号含义
1injection_policy: Dict[type, policy_obj]131用户显式 policy。手动告诉 DS:"把这个 HF 类替换成那个 fused 类"。最精细但要写代码。
2replace_with_kernel_inject: True 152命中 replace_policies registry(GPT/BERT/LLaMA/Falcon/OPT/BLOOM 等)。最常用。
3tensor_parallel.tp_size > 1 155都没命中时,调 AutoTP(见 ch09.13)做兜底切分。不替换 kernel,只切权重。

判定优先级:1 > 2 > 3。模型不在 kernel_inject 白名单(如某些新出的开源模型)时,会自动落到 3(AutoTP);功能上能跑,但比 2 慢,因为没有 fused kernel。

诊断:"我开了 replace_with_kernel_inject=True 但速度跟没开一样" → 说明你的模型类没在 replace_policies 里。打开 DS log,看启动期是否打印 replace_module: TrueAutoTP: True 来确认走了哪条路径。

10.10 v2 / FastGen 的 InferenceEngineV2 API

v1 的 generate() 是静态批,v2 设计为 "持续接收请求 / 持续吐结果" 的服务端 API。源码在 deepspeed/inference/v2/engine_v2.py

方法位置用途
put(batch_uids, batch_tokens, do_checks=True) line 107提交一个 ragged batch(多个序列长度不同)做一次 forward;自动复用已存在的 sequence KV-cache
query(uid, max_request_tokens, max_request_blocks) line 158预检查:这条 sequence 还能塞多少 token / 占多少 block,不分配资源
can_schedule(uids, lengths) line 184dry-run:当前 batch 调度得过吗?给 scheduler 用
free(uid) 释放某条 sequence 的 KV-cache

两个核心数据结构:

FastGen 的 "Dynamic SplitFuse" 就是在 put() 之前做的:把当前队列里的 prefill 请求和 decode 请求合并成一个 batch(prefill 算很多 token、decode 算 1 个 token),让 GPU 一次 forward 同时服务两类负载。

10.11 module_inject policy 怎么写

想给一个 kernel_inject 没支持的新模型加 v1 推理加速?需要在 deepspeed/module_inject/ 写一个 TransformerPolicy 子类。最少实现 3 个方法:

# 简化骨架
class MyModelPolicy(TransformerPolicy):
    def attention(self):
        # 返回 QKV / output 权重的张量切割信息:
        # (qkvw, qkvb, dense_w, dense_b, head_dim, ...)
        ...
    def mlp(self):
        # 返回 MLP 的 4 个张量:intermediate / output 权重和 bias
        ...
    def layernorm(self):
        # 返回 attention / mlp 前的 layernorm 权重
        ...

然后在 replace_policy.py 里把 HFMyModelLayerMyModelPolicy 注册进 replace_policies dict。一次性活——做完后用户写 replace_with_kernel_inject=True 就能享受 fused kernel。这是 DS 推理生态对接新模型的标准 PR 路径,git log deepspeed/module_inject/ 能看到一长串以 "Add inference policy for X" 命名的 commit。

10.12 MII 实际跑的是 v1 还是 v2?

MII 本身是个 "facade"——它根据传入的 engine_config 决定起 v1 还是 v2:

传给 mii.serve() 的参数实际后端
不传 / 老的 tensor_parallel=N 形式 v1 (init_inference)
新的 mii.config.ModelConfig(...) 或带 max_ragged_* 的 dict v2 (build_hf_engine)
明确指定 deployment_type=DeploymentType.NON_PERSISTENTv1 一次性脚本
明确指定 deployment_type=DeploymentType.AML v2 服务化

启动后用 curl http://localhost:28080/v1/models 看 metadata 里有没有 "engine": "v2" 字样能确认。

10.13 这章带走什么