Inference Engineering Philip Kiely

第 4 章

软件

从 CUDA 到 PyTorch、推理引擎与 NVIDIA Dynamo,建立推理软件栈的分层心智模型。

NVIDIA在推理领域的市场主导地位,在很大程度上归功于其硬件周围成熟而完善的软件生态系统。

硬件的迭代周期较慢。像Apple和NVIDIA这样的顶尖硬件公司,新架构和新一代产品的发布频率最多为一年一次,两年一个发布周期更为常见。

但软件迭代速度很快。通常,要在发布第一天就运行一个新发布的开放模型,你需要安装每个软件依赖项的夜间构建版本或其他预发布版本,才能获得对新模型的支持。

软件快速的迭代周期和较低的准入门槛极大地拓展了推理工程的版图。硬件领域以NVIDIA和少数竞争对手为核心,而在推理技术栈的各个层面,却有无数公司在构建软件。

对于推理工程师而言,以下是一些关键参与者:

  • NVIDIA:在其自有的(有时是专有的)软件生态系统上大力投入,从CUDA到Dynamo。

  • Hugging Face:维护着所有开放模型的模型注册中心,以及transformers和diffusers库。

  • Linux基金会:维护着PyTorch和vLLM等与硬件无关的项目。

  • LMSYS Org:开发用于推理和评估的核心工具,其中最具代表性的是SGLang。

还有数千家公司、高校和研究机构为推理领域的开源工作做出了重要贡献。

软件领域范围太广、变化太快,任何一本书都难以详尽记录,更何况是单独一章。因此,本章重点介绍具有长期价值的基础技术。

在本章中,各项技术按照抽象层级由低到高依次介绍:

  • CUDA:直接与GPU通信,对计算和内存进行显式控制(第4.1节)。

  • 深度学习框架:对CUDA的抽象封装,用于在Python中训练、导出和运行神经网络(第4.2节)。

  • 推理引擎:基于PyTorch、高度可配置的推理工具,支持常见架构(第4.3节)。

  • NVIDIA Dynamo:位于推理引擎之上,为大规模部署提供支撑(第4.4节)。

如今,大多数推理工程工作发生在较高的抽象层面,包括配置和部署推理引擎,以及跨多个GPU协调推理任务。无论你在技术栈的哪个层面工作,对相邻抽象层级建立清晰的心智模型,都是指导工作的关键所在。

4.1 CUDA

CUDA 是你为 NVIDIA GPU 编写运行代码的方式。

更正式地说,CUDA 是 NVIDIA 专有的计算平台和编程模型,用于在 GPU 上执行并行任务。“平台”和”编程模型”都是宽泛的定义;从 CUDA 的各个组成部分来理解会更容易:

  • CUDA 内核:一种用户自定义函数,用于在 GPU 上执行并行化代码。

  • CUDA 图:由内核和其他 GPU 操作组成的有向无环图(DAG),用于优化重复性工作流程。

  • CUDA 驱动:应用程序与 GPU 硬件之间的底层接口,用于管理内存和执行。

  • CUDA 运行时:面向开发者的 API,用于启动内核和管理内存。

CUDA——全称为 Compute Unified Device Architecture(统一计算设备架构),尽管这个缩写如今已鲜少被展开——是整个 NVIDIA GPU 生成式 AI 生态系统的基础。

CUDA 不是一种编程语言。CUDA 程序通常以某种编程语言(最常见的是 C++)编写,然后由 nvcc 等编译器将其编译为独立的 CPU 和 GPU 代码。

内核只是一个执行某些并行计算的函数。每当你看到”CUDA 内核”这个短语时,可以将其替换为”为 NVIDIA GPU 编写的一段代码”。

作为”Hello, World!”内核的示例,请看以下六行 C++ 代码,它们接收一个长度为 n 的数组,并将数组中的每个元素翻倍。

示例 CUDA 内核将数组中的每个值翻倍。
图 4.1 示例 CUDA 内核将数组中的每个值翻倍。

