pytorch的多GPU训练
单机多卡
DP(被淘汰)
torch.nn.DataParallel
- 简单一行代码 ,封装model即可。
model = DataParallel(model.cuda(),device_ids=[0,1,23] )
; - 模型保存与加载;由于被封装以后,model已经是一个DataParallel,所以 torch.save 调用
model.module.state_dict()
,torch.load
注意map_location
; - 缺点-(单进程,效率低);
- 缺点- (不支持多机器);
- 缺点-(不支持模型并行);
batch_size
改成每个GPUbatch_size
总和;
DDP (推荐)
**torch.nn.parallel.DistributedDataParallel **
多进程
初始化进程组
torch.distributed.init_process_group("nccl",world_size=n_gpus,rank=args.local_rank)
指定当前进程使用哪一张 GPU 卡
torch.cuda.set_device(args.local_rank)
相当于 CUDA_VISIBLE_DEVICES 环境变量模型封装
(模型先转移到某一张 GPU卡上,然后再被ddp封装,注意是device_ids
指定一张卡就好了,一个进程一张卡。)model = DistributedDataParallel(model.cuda(args.local_rank),device_ids=[args.local_rank])
将数据分布式分配到GPU上,给出一个训练顺序
train_sampler = DistributedSampler(train_dataset)
最好读一读 源码torch/util/data/distributed.py
每个周期开始前,调用
train_sampler.set_epoch(epoch)
打乱数据有了
sampler
就不需要在DataLoader
设置shuffle=True
将
train_sampler
传入train_dataloader
中train_dataloader = DataLoader(...,sampler=train_sampler)
数据拷贝到GPU卡
data = data.cuda(args.local_rank)
执行命令
(定一个节点上用几张卡)
python -m torch.distributed.launch --nproc_per_node=n_gpus train.py
torch.distributed.launch
会定多少个进程,根据前面传入的 节点内卡的数量,launch这个进程会向 每一个 train.py 传入 local_rank。模型保存和加载
torch.save
在local_rank=0
的位置进行保存,同样注意调用model.module.state_dict()
torch.load
注意map_location
每一个进程所需要的
batch_size
应该是每一个 GPU所需要的batch_size
大小
DDP例子
1 | import os |
在终端输入
1 | python -m torch.distributed.launch \ |
找到 PyTorch 安装目录中的 distributed/launch.py
执行这个启动器脚本
启动器会创建多个进程来运行 train.py-m
表示将一个模块作为脚本运行,python a.py arg1 b.py arg2 c.py arg3 经常这样用。命令行参数解释:
--nproc_per_node=4
: 使用4个GPU--master_port=29500
: 指定主进程端口--n_gpus=4
: 总GPU数量--batch_size=32
: 每个GPU的batch size--epochs=10
: 训练轮数
一个我经常用的例子
这个是做 环境部署和GPU性能检测的。
ddp5_env_check.py
他会检测 驱动 torch conda等情况,并用此脚本文件夹中图片做多GPU测试。
1 | import os |
start_ddp.sh
平时运行它、修改它就好了。
1 |
|
以上 例子 需要说明的是 ddp 方式 来做 多进程的 GPU 操作,是不存在主进程的,实际是 用 rank0 所在的进程兼职了主进程,它一边运行着自己的GPU训练一边兼职了主进程的活。所以 我们上面写的 统计 总共用时的写法 是不准确的,事实上也只会 体现出 rank0的 运行时间,但是 我没有想看那么精确 也就没有改了。