导数描述了函数在某一点处的瞬时变化率,即函数在该点处切线的斜率。
微分则是函数在某一点处的局部线性逼近,可以看作是导数的一个近似。如果一个函数f(x)在每个点a处存在导数,我们就称f(x)在a处是可微的。
用途:
- 在神经网络训练中,要让模型变得更好则意味着最小化一个损失函数(loss function)。
- 我们通常会选择对于模型参数可微的损失函数,这样就能通过导数来确定函数的局部极值点。
- 如果沿着导数的负方向更新参数,就能减小损失函数的值。
如果用D表示微分,则可以使用以下规则来对常见函数求导:
对于一些由常见函数组成的函数,则有以下规则:
1)函数与常数相乘求导:
2)函数相加求导:
3)函数相乘求导:
4)函数相除求导:
上面都是对于可微的函数,要想对不可微的函数例如y=|x|
求导,可以采用亚导数
,D|x|有以下三种情况:
将导数由标量拓展到向量后,就称为梯度,梯度一定指向值变化最大的方向。
向量求导要特别注意形状的变化。
梯度计算的目的是寻找变化最大的点。
用途:优化模型的参数,通过梯度可以确定参数的更新方向和大小,使得模型逐渐优化,损失函数逐渐减小。
定义:复合函数的导数等于外层函数对内层函数的导数乘以内层函数对自变量的导数。
链式法则主要用于对深度学习中的是复合多元函数进行求导,假设y=f(u)
, u=g(x)
,则y对x的求导为:
链式法则求导示例:
自动求导是通过计算图做出来的,计算图基本和链式法则的求导过程原理相似:
计算图分为显式构造和隐式构造:
求导的目的是为了寻找参数更新的方向和大小,自动求导有两种方式:
正向传播(又称前向传播),从输入层开始,每一层计算的输出结果作为下一层的输入,继续向前传播,最终得到整个神经网络的输出结果(图中从a->b->z)。
在前向传播过程中,每一层的神经元接收上一层的输出,并根据权重和偏置进行加权求和,并经过激活函数进行非线性变换,得到该层的输出结果。
反向累积:
正向累积和反向累积的对比:
正向累积的问题在于:每层计算都要扫一遍前向传播的过程。
原因:梯度是通过链式法则逐层传播得到的,为了计算某一层的梯度,需要先计算该层之前的所有层的输出结果,也就是需要重复进行前向传播过程。
在神经网络训练过程中,会先走前向传播,再走反向传播。
通过计算损失函数对模型参数的梯度,可以确定参数的更新方向和大小,从而使模型向损失函数的最小值方向调整。
保存前向传播的中间结果,具体是指:
这些变量或值在前向传播过程中会被计算,保存为中间结果后,也能用于反向传播的梯度计算和更新参数。
假设x
是一个列向量,y=2*x*x
import torch
# 等价x=torch.arange(4.0,requires_grad=True)
x = torch.arange(4.0) # tensor([0., 1., 2., 3.])
x.requires_grad_(True) # 找一个地方来保存向量x的梯度值
x.grad # 梯度值初始是None
计算y:
y = 2 * torch.dot(x, x)
y
> tensor(28., grad_fn=<MulBackward0>)
对y调用反向传播函数来计算x向量每个分量(元素)的梯度:
y.backward() # 反向传播计算梯度
x.grad # 输出向量x的梯度
> tensor([ 0., 4., 8., 12.])
这与我们手动求导得出的结果一致(y=2*x*x
对于x
的梯度 =4x
)。