深度学习的基础
常见的临界点的种类为局部最小值和鞍点
task1.1
1.局部最小值
对于任何目标函数f(x),如果在x处对应的f(x)值小于在x附近任意其他点的f(x)值,那么f(x)可能是局部最小值。如果f(x)在x处的值是整个域中目标函数的最小值,那么f(x)是全局最小值。
我们可以看一个例子:
f(x) = x · cos(πx) for − 1.0 ≤ x ≤ 2.0
%matplotlib inline
import numpy as np
import torch
from mpl_toolkits import mplot3d
from d2l import torch as d2l
def f(x):
return x*torch.cos(np.pi*x)
def g(x):
return f(x)+0.2*torch.cos(5*np.pi*x)
def annotate(text,xy,xytext): #@save
d2l.plt.gca().annotate(text,xy=xy,xytext=xytext,arrowprops=dict(arrowstyle='->'))
x=torch.arange(-1.0,2.0,0.01)
d2l.plot(x,[f(x),],'x','f(x)')
annotate('local minimum',(-0.3,-0.25),(-0.77,-1.0))
annotate('global minimum',(1.1,-0.95),(0.6,0.8))
在这个例子中,我们能够很明显的区分出局部最小值和全局最小值
2.鞍点
鞍点(saddle point)是指函数的所有梯度都消失但既不是全局最小值也不是局部最小值的任何位置。
%matplotlib inline
import numpy as np
import torch
from mpl_toolkits import mplot3d
from d2l import torch as d2l
def f(x):
return x*torch.cos(np.pi*x)
def g(x):
return f(x)+0.2*torch.cos(5*np.pi*x)
def annotate(text,xy,xytext): #@save
d2l.plt.gca().annotate(text,xy=xy,xytext=xytext,arrowprops=dict(arrowstyle='->'))
x=torch.arange(-2.0,2.0,0.01)
d2l.plot(x,[x**3],'x','f(x)')
annotate('saddle point',(0,-0.2),(-0.52,-5.0))
怎么判断一个临界点的种类,有什么方法呢?接下来我们一起学习一下:
网络本身很复杂,用复杂网络算出来的损失函数显然也很复杂。虽然无法完整知道整个损失函数的样子,但是如果给定某一组参数,比如 θ′,在 θ′ 附近的损失函数是有办法写出来的——虽然 L(θ) 完整的样子写不出来。θ′ 附近的 L(θ) 可近似为:
其中,第一项 L(θ)′ 告诉我们,当 θ 跟 θ′ 很近的时候,L(θ) 应该跟 L(θ′) 还蛮靠近的;第二项 θg 中,g 代表梯度,它是一个向量,可以弥补 L(θ′) 跟 L(θ) 之间的差距。有时候梯度 g 会写成 ∇L(θ′)。gi 是向量 g 的第 i 个元素,就是 L 关于 θ 的第 i 个元素的微分,即
但是看 g 还是没有办法完整地描述 L(θ),还要的第三项 。第三项跟海森矩阵(Hessian matrix)H 有关。H 里面放的是 L 的二次微分,它第 i 行,第 j 列的值 HiHij 就是把 θ 的第 i 个元素对 L(θ′)作微分,再把 θ 的第 j 个元素对
作微分后的结果,即
在临界点,梯度 g 为零,因此 为零。所以在临界点的附近,损失函数可被近似为L(θ) ≈
为了符号简洁,我们用向量 v 来表示 θ − θ′,可改写为
,有如下三种情况。
(1)如果对所有 v, > 0. 这意味着对任意 θ,L(θ) > L(θ′). 只要 θ 在 θ′ 附近,L(θ) 都大于 L(θ′). 这代表 L(θ′) 是附近的一个最低点,所以它是局部极小值。
(2)如果对所有 v, < 0. 这意味着对任意 θ,L(θ) < L(θ′),θ′ 是附近最高的一个点,L(θ′) 是局部极大值。
(3)如果对于 v,有时候大于零,有时候小于零。这意味着在 θ′ 附近,有时候L(θ) > L(θ′),有时候 L(θ) < L(θ′). 因此在 θ′ 附近,L(θ′) 既不是局部极大值,也不是局部极小值,而是鞍点。
但是我们根据来判断临界点的种类,需要带入所有的θ,比较复杂,所以我们使用
的正负来判断会更简单。算出一个海森矩阵后,不需要把它跟所有的 v 都乘乘看,只要看 H的特征值。若 H 的所有特征值都是正的,H 为正定矩阵,则 v^{T}Hv > 0,临界点是局部极小值。若 H 的所有特征值都是负的,H 为负定矩阵,则
< 0,临界点是局部极大值。若 H 的特征值有正有负,临界点是鞍点。
接下来我使用李宏毅老师的ppt来用例子再解释一下:
在深度学习中,判断临界点的种类可以通过以下几种方法进行详细解释:
1. 梯度方法:梯度是指函数在某一点的变化率,对于一个临界点来说,梯度为零。因此,可以通过计算网络参数的梯度来判断是否达到了临界点。如果梯度接近于零,表明参数已经收敛到一个临界点。
2. Hessian矩阵方法:Hessian矩阵是二阶导数矩阵,它可以提供有关函数在某一点的曲率信息。对于一个临界点来说,Hessian矩阵的特征值为零。因此,可以通过计算网络参数的Hessian矩阵来判断是否达到了临界点。如果主特征值接近于零,表明参数已经收敛到一个临界点。
3. 自适应学习率方法:自适应学习率是指根据网络参数的变化情况自动调整学习率的方法。在训练过程中,如果自适应学习率几乎不再变化,说明参数已经收敛到一个临界点。
4. 梯度探索方法:梯度探索是指在训练过程中,通过调整网络参数的初始值、学习率等超参数,反复训练网络,观察网络达到的各个临界点的性能变化。如果在某个临界点的性能变化较小,说明参数已经收敛到该临界点。
这些方法可以帮助判断网络参数是否达到了临界点,但需要注意的是,临界点并不一定是局部最小值,也可能是鞍点或局部最大值。因此,判断网络参数是否收敛到一个理想的临界点还需要结合其他信息和经验。
task1.2 批量和动量
在现实生活中,我们计算梯度时并不是对所有数据的损失 L 计算梯度,而是把所有的数据分成一个一个的批量。
根据下面这个图,每一个B都是一个小批量即带有 B 笔数据。每次在更新参数的时候,会去取出 B 笔数据用来计算出损失和梯度更新参数。遍历所有批量的过程称为一个次epoch。每一次epoch遍历完进行第二次时,会进行shuffle打乱批量顺序,使得每次遍历的批量顺序都不一样。
大批量:其实就是整个数据,不分开。使用全批量更新参数叫批量梯度下降BGD,这种方法需要把所有数据训练完才可以计算损失和梯度,然后才进行更新。
小批量:随机梯度下降SGD,每次取出一笔数据,如果有20个数据,那么参数更新20次。每笔数据训练完就可以计算损失和梯度。
1.批量法
那么两种批量方法哪一种更好呢?
可能大家会想每一次BGD都需要遍历所有的数据,而SGD一次只需要遍历一小部分,小批量的这个花费时间更小。但是当我们使用GPU并行计算时,可能并不会使BGD的时间比SGD的长
有人已经在MNIST数据集中,试验了这两种方法得到了结果曲线
在上图中可以看到,在批量大小为1000时,计算时间很短。由于GPU也有并行计算的极限,所以在数据很大时,会花费很长的时间。
接下来,再看一看在不同数据集上两个批量梯度下降法的执行结果
在图上可以看出来,批量大小越大,验证集准确率越差。但这不是过拟合,因为批量大小越大,训练准确率也是越低。因为用的是同一个模型,所以这不是模型偏见的问题。 但大的批量大小往往在训练的时候,结果比较差。这个是优化的问题,大的批量大小优化可能会有问题,小的批量大小优化的结果反而是比较好的。
因为在批量梯度下降更新参数时,沿着一个损失函数来更新参数,走到一个局部最小值或鞍点显然就停下来了。梯度是零,如果不看海森矩阵,梯度下降就无法再更新参数了 。但小批量梯度下降法(mini-batch gradient descent)每次是挑一个批量计算损失,所以每一次更新参数的时候所使用的损失函数是有差异的。选到第一个批量的时候,用 L1 计算梯度;选到第二个批量的时候,用 L2 计算梯度。假设用 L1 算梯度的时候,梯度是零,就会卡住。但 L2 的函数跟 L1 又不一样,L2 不一定会卡住,可以换下个批量的损失 L2 计算梯度,模型还是可以训练,还是有办法让损失变小,所以这种有噪声的更新方式反而对训练其实是有帮助的。
2.动量法
动量法其实根据它的名字就可以看出来,动量类似于物理学中的动量,当一个小球从一个坡上滚下来时,它可能不会因为走到了鞍点或者局部最小值就会停下,由于惯性的原因会继续运动。
一般的梯度下降(vanilla gradient descent)如下图所示。初始参数为 θ0,计算一下梯度,计算完梯度后,往梯度的反方向去更新参数 θ1 = θ0 − ηg0。有了新的参数 θ1 后,再计算一次梯度,再往梯度的反方向,再更新一次参数,到了新的位置以后再计算一次梯度,再往梯度的反方向去更新参数。
使用动量后,每次更新参数的时候,会根据梯度的反方向和前一步移动的方向共同决定参数的更新方向。
那么动量有什么好处呢? 它不会只根据梯度决定向哪个方向更新,结合前一步的方向共同判断,可以使得在局部最小值和鞍点处止步的小球越过所谓的山丘,继续前行。
这就是所谓的动量法。
说句人生感慨的话,我们的人生也是一样,不要一遇到困难或坎坷就被困在原地,要想想我们曾经的辉煌,走到现在着实不易,既然辉煌过那么就有下一次的来临,永远都不要轻易放弃!希望小伙伴们都有精彩的人生。