1. 问题和尝试的解决办法

在用4卡A100跑分布式训练任务的时候,遇到了进程卡住的情况,前几个epoch是正常运行的,但是到了第4个epoch跑完时,发现进程卡住了,过了30min后进程超时报错,报错信息如下:

[E ProcessGroupNCCL.cpp:474] [Rank 0] Watchdog caught collective operation timeout: WorkNCCL(SeqNum=58856, OpType=ALLREDUCE, NumelIn=1, NumelOut=1, Timeout(ms)=1800000) ran for 1800389 milliseconds before timing out.
qs-28252-690734-vjob-0:4115:4473 [0] NCCL INFO [Service thread] Connection closed by localRank 0

之后我尝试了很多方法依然存在卡住的问题,这个卡住和报错不一样,需要自己一点点去debug。后来,我仅仅使用单卡来跑模型训练,发现就不会卡住。

所以基本上可以锁定是GPU之间通信的问题,可能是因为GPU之间的进程不同步导致的死锁。然后我在github上面找到有人说,把GPU的P2P通信的环境变量设置成0解决了:

export NCCL_P2P_DISABLE=1

我尝试了之后发现不仅没解决,训练的速度还变慢了。所以只能继续debug,然后发现把整个模型evaluate部分的代码注释掉后,模型训练就不会卡住。

那么现在基本上把问题锁定在evaluate部分,一开始我以为是在做evaluate的all_gather_object把不同gpu上的指标集合在一个gpu上的时候gpu间进程不同步,后来发现注释掉并没有解决问题,说明问题不在这。

2. 最终解决方案

在evaluate之后,代码执行了early_stopping的操作,此时指标下降了,rank0上的update_flag 变成了False,没有执行saving checkpoint的操作。但是rank1、2、3却没有同步rank0的update_flag。执行了saving checkpoint的操作,rank0和rank1、2、3进入的进程不同,导致了死锁,因此,我们只需要同步各个gpu之间的update_flag即可:

update_flag_tensor = torch.tensor(int(update_flag), device=self.device if hasattr(self, "device") else "cuda")

# 广播 rank 0 的判断结果

torch.distributed.broadcast(update_flag_tensor, src=0)

update_flag = bool(update_flag_tensor.item())

运行卡住的问题就解决了!

所以发生卡住的时候,一定要观察是不是在什么地方不同的rank进入了不同的进程

Logo

更多推荐