快捷方式

⚠️ 注意:有限维护

本项目已不再积极维护。虽然现有版本仍然可用,但没有计划的更新、错误修复、新功能或安全补丁。用户应注意,漏洞可能不会得到解决。

使用 NVIDIA MPS 运行 TorchServe

为了部署机器学习模型,TorchServe 会在独立的进程中启动每个 worker,从而将每个 worker 彼此隔离。每个进程创建自己的 CUDA 上下文来执行其 kernel 并访问分配的内存。

虽然 NVIDIA GPU 在默认设置下允许在单个设备上运行多个进程的 CUDA kernel,但这存在以下缺点:

  • kernel 的执行通常是串行化的

  • 每个进程都创建自己的 CUDA 上下文,这会占用额外的 GPU 内存

针对这些场景,NVIDIA 提供了多进程服务(MPS),它可以:

  • 允许多个进程在同一个 GPU 上共享同一个 CUDA 上下文

  • 并行运行它们的 kernel

这可以带来以下结果:

  • 在同一个 GPU 上使用多个 worker 时提高性能

  • 由于共享上下文而降低 GPU 内存利用率

为了利用 NVIDIA MPS 的优势,我们需要在启动 TorchServe 本身之前使用以下命令启动 MPS 守护进程。

sudo nvidia-smi -c 3
nvidia-cuda-mps-control -d

第一个命令为 GPU 启用独占处理模式,仅允许一个进程(MPS 守护进程)使用它。第二个命令启动 MPS 守护进程本身。要关闭守护进程,我们可以执行

echo quit | nvidia-cuda-mps-control

有关 MPS 的更多详细信息,请参阅 NVIDIA 的 MPS 文档。需要注意的是,由于硬件资源有限,MPS 只允许 48 个进程(对于 Volta GPU)连接到守护进程。向同一个 GPU 添加更多客户端/worker 将导致失败。

基准测试

为了展示 TorchServe 在启用 MPS 后的性能,并帮助决定是否为您的部署启用 MPS,我们将使用代表性工作负载进行一些基准测试。

首先,我们希望研究在启用 MPS 的情况下,worker 的吞吐量如何随不同的操作点变化。作为我们基准测试的示例工作负载,我们选择了 HuggingFace Transformers 序列分类示例。我们在 AWS 的 g4dn.4xlarge 实例和 p3.2xlarge 实例上执行基准测试。这两种实例类型每个实例提供一个 GPU,这将导致多个 worker 调度在同一个 GPU 上。对于基准测试,我们重点关注由 benchmark-ab.py 工具测量的模型吞吐量。

首先,我们测量单个 worker 在不同批量大小下的吞吐量,这将显示 GPU 计算资源在何时被完全占用。其次,对于我们预计 GPU 仍有一些剩余资源可共享的批量大小,我们测量部署两个 worker 时的吞吐量。对于每个基准测试,我们执行五次运行并取运行结果的中位数。

我们对基准测试使用以下 config.json 文件,只相应地覆盖 worker 数量和批量大小。

{
    "url":"/home/ubuntu/serve/examples/Huggingface_Transformers/model_store/BERTSeqClassification",
    "requests": 10000,
    "concurrency": 600,
    "input": "/home/ubuntu/serve/examples/Huggingface_Transformers/Seq_classification_artifacts/sample_text_captum_input.txt",
    "workers": "1"
}

请注意,我们将并发级别设置为 600,这将确保 TorchServe 内部的批量聚合将批量填充到最大批量大小。但与此同时,这将扭曲延迟测量结果,因为许多请求将在队列中等待处理。因此,在下文中我们将忽略延迟测量。

G4 实例

我们首先对 G4 实例执行单 worker 基准测试。在下图中,我们看到,批量大小达到四时,吞吐量随批量大小稳步增加。

G4 benchmark, single worker

接下来,我们将 worker 数量增加到两个,以比较启用 MPS 和未启用 MPS 时的吞吐量。为了为第二组运行启用 MPS,我们首先为 GPU 设置独占处理模式,然后按照上面所示启动 MPS 守护进程。

我们根据之前的发现选择批量大小在一到八之间。在图中我们可以看到,对于批量大小为 1 和 8 的情况,吞吐量性能可能更好(最高提高 18%),而对于其他批量大小可能更差(降低 11%)。对此结果的一种解释可能是,当我们在一个 worker 中运行 BERT 模型时,G4 实例没有太多资源可共享。

G4 benchmark, two workers

P3 实例

接下来,我们将使用更大的 p3.2xlarge 实例运行相同的实验。使用单个 worker,我们获得以下吞吐量值

P3 benchmark, single worker

我们可以看到吞吐量稳步增加,但当批量大小超过八时,回报递减。最后,我们在 P3 实例上部署两个 worker,并比较启用和未启用 MPS 时它们的运行情况。我们可以看到,对于批量大小在 1 到 32 之间的情况,启用 MPS 时的吞吐量始终更高(最高提高 25%),批量大小为 16 时除外。

P3 benchmark, two workers

总结

在上一节中,我们看到通过为运行相同模型的两个 worker 启用 MPS,我们得到了混合结果。对于较小的 G4 实例,我们只在某些操作点看到了好处,而对于较大的 P3 实例,我们看到了更一致的改进。这表明使用 MPS 运行部署的吞吐量优势高度依赖于工作负载和环境,需要针对特定情况使用适当的基准测试和工具来确定。需要注意的是,之前的基准测试仅侧重于吞吐量,忽略了延迟和内存占用。由于使用 MPS 只会创建一个 CUDA 上下文,因此可以将更多 worker 打包到同一个 GPU 上,这在相应场景中也需要考虑。

文档

查阅 PyTorch 的全面开发者文档

查看文档

教程

获取针对初学者和高级开发者的深度教程

查看教程

资源

查找开发资源并解答您的疑问

查看资源