背景
我有一个非常小的网络,我想用不同的随机种子进行测试。 该网络仅使用我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上)
对于我的情况,系统已经设置为系统管理大小,但我有相同的错误,这是因为我在一个函数中向多个进程传递了一个较大的变量。我可能需要设置一个非常大的分页文件,因为Windows无法动态创建它,而是选择退出以减少进程数,因为它不是一个经常使用的函数
如果您在Windows中,则最好使用少于pysical核总数的1个(或更多)核,因为Windows中python中的多处理模块在使用all并实际尝试获取所有逻辑核的情况下,会尽可能获取所有核
请参阅此处了解更多详细信息: 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情况下,命令行可能如下所示:
(您还希望在您的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进程之间共享更多内存。实际上,它是有效的。没有我希望的那么好(它提交的内容仍然比它使用的内容多得多),因此我的理解可能有缺陷,但它大大减少了内存提交
在我有限的测试中,我没有遇到任何问题,但我不能保证没有代码路径试图写入我们标记为“只读”的部分。但是,如果您开始遇到问题,您可以恢复备份
我设法解决了这个问题。 打开“高级系统设置”。转到“高级”选项卡,然后单击与性能相关的设置。 再次单击高级选项卡>;改变>;取消选择“自动……”。对于所有驱动器,设置“系统管理大小”。重新启动你的电脑
相关问题 更多 >
编程相关推荐