整理pytorch中一些常用的,容易忘记的知识点,持续更新。。。
1. Module.children() vs Module.modules()区别
简单的说就是children()输出模块的第一层子节点,modules是深度遍历输出所有的子节点
import torch.nn as nn
m = nn.Sequential(nn.Linear(2,2),
nn.ReLU(),
nn.Sequential(nn.Sigmoid(), nn.ReLU()))
list(m.children())
[Linear(in_features=2, out_features=2, bias=True), ReLU(), Sequential(
(0): Sigmoid()
(1): ReLU()
)]
list(m.modules())
[Sequential(
(0): Linear(in_features=2, out_features=2, bias=True)
(1): ReLU()
(2): Sequential(
(0): Sigmoid()
(1): ReLU()
)
), Linear(in_features=2, out_features=2, bias=True), ReLU(), Sequential(
(0): Sigmoid()
(1): ReLU()
), Sigmoid(), ReLU()]
三层嵌套的Sequential也是这样
import torch.nn as nn
m = nn.Sequential(nn.Linear(2,2),
nn.ReLU(),
nn.Sequential(nn.Sequential(nn.ReLU()), nn.Sigmoid(), nn.ReLU()))
list(m.children())
[Linear(in_features=2, out_features=2, bias=True), ReLU(), Sequential(
(0): Sequential(
(0): ReLU()
)
(1): Sigmoid()
(2): ReLU()
)]
list(m.modules())
[Sequential(
(0): Linear(in_features=2, out_features=2, bias=True)
(1): ReLU()
(2): Sequential(
(0): Sequential(
(0): ReLU()
)
(1): Sigmoid()
(2): ReLU()
)
), Linear(in_features=2, out_features=2, bias=True), ReLU(), Sequential(
(0): Sequential(
(0): ReLU()
)
(1): Sigmoid()
(2): ReLU()
), Sequential(
(0): ReLU()
), ReLU(), Sigmoid(), ReLU()]
参考:
https://discuss.pytorch.org/t/module-children-vs-module-modules/4551
https://blog.csdn.net/dss_dssssd/article/details/83958518
2. GPU训练
2.1 单GPU
image = image.cuda(n) #这里的n为GPU的编号,不填的话默认为0
device = torch.device('cuda:n' if torch.cuda.is_available() else 'cpu')#这里的n为GPU的编号
image = image.to(device)#也可以直接image = image.to(n),其中n为GPU的编号
2.2 多GPU
推荐方式一的写法
方式一
os.environ["CUDA_VISIBLE_DEVICES"] = '3, 4' #设置仅编号为3,4的GPU可见,设置之后这两个GPU的编号变为0,1
#对model 的处理
#下面的写法其实省略了最后cuda括号中的0,模型必须在第一块GPU中
model = torch.nn.DataParallel(model).cuda() #或者model = torch.nn.DataParallel(model, device_ids=[0,1]).cuda() 或者 model = torch.nn.DataParallel(model.cuda())
image = image.cuda()
方式二
device = torch.device('cuda:3')
#肯定的是,下面的写法等价于model = torch.nn.DataParallel(model, device_ids=[3,4]).to(device)
model = torch.nn.DataParallel(model, device_ids=[3,4]).cuda(3) #模型必须在第一块GPU中
images = images.to(device)
3. DataLoader
DataLoader在pytorch中用来定义自己的数据,了解其参数含义以及内部源码非常有帮助。
Pytorch的DataLoader, DataSet, Sampler之间的关系
Pytorch Sampler详解
DataLoader源代码剖析
4. 模型保存与加载
一般模型在训练的时候需要保存checkpoint,以免程序突然中止或者由于某些原因需要接着上次的训练接着进行训练。
一般保存模型的卷积层等参数,学习率,以及训练的epoch数。
由于多GPU训练使用了 nn.DataParallel(net, device_ids=gpu_ids) 对网络进行封装,因此在原始网络结构中添加了一层module。如果在多GPU下面训练,单GPU下进行加载可以有两种方式:
方式一:
#保存模型
state = {
'epoch': epoch_num,
'state_dict': retinanet.module.state_dict(),
'best_map': best_map,
'lr': lr,
}
torch.save(state, checkpoint_path) #可以用这个直接复制 shutil.copyfile()
#加载模型:
retinanet = model.resnet50(num_classes=20, pretrained=False) #这里的resnet是被重写了的
checkpoint = torch.load(checkpoint_path)
retinanet.load_state_dict(checkpoint['state_dict'])
或者参考:https://blog.csdn.net/u013066730/article/details/99594892
方式二:
#保存模型
state = {
'epoch': epoch_num,
'state_dict': retinanet.state_dict(),
'best_map': best_map,
'lr': lr,
}
torch.save(state, checkpoint_path) #可以用这个直接复制 shutil.copyfile()
#加载模型:先定义模型,将模型转到多GPU下面,在进行加载
retinanet = model.resnet50(num_classes=20, pretrained=False)#这里的resnet是被重写了的
checkpoint = torch.load(checkpoint_path)
retinanet = torch.nn.DataParallel(retinanet).cuda()
retinanet.load_state_dict(checkpoint['state_dict'])
方式三:
#直接保存整个模型,这样会更加占用内存
torch.save(retinanet, checkpoint_path)
#加载模型:
retinanet = torch.load(checkpoint_path) #这样会让模型直接加载为多GPU的形式,不过实际用一块GPU加载是没有问题的
参考:
【Pytorch】多GPU训练网络与单GPU训练网络保存模型的区别
PyTorch之保存加载模型
5. GPU内存占用率与利用率问题
1.增加batch size,增加GPU的内存占用率,尽量用完内存,而不要剩一半,空的内存给另外的程序用,两个任务的效率都会非常低。
2.在数据加载时候,将num_workers线程数设置稍微大一点,推荐是8,16等,且开启pin_memory=True。,直接映射数据到GPU的专用内存,减少数据传输时间。
深度学习PyTorch,TensorFlow中GPU利用率较低,CPU利用率很低,且模型训练速度很慢的问题总结与分析