通常,在 CPU 上,该函数将以线性时间运行,数组中的每个元素依次被翻倍。但在 GPU 上,数千个元素可以同时处理,从而使该函数效率大幅提升。

编写 CUDA 内核将推理工程的思维方式从关注算法转变为关注实现。例如,作为生成式 AI 核心的传统注意力算法可以用几十行代码来表达。然而,FlashAttention 执行的是相同的数学运算,却需要数万行代码,以便针对特定 GPU 以更节省内存的方式实现该算法。

4.1.1 用于推理的 CUDA 内核

编写 CUDA 内核并不意味着从零开始构建。可供借鉴的先前技术早在 CUDA 出现之前数十年就已存在。BLAS(基础线性代数子程序)最初于 20 世纪 70 年代为 Fortran 实现,是一套涵盖从点积到矩阵乘法等常见线性代数运算的规范。

cuBLAS 是 BLAS 的 CUDA 实现,以预构建内核的形式将该规范引入 CUDA,用于执行基本的线性代数运算。类似地,cuDNN(CUDA 深度神经网络)为神经网络提供了基础原语。

在 BLAS 中,推理中最常用的操作是 GEMM(通用矩阵-矩阵乘法)。模型中的每个线性层都使用矩阵乘法,而 cuBLAS 提供了一个良好的起点。

但你并不局限于 cuBLAS 的实现。由于 GEMM 等操作对推理至关重要,你可能需要更细粒度的控制。你可以针对不同形状的矩阵编写不同的 GEMM 内核,或使其更好地运行在特定的 GPU 架构上。

CUTLASS 是一个模板库,为编写高性能内核提供了构建模块。例如,FlashAttention 3 就使用了 CUTLASS。CuTe 是另一个模板库,为近期架构的分块张量操作引入了抽象。借助 CUTLASS 和 CuTe 等工具,可以在更高的抽象层次上编写内核,同时保持强劲的性能。

内核的另一个来源是 FlashInfer,这是一个为大语言模型推理提供高性能内核实现的库,包含许多优化的注意力内核和融合采样函数。

4.1.2 CUDA 内核选择

大多数推理工程师永远不需要自己编写内核。然而,内核选择——从众多选项中挑选最佳内核——是推理优化的重要组成部分。

内核实现高度专业化。CUDA 提供了用于内存管理和并行计算的底层 API,内核工程师会根据所针对硬件的精确规格来做出实现决策。

理解内核实现与特定硬件细节之间的紧密联系非常重要。内核通常包含基于特定 GPU 的内存带宽、张量核心数量或布局而硬编码的数值。

为 H100 编写的内核很可能无法充分利用 B200 的架构和额外内存,而为 B200 编写的内核可能与上一代 Hopper 架构不向后兼容。每一代新 GPU 推出时,将手写内核移植到新架构上以实现最优运行都需要大量的工程工作。

大多数内核选择是自动进行的。深度学习框架和推理引擎为各种架构预配置了内核,而 PyTorch 和 TensorRT-LLM 则在其编译步骤中包含了自动内核选择功能。

但是,你可能需要为关键算法手动选择少数内核,以加速推理。

例如,大多数生产就绪的 GEMM 内核来自 cuBLAS。但当 DeepSeek 实验室发布其更新版本的 DeepSeek-V3 时,他们同时发布了 DeepGEMM,为在 Hopper GPU 架构上以 FP8 格式运行矩阵乘法提供了更高效的 GEMM 内核。

手动内核选择允许你将 DeepGEMM 内核作为插件插入,以加速推理中的特定步骤,例如对特定维度的两个矩阵进行乘法运算。但要注意确保兼容性。例如,如果你升级到 B200 GPU,你就必须将内核换回原来的版本,等待 DeepGEMM 支持 Blackwell(截至本文发布时已支持),或者自行移植该内核。

4.1.3 通过内核融合减少内存访问

在相同数据上依次运行两个不同的内核,会导致不必要的内存读写浪费。

