PyTorch 20. PyTorch技巧(持续更新)

查看模型每层输出详情

from torchsummary import summary
summary(your_model, input_size=(channels, H, W))

input_size是根据自己的网络模型的输入尺寸进行设置

梯度裁剪(Gradient Clipping)

import torch.nn as nn
outputs = model(data)
loss = loss_fn(outputs, target)
optimizer.zero_grad()
loss.backward()
nn.utils.clip_grad_norm_(model.parameters(), max_norm=20, norm_type=2)
optimizer.step()

nn.utils.clip_grad_norm_的参数:

  • parameters 一个基于变量的迭代器,会进行梯度归一化
  • max_norm 梯度的最大范数
  • norm_type 规定范数的类型,默认为2

扩展单张图片的维度

view()实现

import cv2
import torch
image = cv2.imread(img_path)
image = torch.tensor(image)
print(image.size)

img = image.view(1, *image.size())
print(img.size())

np.newaxis实现

import cv2
import torch

image = cv2.imread(img_path)
print(image.shape)
img = image[np.newaxis, :, :, :]
print(img.shape)

unsqueeze()实现

import cv2
import torch

iamge = cv2.imread(img_path)
image = torch.tensor(image)
print(img.size())

img = image.unsqueeze(dim=0)
print(img.size())

独热编码

在PyTorch中使用交叉熵损失函数的时候会自动把label转换成onehot,所以不用手动转化,而使用MSE需要手动转化成onehot编码

import torch.nn.functional as F
import torch

tensor = torch.arange(0, 5)
one_hot = F.one_hot(tensor)
# 输出:
# tensor([[1, 0, 0],
#         [0, 1, 0],
#         [0, 0, 1],
#         [1, 0, 0],
#         [0, 1, 0]])

F.one_hot会自己检测不同类别个数,生成对应独热编码,我们也可以自己指定类别数:

tensor =  torch.arange(0, 5) % 3  # tensor([0, 1, 2, 0, 1])
one_hot = F.one_hot(tensor, num_classes=5)

# 输出:
# tensor([[1, 0, 0, 0, 0],
#         [0, 1, 0, 0, 0],
#         [0, 0, 1, 0, 0],
#         [1, 0, 0, 0, 0],
#         [0, 1, 0, 0, 0]])

防止验证模型时爆显存

验证模型时不需要求导,即不需要梯度计算,关闭autograd,可以提高速度,节约内存,如果不关闭可能会爆显存

with torch.no_grad():
	# 使用model进行预测的代码
	pass

对于使用torch.cuda.empty_cache()的原因,是因为随着Pytorch的训练,无用的临时变量可能会越来越多,导致out of memory

意思就是Pytorch的缓存分配器会事先分配一些固定的显存,即使实际上tensors并没有使用完这些显存,这些显存也不能被其他应用使用。这个分配过程由第一次CUDA内存访问触发的。

torch.cuda.empty_cache()的作用就是释放缓存分配器当前持有的且未占用的缓存显存,以便这些显存可以被其他GPU应用程序中使用,注意使用此命令不会释放tensors占用的显存。

监控工具

sudo apt-get install htop #监控内存(-d为更新频率)
htop -d=0.1
watch -n 0.1 nvidia-smi #监控显存(-n为更新频率,每0.1s更新一次)

Pytorch-Memory-Utils监控显存占用

显存占用

显存占用=模型参数+计算产生的中间变量
减少显存占用的方法

  1. inplace替换
  2. 用del一边计算一边清除中间变量
  3. 减少batch_size,避免用全连接,多用下采样
  4. 因为每次迭代都会引入点临时变量,会导致训练速度越来越慢,基本呈线性增长。但是如果周期性的使用torch.cuda.empty_cache()的话就可以解决这个问题。

冻结某些层的参数

在加载预训练模型的时候,我们有时想冻结前面几层,使其参数在训练过程中不发生变化。
我们需要先知道每一层的名字,通过以下代码打印:

net = Network() #获取自定义网络结构
for name, value in net.named_parameters():
	print('name: {0},\t grad: {1}'.format(name, value.requires_grad))

假设前几层信息如下:

