Process finished with exit code 137 (interrupted by signal 9: SIGKILL)
今天遇到这个错误,按照网上说的,修改了batchsize之类的,没有用。经过2小时的排查,发现问题出在num_workers这个参数的设置上!
解决方法:减小num_workers!
PS:出现这个报错,基本可以肯定是内存爆了,ubuntu环境的话你可以用top命令看看训练时内存是不是一直在增加。所以解决问题的思路就是排查哪些地方会增加内存占用。
PPS:关于num_workers为啥会增加内存占用,来看GPT的回答:
在使用 PyTorch 的 DataLoader
时,num_workers
参数决定了用于数据加载的子进程(或线程)的数量。虽然增加 num_workers
可以提升数据加载的并行度,从而加快训练过程,但过多的 num_workers
也可能导致内存溢出(OOM,Out of Memory)。以下是详细原因解析:
1. 每个工作进程的内存开销
独立的内存空间:
- 每个
num_workers
对应一个独立的子进程(在 Unix 系统上,通常使用fork
方法创建进程)。 - 每个子进程会复制主进程的一部分内存空间,尤其是当数据集较大时,这种复制会显著增加整体内存使用。
内存复制机制:
- 操作系统通常使用写时复制(Copy-On-Write, COW)机制来优化子进程的内存使用。然而,当子进程开始修改数据时,COW 会导致实际的内存复制,从而增加内存占用。
- 如果数据加载过程中需要频繁修改数据,COW 机制的效率会下降,导致内存使用量快速增加。
2. 数据加载与缓存
数据缓存:
- 多个子进程可能会在内存中缓存数据,以加快数据的访问速度。这在数据集较大时,会显著增加内存需求。
- 特别是当使用自定义的
collate_fn
或数据预处理函数时,如果这些函数在子进程中生成大量中间变量,内存消耗会进一步增加。
共享内存限制:
- 虽然 PyTorch 使用共享内存(shared memory)来在主进程和子进程之间高效传递数据,但共享内存的容量是有限的。
- 当
num_workers
增加时,更多的子进程同时访问和写入共享内存,可能导致共享内存耗尽,从而引发 OOM 错误。
3. 操作系统资源限制
进程数量限制:
- 操作系统对每个用户或进程的最大子进程数量有一定的限制。过多的子进程不仅增加内存消耗,还可能导致系统资源耗尽,进而影响数据加载的稳定性。
上下文切换开销:
- 大量的子进程会增加上下文切换的频率,导致系统性能下降。这种性能下降有时会间接影响内存管理,增加内存泄漏或碎片化的风险。
4. 数据加载的具体实现
数据预取与异步加载:
- 如果数据加载过程涉及复杂的预取或异步操作,增加
num_workers
可能导致更多的数据被预加载到内存中,超出预期的内存预算。
数据增强与预处理:
- 复杂的数据增强和预处理操作会增加每个子进程的内存需求。多个子进程同时进行这些操作,会导致整体内存消耗快速增加。
如何解决内存溢出问题
-
合理设置
num_workers
:- 根据系统的内存容量和 CPU 核心数,合理设置
num_workers
。通常,num_workers
的值设置为 CPU 核心数的几分之一较为合适。
- 根据系统的内存容量和 CPU 核心数,合理设置
-
优化数据加载与预处理:
- 简化数据增强和预处理操作,减少每个子进程的内存需求。
- 使用高效的
collate_fn
,避免不必要的内存复制和中间变量的生成。
-
减少批次大小 (
batch_size
):- 减少每个批次的数据量,可以有效降低内存占用,但需要在性能和内存之间找到平衡。
-
使用共享内存机制:
- 在
DataLoader
中设置persistent_workers=True
,可以减少子进程的频繁创建和销毁,从而降低内存开销。
- 在
-
监控与调试:
- 使用工具(如
memory_profiler
、htop
、nvidia-smi
)实时监控内存使用情况,识别内存泄漏或异常高的内存消耗点。 - 分阶段调试数据加载过程,确定具体导致内存增加的代码段。
- 使用工具(如
-
分布式数据加载:
- 如果单机内存不足,可以考虑使用分布式数据加载,将数据加载任务分散到多台机器上,均衡内存使用。
-
内存清理与优化:
- 确保数据加载过程中没有不必要的内存持有,及时释放不再使用的变量。
- 使用内存优化工具或技术,如内存映射(memory mapping),以减少内存占用。