举一个简单的例子,假设有两个内核:multiply_by_2 和 multiply_by_3。如果这两个内核依次运行,操作顺序将是:

  1. 从内存中读取输入向量 [1, 2, 3]。
  2. 对该向量运行 multiply_by_2。
  3. 将输出向量 [2, 4, 6] 保存到内存。
  4. 从内存中读取新的输入向量 [2, 4, 6]。
  5. 对该向量运行 multiply_by_3。
  6. 将最终输出向量 [6, 12, 18] 保存到内存。

低效之处显而易见:第三步和第四步构成了一次不必要的内存往返。在解码阶段(LLM 推理中受带宽限制的阶段),推理引擎无法承受不必要的内存读写开销。

内核融合是将两个或多个内核重新实现为一个能够同时处理所有操作的单一内核的过程。在本例中,融合后的内核将是 multiply_by_6,新的操作顺序将变为:

  1. 从内存中读取输入向量 [1, 2, 3]。
  2. 对该向量运行 multiply_by_6。
  3. 将最终输出向量 [6, 12, 18] 保存到内存。

在实践中,内核融合要复杂得多——函数更为复杂,数据的重叠也没有那么整齐。但在推理的内核融合中存在一些常见模式,例如将矩阵乘法、偏置添加和激活函数合并在一起。

内核融合减少了 GPU 内部内存与计算单元之间的读写操作。
图 4.2 内核融合减少了 GPU 内部内存与计算单元之间的读写操作。

内核融合可以是自动过程,也可以是手动过程。编译器能够识别简单的融合机会并自动创建融合内核。但对于更复杂的算法(如 FlashAttention),则需要手写融合内核,并在推理过程中通过插件的方式调用。

4.2 深度学习框架与库

深度学习框架和库是直接在 CUDA 中工作与使用 vLLM 等现成推理引擎之间的桥梁。这些库在训练和推理中均有应用。

过去几年,PyTorch 已成为该技术栈层级中明确的领导者。还有另外两个框架,为简洁起见,我仅简要提及:

  • TensorFlow:一个由 Google 官方支持的端到端机器学习平台,TensorFlow 在 2010 年代的机器学习时代曾十分突出,但如今已逐渐失去青睐。

  • JAX:一个与 Google 非官方关联的研究项目,JAX 提供了更简洁的接口,没有太多历史遗留特性和操作。然而,正如其文档所警告的,使用时需预期可能遇到一些棘手的问题。

本节的其余部分将重点介绍 PyTorch 及其在技术栈中周边和上层的相关技术。

4.2.1 PyTorch

PyTorch 是一个用于描述张量运算的 Python 包。它最初由 Meta 创建,现已成为 Linux 基金会的一部分。PyTorch 是生成式 AI 模型训练和推理的行业标准技术。

就我个人而言,我整个职业生涯都是一名 Python 程序员,我觉得编写底层 C++ 代码很困难。借助 PyTorch,我可以用 Python 为 CPU 和 GPU 编写高性能的推理代码,同时在必要时也可以通过插入特定的内核来深入使用 CUDA。

PyTorch 可以训练任何类型的神经网络。PyTorch 文档展示了一个基本的神经网络示例:

PyTorch 中的一个基本神经网络,改编自 PyTorch 文档。
图 4.3 PyTorch 中的一个基本神经网络,改编自 PyTorch 文档。

虽然这是一个非常简单的示例,但你可能已经认出了第 2 章中讨论的线性层和 ReLU 激活函数,它们是神经网络的关键组成部分。

PyTorch 通过其 autograd 模块自动计算任意可微函数的梯度。这正是 PyTorch 在训练方面如此强大的原因——你定义一个计算图,就能获得用于训练的梯度。

但 PyTorch 的特别之处在于,它不仅擅长训练,在推理方面同样强大。PyTorch 在内置函数和自动性能优化与所需的手动控制之间取得了平衡。

将模型从训练转换为推理的关键步骤是编译。PyTorch 编译(torch.compile)针对特定 GPU,并执行自动内核选择和内核融合,以确保最优性能。

