【02】Pytorch autograd 线性回归踩坑记录

作业题
1.调整线性回归模型停止条件以及y = 2x + (5 + torch.randn(20, 1))中的斜率,训练一个线性回归模型。

我先记录了自己的踩坑记录,最后附上了完整的代码,个人觉得踩坑的过程收获更大,共勉吧。

step5 反向更新梯度,训练模型

w  = w -  learning_rate * w.grad
b  = b -  learning_rate * b.grad

这里报错:
在这里插入图片描述

原因是我又重新创建了一个变量。

## step 2 构建模型
w = Variable(torch.Tensor([1]),requires_grad = True)
print('original address')
print(id(w))
b =  Variable(torch.Tensor([1]),requires_grad = True)
print(id(b))
 ## step5 反向更新梯度,训练模型
w  = w -  learning_rate * w.grad
b  = b -  learning_rate * b.grad
print('New address')
print(id(w))
print(id(b))

我通过打印地址来查看两次操作以后张量的地址:

original address 
2613165770072 
2613165770648 
tensor(4.4057, grad_fn=<MeanBackward0>) 
New address 
2613165727104 
2613165848760

结果看到更新梯度以后的w和b的地址与创建的时候的是不一致的,在执行w = w - learning_rate * w.grad;b = b - learning_rate * b.grad计算时,w,b都变成了中间节点,此时梯度会释放,因此在反向传播的时候没有梯度可以参与计算了,于是就报错NoneType。

于是继续查找资料.既然地址不能改变,那我就直接in place原位操作好了,遂暴力执行:

## step5 反向更新梯度,训练模型
w  -=  learning_rate * w.grad
b  -=  learning_rate * b.grad

哭泣,报错:a leaf Variable that requires grad has been used in an in-place operation.
原因是在定义w,b的时候,w,b是一个叶子节点,什么是叶子节点呢?要先回顾一下pytorch的动态图的计算原理了
Pytorch计算图原理

在这个计算图中,w,b就是叶子节点,不允许in Place操作,就是不允许更新以后的值(执行加减法计算后的值)保存在原来的内存地址上;于是,继续修改,想着,再复制一份一样的数据用来计算梯度,并且新的结果不保存再w,b原来的地址不就好了!

于是,查资料,tensor.data能处,有问题它真上!

Tensor.data的解释是:
out = x .data 返回和 x 的相同数据 tensor,而且这个新的tensor out和原来的tensor x是共用数据的,一者改变,另一者也会跟着改变,而且新分离得到的tensor的require s_grad = False, 即不可求导的。(这一点其实detach是一样的)

于是报错的代码改成:

w.data  -=  learning_rate * w.grad; b.data  -=  learning_rate * b.grad

**Run了! 奈斯!!**查看一开始创建的w,b以及更新梯度后w,b的存储地址,并检查是否是叶子节点:

original address
The original address of w is: 2613166122544
The original address of b is: 2613166121320
cheak leaf node:
Is w a leaf node? True
Is b a leaf node? True
tensor(4.6758, grad_fn=<MeanBackward0>)
New address
The current address of w is: 2613166122544
The current address of b is: 2613166121320
Check grad function of w : None
Check grad function of b : None
Now, is w a leaf node? True
Now, is b a leaf node? True

现在,附上完整的代码:

## step1 需要生成数据
import torch
from torch.autograd import Variable
x = torch.rand(20,1)*5
print(x.size())
y  = 2*x + torch.randn((20,1))
## step 2 构建模型
w = Variable(torch.Tensor([1]),requires_grad = True)
print('original address')
print(f'The original address of w is: {id(w)}')
b =  Variable(torch.Tensor([1]),requires_grad = True)
print(f'The original address of b is: {id(b)}')
#print(w.grad_fn)
#print(b.grad_fn)
print('cheak leaf node:')
print(f'Is w a leaf node? {w.is_leaf}')
print(f'Is b a leaf node? {b.is_leaf}')
epochs = 100
for i in range(epochs):
    yy = torch.mul(w,x)
    y_predict = yy + b
    ## step3 计算损失函数
    loss = (0.5*(y-y_predict)**2).mean()
    print(loss)
    loss.backward()
    ## step4 设计优化器
    learning_rate = 0.01

    ## step5 反向更新梯度,训练模型
    w.data  -=  learning_rate * w.grad
    b.data  -=  learning_rate * b.grad
    print('New address')
    print(f'The current address of w is: {id(w)}')
    print(f'The current address of b is: {id(b)}')
    print(f'Check grad function of w : {w.grad_fn}')
    print(f'Check grad function of b : {b.grad_fn}')
   
    print(f'Now, is w a leaf node? {w.is_leaf}')
    print(f'Now, is b a leaf node? {b.is_leaf}')

    w.grad.zero_()
    b.grad.zero_()
    if loss <=0.1:
        break

为了查看最后学习的模型长什么样子,我可视化了一下。

import matplotlib.pyplot as plt
final_x = x.numpy()
final_y = y_predict.data.numpy()
plt.scatter(final_x,y.data.numpy())
plt.plot(final_x,final_y,'y-')
plt.show()

在这里插入图片描述

总结:

  • 𝑤,𝑏均是叶子节点,在创建的时候requires_grad = True 不支持in place操作
  • w = w-w.gradlr or b = b- b.gradlr 会破坏上述计算图,使得w,b变成中间节点,w,b的存储地址会较创建它们时候的地址发生改变;中间节点不会保存其梯度,所以无法进行更新;
  • 正确更新方式为:w.data = w.data – w.grad*lr; b.data = b.data – b.grad*lr或者
    w.data.sub_(w.grad*lr); b.data.sub_(b.data*lr) 或者w.data -= lr* w.grad; b.data -= lr* b.grad Sub_(下划线表示的是原位操作)

2. 计算图的两个主要概念是什么?

计算图是一个有向的无环图。

两个主要概念是节点和边:节点表示的是变量;边表示的是计算。

3. 动态图与静态图的区别是什么?

动态图是变量与运算操作边执行边创建;

静态图则是先创建好变量,再执行操作。

举个例子:动态图是自驾游,静态图是跟团游。

作业内容来自【深度之眼】的pytorch训练班。

`

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值