在我们学习深度学习的路上,肯定会碰到梯度下降法。而理解梯度下降法的前提是,自动求导。
自动求导
神经网络的目的是为了逼近某个函数,而这些函数基本上都是多元函数,而对多元函数的求导,我们求的是偏导,比如下面的例子:(我们以线性多元函数为例)
①先以一维标量的例子:
y = 2 * a + a * b, 求在a=2, b=4 出y对于a 和 b 的偏导,手算过程如下:
我们可以看出y是复合函数。所以我们设:
y = f1 + f2
f1 = 2 * a
f2 = a * b
则:
同理得,对b求偏导为:
这里就用到了链式法则,链式法则的简例为:
而y = 2 * a + a * b,在python的实现为:(此处用pytorch框架来实现)
首先我们先构建这个方程式,构建该方程式的过程为正向传播,也称为计算图的构建
计算图的构建如下:
代码实现如下:
import torch
a = torch.tensor(2., requires_grad=True)
b = torch.tensor(4., requires_grad=True) // 在这里要注意a和b必须为浮点数
f1 = 2 * a
f2 = a * b
y = f1 + f2 // 构建的过程称为正向传播
y.backward() // 反向传播
a.grad, b.grad
// 结果为:(tensor(6.), tensor(2.))
// 以上为在jupyter中实现的
在这里可以验证和我们手算的结果相同
②在以多维,矩阵的例子来介绍自动求导:
不妨设:c为一个2 * 4的矩阵,d为4 * c,e为d中每个元素的平方,f为e中每个相加后除以元素的个数(求均值),然后求f在c=[[1,2,3,4],[5,6,7,8]]下的偏导。如下图:
在这里计算的时候要注意和矩阵中的计算有点小差别。
计算的过程为:
代码实现如下:
c = torch.arange(1.0, 9.0).reshape(2,4)
c.requires_grad_(True) // 标记需要对c进行求导
d = 4 * c
e = torch.mul(d, d) // 等价于e = d * d
f = e.mean() // 元素相加求平均
// 以上为正向传播的过程
f.backward() // 反向传播
c.grad
//answer为:tensor([[ 4., 8., 12., 16.],[20., 24., 28., 32.]])
可以验证和手算的的结果相同(小瑕疵在手算的过程,矩阵中的数应该为浮点数,而我用的是int,在代码中必须是浮点数,要不然报错)
在这里要着重注意的一点是:
在pytorch中求导,只能是标量对标量,标量对向量或矩阵求导!若向量或矩阵对(标量,向量,矩阵)求导会报错!!!
③变量不需要求导
假如我们在计算某个变量的过程中,该变量不需要进行求导,可以有如下两种写法:
//第一种
with torch.no_grad():
g = e.mean()
f, g
//answer: (tensor(408., grad_fn=<MeanBackward0>), tensor(408.))
可以看出g是没有求导这个属性的
//第二种
h = f.detach()
f, h
//answer: (tensor(408., grad_fn=<MeanBackward0>), tensor(408.))
可以看出h也是没有求导这个属性的
ok,自动求导大致为这样,而我们学习自动求导的其中一个目的为了梯度下降法
码字不易,求三连!!!
完整代码链接:自动求导完整代码
希望大家都能学会✨✨✨✨✨✨