文章目录
前言
想变得更快
简单使用
import
from torch.utils.data.distributed import DistributedSampler
import torch.distributed as dist
argments
在参数中添加local_rank
parser.add_argument("--local_rank",type = int,default=-1)
主函数中配置
local_rank = parser.local_rank
if local_rank != -1:
dist_backend = 'nccl'
dist.init_process_group(backend=dist_backend) # 初始化进程组,同时初始化 distributed 包
device = local_rank if local_rank != -1 else (torch.device('cuda:0') if torch.cuda.is_available() else torch.device('cpu'))
torch.cuda.set_device(local_rank) # 配置每个进程的gpu
模型
model.to(device) # 封装之前要把模型移到对应的gpu
if torch.cuda.device_count() > 1:
print("Let's use", torch.cuda.device_count(), "GPUs!")
model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[local_rank], find_unused_parameters=True)
sampler
# 使用DistributedSampler
train_loader = DataLoader(train_data,
shuffle=True if not train_sampler else False,
sampler = train_sampler,
batch_size=args.batch_size)
train_sampler = DistributedSampler(train_data) # 这里的train_data是一个dataset
# 下面错了,valid不需要分布
valid_sampler = DistributedSampler(valid_data)
valid_loader = DataLoader(valid_data,
shuffle=False,
sampler=valid_sampler,
batch_size=batch_size)
命令行执行
CUDA_VISIBLE_DEVICES=0,1,2,3 python -m torch.distributed.launch --nproc_per_node=4 train_snli.py --checkpoint=False --batch_size=128
torch.distributed.launch 会给模型分配一个args.local_rank的参数,也可以通过torch.distributed.get_rank()获取进程id
常见问题
问题一:显存不释放
我认为是我的代码有问题:
代码逻辑是这样:在0节点上我去判断accuracy有没有下降,没有的话patience_counter就会+1…
然后下面的if是判断程序是否要提前stop…
由于只在0节点上判断,patience_counter也只可能在0节点上+1,导致其它子进程不会随着0节点的进程一起停止,这就会导致子进程依旧占用着显存的问题。
#解决问题一(1):
其实,上面的代码那样写的本意是想让一个节点去保存模型,因为多个节点好像会出错(?)。那我其实可以让所有节点做判断,然后让其中一个节点保存模型:
#解决问题一(2):
我试着在程序的最后加上了(还不知道有没有用):
dist.destroy_process_group()
#解决问题一(3):
话说,如果产生了显存不释放的问题怎么办?这时候可能你用nvidia-smi语句都会卡住,解决方法如下:
首先,执行下面语句,会看到很多卡死的进程
fuser -v /dev/nvidia*
然后试着用kill -9去杀死它们,我因为使用kill -9没有用…所以直接执行下面的语句,杀死了我的所有进程:
killall -u usrname
问题二:DistributedDataParallel’ object has no attribute XXXX
我在我的模型里定义了损失函数:
然后把模型
然后报错:
#解决问题二
model.module.XXXX
问题三:
self.reducer.prepare_for_backward(list(_find_tensors(output)))
RuntimeError: Expected to have finished reduction in the prior
iteration before starting a new one. This error indicates that your
module has parameters that were not used in producing its output (the
return value offorward
). You can enable unused parameter detection
by passing the keyword argumentfind_unused_parameters=True
to
torch.nn.parallel.DistributedDataParallel
. If you already have this
argument set, then the distributed data parallel module wasn’t able to
locate the output tensors in the return value of your module’s
forward
function. Please include the structure of the return value
offorward
of your module when reporting this issue (e.g. list,
dict, iterable). (prepare_for_backward at
/pytorch/torch/csrc/distributed/c10d/reducer.cpp:408)
emmmmm我跟网上的情况不太一样,我明明已经加了:fine_unused_parameters=True了
我猜测自己的错误原因在于,我的model在定义的时候用到了encoder,这里面的encoder是我用来作embeddings的另一个类。
然后可能encoder的参数更新出了某些问题,anyway…
#问题三解决:
翻了翻我以前的代码,看看是怎么用分布式进行训练的,于是就在validate和test过程中, 送入模型之间加入了:with torch.no_grad():
然后莫名就不报错了。。。
但真正的错误原因,一直没有找到。
一些原理
原理一:batch_size
如果我用三块显卡:
CUDA_VISIBLE_DEVICES=0,1,2 python -m torch.distributed.launch --nproc_per_node=3
如果我的batchsize设置为3:
parser.add_argument('--train_bs', help='Batch size', type=int, default=3)
那么每一次dataloader会给3块显卡都sample3个样本,等价于你设置的batch_size=9.
参考
解决GPU显存未释放问题
解决进程杀死,显存仍在的问题
PyTorch 报错:ModuleAttributeError: ‘DataParallel‘ object has no attribute ‘ xxx (已解决)