【问题标题】:Sharing GPU memory between process on a same GPU with Pytorch使用 Pytorch 在同一 GPU 上的进程之间共享 GPU 内存
【发布时间】:2020-05-21 00:34:51
【问题描述】:

我正在尝试在 Pytorch 中实现一种有效的并发推理方式。

现在,我在我的 GPU 上启动了 2 个进程(我只有 1 个 GPU,两个进程都在同一个设备上)。每个进程都会加载我的 Pytorch 模型并执行推理步骤。

我的问题是我的模型占用了相当多的内存空间。我在 GPU 上有 12Gb 的内存,而模型仅占用约 3Gb 的内存(没有数据)。这意味着,我的 2 个进程仅用于模型就占用了 6Gb 的内存。


现在我想知道是否可以只加载一次模型,并使用此模型对 2 个不同的进程进行推理。我想要的是模型只消耗 3Gb 的内存,但仍然有 2 个进程。


我遇到this answer 提到 IPC,但据我了解,这意味着进程 #2 将从进程 #1 复制模型,因此我最终仍会为模型分配 6Gb。

我还查看了 Pytorch 文档,关于 DataParallel 和 DistributedDataParallel,但似乎不可能。

This 似乎是我想要的,但我找不到任何关于如何在推理模式下使用 Pytorch 的代码示例。


我知道这可能很难为训练做这样的事情,但请注意,我只是在谈论推理步骤(模型处于只读模式,无需更新梯度)。有了这个假设,我不确定这是否可能。

【问题讨论】:

  • 我不明白为什么您不能只使用相同的(只读)模型进行推理。您可以将不同的数据批次传递到同一个模型中,数据加载和推理可以并行进行。多个用户还可以通过更高级别的界面与模型交谈。导致您使用两个进程的瓶颈在哪里?
  • 感谢您的评论@THN。我目前启动了我的 2 个进程,在每个进程中加载​​模型,然后进行推断。既然进程不能共享内存,你会怎么做?使用线程?
  • 我会使用一个进程来加载一个模型并进行推理。这将适用于大多数目的。你到底想达到什么目标?
  • 你可以通过在数据加载中进行并发(与模型运行过程分开,可以手动完成;@ 987654323@ 具有对最佳并行数据预加载的原生支持,您可以查看它作为示例)和处理(大批量自动)。
  • @THN 我不知道you get most of the benefit of concurrency with a single model on a single process。我认为,如果内存允许,加载 2 个进程会更有效,因此它们可以并行运行。请发表答案!

标签: python gpu pytorch inference


【解决方案1】:

通过在数据加载和模型推理中进行并发,您可以在单个(只读)推理过程中获得单个模型的并发性的大部分好处。

数据加载与模型运行过程是分开的,这可以手动完成。据我所知,tensorflow 对优化并行data preloading 有一些原生支持,您可以查看它作为示例。

模型推理在 GPU 上自动并行。您可以通过使用更大的批处理来最大化这种并发性。

从架构的角度来看,多个用户还可以通过更高级别的界面与模型对话。

【讨论】:

  • 我想知道如何处理以下情况:推理需要 2 秒,2 个用户几乎同时请求推理。请求 #1 被推断 2 秒。然后请求 #2 被推断 2 秒。所以用户 #2 必须等待 4 秒才能收到他的请求。在这种情况下,在 GPU 上有 2 个进程不是更好吗?所以用户的 #2 请求只需要 2 秒,因为我们有一个可用的进程。
  • 你应该看看作业调度问题,它在 OS 中得到了很好的研究,并且有几种算法。实际上,作业不会同时出现,因此您可以在加载另一个作业的同时处理该作业。如有必要,您可以将作业一起批处理,或者如果等待时间可以忽略不计,则仅按顺序处理,或者如果等待时间过长,则将每个作业分开。
  • 我为我的具体案例做了一些基准测试:如果 10 个客户端请求预测,则需要 0.96 秒才能在同一个 GPU 上使用 2 个进程为所有客户端提供服务。相同的实验只有一个进程需要 1.42 秒
  • 您实际测试过很好,但请注意,每个结果都是轶事。如果所有请求同时出现,并且它们只消耗 GPU 的一小部分,并且您单独处理每个请求,那么使用 2 个或更多进程肯定会更快。但有些情况下,一个进程就足够了,比如请求是随机出现的;或者一个过程更好的情况,比如模型很大,请求可以一起批处理的时候。毕竟,您需要查看自己的典型用例,找到瓶颈,并决定在哪里进行优化。
  • 使用多个 CPU 进程读取请求,加载数据,并将它们一起批处理,然后在一个 GPU 进程上运行,与您最初关于共享内存(实际上是模型参数)的问题相同显卡。你仍然需要为此努力。
【解决方案2】:

GPU 本身有很多线程。在执行数组/张量操作时,它会在数组的一个或多个单元上使用每个线程。这就是为什么一个可以充分利用 GPU 的运算似乎应该在没有多个进程的情况下高效扩展的原因——单个 GPU 内核已经被大规模并行化了。

在评论中,您提到在小型基准测试中通过多个进程看到了更好的结果。我建议使用更多作业运行基准测试以确保预热,十个内核似乎太小了一个测试。但是,如果您要找到一个全面的代表性基准来始终更快地运行,我会相信良好的基准而不是我的直觉。

我的理解是在默认 CUDA 流上启动的内核会按顺序执行。如果您希望它们并行运行,我认为您需要多个流。查看 PyTorch 代码,我在内核中看到类似 getCurrentCUDAStream() 的代码,这让我认为 GPU 仍将按顺序运行来自所有进程的任何 PyTorch 代码。

这个 NVIDIA 讨论表明这是正确的:

https://devtalk.nvidia.com/default/topic/1028054/how-to-launch-cuda-kernel-in-different-processes/

较新的 GPU 可能能够并行运行多个内核(使用 MPI?),但这似乎只是通过时间切片实现的,所以我不确定我们是否应该期望更高的总吞吐量:

How do I use Nvidia Multi-process Service (MPS) to run multiple non-MPI CUDA applications?

如果您确实需要在两个并行推理调用之间共享一个模型的内存,您是否可以只使用多个线程而不是进程,并从两个线程中引用同一个模型?

要真正让 GPU 并行运行多个内核,您可以在 PyTorch 中使用 nn.Parallel。请参阅此处的讨论: https://discuss.pytorch.org/t/how-can-l-run-two-blocks-in-parallel/61618/3

【讨论】:

  • 感谢您提供非常详细的回答。我一定要阅读所有这些资源
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-02-16
  • 2018-05-31
  • 2011-03-19
  • 2017-08-28
  • 2012-06-24
  • 1970-01-01
相关资源
最近更新 更多