从零学习PyTorch 第8课 PyTorch优化器基类Optimier

课程目录(在更新,喜欢加个关注点个赞呗):
从零学习pytorch 第1课 搭建一个超简单的网络
从零学习pytorch 第1.5课 训练集、验证集和测试集的作用
从零学习pytorch 第2课 Dataset类
从零学习pytorch 第3课 DataLoader类运行过程
从零学习pytorch 第4课 初见transforms
从零学习pytorch 第5课 PyTorch模型搭建三要素
从零学习pytorch 第5.5课 Resnet34为例学习nn.Sequential和模型定义
从零学习PyTorch 第6课 权值初始化
从零学习PyTorch 第7课 模型Finetune与预训练模型
从零学习PyTorch 第8课 PyTorch优化器基类Optimier
PyTorch中所有的优化器,像是optim.Adadelta,optim.SGD,optim.RMSprop等等,都是Optimizer的子类,Optimizer中定义了一些常用的方法,像是zero_grad(), step(closure), state_dict(), load_state_dict(state_dict) and add_param_group(param_group)。

咱们一个一个来认识

什么是参数组param_group

认识Optimizer的方法之前,我们要了解一个概念,叫做参数组(param_groups).在finetune中,我们为特定层指定学习率,这里会用到参数组的概念

optimizer对于参数的管理,是基于组的概念,可以为每一组参数配置特定的学习率lr,momentum,weight_dacay等等。

参数组在optimizer中表现为一个list(self.param_groups),其中每个元素都是一个dict,表示一个参数及其相应的配置,在dict中包含‘params’、‘weight_decay’、‘lr’、‘momentum’等字段

# coding: utf-8
import torch
import torch.optim as optim
w1 = torch.randn(2, 2)
w1.requires_grad = True
print('w1',w1)
w2 = torch.randn(2, 2)
w2.requires_grad = True
print('w2',w2)
w3 = torch.randn(2, 2)
w3.requires_grad = True
print('w3',w3)
# 一个参数组
optimizer_1 = optim.SGD([w1, w3], lr=0.1)
print('len(optimizer.param_groups): ', len(optimizer_1.param_groups))
print(optimizer_1.param_groups, '\n')
# 两个参数组
optimizer_2 = optim.SGD([{'params': w1, 'lr': 0.1},
                         {'params': w2, 'lr': 0.001}])
print('len(optimizer.param_groups): ', len(optimizer_2.param_groups))
print(optimizer_2.param_groups)

运行结果:
在这里插入图片描述

zero_grad()

功能:将梯度清零。
由于PyTorch不会自动清零梯度,所以在每一次更新前会进行此操作。

# coding: utf-8
import torch
import torch.optim as optim
# ----------------------------------- zero_grad
w1 = torch.randn(2, 2)
w1.requires_grad = True
print('w1',w1)
w2 = torch.randn(2, 2)
w2.requires_grad = True
print('w2',w2)
optimizer = optim.SGD([w1, w2], lr=0.001, momentum=0.9)
optimizer.param_groups[0]['params'][0].grad = torch.randn(2, 2)
print('参数w1的梯度:')
print(optimizer.param_groups[0]['params'][0].grad, '\n')  # 参数组,第一个参数(w1)的梯度
optimizer.zero_grad()
print('执行zero_grad()之后,参数w1的梯度:')
print(optimizer.param_groups[0]['params'][0].grad)  # 参数组,第一个参数(w1)的梯度

运行结果:
在这里插入图片描述


这里稍微讲解一下optim
假设我们已经创建了w1,w2

# 我这里是有两个参数组,只有一个的话,就只会有parameter group 0
print(optimizer)

运行结果:
在这里插入图片描述

print(optimizer.param_groups)
print(optimizer.param_groups[0])
print(optimizer.param_groups[0]['params'])
print(optimizer.param_groups[0]['params'][0])

在这里插入图片描述这下我们也许可以明白,优化其中的参数组和参数之间的 联系!!一个optimizer.param_groups中,返回的是参数组的list,每一个元素是一个dict,这个dict中有’params’,‘lr’,'momentum’这样的参数,然后选中‘params’,里面又是一个list,这个list的每一个元素有grad梯度的属性。总之 list,dict,list这个嵌套的

