PyTorch默认使用从0开始的GPU,且默认只使用0号GPU。如果要使用其他编号的GPU或者使用多块GPU,则要设置。
pytorch并行后,假设batchsize设置为64,表示每张并行使用的GPU都使用batchsize=64来计算(单张卡使用时,使用batchsize=64比较合适时,多张卡并行时,batchsize仍为64比较合适,而不是64*并行卡数)。
DataParallel 会自动拆分数据,并将作业订单发送到多个GPU上的多个模型。 在每个模型完成它们的工作之后,DataParallel 在将结果返回给你之前收集和合并结果。
参考:https://blog.csdn.net/xys430381_1/article/details/106635977
https://blog.csdn.net/zqx951102/article/details/127946871
一、使用环境变量CUDA_VISIBLE_DEVICES的方式
第一步:指定gpu
直接终端中设定:
CUDA_VISIBLE_DEVICES=1
python代码中设定:
1、使用单卡
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "2"
2、使用多块卡的方法。
import os
os.environ["CUDA_VISIBLE_DEVICES"] = '0,1'
第二步:创建设备(device)
作用:将备选GPU进一步选择和指定,真正投入使用中。
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 注意如果 device = torch.device("cuda"),则环境变量CUDA_VISIBLE_DEVICES中指定的全部GPU都会被拿来使用。
# 也可以通过 "cuda:0" 、"cuda:1"等指定环境变量CUDA_VISIBLE_DEVICES中指定的多块GPU中的某一块。
注意对应关系。例如:
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "2, 3, 4, 5" # 将2, 3, 4, 5号GPU作为备选GPU
# 这样cuda:0表示使用 2 号GPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
第三步,将data和model放置到device上
input = data.to(device)
model = MyModule(...).to(device)
注意:如果有多个GPU,则model还需要多做一个操作(模型并行化)
第三步骤的多GPU版本如下:
input = data.to(device)
model = MyModule(...)
#模型并行化
if torch.cuda.device_count() > 1:
print("Let's use", torch.cuda.device_count(), "GPUs!")
model = nn.DataParallel(model)
model = model.to(device)
方法二 函数 set_device + 函数.cuda()
不过官方建议使用CUDA_VISIBLE_DEVICES,不建议使用 set_device 函数。
第一步,函数set_device设置device
import torch
gpu_id = [0, 1, 2]
torch.cuda.set_device(gpu_id)
#运行这里会报错,set_device只能传int,也就是只能用一个gpu训练?
第二部,函数.cuda()使用GPU
data.cuda()
model.cuda()
第二种方法补充:
torch.cuda.set_device(gpu_id)只能指定单个gpu
如果只需要指定一张卡,可以使用torch.cuda.set_device(1)指定gpu使用编号
(不建议用这个方法)
torch.cuda.set_device(1)
print(torch.cuda.device_count()) #可用GPU数量
(我的机器是4卡,所以print结果是:4,说明用torch.cuda.set_device(1)指定,不会改变可见的显卡)
后面还可以用torch.nn.DataParallel(model, device_ids=[1, 2])进行指定,但是必须包含set_device(1)指定的device:1的设备,缺点是仍然会存在占用一些device:0的gpu内存;
小试牛刀:
https://github.com/rwightman/pytorch-image-models
训练代码是第二种方式,只能用1个gpu训练。
修改方法一,直接加上一句nn.DataParallel:
原始代码:
model.cuda()
修改为:
if torch.cuda.device_count() > 1:
print("Let's use", torch.cuda.device_count(), "GPUs!")
model = nn.DataParallel(model, device_ids=[0, 1]) ##指定gpu
model.cuda()
修改前后用nvidia-smi查看gpu使用情况。
修改方法二,较复杂:
os.environ["CUDA_VISIBLE_DEVICES"] = '0,1'
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
...
# torch.cuda.set_device(args.local_rank)
if torch.cuda.device_count() > 1:
print("Let's use", torch.cuda.device_count(), "GPUs!")
model = nn.DataParallel(model)
# model.cuda()
model.to(device)
# train_loss_fn = train_loss_fn.cuda()
# validate_loss_fn = nn.CrossEntropyLoss().cuda()
train_loss_fn = train_loss_fn.to(device)
validate_loss_fn = nn.CrossEntropyLoss().to(device)
# input, target = input.cuda(), target.cuda()
input = input.to(device)
target = target.to(device)
# input = input.cuda()
# target = target.cuda()
input = input.to(device)
target = target.to(device)
方法一不用分布式训练不报错,用分布式训练报错:
RuntimeError: module must have its parameters and buffers on device cuda:0 (device_ids[0]) but found one of them on device: cuda:1
方法二不报错。