pytorch-用优化器来管理参数

1、经典函数,求导

从最简单的tensor开始,我们新建了一个tensor变量a,建立b = 3*a +3,那可以通过b.backward()对函数求导

import torch
from torch import nn

a = torch.tensor(3.0,requires_grad=True)
b = 3*a +3
b.backward(retain_graph=True)

print(a.grad)

输出:tensor(3.0)

b.backward()
print(a.grad)

输出:tensor(6.0)

torch在求导时,不会清除上一次的梯度,会累加

因此,可以使用a.grad.zero_()清零

2、复杂模型求导

当我们使用了神经网络,模型变得复杂,变量被隐藏在了torch的module模块中

问题一:怎么管理我们的参数呢?

问题二:怎么进行求导呢?

2.1、首先,构造一个简单的模型,继承Module类,构造net1网络对象

from torch import nn

torch.manual_seed(0)
class model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=1,out_channels=1,kernel_size=2,stride=1,padding=0)
        self.conv2 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=2, stride=1, padding=0)
    def forward(self,x):
        out = self.conv1(x)
        return out

net1 = model()

对于这样的对象,它的参数可以使用net1.parameters()查看,返回一个迭代器

for para in net1.parameters():
    print(para)

那么,我们怎么对我们模型的参数进行求导呢?和经典函数一样,我们获取目标值,然后利用backward() torch自动对目标值关联的变量进行求导。这里我额外构造了一个损失,因为用out.backward(),会报错,说想要求导的是一个标量(不懂,以后再说)。下面构造了一个损失,变成标量。

print('\n变量')
for para in net1.parameters():
    print(para)

out = net1.forward(torch.ones([1,1,16,16]))
## 损失函数
loss = torch.nn.MSELoss()
out = loss.forward(out,torch.ones_like(out-1))
out.backward(retain_graph=True)

print('\n梯度')
for para in net1.parameters():
    print(para.grad)

tensor([[[[-3.4152, -3.4152],
          [-3.4152, -3.4152]]]])
tensor([-3.4152])

能够正常输出梯度!!!

那然后,我们怎么将每个参数的值,通过梯度下降,结合梯度,更新到参数上呢,想想都觉得太麻烦。

另外,还有一个麻烦的点,我们的梯度在backward()后,会自动加上前面计算的梯度,如果没有归零的话。

2.2、利用优化器来管理参数

注意,我这里说“使用优化器来管理参数”,我理解的就是这样的。

torch.optim这个类实现了两个功能,第一,让所有加载到optim的参数梯度归零;第二,将计算得到的梯度,更新到参数上

1)首先,我们来演示,torch.optim具有参数梯度归零的本领,这里选择使用SGD进行演示(梯度下降法,比较简单)

import torch
from torch import nn

torch.manual_seed(0)
class model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=1,out_channels=1,kernel_size=2,stride=1,padding=0)
        self.conv2 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=2, stride=1, padding=0)
    def forward(self,x):
        out = self.conv1(x)
        return out

net1 = model()

out = net1.forward(torch.ones([1,1,16,16]))
## 损失函数
loss = torch.nn.MSELoss()
out = loss.forward(out,torch.ones_like(out-1))

## 优化器
optimizer_1 = torch.optim.SGD(net1.parameters(),lr = 4)

print('\n输出梯度')
out.backward(retain_graph=True)
for i in net1.parameters():
    print(i.grad)

print('\n梯度清零')
optimizer_1.zero_grad() 

print('\b输出梯度')
for i in net1.parameters():
    print(i.grad)

结果说明,optimizer_1.zero_grad()确实实现了梯度清零的效果

2)演示,torch.optim具有参数梯度更新到参数的本领

import torch
from torch import nn

torch.manual_seed(0)
class model(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(in_channels=1,out_channels=1,kernel_size=2,stride=1,padding=0)
        self.conv2 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=2, stride=1, padding=0)
    def forward(self,x):
        out = self.conv1(x)
        return out

net1 = model()

out = net1.forward(torch.ones([1,1,16,16]))
## 损失函数
loss = torch.nn.MSELoss()
out = loss.forward(out,torch.ones_like(out-1))

## 优化器
optimizer_1 = torch.optim.SGD(net1.parameters(),lr = 0.4)



print('\n输出参数')
for para in net1.parameters():
    print(para)

optimizer_1.zero_grad()    # 梯度清零
out.backward()             # 计算梯度
print('\n输出梯度')
for i in net1.parameters():
    print(i.grad)

optimizer_1.step()        # 梯度更新
print('\n输出参数')
for para in net1.parameters():
    print(para)

 

 证明完毕

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值