欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【PyTorch基础】

程序员文章站 2022-06-26 11:30:37
...


参考教程 https://www.jianshu.com/p/aee6a3d72014

搭建一个简单的网络

import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

class mymodel(nn.Module):
    def __init__(self):
        super(mymodel, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5) # in_channels, out_channels, kernel_size
        self.pool = nn.MaxPool2d(2,2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc = nn.Linear(16*5*5, 120)
    def forward(self, x):
        out = self.pool(F.relu(self.conv1(x)))
        out = self.pool(F.relu(self.conv2(out)))
        print(out.shape)
        out = out.view(-1, 16*5*5)
        out = F.relu(self.fc(out))
        return out

model = mymodel() # 初始化模型
print(model.parameters()) # 打印模型参数(是一个生成器)
for param in model.state_dict():
    print(param, "\t", model.state_dict()[param].size())  # 打印模型参数
    
optimizer = optim.SGD(model.parameters(),lr=0.001, momentum=0.9)  # 初始化优化器
for var in optimizer.state_dict(): # 打印优化器参数
    print(var, "\t", optimizer.state_dict()[var])

使用优化器是用来训练网络的,optim优化器的定义在 https://github.com/pytorch/pytorch/tree/master/torch/optim 可以使用Adam,SGD等多种优化器。

构造优化器

https://blog.csdn.net/gdymind/article/details/82708920
要构造一个optimizer,需要使用一个用来包含所有参数(Tensor形式)的iterable,把相关参数(如learning rate、weight decay等)装进去。
注意,如果想要使用.cuda()方法来将model移到GPU中,一定要确保这一步在构造Optimizer之前。因为调用.cuda()之后,model里面的参数已经不是之前的参数了。

将需要训练的参数加入优化器

optimizer = optim.SGD(params=model.parameters(), lr = 0.01, momentum = 0.9) # 将模型的所有参数都加进去
optimizer = optim.SGD(params=model.classifier.parameters(), lr = 0.01, momentum = 0.9) # 指定模型的classifier层的参数,加入优化器
optimizer = optim.Adam(params=[var1, var2], lr = 0.0001) # 加入[var1, var2]

单独指定参数

也可以用一个dict的iterable指定参数。这里的每个dict都必须要params这个key,params包含它所属的参数列表。除此之外的key必须它的Optimizer(如SGD)里面有的参数。
这在针对特定部分进行操作时很有用。比如只希望给指定的几个层单独设置学习率:

optim.SGD([
			{'params': model.base.parameters()},
			{'params': model.classifier.parameters(), 'lr': 0.001}
			],	 
			lr = 0.01, momentum = 0.9)

在上面这段代码中model.base将会使用默认学习率0.01,而model.classifier的参数蒋欢使用0.001的学习率。

使用optimizer.step()进行单次优化

所有optimizer都实现了step()方法,调用optimizer.step()方法可以更新参数:

for input, target in dataset:
	optimizer.zero_grad() # 每个mini-batch使用之前,optimzier使用之前需要zero清零一下,因为如果不清零,那么使用的这个grad就得同上一个mini-batch有关
    output = model(input)
    loss = cal_loss(target, output)  # 计算损失函数
    loss.backward() 
    optimizer.step()  # optimizer更新参数空间需要基于反向梯度,因此要先进行loss.backward()这个回传操作

关于loss.backward()

参考 https://blog.csdn.net/douhaoexia/article/details/78821428 讲的十分详细
这里需要注意:

  • 只有标量才可以使用backward()
  • 对于需要backward()的变量,必须满足requires_grad = True,否则会报错。
  • 创建的tensor默认requires_grad = False,需要在创建时指定,例如my_tensor = torch.zeros(3, 4, requires_grad=True),也可以在创建后对其修改,例如existing_tensor.requires_grad_()existing_tensor.requires_grad()
  • 对于继承自 nn.Module 的某一网络 net 或网络层,定义好后,发现 默认情况下,net.paramters 的 requires_grad 就是 True 的

pytorch0.4开始合并Tensor和Variable,torch.Tensor 能够像之前的Variable一样追踪历史和反向传播。Variable仍能够正常工作,但是返回的是Tensor。所以在0.4的代码中,不需要使用Variable了。(参考

optimizer.step() 和scheduler.step()的区别

https://blog.csdn.net/qq_20622615/article/details/83150963
https://blog.csdn.net/xiaoxifei/article/details/87797935

optimizer.step()通常用在每个mini-batch之中,而scheduler.step()通常用在epoch大循环里面。
只有用了optimizer.step(),模型才会更新,而scheduler.step()是对lr进行调整。
在scheduler的step_size表示scheduler.step()每调用step_size次,对应的学习率就会按照策略调整一次。所以如果scheduler.step()是放在mini-batch里面,那么step_size指的是经过这么多次迭代,学习率改变一次。

模型保存和读取

参考这里 https://blog.csdn.net/aaon22357/article/details/82696938

加载不同的模型

加载他人训练的模型,可能需要忽略部分层。则将load_state_dict方法的strict参数设置为False。(strict参数的意思是,参数名字必须完全对应才能加载)例如:

torch.save(model1.state_dict(),PATH) # 把model1的参数保存到PATH中(只存了参数,没有存模型)
model2.load_state_dict(torch.load(PATH), strict=False) # 将model1模型的参数导入到model2中

加载不同设备的模型

将GPU保存的模型加载到CPU上

将torch.load()函数中的map_location参数设置为torch.device(‘cpu’),例如:

device = torch.device('cpu')
model.load_state_dict(torch.load(PATH, map_location=device))

将由GPU保存的模型加载到GPU上

确保对输入的tensors调用input = input.to(device)方法

device = torch.device("cuda")
model.load_state_dict(torch.load(PATH))
model.to(device) # 将模型 load进来后要转到cuda上去