torch.compile 无法融合 DeepGEMM、FlashAttention 或自定义内核等插件内核。这限制了它在 LLM 推理中的实用性,因为 LLM 推理中大多数内核都是自定义的。然而,PyTorch 编译对于优化不常见的模型架构以及编译一长串轻量级内核非常有用。当你优化具有自定义或罕见架构的模型时,可能需要将函数重写得更加抽象——尤其是在涉及 Python 特定语言特性方面——才能使编译成功。

PyTorch 本身就是构建高性能推理服务的强大而灵活的工具。但在 PyTorch 之上还有一个丰富的生态系统,可以更快速地实现、编译和执行针对常见模型架构的优化代码。

4.2.2 模型文件格式

用于序列化模型权重的主流文件格式是 safetensors,由 Hugging Face 创建。

Safetensors 是对 bin 等通用格式的替代,专门为存储模型权重而设计。safetensors 的”安全性”在于:与那些在反序列化过程中可以执行任意 Python 代码的通用格式不同,safetensors 只存储张量数据,而不包含可执行代码。

生成式 AI 模型拥有数百 GB 的权重数据,这些权重被分散存储在数十个 safetensors 文件中。safetensors 格式采用内存映射技术,确保文件在加载时无需分配完整内存,从而使模型权重的加载更快、更安全。

另一种主流格式 ONNX(开放神经网络交换格式)将权重与模型的执行图一同存储。safetensors 格式将权重与架构分离,而 ONNX 则将两者捆绑在一起。

ONNX 文件具有极强的可移植性。凭借与 PyTorch 的深度集成以及对多种硬件选项的支持,当您希望存储的是模型图而不仅仅是权重时,ONNX 是 safetensors 的绝佳替代方案。

4.2.3 ONNX Runtime 与 TensorRT

ONNX Runtime 和 TensorRT 是高性能推理运行时。PyTorch 模型可以导出为 ONNX 格式,ONNX Runtime 可以直接执行该格式,或者 TensorRT 可以将其编译为高度优化的引擎。

ONNX RuntimeTensorRT
开源,隶属于 Linux 基金会由 NVIDIA 构建,包含专有组件与开源组件的混合
PyTorch 生态系统中的一流导出工具通过 Torch-TensorRT 与 PyTorch 集成
支持多种类型的 GPU仅支持 NVIDIA GPU

ONNX Runtime 是一个开放的社区标准,而 TensorRT 则专属于 NVIDIA GPU。

导出过程与 Torch 编译有些相似。然而,这些标准并不支持 PyTorch 中的所有数据结构、类型和操作。导出过程可以识别 PyTorch 代码中的这些问题,但对于更复杂的模型,这会变得相当棘手。

DeepSeek V3 就是一个典型案例,它引入了多潜在注意力机制(MLA)。在 PyTorch 中实现的 MLA 难以导出,但 Transformer 架构整体上足够简单,手动融合算子(kernel)是可行的。

如今,对于这些引擎所支持的模型,越来越流行的做法是直接从 PyTorch 跳转到 vLLM 或 TensorRT-LLM 等推理引擎,绕过中间表示步骤,仅将权重导出为 safetensors 格式。ONNX Runtime 和 TensorRT 仍被广泛使用——TensorRT 尤其因其对图像和视频模型出色的开箱即用运行时表现而备受青睐——但整个行业正在分化为两种路线:手写 PyTorch 代码所带来的灵活控制,或预构建推理引擎所提供的便捷性。

4.2.4 Transformers 与 Diffusers

Hugging Face 的 transformers 和 diffusers 库构建于 PyTorch 之上,但并非为大规模生产推理而设计。相反,这些库提供了模型的参考实现,供推理工程师学习和借鉴。

虽然这些库是供探索和试验的工具箱,但它们确实包含了关于模型的重要信息,以及用于构建模型推理服务器的实用工具。随 transformers 和 diffusers 所实现的模型一同提供的 config.json 文件包含关键信息,而这些库中用于 Hugging Face 操作(如下载模型权重)的实用工具也被广泛使用。

