一、梯度介绍
梯度是一个向量,是学习(参数更新的方向)。收集数据,构建机器学习模型,得到
判断模型好坏的方法:
(回归损失)
(分类损失)
通过调整参数,尽可能降低
随机选择一个起始,通过调整,使得函数取得最小值。
的更新方法:
①计算的梯度(即导数):
②更新:
其中,,意味着将增大, ,意味着将减小。当小到一定的程度或者循环达到一定次数后,或停止循环。
二、反向传播算法
2.1计算图和反向传播
计算图:通过图的方式来描述函数的图形。
例如,令,,将其绘制为计算图可以表示为:
绘制为计算图后,可以清楚地看到向前计算的过程,之后对每个节点求偏导可以有:
则反向传播的过程就是一个上图的从左到右的过程,自变量各自的偏导就是连线上的梯度的乘机:。
2.2神经网络中的反向传播
表示网络第n层权重,表示第n层第i个神经元,连接到第n+1层第j个神经元的权重。
将其化为计算图可得:
其中的f函数是激活函数,是根据损失函数对预测值进行求导得到的结果。
则此时的偏导,通过观察,发现out到的连线有两条。结果为:
其中的指的是传入数据后的求偏导。
这样做,当模型很大的时候,计算量会很大,所以反向传播的思想是对其中某一个参数单独求梯度:
不会一次性地从输出层计算到输入层,而是一层一层地反向传播,
更新参数之后,继续反向传播:
继续反向传播:
通常的描述为:
三、pytorch中反向传播和梯度计算
3.1向前计算
对于pytorch中的一个tensor,如果设置它的属性.requires_grad为True,那么它会追踪该张量的所有操作。或者可以理解为,这个tensor是一个参数,后续会被计算梯度,更新该参数。
假设有以下条件(1/4表示求均值,为2*2的矩阵),使用torch完成向前的计算过程
其中:
如果为参数,需要对其进行梯度的计算和更新。则最开始指定的值的过程中,需要指定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(),进行深拷贝。