name: cnn.VGG_16.convolution1_1.weight,	 grad: True
name: cnn.VGG_16.convolution1_1.bias,	 grad: True
name: cnn.VGG_16.convolution1_2.weight,	 grad: True
name: cnn.VGG_16.convolution1_2.bias,	 grad: True
name: cnn.VGG_16.convolution2_1.weight,	 grad: True
name: cnn.VGG_16.convolution2_1.bias,	 grad: True
name: cnn.VGG_16.convolution2_2.weight,	 grad: True
name: cnn.VGG_16.convolution2_2.bias,	 grad: True

后面的True表示该层的参数可训练,然后我们定义一个要冻结的层的列表

no_grad = [
    'cnn.VGG_16.convolution1_1.weight',
    'cnn.VGG_16.convolution1_1.bias',
    'cnn.VGG_16.convolution1_2.weight',
    'cnn.VGG_16.convolution1_2.bias'
]

冻结方法如下:

net = Net.CTPN()  # 获取网络结构
for name, value in net.named_parameters():
    if name in no_grad:
        value.requires_grad = False
    else:
        value.requires_grad = True

最后在定义优化器时,只对requires_grad为True的层的参数进行更新

optimizer = optim.Adam(filter(lambda p: p.requires_grad, net.parameters()), lr=0.01)

