PyTorch DDP分布式训练触发SIGSEGV段错误的排查求助
PyTorch DDP训练SIGSEGV段错误排查与修复方案
直接匹配已观测触发规律的修复
你已经复现的「rank0先于rank1结束就触发SIGSEGV」是DDP收尾阶段的最高发问题,本质是NCCL通信后端对进程销毁顺序有严格要求:只要任意一个进程提前断开通信链路,其他进程访问已经被释放的通信句柄、共享内存段时,就会直接触发内核级段错误,完全绕过Python层的异常捕获。
- 你目前加的
time.sleep(1)是临时延时规避,不是根治。正确的收尾流程需要严格按顺序执行:# 训练全流程结束后的固定收尾逻辑 # 1. 第一处全局同步:等所有进程把自己负责的训练步跑完,没有未完成的集合通信操作 torch.distributed.barrier() # 2. 所有rank0独占操作(检查点保存、TensorBoard日志写入、终端打印)全部在这个阶段完成 if rank == 0: # 放置rank0专属的收尾逻辑 pass # 3. 第二处全局同步:等所有rank完成各自的收尾操作,确保没有进程提前退出 torch.distributed.barrier() # 4. 所有进程同步销毁分布式进程组 torch.distributed.destroy_process_group() # *禁止在上述同步完成前让train函数提前return,尤其是rank0绝对不能先退出*
其他高频触发场景的排查优先级
按出现概率从高到低逐一排查:
- 共享内存溢出:即使使用文件描述符模式的共享策略,/dev/shm剩余空间不足时,多进程加载数据集、CPU张量共享会被内核回收内存段,直接触发段错误。执行
df -h /dev/shm检查使用率,超过90%时可临时扩容(mount -o remount,size=16G /dev/shm)、将DataLoader的num_workers临时设为0排除异常、关闭persistent_workers避免worker残留的共享内存占用。 - NCCL拓扑探测兼容性:TITAN X(Pascal)架构搭配CUDA 11.0时,默认NCCL的IB探测、跨GPU拓扑检查逻辑经常触发非法内存访问。在训练启动前设置环境变量规避:
通过打印的NCCL日志确认是否卡在拓扑探测环节,禁用不支持的IB传输即可解决。export NCCL_DEBUG=INFO export NCCL_IB_DISABLE=1 export NCCL_SOCKET_IFNAME=lo - 跨进程传递对象的生命周期问题:
mp.spawn启动的子进程拥有独立地址空间,禁止将主进程提前初始化的CUDA张量、可变模型对象、已加载的数据集作为spawn参数传入。spawn的入参仅保留不可变的配置类对象,所有模型初始化、数据集加载逻辑全部放到每个子进程的train函数内部完成,避免主进程提前释放显存/内存后,子进程访问非法地址。 - 残留进程的显存冲突:当前nvidia-smi显示GPU2上已有一个占用11.9G显存的python残留进程(PID 31809),部分PyTorch版本初始化CUDA上下文时会遍历所有GPU设备,和残留进程触发通信句柄冲突。先强制杀掉该残留进程再启动训练。
- 单文件数据集的序列化开销:如果将主进程加载完成的单个JSON大文件数据集作为参数传给spawn子进程,序列化传输时超过内核多进程内存传输阈值会直接触发段错误。将数据集加载逻辑移到train函数内部,每个子进程自行加载对应rank的数据集切片即可规避。
无堆栈问题的快速定位方法
- 开启core dump捕获:执行
ulimit -c unlimited后启动训练,触发段错误后用gdb python core.xxx读取核心转储,输入bt即可直接看到native层的崩溃堆栈,快速定位是卡在NCCL通信、共享内存访问还是显存释放环节。 - 逐段插入同步栅栏:从训练代码的开头、每个epoch结束位置、每个batch计算结束位置依次插入
torch.distributed.barrier(),哪两个相邻栅栏之间不再触发崩溃,问题代码就位于该区间内。
内容的提问来源于stack exchange,提问作者Charlie Parker
相关产品推荐
相关产品推荐

