pytorch——梯度计算

一、梯度介绍

        梯度是一个向量,是学习(参数更新的方向)。收集数据x,构建机器学习模型f,得到f(x,w)=Y_{predict} 

判断模型好坏的方法:

(回归损失)

loss=Y_{true}\cdot log(Y_{predict})(分类损失) 

        通过调整参数w,尽可能降低loss

         随机选择一个起始w_{0},通过调整w_{0},使得loss函数取得最小值。

        w的更新方法:

①计算w的梯度(即导数):grad(w)=\frac{f(w+0.000001)-f(w-0.000001)}{2*0.000001}

②更新ww=w-\alpha *grad(w)

        其中,grad(w)<0,意味着w将增大, grad(w)>0,意味着w将减小。当w小到一定的程度或者循环达到一定次数后,或停止循环。

二、反向传播算法

2.1计算图和反向传播

        计算图:通过图的方式来描述函数的图形。

        例如J(a,b,c)=3(a+bc),令u=a+vv=bc,将其绘制为计算图可以表示为:

         绘制为计算图后,可以清楚地看到向前计算的过程,之后对每个节点求偏导可以有:

         则反向传播的过程就是一个上图的从左到右的过程,自变量a,b,c各自的偏导就是连线上的梯度的乘机:\frac{dJ}{da}=3\times 1, \frac{dJ}{db}=3\times 1\times c,\frac{dJ}{dc}=3\times 1\times b

2.2神经网络中的反向传播

        w1,w2,...,wn表示网络第n层权重,w_{n}[i,j]表示第n层第i个神经元,连接到第n+1层第j个神经元的权重。

         将其化为计算图可得:

         其中的f函数是激活函数,grad(out)是根据损失函数对预测值进行求导得到的结果。   

        则此时w1[1,2]的偏导,通过观察,发现out到w1[1,2]的连线有两条。结果为:

         其中的grad(out)指的是传入数据后的Y_{predict}求偏导。

        这样做,当模型很大的时候,计算量会很大,所以反向传播的思想是对其中某一个参数单独求梯度:

        不会一次性地从输出层计算到输入层,而是一层一层地反向传播,

         更新参数之后,继续反向传播:

                 继续反向传播:

                 通常的描述为:

grad(a_{l}^{i})=f{}'(a_{i}^{l})*(\sum_{j=1}^{m}w_{i,j}*grad(a_{j}^{l+1}))

三、pytorch中反向传播和梯度计算

3.1向前计算

         对于pytorch中的一个tensor,如果设置它的属性.requires_grad为True,那么它会追踪该张量的所有操作。或者可以理解为,这个tensor是一个参数,后续会被计算梯度,更新该参数。

        假设有以下条件(1/4表示求均值,x_{i}为2*2的矩阵),使用torch完成向前的计算过程

o=\frac{1}{4}\sum z_{i}

z_{i}=3(x_{i}+2)^{2}

其中: x_{1}=1,z_{1}=27

        如果x为参数,需要对其进行梯度的计算和更新。则最开始指定x的值的过程中,需要指定requires_grad为True

>>> import torch
>>> x = torch.ones(2,2,requires_grad = True)
>>> x
tensor([[1., 1.],
        [1., 1.]], requires_grad=True)
>>> y = x + 2
>>> y
tensor([[3., 3.],
        [3., 3.]], grad_fn=<AddBackward0>)
>>> z = y ** 2 * 3
>>> z
tensor([[27., 27.],
        [27., 27.]], grad_fn=<MulBackward0>)
>>> out = z.mean()
>>> out
tensor(27., grad_fn=<MeanBackward0>)

从上可以看出,每次的操作都会修改其grad_fn属性,用来记录做过的操作。

        为了防止跟踪历史记录(和使用内存),可以将代码块包装在with torch.no_grad():中。在评估模型时特别有用,因为模型可能具有requires_grad = True的可训练的参数,但是我们不需要在此过程中对他们进行梯度计算。

import torch

a = torch.randn(2,2)
a = ((a * 3) / (a - 1))
print(a.requires_grad)#False
a.requires_grad_(True)#更改
print(a.requires_grad)#True
b = (a * a).sum()
print(b.grad_fn)#<SumBackward0 object at 0x00000148E9E46188>
with torch.no_grad():
    c = (a * a).sum()

print(c.requires_grad)#False

3.2梯度计算 

        对于3.1中的out而言,我们可以用backward方法进行反向传播,计算梯度out.backward(),此时便能够求出导数d(out)/d(x),调用x.grad能够获取导数值,如下:

>>> out
tensor(27., grad_fn=<MeanBackward0>)
>>> out.backward()
>>> x.grad
tensor([[4.5000, 4.5000],
        [4.5000, 4.5000]])         #x为1时,值为4.5

         在输出为一个标量的情况下,我们可以调用tensor的backward()方法,但是在数据是一个向量的时候,调用backward()的时候还需要传入其他参数torch.ones_like(输入名)。loss.backward()就是根据损失函数,计算其梯度,并且将其累加保存到x_gard,此时还并未更新其梯度。在第二次反向传播时,应该先对参数的梯度清零。

注意:

        tensor.data:在tensor的require_grad=False,tensor.data和tensor等价。require_grad = True时,tensor.data仅是获取tensor中的数据,不带grad等属性。

        tensor.numpy():require_grad = True时,不能够直接转换,需要使用tensor.detach().numpy(),进行深拷贝。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值