纯净、安全、绿色的下载网站

首页|软件分类|下载排行|最新软件|IT学院

当前位置:首页IT学院IT技术

Pytorch计算梯度默认累加 Pytorch反向传播中的细节-计算梯度时的默认累加操作

Miracle8070   2021-06-05 我要评论
想了解Pytorch反向传播中的细节-计算梯度时的默认累加操作的相关内容吗Miracle8070在本文为您仔细讲解Pytorch计算梯度默认累加的相关知识和一些Code实例欢迎阅读和指正我们先划重点:Pytorch,反向传播,计算梯度,默认累加下面大家一起来学习吧。

Pytorch反向传播计算梯度默认累加

今天学习pytorch实现简单的线性回归发现了pytorch的反向传播时计算梯度采用的累加机制 于是百度来一下好多博客都说了累加机制但是好多都没有说明这个累加机制到底会有啥影响 所以我趁着自己练习的一个例子正好直观的看一下以及如何解决:

pytorch实现线性回归

先附上试验代码来感受一下:

torch.manual_seed(6)
lr = 0.01   # 学习率
result = []

# 创建训练数据
x = torch.rand(20, 1) * 10
y = 2 * x + (5 + torch.randn(20, 1)) 

# 构建线性回归函数
w = torch.randn((1), requires_grad=True)
b = torch.zeros((1), requires_grad=True)
# 这里是迭代过程为了看pytorch的反向传播计算梯度的细节我先迭代两次
for iteration in range(2):

    # 前向传播
    wx = torch.mul(w, x)
    y_pred = torch.add(wx, b)

    # 计算 MSE loss
    loss = (0.5 * (y - y_pred) ** 2).mean()
    
    # 反向传播
    loss.backward()
    
    # 这里看一下反向传播计算的梯度
    print("w.grad:", w.grad)
    print("b.grad:", b.grad)
    
    # 更新参数
    b.data.sub_(lr * b.grad)
    w.data.sub_(lr * w.grad)

上面的代码比较简单迭代了两次 看一下计算的梯度结果:

w.grad: tensor([-74.6261])
b.grad: tensor([-12.5532])
w.grad: tensor([-122.9075])
b.grad: tensor([-20.9364])

然后我稍微加两行代码 就是在反向传播上面我手动添加梯度清零操作的代码再感受一下结果:

torch.manual_seed(6)
lr = 0.01
result = []
# 创建训练数据
x = torch.rand(20, 1) * 10
#print(x)
y = 2 * x + (5 + torch.randn(20, 1)) 
#print(y)
# 构建线性回归函数
w = torch.randn((1), requires_grad=True)
#print(w)
b = torch.zeros((1), requires_grad=True)
#print(b)
for iteration in range(2):
    # 前向传播
    wx = torch.mul(w, x)
    y_pred = torch.add(wx, b)

    # 计算 MSE loss
    loss = (0.5 * (y - y_pred) ** 2).mean()
    
    # 由于pytorch反向传播中梯度是累加的所以如果不想先前的梯度影响当前梯度的计算需要手动清0
     if iteration > 0: 
        w.grad.data.zero_()
        b.grad.data.zero_()
    
    # 反向传播
    loss.backward()
    
    # 看一下梯度
    print("w.grad:", w.grad)
    print("b.grad:", b.grad)
    
    # 更新参数
    b.data.sub_(lr * b.grad)
    w.data.sub_(lr * w.grad)

w.grad: tensor([-74.6261])
b.grad: tensor([-12.5532])
w.grad: tensor([-48.2813])
b.grad: tensor([-8.3831])

从上面可以发现pytorch在反向传播的时候确实是默认累加上了上一次求的梯度 如果不想让上一次的梯度影响自己本次梯度计算的话需要手动的清零。

但是 如果不进行手动清零的话会有什么后果呢? 我在这次线性回归试验中遇到的后果就是loss值反复的震荡不收敛。下面感受一下:

torch.manual_seed(6)
lr = 0.01
result = []
# 创建训练数据
x = torch.rand(20, 1) * 10
#print(x)
y = 2 * x + (5 + torch.randn(20, 1)) 
#print(y)
# 构建线性回归函数
w = torch.randn((1), requires_grad=True)
#print(w)
b = torch.zeros((1), requires_grad=True)
#print(b)

for iteration in range(1000):
    # 前向传播
    wx = torch.mul(w, x)
    y_pred = torch.add(wx, b)

    # 计算 MSE loss
    loss = (0.5 * (y - y_pred) ** 2).mean()
#     print("iteration {}: loss {}".format(iteration, loss))
    result.append(loss)
    
    # 由于pytorch反向传播中梯度是累加的所以如果不想先前的梯度影响当前梯度的计算需要手动清0
    #if iteration > 0: 
    #    w.grad.data.zero_()
    #    b.grad.data.zero_()
  
    # 反向传播
    loss.backward()
 
    # 更新参数
    b.data.sub_(lr * b.grad)
    w.data.sub_(lr * w.grad)
    
    if loss.data.numpy() < 1:
        break
   plt.plot(result)

上面的代码中我没有进行手动清零迭代1000次 把每一次的loss放到来result中 然后画出图像感受一下结果:

没有进行手动清零

接下来我把手动清零的注释打开进行每次迭代之后的手动清零操作得到的结果:

手动清零之后的操作

可以看到这个才是理想中的反向传播求导然后更新参数后得到的loss值的变化。

总结

这次主要是记录一下pytorch在进行反向传播计算梯度的时候的累加机制到底是什么样子? 至于为什么采用这种机制我也搜了一下大部分给出的结果是这样子的:

但是如果不想累加的话可以采用手动清零的方式只需要在每次迭代时加上即可

w.grad.data.zero_()
b.grad.data.zero_()

另外 在搜索资料的时候在一篇博客上看到两个不错的线性回归时pytorch的计算图在这里借用一下:

前向传播
反向传播

以上为个人经验希望能给大家一个参考也希望大家多多支持。


相关文章

猜您喜欢

  • PyTorch检查梯度是否可导 PyTorch 怎样检查模型梯度是否可导

    想了解PyTorch 怎样检查模型梯度是否可导的相关内容吗烟雨风渡在本文为您仔细讲解PyTorch检查梯度是否可导的相关知识和一些Code实例欢迎阅读和指正我们先划重点:PyTorch,检查梯度,检查模型梯度下面大家一起来学习吧。..
  • pytorch weight与grad可视化 pytorch 权重weight 与 梯度grad 可视化操作

    想了解pytorch 权重weight 与 梯度grad 可视化操作的相关内容吗rainbow_lucky0106在本文为您仔细讲解pytorch weight与grad可视化的相关知识和一些Code实例欢迎阅读和指正我们先划重点:pytorch,权重weight,梯度grad,可视化下面大家一起来学习吧。..

网友评论

Copyright 2020 www.Shellfishsoft.com 【贝软下载站】 版权所有 软件发布

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 点此查看联系方式