在 Hugging Face 上大多数热门开放模型的模型卡片中,您都能找到 transformers 或 diffusers 的示例代码。这些示例代码非常适合用于了解模型的精确输入输出规范,或用于本地推理和 Notebook 运行。但对于生产环境,您需要直接编写并编译 PyTorch 代码,或使用生产级推理引擎。

4.3 推理引擎

目前市场上有三种主流推理引擎:vLLM、SGLang 和 TensorRT-LLM。

这些框架为大型语言模型(LLM)及其他具有类似架构的模态提供了良好的开箱即用性能(第6章)。

2025年底,vLLM 和 SGLang 也分别通过 vLLM Omni 和 SGLang Diffusion 开始支持部分图像和视频生成模型。TensorRT-LLM 不支持图像或视频生成模型。推理工程师也可以直接使用 TensorRT 或 PyTorch 来运行这些模型(第6.5节)。

推理引擎之所以强大,在于其高度可配置性。推理工程师通过在更高抽象层级上使用预优化组件,可以将精力集中在测试各种技术组合上,而无需重复常规的实现工作。

从整体来看,vLLM 和 SGLang 是更通用的工具,更易于上手,且对更多模型具备零日支持;而 TensorRT-LLM 的学习曲线较陡,但通常能实现最佳性能。

引擎vLLMSGLangTensorRT-LLM
性能良好良好最佳
易用性简单简单困难
模型支持最多最多部分
硬件支持GPU、TPUNVIDIA、AMD仅 NVIDIA
许可证Apache 2.0Apache 2.0Apache 2.0

每个框架均可开箱即用,支持持续批处理等核心功能,并支持主要的性能优化技术——训练后量化、推测解码、前缀缓存、并行化、解耦。

在 Baseten,我们同时使用这三种框架,但最常用的是 TensorRT-LLM。推理工程师应熟悉全部三种框架,并根据每次具体的部署需求进行选择。

4.3.1 vLLM

vLLM 在推理引擎中拥有最大的市场份额。GitHub stars 是衡量受欢迎程度的粗略指标,但在本文发布时,vLLM 的 stars 数量是 SGLang 和 TensorRT-LLM 总和的两倍。

vLLM 于 2023 年夏季首次发布,是这些推理引擎中历史最悠久的,领先其他引擎数月。vLLM 最初由加州大学伯克利分校创建,现在由 Linux 基金会旗下的 PyTorch 项目托管。

vLLM 最大的卖点在于其广泛的支持性。它支持最多的硬件选项——NVIDIA、AMD 和 Intel GPU 以及 Google TPU——同时也支持最多的模型和架构。几乎所有开源大语言模型从发布第一天起就与 vLLM 集成。vLLM 还通过 vLLM Omni 支持多模态推理,将引擎扩展为支持图像、音频和视频的输入与输出。

推理工程的核心原则之一是:引入的约束越多,能够实现的性能就越好。vLLM 的广泛平台在经过合理配置后可以实现令人印象深刻的性能结果,但根据我的经验,它仍不及 TensorRT-LLM 等专用框架所能达到的顶级性能。

vLLM 的开发者体验围绕 vllm serve 命令构建,服务器配置以标志(flags)的形式传入。

vLLM 在八块 GPU 上的推理示例。
图 4.4 vLLM 在八块 GPU 上的推理示例。

vLLM 支持通过 pip 安装,并提供官方 Docker 镜像,预置了相关依赖项并支持多种硬件架构。

在以下情况下,你应该使用 vLLM:

  • 你希望快速搭建一个模型服务器,对几乎所有开源模型都能开箱即用并提供稳定的性能。

  • 你希望运行具有多种输入和输出模态的”Omni”模型。

  • 你正在使用较小的 GPU 或较旧的架构,而 TensorRT-LLM 在此场景下性能提升有限。

4.3.2 SGLang

SGLang 是另一个主要的社区驱动的快速推理框架。SGLang 于 2023 年 12 月首次发布,随着 DeepSeek 和 Qwen 等中国开源模型的兴起而声名大噪,并且是 xAI 推理引擎的首选。

