一文理解 pytorch 拟合网络的过程

下面给一个小的例子,比如我们待拟合的函数是 y = 5*x,(假设你对深度学习有基础,懂损失函数之类的,没有的话建议看完再继续),则我们需要一堆的x以及对应labbel,比如(x,label) = (1,5) (2,10) (3,15),然后我们构造一个前向传播 y' = w *x,其中这个里面w就是我们最终要求的,也就是5,所以需要对w进行更新。简单代码如下 :

import torch
from torch.autograd import Variable
x = torch.Tensor([2])
y = torch.Tensor([10])
loss = torch.nn.MSELoss()
w = Variable(torch.randn(1),requires_grad=True)
print(w)
for i in range(10):
    y_ = w*x
    l = loss(y,y_)
    l.backward()
    print(w.grad.data)
    print(-2*x*(y-y_))

首先,我们定义了一个输入和输出也就是x和y,x为2,y为10,之后我们定义了一个均方误差loss,下面定义了一个w,注意w是一个Variable形式,并且requires_grad=True,为什么需要这样,因为w是一个待求的,所以需要进行梯度下降,所以包装成一个requires_grad=True的Variable,这样pytorch才能认识,并且w我们是随机生成的,类似于之前学习两层的神经网络时候的w,只不过这个比较简单。

之后我么就进行了10次迭代,计算了loss并进行反向传播,然后打印出来,print(-2*x*(y-y_))是我手动计算了一下l对w的导数,然后输出了出来。最后输出如下(部分):

tensor([-0.8820], requires_grad=True)
tensor([-47.0557])
tensor([-47.0557], grad_fn=<MulBackward0>)
tensor([-94.1115])
tensor([-47.0557], grad_fn=<MulBackward0>)
tensor([-141.1672])
tensor([-47.0557], grad_fn=<MulBackward0>)
tensor([-188.2230])

可以发现我们的w初始为-0.8820,计算出来的导数为-47.0557 第2行是backward计算的,第3行是我们自己计算的。但是发现下面的第4、5行和想象的不一样,手动计算的好像没问题还是-47.0557,但为什么backward计算的变成了-94.1115,似乎是-47.0557*2,其实是因为pytorch设计就是这样的,它的梯度默认会保存累加,所以这次的梯度是我们这次的加上上一次的。讲到这里,估计也就明白了为什么我们在进行梯度下降的时候需要用optimizer.zero_grad()了。主要就是清空梯度。上面的例子只是计算了梯度,并没有进行梯度更新,下面对for循环里面的代码增加点东西:

    y_ = w*x
    l = loss(y,y_)

    l.backward()
    print(w.grad.data)
    w = Variable(w - 0.1 * w.grad.data,requires_grad=True)
    print(w)
    # w.grad.data = torch.Tensor([0])
    print(-2*x*(y-y_))

核心就是增加了w = Variable(w - 0.1 * w.grad.data,requires_grad=True)这个代码,熟悉深度学习的应该不陌生,其实就是更新了w,0.1相当于学习率。最后输出为:

tensor([-2.0593], requires_grad=True)
tensor([-56.4745])
tensor([3.5881], requires_grad=True)
tensor([-56.4745], grad_fn=<MulBackward0>)
tensor([-11.2949])
tensor([4.7176], requires_grad=True)
tensor([-11.2949], grad_fn=<MulBackward0>)
tensor([-2.2590])
tensor([4.9435], requires_grad=True)
tensor([-2.2590], grad_fn=<MulBackward0>)
tensor([-0.4518])
tensor([4.9887], requires_grad=True)
tensor([-0.4518], grad_fn=<MulBackward0>)
tensor([-0.0904])
tensor([4.9977], requires_grad=True)
tensor([-0.0904], grad_fn=<MulBackward0>)
tensor([-0.0181])
tensor([4.9995], requires_grad=True)
tensor([-0.0181], grad_fn=<MulBackward0>)
tensor([-0.0036])
tensor([4.9999], requires_grad=True)
tensor([-0.0036], grad_fn=<MulBackward0>)
tensor([-0.0007])
tensor([5.0000], requires_grad=True)
tensor([-0.0007], grad_fn=<MulBackward0>)
tensor([-0.0001])
tensor([5.0000], requires_grad=True)
tensor([-0.0001], grad_fn=<MulBackward0>)
tensor([-3.0518e-05])
tensor([5.0000], requires_grad=True)
tensor([-3.0518e-05], grad_fn=<MulBackward0>)

很明显看出最后w更新为5了,和我们的函数拟合上了。这里你可能会问这个也没有做梯度置为0的操作啊,之所以没做是因为我们w重新赋了值,所以里面的w.grad.data变为None了,所以不用重新置为0了。

说在最后,其实上面这个例子过于简单,所以可能看完还是和你用的nn.Linear这种操作无法联系到一起,其实我们的w就相当于nn.Linear中的w,只不过pytorch封装起来了,你看不到,而x就相当于你输入的数据,比如mnist的12828的那个矩阵。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值