显式指定model.train()和model.eval()
我们的模型中经常会有一些子模型,其在训练时候和测试时候的参数是不同的,比如dropout中的丢弃率和Batch Normalization中的 γ \gamma γ β \beta β等,这时我们需要显式地指定不同阶段,在pytorch中我们通过model.train()model.eval()进行显式指定(因为BN的running_mean等并非nn.Parameter,用requires_grad冻不住,需要调用BN的.eval()

对不同层使用不同学习率

以如下模型为例:

net = Network()  # 获取自定义网络结构
for name, value in net.named_parameters():
    print('name: {}'.format(name))

# 输出:
# name: cnn.VGG_16.convolution1_1.weight
# name: cnn.VGG_16.convolution1_1.bias
# name: cnn.VGG_16.convolution1_2.weight
# name: cnn.VGG_16.convolution1_2.bias
# name: cnn.VGG_16.convolution2_1.weight
# name: cnn.VGG_16.convolution2_1.bias
# name: cnn.VGG_16.convolution2_2.weight
# name: cnn.VGG_16.convolution2_2.bias

对convolution1和convolution2设置不同的学习率,首先将它们分开,放到不同的列表中:

conv1_params = []
conv2_params = []

for name, params in net.named_parameters():
	if "convolution1" in name:
		conv1_params += [params]
	else:
		conv2_params += [params]
# 然后在优化器中进行如下操作:
optimizer = optim.Adam(
[
	{"params": conv1_params, 'lr':0.01},
	{"params": conv2_params, 'lr':0.001},
],
weight_decay = 1e-3
)

我们将模型划分为两部分,存放到一个列表里,每部分就对应上面的一个字典,在字典里设置不同的学习率,当着两部分有相同的其他参数时,就将参数放到列表外面作为全局参数,如上面的‘weight_decay’。

也可以在列表外设置一个全局学习率,当各部分字典里设置了局部学习率时,就使用该学习率,否则就使用列表外的全局学习率。

retain_graph使用

在对一个损失进行反向传播时,在pytorch中调用out.backward()即可实现,
对loss进行反向传播就可以求得损失函数对于学习参数的梯度,在.backward()中,

backward(gradient=None, retain_graph=None, create_graph=False)

这里我们关注的是retain_graph这个参数,这个参数如果为False或者None则在反向传播完后,就释放掉构建出来的graph,如果为True则不对graph进行释放。

但是我们已经计算完梯度了,为什么还要保存graph呢?这里举个例子,比如在对抗生成网络GAN中需要先对某个模块比如生成器进行训练,后对判别器进行训练,这个时候整个网络就会存在两个以上的loss,

G_loss = ...
D_loss = ...

opt.zero_grad() #对所有梯度清0
D_loss.backward(retain_graph=True) #保存graph结构,后续使用
opt.step() # 更新梯度,只更新D的梯度,因为只有D的梯度不为0

opt.zero_grad() # 对所有梯度清0
G_loss.backward(retain_graph=False) #不保存graph结构,可以释放graph
# 下一个迭代中通过forward还可以build出来
opt.step() #更新梯度,只更新G的,因为只有G的不为0

这个时候就可以对网络中多个loss进行分步训练了。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 学习 PyTorch 可以通过以下几个步骤: 1. 了解 PyTorch 的基本概念,包括张量(tensor)、自动求导(autograd)、神经网络(neural network)等。 2. 阅读官方文档和教程,了解 PyTorch 的使用方法和语法。PyTorch 官网上有大量的文档和教程,可以帮助您快速入门。 3. 实战演练,通过完成一些简单的项目来加深对 PyTorch 的理解。您可以参考官方的教程或示例代码,也可以尝试自己编写代码解决实际问题。 4. 学习相关的知识,如机器学习、深度学习等,这样可以帮助您更好地理解 PyTorch 中的技术。 5. 加入社区,与其他 PyTorch 用户交流和合作。可以加入线上或线下的 PyTorch 社区,和其他 PyTorch 爱好者交流经验、探讨问题。 希望这些建议能帮助您快速学习 PyTorch。 ### 回答2: 学习PyTorch的关键是掌握一些基本的步骤和资源。以下是学习PyTorch的建议: 1. 入门:首先,了解PyTorch的基本概念和特点。可以通过官方文档、教程和在线资源来学习。理解基本概念如张量(Tensor)、自动求导(Autograd)和神经网络(Neural Network)。 2. Python编程和机器学习基础:学习PyTorch之前,需要掌握Python编程语言和机器学习的基础知识。了解NumPy库和机器学习算法对于理解和应用PyTorch至关重要。 3. 官方文档和教程:官方文档是学习PyTorch的首要资源。详细阅读官方文档,特别是教程和示例代码,从而掌握PyTorch的使用方法和技巧。 4. 实践项目:通过实践来巩固所学知识。尝试使用PyTorch完成一些小项目,例如使用神经网络进行图像分类或文本情感分析。这样可以加深对PyTorch的理解,并提升解决实际问题的能力。 5. 社区资源:加入PyTorch社区,参与讨论和分享经验。访问论坛、博客和社交媒体,与其他使用PyTorch的人交流,并从他们的经验中学习。 6. 深入学习:一旦掌握了基本概念和技巧,可以深入研究PyTorch的高级功能,如分布式训练、模型部署和模型优化。阅读相关论文和研究资料,了解最新的PyTorch发展和应用。 总之,学习PyTorch需要有坚实的Python编程和机器学习基础,并充分利用官方文档、教程和社区资源。通过实践项目,加深对PyTorch的理解和应用能力,并持续关注最新发展,不断提升自己的技能。 ### 回答3: 要学习PyTorch,可以采取以下步骤: 1. 基础知识学习:首先,了解Python编程语言的基础知识。掌握Python语法、变量、数据类型等基本概念。同时,学习NumPy和Pandas,这些是PyTorch的一些核心库。 2. PyTorch官方文档:PyTorch提供了详细的官方文档,包含了各种教程、示例代码和API的详细说明。深入学习和理解PyTorch的各种功能和用法,可以通过官方文档进行实践和编码。 3. 在线教育平台学习:有许多在线教育平台提供了关于PyTorch的各种课程。可以通过Coursera、Udacity、Udemy等平台找到适合自己的PyTorch教程。这些课程往往结合理论和实践,通过视频、讲义和编程任务来指导学习。 4. 研究论文和开源项目:阅读最新的研究论文和开源项目可以帮助了解PyTorch在实际应用中的使用。深入学习并复现优秀的论文和项目,可以提高自己的PyTorch技能。 5. 实践项目:通过完成实际项目来巩固所学的知识,将理论应用到实际场景中。可以参与开源项目,或者自己选择一个感兴趣的问题进行研究和解决,掌握PyTorch的实际应用能力。 6. 参与社区和讨论:加入PyTorch的在线社区和论坛,与其他PyTorch开发者交流、分享经验和解决问题。积极参与讨论,相互学习和帮助。 7. 持续学习和实践:PyTorch是一个不断发展的框架,持续学习和实践能够帮助跟上最新的技术和进展。定期阅读最新的官方文档和相关论文,参与项目和比赛等,以提升自己在PyTorch上的能力。 总之,学习PyTorch需要一定的编程基础和学习计划。通过官方文档、在线教育平台和实践项目等多种途径,结合实践和理论的学习方法,可以有效提高自己在PyTorch上的技能水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值