SGLang 在模型服务问题上的独特视角体现在其开发者体验上,它将快速的后端运行时与灵活的前端语言相结合。在实践中,这意味着您可以选择引擎的各个组件进行深度定制,而无需从头重写其他所有内容。

SGLang 同时支持 NVIDIA 和 AMD GPU,并对广泛的模型提供强大的零日支持。SGLang 与 DeepSeek、Qwen、Kimi 和 Z AI 等实验室密切合作,发布针对新架构特性(如 DeepSeek 的多潜在注意力机制)的优化实现。

SGLang 在支持 MoE 大语言模型的大规模部署方面投入了大量资源,特别是在 GB200 NVL72 等系统上的多节点部署,以实现高吞吐量。这些系统为具有大量流量的大型模型提供了极具成本效益的推理能力。

SGLang 的开发者体验围绕 sglang.launch_server 命令构建,服务器配置以标志形式传入。

在八块 GPU 上运行的 SGLang 推理示例。
图 4.5 在八块 GPU 上运行的 SGLang 推理示例。

SGLang 还通过 SGLang Diffusion 支持图像和视频生成模型的推理。

SGLang Diffusion 引入了一种流水线抽象,用于编排多个阶段。这种灵活的方法与图像和视频生成模型的架构高度契合。在性能方面,SGLang Diffusion 增加了对各种扩散模型专用并行方法的支持,并复用了主 SGLang 包中的调度器和优化内核。

在以下情况下,您应该使用 SGLang:

  • 您希望在 DeepSeek 和 Kimi 等大型 MoE 模型上获得出色的开箱即用吞吐量和良好的延迟表现。

  • 您需要针对图像和视频生成模型的推理引擎体验。

  • 您希望拥有控制权和定制能力,并期待参与 SGLang 社区。

4.3.3 TensorRT-LLM

TensorRT-LLM 是 NVIDIA 的开源推理引擎。在三个主要选项中,TensorRT-LLM 为专业用户提供了最高的性能和最大的灵活性。

关于命名的说明:TensorRT-LLM 有两个主要版本。只有旧版本与 TensorRT 实际相关:

  • TensorRT-LLM V0(0.X.Y):主版本号以零开头的版本是 NVIDIA TensorRT 的插件。

  • TensorRT-LLM V1(1.X.Y):主版本号以一开头的版本是基于 PyTorch 的独立软件包,不依赖 TensorRT。

最初,TensorRT-LLM 通过构建 TensorRT 引擎来服务语言模型。而在现代基于 PyTorch 的版本中,TensorRT-LLM 绕过了 TensorRT 的中间表示,直接使用 PyTorch。

TensorRT-LLM V1 于 2025 年夏季发布。前一主要版本的部署仍然很常见——请务必确认您正在使用的是哪个版本。

TensorRT-LLM 之所以能实现最佳性能,很大程度上是因为它可以访问由 NVIDIA 工程师编写的内核,其中包括一些闭源内核。这些手写且经过手动融合的内核对最新硬件架构(如 Hopper 和 Blackwell)以及 NVIDIA 特定数字格式(如 NVFP4)提供了出色的支持。

TensorRT-LLM 提供了稳健的动态批处理(令牌级连续批处理)实现,有助于提升吞吐量。它还支持几乎所有您能想到的模型性能优化设置,包括量化、推测算法、前缀缓存、分块预填充、灵活并行以及解聚合。

在 V1 版本中,TensorRT-LLM 引入了与 vLLM 和 SGLang 非常相似的开发者体验。但除了 trtllm-serve 命令上的标志参数之外,它还需要一个 config.yaml 文件来进行更深层次的自定义。

TensorRT-LLM 在八块 GPU 上的推理示例。
图 4.6 TensorRT-LLM 在八块 GPU 上的推理示例。

安装 TensorRT-LLM 的最佳方式是通过 NVIDIA 官方 Docker 容器运行。