state_dict()

功能:获取模型当前的参数,以一个有序字典形式返回
这个有序字典中,key是各层参数名字,value就是参数

# coding: utf-8
import torch.nn as nn
import torch.nn.functional as F
# ----------------------------------- state_dict
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 1, 3)
        self.pool = nn.MaxPool2d(2, 2)
        self.fc1 = nn.Linear(1 * 3 * 3, 2)
    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = x.view(-1, 1 * 3 * 3)
        x = F.relu(self.fc1(x))
        return x
net = Net()
# 获取网络当前参数
net_state_dict = net.state_dict()
print('net_state_dict类型:', type(net_state_dict))
print('net_state_dict管理的参数: ', net_state_dict.keys())
for key, value in net_state_dict.items():
    print('参数名: ', key, '\t大小: ',  value.shape)

运行结果:
在这里插入图片描述

load_state_dict(state_dict)

功能:将state_dict中的参数加载到当前网络,常用于finetune

# coding: utf-8
import torch
import torch.nn as nn
import torch.nn.functional as F
# ----------------------------------- load_state_dict
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 1, 3)
        self.pool = nn.MaxPool2d(2, 2)
        self.fc1 = nn.Linear(1 * 3 * 3, 2)
    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = x.view(-1, 1 * 3 * 3)
        x = F.relu(self.fc1(x))
        return x
    def zero_param(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                torch.nn.init.constant_(m.weight.data, 0)
                if m.bias is not None:
                    m.bias.data.zero_()
            elif isinstance(m, nn.Linear):
                torch.nn.init.constant_(m.weight.data, 0)
                m.bias.data.zero_()
net = Net()
# 保存,并加载模型参数(仅保存模型参数)
torch.save(net.state_dict(), 'net_params.pkl')   # 假设训练好了一个模型net
pretrained_dict = torch.load('net_params.pkl')
# 将net的参数全部置0,方便对比
net.zero_param()
net_state_dict = net.state_dict()
print('conv1层的权值为:\n', net_state_dict['conv1.weight'], '\n')
# 通过load_state_dict 加载参数
net.load_state_dict(pretrained_dict)
print('加载之后,conv1层的权值变为:\n', net_state_dict['conv1.weight'])

运行结果:
在这里插入图片描述

add_param_group()

功能:给optimizer管理的参数组中增加一组参数,可为该组制定lr,momentum,weight_decay等等,在finetune中常用

# coding: utf-8
import torch
import torch.optim as optim
# ----------------------------------- add_param_group
w1 = torch.randn(2, 2)
w1.requires_grad = True
w2 = torch.randn(2, 2)
w2.requires_grad = True
w3 = torch.randn(2, 2)
w3.requires_grad = True
# 一个参数组
optimizer_1 = optim.SGD([w1, w2], lr=0.1)
print('当前参数组个数: ', len(optimizer_1.param_groups))
print(optimizer_1.param_groups, '\n')
# 增加一个参数组
print('增加一组参数 w3\n')
optimizer_1.add_param_group({'params': w3, 'lr': 0.001, 'momentum': 0.8})
print('当前参数组个数: ', len(optimizer_1.param_groups))
print(optimizer_1.param_groups, '\n')
print('可以看到,参数组是一个list,一个元素是一个dict,每个dict中都有lr, momentum等参数,这些都是可单独管理,单独设定,十分灵活!')

运行结果:
在这里插入图片描述

step(closure)

功能:执行一步权值更新,其中可传入参数closure。如,当采用LBFGS优化方法时,需要多次计算,因此需要传入一个闭包去允许他们重新计算loss
例如:

for input, target in dataset:
	def closure():
		optimizer.zero_grad()
		output = model(input)
		loss = loss_fn(output,target)
		loss.backward()
		return loss
	optimizer.step(closure)
发布了78 篇原创文章 · 获赞 14 · 访问量 9730

猜你喜欢

转载自blog.csdn.net/qq_34107425/article/details/104109337
今日推荐