目录

1.数学优化问题

1.1梯度问题:

1.2凸函数问题与梯度下降

1.2.1凸集与凸函数

1.2.2梯度下降

1.2.3梯度下降的参数求解

1.2.4梯度下降步骤

1.2.5迭代的终止条件

1.2.6代码实现

1.3求最优解的方法

1.3.1梯度下降法

1.3.2牛顿法

1.3.3拟牛顿法

1.3.4启发式优化方法

1.3.5EM算法

1.4 损失函数(基于pytorch)

1.4.1 L1 Loss函数:

1.4.2 L2 Loss函数:

1.4.3 Smooth L1 Loss函数

1.4.4 交叉熵损失函数(CrossEntropy Loss)

1.4.5 NLL Losss损失函数

2.线代矩阵分析

3.概率计算类


这部分内容属于大学以及考研的数学基础,如果这部分有不了解的部分,可以先去b站听一些相关的基础课程,这边我只强调一些较为重要的部分。

1.数学优化问题

1.1梯度问题:

梯度和导数是密切相关的一对概念,实际上梯度是导数对多元函数的推广,它是多元函数对各个自变量求偏导形成的向量。中学时,我们接触“微分”这个概念是从“函数图像某点切线斜率”或“函数的变化率”这个认知开始的。梯度实际上就是多变量微分的一般化,例如:

J(\theta)=3\theta_1+4\theta_2-5\theta_3-1

对该函数求解微分,也就得到了梯度:

\nabla J\left(\theta\right)=\left\langle\dfrac{\partial J}{\partial\theta_1},\dfrac{\partial J}{\partial\theta_2},\dfrac{\partial J}{\partial\theta_3}\right\rangle=\left\langle3,\textbf{4,-5}\right\rangle

梯度的本意是一个向量,表示某一函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)。用人话说,就是如果按照梯度方向变化,函数值变化最大,梯度下降就是按照这个原理来的。

1.2凸函数问题与梯度下降

优化问题可以分为凸优化问题和非凸优化问题,非凸优化问题相对凸优化问题来说要困难得多,一个问题如果可以表述为凸优化问题,很大程度上意味着这个问题可以被彻底解决,而非凸优化问题常常无法被解决。因此,凸优化在数学规划领域具有非常重要的地位。凸优化问题是指定义在凸集中的凸函数最优化的问题,它在机器学习领域有十分广泛且重要的应用,典型应用场景就是目标函数极值问题的求解。凸优化问题的求解目前已经较为成熟,所以当一个极值求解问题被归为凸优化问题时往往意味着该问题是可以被求解的。凸优化问题的局部最优解就是全局最优解,因此机器学习中很多非凸优化问题都需要被转化为等价凸优化问题或者被近似为凸优化问题。(啥叫凸优化,举个最简单的例子y=ax^{2}就是一个典型的  凸函数,可以找到最优解,找解的过程就是凸优化)

1.2.1凸集与凸函数

凸集表示一个欧几里得空间中的区域,这个区域具有如下特点:区域内任意两点之间的线段都包含在该区域内;更为数学化的表述为,集合C内任意两点间的线段也均在集合C内,则称集合C为凸集。

 上图中a,b,c满足凸集要求,d不满足,d中并不是所有点的欧式距离都在都在被线段分割出来的集合当中。

 

那么啥是凸函数,先看一个冰冷的公式:

f((x_{1}+x_{2})/2)\leqslant(f(x_{1})+f(x_{2}))/2

凸函数是一个定义在某个向量空间的凸子集C(区间)上的实值函数f,而且对于凸子集C中的任意两个向量,如果f((x_{1}+x_{2})/2)\leqslant(f(x_{1})+f(x_{2}))/2则f(x)是定义在凸子集C中的凸函数。实际上,如果某函数的上镜图(函数曲线上的点和函数曲线上方所有的点的集合)是凸集,那么该函数就是凸函数。为了方便快速理解直接上图。

                                          a凸,b非凸

可以发现:凸函数图像任意两点连接而成的线段与函数没有交点。通常,我们可以考虑使用这条规则来快速判断函数是否为凸函数。从图中我们就可以看出凸函数的局部极小值就是全局最小值。这样,我们就可以利用这条性质快速找到问题的最优解。机器学习中有很多优化问题都要通过凸优化来求解,另外一些非凸优化问题也常常被转化为凸优化问题来求解。

                                          a凸曲面,b非凸曲面

如果我们将一颗弹珠扔到曲面中,会出现不同的情况。当函数是凸函数时[(a)所示的凸曲面],无论弹珠起始位置在何处,弹珠最终都会落在曲面的最低点,而这个极小值恰好是全局最小值。当函数是非凸函数时[(b)所示的非凸曲面],弹珠仍然会落在曲面的某个低点,但这个极小值不能保证是全局最小值。
上述弹珠下降的过程跟梯度下降的最优化算法思想是类似的,这也正是我们“热爱”凸函数的原因。实际上,学术界对于非凸优化的优化问题也没有一个很好的通用解决方法,所以我们定义损失函数的时候尽量将其定义为凸优化问题或者转化为等价凸优化问题,这样有助于问题的求解。

1.2.2梯度下降

机器学习算法都可归结为凸优化问题的求解,梯度下降法是最简单、也是最常见的一种最优化问题求解方法。机器学习中一般将凸优化问题统一表述为函数极小值求解问题,即minf(x)。其中x是需要被优化的变量,f为目标函数。如果碰到极大值问题,则可以将目标函数加上负号,从而将其转换成极小值问题来求解。目标函数的自变量x往往受到各种约束,满足约束条件的自变量x的集合称为自变量的可行域。

梯度下降法是一种逐步迭代、逐步缩减损失函数值,从而使损失函数值最小的方法。如果把损失函数的值看作一个山谷,我们刚开始站立的位置可能是在半山腰,甚至可能是在山顶。但是,只要我们往下不断迭代、不断前进,总可以到达山谷,也就是损失函数的最小值处。例如,假设一个高度近视的人在山的某个位置上(起始点),需要从山上走下来,也就是走到山的最低点。这个时候,他可以以当前位置点(起始点)为基准,寻找这个位置点附近最陡峭的地方,然后朝着山的高度下降的方向走,如此循环迭代,最后就可以到达山谷位置。