在以下情况下使用 TensorRT-LLM:

  • 您正在 Hopper 或更新的 GPU 上运行受到良好支持的模型架构。

  • 您愿意进行额外的工程工作以获得尽可能最佳的性能。

  • 可选地,您计划使用 NVIDIA Dynamo 进行服务,并希望获得集成最深的引擎。

4.4 NVIDIA Dynamo

NVIDIA Dynamo 是一个用于模型服务的分布式系统,于 2025 年 3 月在 NVIDIA GTC 上首次发布。

Dynamo 兼容所有主流推理引擎——vLLM、SGLang 和 TensorRT-LLM——将其作为后端,同时 Dynamo 本身为大规模部署提供编排层。

Dynamo 支持以下关键模型性能优化技术:

  • KV 缓存复用:在请求之间保留 KV 信息,并根据前缀匹配来路由请求。
  • 分离式推理:将预填充(prefill)和解码(decode)分离到各自独立优化的引擎上,并支持独立扩展。
  • 多节点并行:可选择在单个模型副本中使用两个或更多 GPU 节点,通常结合专家并行(Expert Parallelism)使用。

上述每种技术将在第 5 章中详细介绍。与推理引擎一样,推理工程师需要完成大量配置工作,以针对其具体使用场景调优 Dynamo 并实现最佳性能。

Dynamo 为分布式 KV 路由、分离式推理和多节点模型并行提供了经过精心设计的抽象层,能够在运行时高效聚合信息,支持根据流量变化实时调整配置。例如,你可以通过基于 SLA 的调度器,依据用户自定义的 TTFT 和 TPS 约束,自动对预填充和解码工作节点进行弹性扩缩容。

作为一项通用原则,规模越大,可供使用的推理优化工具和技术就越多。

Dynamo 专为大规模场景而生:大模型、大流量。它尤其擅长为万亿参数级别的 Kimi 系列等基础模型提供服务,支持大量并发用户。对于较小的模型,Dynamo 在大规模部署中仍能带来一定程度的性能提升。

如果你正在为从头构建的基础模型搭建推理 API,或者在高流量产品中部署开源模型,Dynamo 是一个绝佳选择。

但许多部署场景并不需要 Dynamo 所带来的额外复杂性。除非你的业务量足够大,使得分离式推理和 KV 感知路由真正发挥作用,否则引入 Dynamo 只会增加不必要的工作量和额外开销。在这些情况下,可以直接使用推理引擎。

Dynamo 是本章所介绍的最新项目,其功能仍在持续完善中。Dynamo 以 Apache 2.0 许可证开源发布。围绕 Dynamo 的社区十分活跃,项目设有公开的 CI 流程,并得到 NVIDIA 工程师的支持,欢迎社区贡献。

4.5 性能基准测试与负载测试

基准测试是模型性能优化的重要组成部分。如果没有精确、准确的性能基准,就无法判断优化措施是否真正有效。

高质量的基准测试应尽可能贴近真实场景。最佳的基准测试方法是将真实的生产流量镜像到待测系统上。流量镜像是指将传入的请求复制到测试系统的过程,从而在不影响原始请求的情况下对其性能进行基准测试。

如果无法对真实使用情况进行镜像,则需要对其进行模拟。LLM 的性能受多种因素影响。在模拟流量时,需要从多个维度匹配预期的生产负载:

  • 序列长度:首个令牌的生成时间和内存使用量取决于输入序列长度(ISL)和输出序列长度(OSL),即提示词和响应中的令牌数量。
  • 流量的大小和模式:批处理和服务器负载取决于并发请求的数量。应对流量添加抖动以模拟真实使用情况。
  • 请求内容:每个请求中的实际提示词会影响缓存命中率和草稿令牌接受率等性能指标。
  • 输入参数:温度、推理强度等影响推理过程的设置,应配置为预期的生产环境值。

请记住,优化的本质是权衡与约束。如果针对劣质输入来最大化基准性能,那么生产环境中的实际性能将无法达到预期。

4.5.1 性能基准测试工具

