昇腾卡上训练模型遇到报错rtEnableP2P failed的解决方法
因此,模型初始化各网络层时的npu()数据 和 模型加载的ckpt都在0卡上,但训练时产生的数据都在各个卡上,一起计算时就会出现0卡和其它卡之间的通信拷贝。每张卡pcie有16个atu资源,每张卡通信时都占用2个atu(一个发送,一个接受),意味着同时最多只能和8个device p2p enable.组网时HCCL又限制了只能在当前环所有卡,和另外一个环里的一张卡,比如0和8,1和9。4)排查模型
问题描述
在昇腾A+X 16卡上用Pytorch Lighting训练多模态语音模型Make-An-Audio-2时遇到报错:rtEnableP2P failed。
问题定位和解决过程
阶段1
1)通过log定位到报错的位置是在to方法内部,传入一个model,实际上挨个将每个tensor转移到目标device上。
2)按照调用堆栈向上排查,发现正在将模型权重move_to_device,通过打印发现部分权重在cpu,部分在npu:0上。
3)权重原本是在cuda上,通过transfer_to_npu加载了到了npu:0上。
4)理论上应该加载到各自的device,但此时先想到应该和其它一样加载到cpu上,因此先把这部分权重放到了cpu。
5)问题解决,但在下一步又出现了同样报错。
阶段2
1)继续按照调用堆栈向上排查,发现是在forward方法中,计算用的算子权重在npu:0上。
2)只有set_device()后才会迁移到各自的卡上,此时以为模型代码和pytorch_lighting没有set_device。
3)打开代码发现pytorch_lighting中有set_device,但在初始化模型后面。
4)排查模型代码,发现模型初始化有很多.cuda操作,通过transfer_to_npu加载了到了npu:0上。
5)删除这些.cuda操作,在forward时再to npu即可。
问题根因分析
底层原理
每张卡pcie有16个atu资源,每张卡通信时都占用2个atu(一个发送,一个接受),意味着同时最多只能和8个device p2p enable.组网时HCCL又限制了只能在当前环所有卡,和另外一个环里的一张卡,比如0和8,1和9。也可以0和15,但需要设置。
直接原因
A+X 16卡实际分为前8卡和后8卡两个环,NPU不支持前8卡和后7卡通信。而模型中存在0卡tensor往后7卡的p2p拷贝动作,因此报错。之所以存在0卡tensor往后7卡拷贝有两个原因:
原因一:
- 模型加载的部分CKPT默认在NPU上
- 模型部分结构在初始化时,加了.cuda()操作,transfer_to_npu()会给他转成.npu()。
原因二:
模型使用pytorch_lighting框架中的训练方法,导致逻辑顺序是这样的:
- 模型初始化各网络层
- 模型加载ckpt,并move到device上
- 在pytorch_lighting框架中初始化分布式训练,为16张卡分别绑定独立进程
- 给每个进程set_device,绑定device
- 开始训练
重点:只有在set_device后,.npu() 或.cuda()等操作才会是拷贝到各个卡上,而在set_device前,只会拷贝到0卡。因此,模型初始化各网络层时的npu()数据 和 模型加载的ckpt都在0卡上,但训练时产生的数据都在各个卡上,一起计算时就会出现0卡和其它卡之间的通信拷贝。
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐

所有评论(0)