首先,选取任意参数(ω和b)值作为起始值。刚开始,我们并不知道使损失函数取得最小值的参数(ω和b)值是多少,所以选取任意参数值作为起始值,从而得到损失函数的起始值。
其次,明确迭代方向,逐步迭代。我们站在半山腰或者山顶,环顾四周,找到一个最陡的方向下山,也就是直接指向山谷的方向下山,这样下山的速度是最快的。这个最陡在数学上的表现就是梯度,也就是说沿着负梯度方向下降能够最快到达山谷。
最后,确定迭代步长。下山的起始点知道了,下降的方向也知道了,还需要我们确定下降的步长。如果步长太大,虽然能够更快逼近山谷,但是也可能由于步子太大,踩不到谷底点,直接就跨过了山谷的谷底,从而造成来回振荡。如果步长太小,则延长了到达山谷的时间。所以,这需要做一下权衡和调试。(太短学的慢,太长容易跨过最优处)
上述梯度下降的过程中有个问题需要特别注意,就是当我们沿着负梯度方向进行迭代的时候“每次走多大的距离”,也就是“学习率”的大小是需要算法工程师去调试的;或者说,算法工程师的一项工作就是要调试合适的“学习率”,从而找到“最佳”参数。(学习率也被称为迭代的步长

1.2.3梯度下降的参数求解

梯度下降是一种求解凸函数极值的方法,它以损失函数作为纽带,损失函数是模型预测值与训练集数据真实值的差距,它是模型参数(如ω和b)的函数。这里需要注意区分一个细节,损失函数有时候指代的是训练集数据中单个样本的预测值与真实值的差距,有时候指代的则是整个训练集所有样本的预测值与真实值的差距(也称为成本函数)。
例如训练集有100个样本,那么参数求解的过程中模型会对这100个样本逐一预测并与其真实值比较。根据损失函数可以求得每个样本的预测偏差值。有时候某组模型参数(如ω和b)使得其中某个样本(如1号样本)损失函数值最小,但可能导致其他样本(如2号样本、3号样本等)损失函数值很大,所以我们不能只看一部分样本的损失函数值就决定模型参数,而应该考虑总体情况。成本函数描述的就是样本总体的预测偏差情况,它可以是各个样本损失函数值之和,也可以是各个样本损失函数值之和的平均值。
所以损失函数描述的是个体预测值与真实值的差距,成本函数描述的是总体预测值与真实值的差距,但由于两者本质上一致且只在引入样本数据进行模型实际求解的时候才需要严格区分,因此大部分图书中并未严格区分两者,往往都是用损失函数来统一指代

1.2.4梯度下降步骤

首先看一下梯度下降的迭代公式:

\theta^1=\theta^0-a\nabla J(\theta)

任意给定一组初始参数值\theta_{0},只要沿着损失函数J()的梯度下降方向前进一段距离a,就可以得到一组新的参数值\theta_{1}。这里的\theta_{0}\theta_{1}对应到机器学习中就是指模型参数(如ω和b)。

来看一个实际的案例:

J(\theta)=\theta_{1}^{2}+\theta_{2}^{2}

根据微积分的知识很容易知道损失函数在点(0,0)处取得最小值。接下来,我们就通过该例子来体会梯度下降法如何一步一步找到(0,0)这个最佳参数值,从而使得损失函数在该点取得最小值。
假设参数的起始值:初始学习率为a=0.1

\theta^{0}=(4,-2)

由此可以知道该点(4,-2)的函数梯度为:

\nabla J(\theta)=\left\langle\dfrac{\partial J}{\partial\theta_1},\dfrac{\partial J}{\partial\theta_2}\right\rangle=\left\langle2\theta_1,2\theta_2\right\rangle

开始迭代:
\theta^1=\theta^0-a\nabla J(\theta)

1.2.5迭代的终止条件

  • 设置阈值。设置一个迭代结束的阈值,当两次迭代结果的差值小于该阈值时,迭代结束。(就是两者的函数值变化在阈值之内,变化很小可以认为基本趋向于极值
  • 设置迭代次数。设置一个迭代次数(如200),当迭代次数达到设定值,迭代结束。一般来说,只要这个迭代次数设置得足够大,损失函数最终都会停留在极值点附近。同时,采用这种方法我们也不用担心迭代次数过多会导致损失函数“跑过”极值点的情况,因为损失函数在极值点时函数梯度为0,一旦过了极值点函数梯度正负性就发生变化了,会使函数围绕极值点再次“跑回来”。所以,即使设置的迭代次数过大,最终结果也会在极值点处“徘徊”。(一般机器学习采取降低学习率,提高迭代次数来寻找最优解

1.2.6代码实现

一元函数:

f(x)=x^{2}+3

梯度为:   

{\frac{\mathrm{d}f}{\mathrm{d}x}}=2x

代码:暂时略

多元函数:

f(x,y)=x^{2}+y^{2}

梯度为:f'(x)=2x,f'(y)=2y

代码:暂时略

1.3求最优解的方法

1.3.1梯度下降法

一,批量梯度下降(Batch Gradient  Descent,BGD)

为了方便理解,我们用一个线性回归举例子:

h_\theta\bigl(x^{(i)}\bigr)=\theta_1x^{(i)}+\theta_0

其中 i=1,2,...,m表示样本数。

我们将损失函数设置为(此处可能有人会疑惑为什么是2m,主要方便后面求导):

J(\theta_0,\theta_1)=\dfrac{1}{2m}\sum_{i=1}^m(h_\theta(x^{(i)})-y^{(i)})^2

对于批梯度下降来说,就是在更新每一参数时都使用所有的样本来进行梯度更新(准确来说是样本的均值)。下面看一下梯度更新的公式:
\frac{\partial J(\theta_0,\theta_1)}{\partial \theta_j}=\dfrac{1}{m}\sum_{i=1}^m(h_\theta(x^{(i)})-y^{(i)})x_j^{(i)}

这时候就会有问题了,有些博主不知道怎么互相抄抄,然后不说明x_j^{(i)是怎么回事,此处令j=0时,x_j^{(i)}= 1,当j=1时,x_j^{(i)由具体值由具体样本确定。 

每次迭代用所有样本对参数进行更新:(可能有小可爱会问,为什么是参数更新,因为这里用的是参数值减去梯度学习值进行参数更新,反映到h_\theta\bigl(x^{(i)}\bigr)中相当于进行了目标函数式梯度下降)

\theta_j:=\theta_j-\alpha\dfrac{1}{m}\sum_{i=1}^m(h_\theta(x^{(i)})-y^{(i)})x_j^{(i)}

看到上面的累加公式了吗,把所有样本点的梯度值累加起来用于参数更新,这样可以求解得到整体的最优解。

优点:
  (1)一次迭代是对所有样本进行计算,此时利用矩阵进行操作,实现了并行。
  (2)由全数据集确定的方向能够更好地代表样本总体,从而更准确地朝向极值所在的方向。当目标函数为凸函数时,BGD一定能够得到全局最优
缺点:
  (1)当样本数目 m很大时,每迭代一步都需要对所有样本计算,训练过程会很慢。
从迭代的次数上来看,BGD迭代的次数相对较少。其迭代的收敛曲线示意图可以表示如下(抄的网图,看一下,大致理解什么意思就可以了):

二,随机梯度下降(Stochastic Gradient Descent,SGD)

随机梯度下降法不同于批量梯度下降,随机梯度下降是每次迭代使用一个样本来对参数进行更新。使得训练速度加快。对于一个样本的目标函数为(损失函数):

J^{(i)}(\theta_0,\theta_1)=\dfrac{1}{2}(h_\theta(x^{(i)})-y^{(i)})^2

对损失函数进行求偏导:
\frac{\partial J^{(i)}(\theta_0,\theta_1)}{\partial \theta_j}=(h_\theta(x^{(i)})-y^{(i)})x_j^{(i)}

对参数进行更新:
\theta_j:=\theta_j-\alpha(h_\theta(x^{(i)})-y^{(i)})x_j^{(i)}

同上面的批量梯度下降:此处令j=0时,x_j^{(i)}= 1,当j=1时,x_j^{(i)由具体值由具体样本确定。(还是拿刚才那个线性回归举例子,但是别死记这个公式)

如果我们的数据集很大,比如几亿条数据,我们的迭代次数(这个迭代的次数其实就是随机样本数,我们再说的通俗点,就是x_j^{(i)}取的个数,每次迭代结束都有一个最优的解,在进行第二次迭代)基本上设置1,2,(10以内的就足够了)就可以。但是SGD也有缺点,因为每次只用一个样本来更新参数,会导致不稳定性大些(可以看下图(图片来自ng deep learning 课),每次更新的方向,不想batch gradient descent那样每次都朝着最优点的方向逼近,会在最优点附近震荡)。因为每次训练的都是随机的一个样本,会导致导致梯度的方向不会像BGD那样朝着最优点。

优点:
  (1)由于不是在全部训练数据上的损失函数,而是在每轮迭代中,随机优化某一条训练数据上的损失函数,这样每一轮参数的更新速度大大加快。
缺点:
  (1)准确度下降。由于即使在目标函数为强凸函数的情况下,SGD仍旧无法做到线性收敛。
  (2)可能会收敛到局部最优,由于单个样本并不能代表全体样本的趋势。
  (3)不易于并行实现。

三,小批量梯度下降(Mini-Batch Gradient Descent, MBGD)

我们知道经典梯度下降虽然稳定性比较强,但是大样本情况下迭代速度较慢;随机梯度下降虽然每一步迭代计算较快,但是其稳定性不太好,而且实际使用中,参数的调整往往更加麻烦。所以,为了协调稳定性和速度,小批量梯度下降应运而生啦。其实很简单,小批量梯度下降法和前面两种梯度下降的主要区别就是每一步迭代过程中目标函数的选择不同。小批量梯度下降是从m个样本中随机且不重k个进行损失函数的求和。下面看个公式:

J(\theta_0,\theta_1)=\dfrac{1}{2k}\sum_{i=1}^k(h_\theta(x^{(i)})-y^{(i)})^2

对损失函数进行求偏导:(其他参数条件同上)
\frac{\partial J(\theta_0,\theta_1)}{\partial \theta_j}=\dfrac{1}{k}\sum_{i=1}^k(h_\theta(x^{(i)})-y^{(i)})x_j^{(i)}

参数更新:

\theta_j:=\theta_j-\alpha\frac{1}{k}(h_\theta(x^{(i)})-y^{(i)})x_j^{(i)}

每次用一部分样本来更新参数,即batch_size。因此,若batch_size=1即k,则变成了SGD,若batch_size=m则变成了batch gradient descent。batch_size通常设置为2的幂次方,通常设置2,4,8,16,32,64,128,256,512(很少设置大于512)。因为设置成2的幂次方,更有利于GPU加速。现在深度学习中,基本上都是用 mini-batch gradient descent,(在深度学习中,很多直接把mini-batch gradient descent(a.k.a stochastic mini-batch gradient descent)简称为SGD,所以当你看到深度学习中的SGD,一般指的就是mini-batch gradient descent)。

优点:
  (1)通过矩阵运算,每次在一个batch上优化神经网络参数并不会比单个数据慢太多。
  (2)每次使用一个batch可以大大减小收敛所需要的迭代次数,同时可以使收敛到的结果更加接近梯度下降的效果。(比如样本的数据为30W,设置batch_size=100时,需要迭代3000次,远小于SGD的30W次)
  (3)可实现并行化。
缺点:
  (1)batch_size的不当选择可能会带来一些问题。
batcha_size的选择带来的影响:
  (1)在合理地范围内,增大batch_size的好处:
    a. 内存利用率提高了,大矩阵乘法的并行化效率提高。
    b. 跑完一次 epoch(全数据集)所需的迭代次数减少,对于相同数据量的处理速度进一步加快。
    c. 在一定范围内,一般来说 Batch_Size 越大,其确定的下降方向越准,引起训练震荡越小。
  (2)盲目增大batch_size的坏处:
    a. 内存利用率提高了,但是内存容量可能撑不住了。
    b. 跑完一次 epoch(全数据集)所需的迭代次数减少,要想达到相同的精度,其所花费的时间大大增加了,从而对参数的修正也就显得更加缓慢。
    c. Batch_Size 增大到一定程度,其确定的下降方向已经基本不再变化。
 

1.3.2牛顿法

牛顿法可以求解函数的极值问题,还可以求解方程的根,求解函数极值就是寻找导数为0的点。核心思想是在某点处用二次函数来近似目标函数,得到导数为0的方程,求解该方程,得到下一个迭代点。因为是用二次函数近似,因此可能会有误差,需要反复这样迭代,直到到达导数为0的点处。

和梯度下降法一样,牛顿法寻找的也是导数为0的点,这不一定是极值点,因此会面临局部极小值和鞍点问题。

牛顿法面临的另外一个问题是Hessian矩阵可能不可逆,从而导致这种方法失效。此外,求解Hessian矩阵的逆矩阵或者求解线性方程组计算量大,需要耗费大量的时间。为此,提出了拟牛顿法这种改进方案,在后面会介绍。

除此之外,牛顿法在每次迭代时序可能不会收敛到一个最优解,它甚至不能保证函数值会按照这个序列递减。解决第一个问题可以通过调整牛顿方向的步长来实现,目前常用的方法有两种:直线搜索和可信区域法。

一,一元函数

根据一元函数的泰勒展开公式,我们对目标函数在x0点处做泰勒展开:

f\big(x\big)=f\big(x_0\big)+f^{'}\big(x_0\big)\big(x-x_0\big)+\dfrac{1}{2}f^{''}\big(x_0\big)\big(x_0\big)^{2}+...+\dfrac{1}{n!}f^{(n)}\big(x_0\big)\big(x-x_0\big)^{n}...

 如果忽略2次以上的项,则有:

f(x)=f(x_0)+f'(x_0)(x-x_0)+\dfrac{1}{2}f''(x_0)(x-x_0)^2

现在我们在点x_0处,要以它为基础,找到导数为0的点,即导数为0。对上面等式两边同时求导,并令导数为0,可以得到下面的方程:(此时将f^{'}\big(x\big)看成了新的函数,0点则为切线与坐标轴交叉带点

f^{'}\big(x\big)=f^{'}\big(x_{0}\big)+f^{''}\big(x_{0}\big)\big(x-x_{0}\big)=0

可以解得:

x=x_0-\frac{f'\left(x_0\right)}{f''\left(x_0\right)}

这样我们就得到了下一点的位置,从而走到x_1。接下来重复这个过程,直到到达导数为0的点,由此得到牛顿法的迭代公式:

x_{t+1}=x_t-\dfrac{f^{'}\left(x_t\right)}{f^{''}\left(x_t\right)}

给定初始迭代点x_0,反复用上面的公式进行迭代,直到达到导数为0的点或者达到最大迭代次数。 

说了这么多可能有点懵逼,直接上图:

二,多元函数

雅克比Jacobian 矩阵:

在向量微积分学中,雅可比矩阵是向量对应的函数(就是多变量函数,多个变量可以理解为一个向量,因此多变量函数就是向量函数)的一阶偏微分以一定方式排列形成的矩阵。如果这个矩阵为方阵,那么这个方阵的行列式叫雅可比行列式。

假设函数f可以将一个n维向量{\vec{x}}({\vec{x}}\in R^{n})变成一个m维向量\operatorname{f}(\vec{x}),f(\vec{x})\in R^{m}(显然f是由m个实函数组成的函数)则函数f的雅可比矩阵:

 对于单个元素而言,可以定义如下:

J_{ij}=\frac{\partial f_i}{\partial x_i}

函数f的雅可比矩阵的其它标记方法为:

\frac{\partial(f_{1},\ldots,f_{m})}{\partial(x_{1},\ldots,x_{n})}

下面看几个维基百科的例子:

 

雅可比矩阵​就是函数f在n维空间某点p处的导数,它是一个线性映射(因为它是一个矩阵,矩阵本身代表着线性变换),它代表着函数f在点p处的最优线性逼近,也就是当x足够靠近点p时,我们有:(代表经过变换后的空间与原空间的面积(2维)、体积(3维)等等的比例,也有人称缩放因子。)

f(x)\approx f(p)+J_{f}(p)*(x-p)

这跟2维空间中在某点附近线性逼近一段曲线很类似,如果雅可比矩阵只有一个元素,它就等于2维空间中曲线在某点处的导数。

海森 Hessian 矩阵:

是一个多元函数的二阶偏导数构成的方阵,描述了函数的局部曲率在工程实际问题的优化设计中,所列的目标函数往往很复杂,为了使问题简化,常常将目标函数在某点邻域展开成泰勒多项式来逼近原函数,此时函数在某点泰勒展开式的矩阵形式中会涉及到海森矩阵。

若一元函数f(x)在点{\boldsymbol{x}}={\boldsymbol{x}}^{(0)}的某个邻域内具有任意阶导数,则:

f\left(x\right)=f\left(x^{(0)}\right)+f^{'}\left(x^{(0)}\right)\Delta x+{\frac{1}{2}}f^{''}\left(x^{(0)}\right)\left(\Delta x\right)^{2}+\cdots

其中:

\Delta x=x-x^{(0)},\Delta x^{2}=\left(x-x^{(0)}\right)^{2}

二元函数在的泰勒展开:

\begin{gathered} f\left(x_1, x_2\right)=f\left(x_1^{(0)}, x_2^{(0)}\right)+\left.\frac{\partial f}{\partial x_1}\right|_{X^{(0)}} \Delta x_1+\left.\frac{\partial f}{\partial x_2}\right|_{X^{(0)}} \Delta x_2+ \\ \frac{1}{2}\left[\left.\frac{\partial^2 f}{\partial x_1^2}\right|_{X^{(0)}} \Delta x_1^2+\left.2 \frac{\partial^2 f}{\partial x_1 \partial x_2}\right|_{X(0)} \Delta x_1 \Delta x_2+\left.\frac{\partial^2 f}{\partial x_2^2}\right|_{X^{(0)}} \Delta x_2^2\right]+\cdots \end{gathered}

其中:

\Delta x_{1}=x_{1}-x_{1}^{(0)},\Delta x_{2}==x_{2}-x_{2}^{(0)}

将上述展开式写成矩阵形式,则有:

f(X)=f\left(X^{(0)}\right)+\left(\frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}\right)_{X^{(0)}}\left(\begin{array}{l} \Delta x_1 \\ \Delta x_2 \end{array}\right)+\left.\frac{1}{2}\left(\Delta x_1, \Delta x_2\right)\left(\begin{array}{cc} \frac{\partial^2 f}{\partial x_1^2} & \frac{\partial^2 f}{\partial x_1 \partial x_2} \\ \frac{\partial^2 f}{\partial x_2 \partial x_1} & \frac{\partial^2 f}{\partial x_2^2} \end{array}\right)\right|_{X^{(0)}}\left(\begin{array}{c} \Delta x_1 \\ \Delta x_2 \end{array}\right)+\cdots

即:

f(X)=f(X^{(0)})+\nabla f(X^{(0)})^T\Delta X+\dfrac{1}{2}\Delta X^T G(X^{(0)})\Delta X+\cdots

其中:

G(X^{(0)})=\left.\begin{pmatrix}\frac{\partial^2f}{\partial x_1^2}&\frac{\partial^2f}{\partial x_1\partial x_2}\\ \frac{\partial^2f}{\partial x_1\partial x_1}&\frac{\partial^2f}{\partial x_2^2}\end{pmatrix}\right|_{X^{(0)}},\Delta X=\left(\begin{matrix}\Delta x_1\\ \Delta x_2\end{matrix}\right)

G(X^{(0)})f\left(x_{1},x_{2}\right)X^{(0)}处的海森矩阵

同理多元函数f(x_{1},x_{2},\cdots,x_{n})X^{(0)}处的泰勒展开为:

f(X)=f(X^{(0)})+\nabla f(X^{(0)})^T\Delta X+\dfrac{1}{2}\Delta X^T G(X^{(0)})\Delta X+\cdots

其中:

\nabla f\left(X^{(0)}\right)=\left.\left[\frac{\partial f}{\partial x_1}, \frac{\partial f}{\partial x_2}, \cdots, \frac{\partial f}{\partial x_n}\right]\right|_{X^{(0)}} ^T

上面为在x_0处的梯度公式

G(X^{(0)})=\begin{bmatrix}\frac{\partial^2f}{\partial x_1^2}&\frac{\partial^2f}{\partial x_1\partial x_2}&\cdots&\frac{\partial^2f}{\partial x_1\partial x_n}\\ \frac{\partial^2f}{\partial x_2\partial x_1}&\frac{\partial^2f}{\partial x_2^2}&\cdots&\frac{\partial^2f}{\partial x_2\partial x_n}\\ \vdots&\vdots&\ddots&\vdots\\ \frac{\partial^2f}{\partial x_1\partial x_1}&\frac{\partial f}{\partial x_n\partial x_2}&\cdots&\frac{\partial^2f}{\partial x_n\partial x_n^2}\end{bmatrix}_{X^{(0)}}     

 上面为在x_0处的海森矩阵                            

如果函数f在D区域内连续可导:对于海森矩阵H有H_{ij}=H_{ji}

设n多元实函数在点的邻域内有二阶连续偏导,若有:

\left.\frac{\partial f}{\partial x_j}\right|_{(a_1,a_2,\ldots,a_n)}=0,j=1,2,\ldots,n

A=\begin{bmatrix}\frac{\partial^2f}{\partial x_1^2}&\frac{\partial^2f}{\partial x_1\partial x_2}&\cdots&\frac{\partial^2f}{\partial x_1\partial x_n}\\ \frac{\partial f}{\partial x_2\partial x_1}&\frac{\partial^3f}{\partial x_2^2}&\cdots&\frac{\partial^3f}{\partial x_2\partial x_n}\\ \vdots&\vdots&\ddots&\vdots\\ \frac{\partial f f}{\partial x_n\partial x_1}&\frac{\partial^3f}{\partial x_n\partial x_2}&\cdots&\frac{\partial^3f}{\partial x_n^2}\end{bmatrix}

(1)当A正定矩阵时f(x_{1},x_{2},\cdots,x_{n})在处是M_{0}(a_{1},a_{2},\ldots,a_{n})极小值。

(2)当A负定矩阵时f(x_{1},x_{2},\cdots,x_{n})​在​处是M_{0}(a_{1},a_{2},\ldots,a_{n})极大值。

(3)当A不定矩阵时​在M_{0}(a_{1},a_{2},\ldots,a_{n})​处不是极值点。

(4)当A半正定,半负定矩阵时​M_{0}(a_{1},a_{2},\ldots,a_{n})在处未知。

看个例子:

根据多元函数的泰勒展开公式,我们对目标函数在x0点处做泰勒展开,有:

f\left(\mathbf{x}\right)=f\left(\mathbf{x}_0\right)+\nabla f\left(\mathbf{x}_0\right)^{T}\left(\mathbf{x}-\mathbf{x}_0\right)+\dfrac{1}{2}\left(\mathbf{x}-\mathbf{x}_0\right)^{T}\nabla^2f\left(\mathbf{x}_0\right)\left(\mathbf{x}-\mathbf{x}_0\right)+o\left(\left(\mathbf{x}-\mathbf{x}_0\right)^2\right)

根据多元函数的泰勒展开公式,忽略二次及以上的项,并对上式两边同时求梯度(就是求导),得到函数的导数(梯度向量)为:

\nabla\big(\mathbf{x}\big)=\nabla f\big(\mathbf{x}_0\big)+\nabla^2f\big(\mathbf{x}_0\big)\big(\mathbf{x}-\mathbf{x}_0\big)

其中\nabla^{2}f(x_{0})为海森矩阵在后面我们写成H。令函数的梯度为 0,则有:

\nabla f\left(\mathbf{x}_0\right)+\nabla^2f\left(\mathbf{x}_0\right)\left(\mathbf{x}-\mathbf{x}_0\right)=0\Longrightarrow\mathbf{x}=\mathbf{x}_0-\left(\nabla^2f\left(\mathbf{x}_0\right)\right)^{-1}\nabla f\left(\mathbf{x}_0\right)

这是一个线性方程组的解。如果将\nabla f\left(\mathbf{x}_{0}\right)梯度向量简写为g,上面的公式可以简写为:

\mathbf{x}=\mathbf{x}_0-\mathbf{H}^{-1}\mathbf{g}

从初始点处开始,反复计算函数在处的Hessian矩阵和梯度向量,然后用下述公式进行迭代:

\mathbf x_{_{k+1}}=\mathbf x_{_k}-\mathbf H_{_k}^{-1}\mathbf g_{_k}

最终会到达函数的驻点处。其中-\mathbf{H}^{-1}\mathbf{g}称为牛顿方向。迭代终止的条件是梯度的模接近于0,或者函数值下降小于指定阈值。

1.3.3拟牛顿法

牛顿法在每次迭代时需要计算出Hessian矩阵,然后求解一个以该矩阵为系数矩阵的线性方程组,这非常耗时,另外Hessian矩阵可能不可逆。为此提出了一些改进的方法,典型的代表是拟牛顿法(Quasi-Newton)。拟牛顿法的思想是不计算目标函数的Hessian矩阵然后求逆矩阵,而是通过其他手段得到Hessian矩阵或其逆矩阵的近似矩阵。具体做法是构造一个近似Hessian矩阵或其逆矩阵的正定对称矩阵,用该矩阵进行牛顿法的迭代。在x_{k+1}处泰勒展开:

f\left(\mathbf{x}\right)\mathbf{=}f\left(\mathbf{x}_{_{k+1}}\right)+\nabla f\left(\mathbf{x}_{_{k+1}}\right)^{T}\left(\mathbf{x}-\mathbf{x}_{_{k+1}}\right)+\dfrac{1}{2}\left(\mathbf{x}-\mathbf{x}_{_{k+1}}\right)^{T}\nabla^2f\left(\mathbf{x}_{_{k+1}}\right)\left(\mathbf{x}-\mathbf{x}_{_{k+1}}\right)\quad

对上式两边同时取梯度(求导),有:

\nabla f\big(\mathbf{x}\big)\approx\nabla f\big(\mathbf{x}_{k+1}\big)+\nabla^2f\big(\mathbf{x}_{k+1}\big)\big(\mathbf{x}-\mathbf{x}_{k+1}\big)

X=X_{k},有:
\nabla f\left(\mathbf{x}_{_{k+1}}\right)-\nabla f\left(\mathbf{x}_k\right)\approx\nabla^2f\left(\mathbf{x}_{_{k+1}}\right)\left(\mathbf{x}_{_{k+1}}-\mathbf{x}_k\right)

这可以简写为:

\mathbf{g}_{k+1}-\mathbf{g}_{k}\approx\mathbf{H}_{k+1}\left(\mathbf{x}_{k+1}-\mathbf{x}_{k}\right)

如果令:

\begin{array}{c}{\mathbf{s}_{k}=\mathbf{x}_{k+1}-\mathbf{x}_{k}}\\ {\mathbf{y}_{k}=\mathbf{g}_{k+1}-\mathbf{g}_{k}}\\ \end{array}

上式可以简写为:

\mathbf{y}_k\approx\mathbf{H}_{k+1}\mathbf{s}_k

即:

\mathrm{s}_k\approx\mathrm{H}_{k+1}^{-1}\mathrm{y}_k和上面的牛顿法保持一致

这个条件称为拟牛顿条件,用来近似代替Hessian矩阵的矩阵需要满足此条件。根据此条件,构造出了多种拟牛顿法,典型的有DFP算法、BFGS算法、L-BFGS算法等。

1.3.4启发式优化方法

1.3.5EM算法

1.4 损失函数(基于pytorch

损失函数:听词如见面,就是关于损失值的函数,损失值就是预测值和真实值之间的差值(知道介绍上文的梯度原理和最优化原理的意义了吧)。在机器学习中,为了让预测值无限接近于真实值,需要将两者差值降到最低即损失函数最此过程中损失函数的选择非常关键,在具体的项目中,有些损失函数计算的差值梯度下降的快,而有些下降的慢。

在机器学习中,我们知道输入的特征feature(或称为x)需要通过模型(model)预测出y,此过程称为向前传播(forward pass),而要将预测与真实值的差值减小需要更新模型中的参数,这个过程称为向后传播(backward pass),其中我们损失函数(lossfunction)就基于这两种传播之间,起到一种有点像承上启下的作用,承上指:接収模型的预测值,启下指:计算预测值和真实值的差值,为下面反向传播提供输入数据。

1.4.1 L1 Loss函数:

L1 Loss函数的别称:

  • L1 范数损失
  • 最小绝对值偏差(LAD)
  • 最小绝对值误差(LAE)
  • MAE

 它是把目标值y_i与模型输出(估计值)f(x_i) 做绝对值得到的误差。公式如下:

loss(x,y)=\frac{1}{n}\sum_{i=1}^{n}|y_i-f(x_i)|

L1 Loss函数的使用场景:

  • 回归任务

  • 简单的模型

  • 由于神经网络通常是解决复杂问题,所以很少使用。

 pytorch实现代码:

import torch as th
import torch.nn as nn
 
loss=nn.L1Loss()
 
input=th.Tensor([2,3,4,5])
target=th.Tensor([4,5,6,7])
output=loss(input,target)
 

因为我们函数的“reduction”(L1 Loss函数的参数)选择的是默认的"mean"(平均值),所以还会在除以一个"4",如果我们设置“loss=L1Loss(reduction='sum')则不用再除以4。 

1.4.2 L2 Loss函数:

L1 Loss函数的别称:

  • L2 范数损失
  • 最小均方值偏差(LSD)
  • 最小均方值误差(LSE)
  • MSE

它是把目标值y_i与模型输出(估计值)f(x_i) 做绝对值得到的误差。公式如下:

loss(x,y)=\frac{1}{n}\sum_{i=1}^n(y_i-f(x_i))^2

L2 Loss函数的使用场景:

  • 回归任务
  • 数值特征不大
  • 问题维度不高

pytorch实现代码:

import torch as th
import torch.nn as nn
 
loss=nn.MSELoss()
 
 
input=th.Tensor([2,3,4,5])
target=th.Tensor([4,5,6,7])
output=loss(input,target)
 

 

1.4.3 Smooth L1 Loss函数

先看公式:

l_n=\begin{cases}0.5(x_n-y_n)^2/beta,&\text{if}~|x_n-y_n|<beta\\ |x_n-y_n|-0.5*beta,&\text{otherwise}\end{cases}

\ell(x,y)=\begin{cases}\textrm{mean}(L),&\textrm{if reduction}=\textrm{'mean'};\\ \textrm{sum}(L),&\textrm{if reduction}=\textrm{'sum'.}\end{cases}

根据公式可以看出这是一个分段函数,我们将绝对值差视为一个变量z ,那么这个变量是大于0的,即分段函数只在大于等于0处有定义,有图像。我们再来看看分段点,就是beta。有意思的是,在分段函数和这个分段点有关,在第一个公式(左边分段函数)中,函数值小于等于0.5z ,因为除了beta。右边分段函数中,大于等于0.5z。所以是连续的,所以叫做Smooth。而且beta固定下来的时候,当z很大时,损失是线性函数,也就是说损失不会像MSE那样平方倍的爆炸。

当预测值和ground truth(真实值)差别较小的时候(绝对值差小于1),其实使用的是L2 Loss;而当差别大的时候,是L1 Loss的平移。SooothL1Loss其实是L2Loss和L1Loss的结合,它同时拥有L2 Loss和L1 Loss的部分优点。

  • 当预测值和ground truth差别较小的时候(绝对值差小于1),梯度不至于太大。(损失函数相较L1 Loss比较圆滑)
  • 当差别大的时候,梯度值足够小(较稳定,不容易梯度爆炸)。

总结就是:前半段随着z的增长,损失增长得非常缓慢,后面快了一点点,但是也仍然是线性的。
 

Smooth L1 Loss函数的使用场景:

  • 回归
  • 当特征中有较大的数值
  • 适合大多数问题

pytorch实现代码:

import torch
import torch.nn as nn
a=[1,2,3]
b=[3,1,9]
loss_fn=nn.SmoothL1Loss()
loss_fn(torch.tensor(a,dtype=torch.float32),torch.tensor(b,dtype=torch.float32))

1.4.4 交叉熵损失函数(CrossEntropy Loss)

熵:首先了解什么是熵,熵本质是一个系统“内在的混乱程度”。更具体地,可以理解为一件事发生概率P的确定性。比如当 P=0 一定不发生或者 P=1 一定发生时,熵最小为0;当 P=0.5 最不确定发生或者不发生时熵最大为1。即一件事情越难猜测发生或者不发生时熵就越大,越好猜测的熵就越小。(越稳定熵越小,不确定性越大熵越大)

信息量:信息论奠基人香农(Shannon)认为“信息是用来消除随机不确定性的东西”。也就是说衡量信息量大小就看这个信息消除不确定性的程度。

“太阳从东方升起了”这条信息没有减少不确定性。因为太阳肯定从东面升起。这是句废话,信息量为0。

“六月份下雪了”,这条信息就比较有价值,根据历史统计信息来看,六月份鲜有下雪记录,可知该语句信息量较大。

从上面两个例子可以看出:信息量的大小和事件发生的概率成反比。由此引出信息量的表示:

  • 事件发生的概率越低,信息量越大;
  • 事件发生的概率越高,信息量越低;
  • 多个事件同时发生的概率是多个事件概率相乘,总信息量是多个事件信息量相加。

\small I(x)=-l o g(P(x))

P(x)表示为事件发生概率

信息熵:信息量度量的是一个具体事件发生所带来的信息,而信息熵则是在结果出来之前对可能产生的信息量的期望——考虑该随机变量的所有可能取值,即所有可能发生事件所带来的信息量的期望。因此我们可以得到其表现公式为:

\small H(X)=-\sum_{i=1}^{n}p(x_i)log(p(x_i))

P(x)表示为事件发生概率,信息熵是用来衡量事物不确定性的。信息熵越大,事物越具不确定性,事物越复杂。

相对熵:相对熵(relative entropy),又被称为Kullback-Leibler散度(KL散度)或信息散度(information divergence),是两个概率分布(probability distribution)间差异的非对称性度量 。在信息理论中,相对熵等价于两个概率分布的信息(Shannon entropy)的差值 。可以理解为对于同一个随机变量x有两个概率分布,判断这两个概率分布的差异。假设两个概率分布对应为p(x),q(x), 如何表示这两个分布得差异,我们可以使用信息熵判断,于是相对熵产生。

p(x)分布的信息熵为:

H_{pp}(X)=-\sum_{i=1}^{n}p(x_{i})log(p(x{_{i}}))

q(x)分布的信息熵为:

H{_{pq}}(X)=-\sum_{i=1}^{n}p(x_{i})log(q(x{_{i}}))

相对熵为:

H_{pq}(X)-H_{pp}(X)

p(x)为样本真实分布,q(x)为预测分布

于是得到相对熵(KL散度)公式为:

D_{KL}(p||q)=H_{pq}(X)-H_{pp}(X)=-\sum_{i=1}^{n}p(x_{i})log(q(x{_{i}}))-[-\sum_{i=1}^{n}p(x_{i})log(p(x{_{i}}))]

D_{KL}(p||q)=\sum_{i=1}^{n}p(x_{i})log(p(x{_{i}}))-\sum_{i=1}^{n}p(x_{i})log(q(x{_{i}}))=\sum_{i=1}^{n}p(x_{i})log(\frac{p(x_{i})}{q(x^{_{i}})})

KL散度越小,表示P(x) 与Q(x)的分布更加接近,可以通过反复训练Q (x)来使Q (x) 的分布逼近P(x)。

交叉熵:

交叉熵的函数表示为:

H(p,q)=-\sum_{i=1}^{n}p(x_{i})log(q(x{_{i}}))

我们观察可以看出,这里与相对熵(KL散度)较为相似,个人认为交叉熵为相对熵(KL散度)的变体,由于我们进行模型训练,有监督训练,样本标签已经确定,相当于真实的概率的分布P(x)已经得知,下面公式的H(X)固定值,相当于常量

H(X)=-\sum_{i=1}^{n}p(x_{i})log(p(x{_{i}}))

在我们模型训练中:

D_{KL}(p||q)=\sum_{i=1}^{n}p(x_{i})log(p(x{_{i}}))-\sum_{i=1}^{n}p(x_{i})log(q(x{_{i}}))

相对熵(KL散度)变为:

D_{KL}(p||q)=constant-\sum_{i=1}^{n}p(x_{i})log(q(x{_{i}}))

对于其做为损失函数,常量可以忽略,因此得到了交叉熵的表现形式。

pytorch实现代码:

直接使用pytorch中的 nn.CrossEntropyLoss() 计算得到的结果与 softmax_log(x)+NLLLoss计算得到的结果是一致的。

CrossEntropyLoss()=log_softmax() + NLLLoss() 
import torch
import torch.nn as nn

x_input = torch.randn(3, 3)  # 随机生成输入
print('x_input:\n', x_input)
y_target = torch.tensor([1, 2, 0])  # 设置输出具体值 print('y_target\n',y_target)

# 计算输入softmax,此时可以看到每一行加到一起结果都是1
softmax_func = nn.Softmax(dim=1)
soft_output = softmax_func(x_input)
print('soft_output:\n', soft_output)

# 在softmax的基础上取log
log_output = torch.log(soft_output)
print('log_output:\n', log_output)

# 对比softmax与log的结合与nn.LogSoftmaxloss(负对数似然损失)的输出结果,发现两者是一致的。
logsoftmax_func=nn.LogSoftmax(dim=1)
logsoftmax_output=logsoftmax_func(x_input)
print('logsoftmax_output:\n', logsoftmax_output)

# pytorch中关于NLLLoss的默认参数配置为:reducetion=True、size_average=True
nllloss_func = nn.NLLLoss()
nlloss_output = nllloss_func(logsoftmax_output, y_target)
print('nlloss_output:\n', nlloss_output)

# 直接使用pytorch中的loss_func=nn.CrossEntropyLoss()看与经过NLLLoss的计算是不是一样
crossentropyloss = nn.CrossEntropyLoss()
crossentropyloss_output = crossentropyloss(x_input, y_target)
print('crossentropyloss_output:\n', crossentropyloss_output)

1.4.5 NLL Losss损失函数

softmax函数:又称为归一化指数函数,它可以把一个多维向量压缩在(0,1)之间,并且它们的和为1。公式如下:

\sigma(\mathbf{z})_j=\dfrac{e^{z_j}}{\sum_{k=1}^K e^{z_k}}\quad\text{for}j=1,...,K.

示例代码:

import math
z = [1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 3.0]
z_exp = [math.exp(i) for i in z]  
print(z_exp)  # Result: [2.72, 7.39, 20.09, 54.6, 2.72, 7.39, 20.09] 
sum_z_exp = sum(z_exp)  
print(sum_z_exp)  # Result: 114.98 
softmax = [round(i / sum_z_exp, 3) for i in z_exp]
print(softmax)  # Result: [0.024, 0.064, 0.175, 0.475, 0.024, 0.064, 0.175]

log_softmax:log_softmax是指在softmax函数的基础上,再进行一次log运算,此时结果有正有负,log函数的值域是负无穷到正无穷,当x在0—1之间的时候,log(x)值在负无穷到0之间。

nn.NLLLoss:nn.NLLLoss的结果就是把上面的输出与Label对应的那个值拿出来,再去掉负号,再求均值。

示例代码:

import torch
input=torch.randn(3,3)
soft_input = torch.nn.Softmax(dim=0)
soft_input(input)
Out[20]: 
tensor([[0.7284, 0.7364, 0.3343],
        [0.1565, 0.0365, 0.0408],
        [0.1150, 0.2270, 0.6250]])

#对softmax结果取log
torch.log(soft_input(input))
Out[21]: 
tensor([[-0.3168, -0.3059, -1.0958],
        [-1.8546, -3.3093, -3.1995],
        [-2.1625, -1.4827, -0.4701]])

假设标签是[0,1,2],第一行取第0个元素,第二行取第1个,第三行取第2个,去掉负号,即[0.3168,3.3093,0.4701],求平均值,就可以得到损失值。

(0.3168+3.3093+0.4701)/3
Out[22]: 1.3654000000000002

#验证一下

loss=torch.nn.NLLLoss()
target=torch.tensor([0,1,2])
loss(input,target)
Out[26]: tensor(0.1365)

2.线代矩阵分析

3.概率计算类

参考书籍:从零开始:机器学习的数学原理和算法实践 ISBN:978-7-115-55696

参考博文:

批量梯度下降(BGD)、随机梯度下降(SGD)以及小批量梯度下降(MBGD)的理解 - EEEEEcho - 博客园 (cnblogs.com)

浅谈随机梯度下降&小批量梯度下降 - 知乎 (zhihu.com)

几种梯度下降方法对比(Batch gradient descent、Mini-batch gradient descent 和 stochastic gradient descent)_天泽28的博客-CSDN博客理解牛顿法 - 知乎 (zhihu.com)

 损失函数(lossfunction)的全面介绍(简单易懂版)_小林学编程的博客-CSDN博客_损失函数

PyTorch中的损失函数--L1Loss /L2Loss/SmoothL1Loss - 知乎 (zhihu.com)

 pytorch之SmoothL1Loss原理与用法_音程的博客-CSDN博客_pytorch smoothl1损失函数——交叉熵损失函数(CrossEntropy Loss)_深度学习_winupup-DevPress官方社区 (csdn.net)Pytorch损失函数torch.nn.NLLLoss()详解_Jeremy_lf的博客-CSDN博客_torch.nn.nllloss

Logo

一站式 AI 云服务平台

更多推荐