性能指南¶
如果您有兴趣优化使用 TorchServe 提供的 PyTorch 模型的内存使用量、延迟或吞吐量,本指南适合您。
我们还创建了一个快速清单,其中包含本页未涵盖的其他尝试事项。您可以在此处找到清单。
优化 PyTorch¶
有很多技巧可以优化 PyTorch 模型以用于生产,包括但不限于蒸馏、量化、融合、剪枝、设置环境变量,我们鼓励您进行基准测试并查看哪些方法最适合您。
通常很难优化模型,最简单的做法可能是导出到 ORT、TensorRT、IPEX 或 FasterTransformer 等运行时。我们在TorchServe github 页面上提供了许多关于如何集成这些运行时的示例。如果您的首选运行时不受支持,请随时打开一个 PR。
torch.compile
从 PyTorch 2.0 开始,torch.compile
为大量模型提供了开箱即用的速度提升(~1.8x)。您可以参考此仪表盘,该仪表盘每天都会跟踪此信息。
使用 torch.compile
进行了完全优化的模型显示出高达 10 倍的性能提升
在使用较小的批次大小的情况下,使用 mode="reduce-overhead"
和 torch.compile
可以提高性能,因为它利用了 CUDA 图。
您可以在此处找到所有使用 torch.compile
的 TorchServe 示例
有关 torch.compile
GenAI 示例的详细信息可以在此链接中找到
ONNX 和 ORT 支持
TorchServe 原生支持 ONNX 模型,这些模型可以通过 ORT 加载,以进行加速的 CPU 和 GPU 推理。ONNX 与常规 PyTorch 模型的工作方式略有不同,在运行转换时,您需要明确设置并命名输入和输出维度。请参阅此示例。
总体而言,TorchServe 允许您执行以下操作
打包序列化 ONNX 权重
torch-model-archiver --serialized-file model.onnx ...
使用
ort_session = ort.InferenceSession(self.model_pt_path, providers=providers, sess_options=sess_options)
从base_handler.py
加载这些权重,该代码支持 CPU 和 GPU 推理的合理默认值允许您定义自定义的预处理和后处理函数,以使用自定义处理程序将数据传递到您的 onnx 模型预期的格式
要在 TorchServe Docker 上使用带 GPU 的 ONNX,我们需要使用NVIDIA CUDA 运行时作为基础镜像构建一个镜像,如此处所示
TensorRT
TorchServe 还支持通过 TensorRT 优化的模型。要利用 TensorRT 运行时,您可以按照这些说明转换您的模型,转换完成后,您将获得序列化的权重,可以使用torch.jit.load()
加载这些权重。
转换后,PyTorch 对 Torchscript 模型和 TensorRT 模型的处理方式没有区别。
Better Transformer
来自 PyTorch 的 Better Transformer 实现了 torch.nn.TransformerEncoder
的向后兼容快速路径,用于 Transformer Encoder 推理,并且不需要模型作者修改他们的模型。BetterTransformer 的改进可以在许多常见执行场景中将速度和吞吐量提高 2 倍以上。您可以在此处和此处找到有关 Better Transformer 的更多信息。
优化 TorchServe¶
如果您尝试提高 TorchServe 的性能,应该从 config.properties
中调整的主要设置是 batch_size
和 batch_delay
。更大的批次大小意味着更高的吞吐量,但延迟会更低。
第二重要的设置是工作线程数量和 GPU 数量,它们将对 CPU 和 GPU 性能产生重大影响。
并发性和工作线程数量
TorchServe 公开了配置,允许用户配置 CPU 和 GPU 上的工作线程数量。有一个重要的配置属性可以根据工作负载来加快服务器速度。注意:以下属性在高负载下影响更大。
CPU 上的 TorchServe
如果您在 CPU 上使用 TorchServe,可以通过在 config.properties
中设置以下内容来提高性能
cpu_launcher_enable=true
cpu_launcher_args=--use_logical_core
这些设置通过启动器核心绑定显著提高了性能。此改进背后的理论在这篇博客中进行了讨论,可以简单总结为
在支持超线程的系统中,通过核心绑定将线程亲缘性设置为仅物理核心,以避免逻辑核心。
在具有 NUMA 的多插槽系统中,通过核心绑定将线程亲缘性设置为特定插槽,以避免跨插槽的远程内存访问。
GPU 上的 TorchServe
有一个名为 number_of_gpu
的配置属性,它告诉服务器为每个模型使用特定数量的 GPU。在向服务器注册多个模型的情况下,这将适用于所有注册的模型。如果将其设置为较低的值(例如:0 或 1),则会导致 GPU 利用率不足。相反,如果将其设置为较高的值(>= 系统上可用的最大 GPU),则会导致为每个模型生成尽可能多的工作线程。显然,这会导致 GPU 不必要的争用,并可能导致线程到 GPU 的调度次优。
ValueToSet = (Number of Hardware GPUs) / (Number of Unique Models)
NVIDIA MPS
虽然 NVIDIA GPU 允许多个进程在 CUDA 内核上运行,但这也有其自身的缺点,即
内核的执行通常是串行的
每个进程都会创建自己的 CUDA 上下文,这会占用额外的 GPU 内存
为了克服这些缺点,您可以利用 NVIDIA 多进程服务 (MPS) 来提高性能。 您可以在此处找到有关如何在 TorchServe 中使用 NVIDIA MPS 的更多信息 这里.
NVIDIA DALI
NVIDIA 数据加载库 (DALI) 是一个用于数据加载和预处理的库,用于加速深度学习应用程序。 它可以用作流行的深度学习框架中内置数据加载器和数据迭代器的可移植替代品。 DALI 提供了一套高度优化的构建块,用于加载和处理图像、视频和音频数据。 您可以在此处找到一个 DALI 优化与 TorchServe 集成的示例 这里.
基准测试¶
为了便于比较各种模型和 TorchServe 配置,我们添加了一些辅助脚本,这些脚本以清晰的报告形式输出性能数据(如 p50、p90、p99 延迟) 这里,并且主要需要您通过 JSON 或 YAML 确定一些配置。 您可以在此处找到有关 TorchServe 基准测试的更多信息 这里.
分析¶
TorchServe 原生支持 PyTorch 分析器,它将帮助您找到代码中的性能瓶颈。
如果您创建了一个自定义的 handle
或 initialize
方法来覆盖 BaseHandler,则必须定义 self.manifest
属性才能运行 _infer_with_profiler
。
export ENABLE_TORCH_PROFILER=TRUE
访问此 链接 了解有关 PyTorch 分析器的更多信息。
更多资源¶
动画绘图应用程序上的 TorchServe
为了深入了解在应用程序中微调 TorchServe 性能,请查看此 文章。 这里展示的案例研究使用来自 Meta 的动画绘图应用程序来提高 TorchServe 性能。
性能检查清单
我们还创建了一个快速清单,其中包含本页未涵盖的其他尝试事项。您可以在此处找到清单。