如何高效地同时运行多个Pytorch流程/模型?回溯:分页文件太小,无法完成此操作

2024-04-26 11:11:32 发布

您现在位置:Python中文网/ 问答频道 /正文

背景

我有一个非常小的网络,我想用不同的随机种子进行测试。 该网络仅使用我GPU计算能力的1%,因此理论上我可以一次运行50个进程,一次尝试许多不同的种子

问题

不幸的是,我甚至不能在多个进程中导入pytorch。当进程的nr超过4时,我会得到一个关于太小分页文件的回溯

最小可复制代码§-dispatcher.py

from subprocess import Popen
import sys

procs = []
for seed in range(50):
    procs.append(Popen([sys.executable, "ml_model.py", str(seed)]))

for proc in procs:
    proc.wait()

§我增加了种子的数量,因此拥有更好机器的人也可以繁殖种子

最小可复制代码-ml_model.py

import torch
import time
time.sleep(10)
 
 Traceback (most recent call last):
  File "ml_model.py", line 1, in <module>
    import torch
  File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\torch\__init__.py", line 117, in <module>
    import torch
  File "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\torch\__init__.py", line 117, in <module>
    raise err
 OSError: [WinError 1455] The paging file is too small for this operation to complete. Error loading "C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\torch\lib\cudnn_cnn_infer64_8.dll" or one of its dependencies.
    raise err

进一步调查

我注意到每个进程都将大量dll加载到RAM中。当我关闭所有其他使用大量RAM的程序时,我最多可以得到10个进程,而不是4个。因此,这似乎是一种资源约束

问题

有解决办法吗

在一个gpu上使用pytorch训练许多小型网络的推荐方法是什么

我应该编写自己的CUDA内核,还是使用不同的框架来实现这一点

我的目标是一次运行大约50个进程(在16GB RAM机器上,8GB GPU RAM上)


Tags: inpyimport网络formodel进程lib
3条回答

对于我的情况,系统已经设置为系统管理大小,但我有相同的错误,这是因为我在一个函数中向多个进程传递了一个较大的变量。我可能需要设置一个非常大的分页文件,因为Windows无法动态创建它,而是选择退出以减少进程数,因为它不是一个经常使用的函数

如果您在Windows中,则最好使用少于pysical核总数的1个(或更多)核,因为Windows中python中的多处理模块在使用all并实际尝试获取所有逻辑核的情况下,会尽可能获取所有核

import multiprocessing
multiprocessing.cpu_count()
12  
# I actually have 6 pysical cores, if you use this as base it will likely hog system


import psutil 
psutil.cpu_count(logical = False)
6 #actual number of pysical cores

psutil.cpu_count(logical = True)
12 #logical cores (e.g. hyperthreading)

请参阅此处了解更多详细信息: Multiprocessing: use only the physical cores?

今晚我已经仔细研究过了。我没有解决方案(编辑:我有缓解措施,请参阅最后的编辑),但我有更多的信息

问题似乎是由NVidia fatbins(.nv_fatb)加载到内存中引起的。一些dll,如cusolver64_xx.dll、torcha_cuda_cu.dll和其他一些dll中都有.nv_fatb节。这些包含了大量不同GPU的CUDA代码变体,因此它最终会达到几百兆到几千兆字节

当Python导入“torch”时,它加载这些DLL,并将.nv_fatb部分映射到内存中。出于某种原因,它不仅仅是一个内存映射文件,实际上是在占用内存。该部分被设置为“写入时复制”,因此有可能写入了某些内容?我不知道。但是无论如何,如果您使用VMMap(https://docs.microsoft.com/en-us/sysinternals/downloads/vmmap)查看Python,您可以看到这些DLL正在为这个.nv_fatb部分提交大量已提交的内存。令人沮丧的是,它似乎没有使用内存。例如,现在我的Python.exe已提交2.7GB,但工作集只有148MB

加载这些DLL的每个Python进程都会提交几GB的内存来加载这些DLL。因此,如果一个Python进程正在浪费2GB内存,而您尝试运行8个worker,那么您需要16GB的内存来备用,以便加载DLL。看起来这段记忆并没有被使用,只是被提交了

我对这些FATBinary了解不够,无法尝试修复它,但从过去两个小时的观察来看,它们确实是问题所在。也许这是NVidia的问题,它们正在提交内存

编辑:我制作了这个python脚本:https://gist.github.com/cobryan05/7d1fe28dd370e110a372c4d268dcb2e5

获取它并安装它的pefile依赖项(python-mpipinstallpefile)

在你的手电筒和cuda DLL上运行它。在OPs情况下,命令行可能如下所示:

python fixNvPe.py  input=C:\Users\user\AppData\Local\Programs\Python\Python38\lib\site-packages\torch\lib\*.dll

(您还希望在您的cusolver64_*.dll和朋友所在的任何位置运行此脚本。此可能在您的torch\lib文件夹中,也可能是,例如,C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vXX.X\bin。如果它在Program Files下,您需要以管理权限运行脚本)

此脚本要做的是扫描输入glob指定的所有DLL,如果找到.nv_fatb节,它将备份DLL,禁用ASLR,并将.nv_fatb节标记为只读

ASLR是“地址空间布局随机化”。它是一种安全功能,用于随机化DLL在内存中的加载位置。我们为此DLL禁用它,以便所有Python进程将DLL加载到相同的基本虚拟地址。如果所有使用DLL的Python进程都在相同的基址加载它,那么它们都可以共享DLL。否则,每个进程都需要自己的副本

将部分标记为“只读”可以让Windows知道内容在内存中不会更改。如果您将文件映射到内存读/写,Windows必须提交足够的内存,以备您对其进行修改。如果节是只读的,则无需在页面文件中对其进行备份。我们知道它没有修改,所以它总是可以在DLL中找到

该脚本背后的理论是,通过更改这两个标志,将为.nv_fatb提交更少的内存,并在Python进程之间共享更多内存。实际上,它是有效的。没有我希望的那么好(它提交的内容仍然比它使用的内容多得多),因此我的理解可能有缺陷,但它大大减少了内存提交

在我有限的测试中,我没有遇到任何问题,但我不能保证没有代码路径试图写入我们标记为“只读”的部分。但是,如果您开始遇到问题,您可以恢复备份

我设法解决了这个问题。 打开“高级系统设置”。转到“高级”选项卡,然后单击与性能相关的设置。 再次单击高级选项卡>;改变>;取消选择“自动……”。对于所有驱动器,设置“系统管理大小”。重新启动你的电脑

相关问题 更多 >