由于性能基准测试应当紧密反映生产环境中的实际流量,每个人的基准测试配置都会有所不同。但有一些常用工具:

  • SGLang Genai-bench:由 SGLang 团队开发的命令行界面和仪表板工具,用于对使用任意推理框架部署的模型进行基准测试。

  • NVIDIA GenAI-Perf:NVIDIA 开发的客户端工具,用于在不同流量条件下测量延迟和吞吐量。

  • Locust:一个开源负载测试工具,并非专门针对生成式 AI 系统,可模拟多达数百万名同时在线的用户。

另一个优秀的基准测试工具是开源评估数据集——从 MMLU 和 gsm8k 等通用评估数据集,到 SWE-bench 等特定领域的评估数据集。

尽管基准测试工作的目的是衡量性能而非模型输出质量,但这些评估数据集具有双重用途:既可作为多样化且贴近实际的输入集合,也可用于抽查性能优化是否影响了模型的输出质量。

在条件允许的情况下,应选择与生产系统预期用途相匹配的评估数据集,例如在降低代码补全系统延迟时,可选用 HumanEval。

4.5.2 性能基准测试技巧

优秀的基准测试除了要贴近实际之外,还需要保持一致性。确保您的基准测试发送足够的流量,以便准确评估性能,同时避免受到异常值的影响。如有疑问,请多次运行基准测试并对结果取平均值。

在进行任何性能优化工作之前,首先要建立一个可靠的基准线。在测试优化方案时,保持基准测试配置的一致性,并对每项优化方案分别进行测试,同时也进行综合测试,以充分了解是什么在推动性能提升。在某些情况下,优化方案之间可能会相互制约,例如在大批量处理时尝试运行推测解码。

每次只改变一个变量的原则同样适用于您的基准测试配置。测试各种流量模式或序列形状是常见需求,但与任何实验一样,每次只改变一个变量,以确保获得清晰的测试结果。

4.5.3 性能分析

性能分析比基准测试更深入一层。基准测试给出单一数值(例如,P90 TTFT 为 350 毫秒),而性能分析工具则显示推理过程中每一毫秒花费在哪里。基准测试告诉你系统的表现如何,性能分析则告诉你为什么会有这样的表现。

内核性能分析器显示内核中每个操作的执行耗时,从而揭示性能瓶颈。
图 4.7 内核性能分析器显示内核中每个操作的执行耗时,从而揭示性能瓶颈。

大多数推理工程师不需要将性能分析作为日常工作的一部分。在使用像推理引擎 TensorRT-LLM 这样已经高性能的工具时,你的工作流程是配置和基准测试的循环——性能分析会显得多余。

然而,如果你正在为 vLLM 或 SGLang 等推理框架做贡献、用 PyTorch 编写自己的推理服务,或者处于视频生成等新模态的前沿,性能分析应当成为你工具箱的一部分。

最流行的推理性能分析工具包括:

  • PyTorch Profiler:一个易于使用的性能分析库,用于捕获推理过程中逐步的性能指标(CPU 时间、GPU 时间、内存使用情况)。

  • NVIDIA Nsight Systems(NSys):一个功能丰富但复杂的 GPU 和 CPU 采样与追踪工具,可跨多个 GPU 及其互联提供系统级分析。

  • NVIDIA Nsight Compute(NCU):一个用于深入分析单个 CUDA 内核在计算和内存使用方面的性能分析工具及命令行界面。

此外,TensorFlow 和 TensorRT 等框架也内置了自己的性能分析器。

性能分析工具之所以有价值,是因为它能提供关于计算和内存使用的细粒度信息,从而引导你的优化工作,专注于改善推理流水线中最耗时的步骤。

例如,使用 PyTorch Profiler,你可能会发现激活函数由于过多的内存读取而耗时异常,进而想出如何编写一个融合内核,将激活运算与注意力机制并行执行,以避免多余的内存读取。然后,你可以将新内核插入 PyTorch 代码中,并重新运行系统级基准测试,以查看是否达到了延迟目标。

性能分析与基准测试相结合,为你提供了改善系统性能所需的信息,并最终让你有信心将优化成果部署到生产环境中。