机器学习/算法面试笔记1——损失函数、梯度下降、优化算法、过拟合和欠拟合、正则化与稀疏性、归一化、激活函数

正值秋招,参考网络资源整理了一些面试笔记,第一篇包括以下7部分。

1、损失函数

2、梯度下降

3、优化算法

4、过拟合和欠拟合

5、正则化与稀疏性

6、归一化

7、激活函数

损失函数

损失函数分为经验风险损失函数和结构风险损失函数。经验风险损失函数指预测结果和实际结果的差别,结构风险损失函数是指经验风险损失函数加上正则项。

常见的损失函数以及其优缺点如下:

1、0-1损失函数(zero-one loss)

0-1损失是指预测值和目标值不相等为1, 否则为0:

特点:

(1)0-1损失函数是一个非凸函数,不太适用。

(2)感知机就是用的这种损失函数。但是相等这个条件太过严格,因此可以放宽条件,即满足 |Y−f(x)|

2、绝对值损失函数MAE

绝对值损失函数是计算预测值与目标值的差的绝对值:L(Y,f(x))=|Y−f(x)|

3、平方损失函数MSE

平方损失函数标准形式如下:L(Y|f(X))=∑N(Y−f(X))2

特点:经常应用于回归问题

MAE与MSE比较:

MSE 通常比 MAE 可以更快地收敛。当使用梯度下降算法时,MSE 损失的梯度为 −yi^ ,而 MAE 损失的梯度为 ±1 ,即 MSE 的梯度的 scale 会随误差大小变化,而 MAE 的梯度的 scale 则一直保持为 1,即便在绝对误差 |yi−yi^| 很小的时候 MAE 的梯度 scale 也同样为 1,这实际上是非常不利于模型的训练的。当然你可以通过在训练过程中动态调整学习率缓解这个问题,但是总的来说,损失函数梯度之间的差异导致了 MSE 在大部分时候比 MAE 收敛地更快。这个也是 MSE 更为流行的原因。

但MAE 对于 outlier 更加 robust,即更加不易受到 outlier 影响。当误差非常大的时候,MSE 损失会远远大于 MAE 损失。因此当数据中出现一个误差非常大的 outlier 时,MSE 会产生一个非常大的损失,对模型的训练会产生较大的影响。

4、交叉熵损失函数 (Cross-entropy loss function)

交叉熵损失函数的标准形式如下:

机器学习/算法面试笔记1——损失函数、梯度下降、优化算法、过拟合和欠拟合、正则化与稀疏性、归一化、激活函数_第1张图片

特点:

(1)本质上也是一种对数似然函数,可用于二分类和多分类任务中。输入数据是softmax或者sigmoid函数的输出。(对数损失函数和交叉熵损失函数应该是等价的。)

(2)当使用sigmoid作为激活函数的时候,常用交叉熵损失函数而不用均方误差损失函数,因为它可以完美解决平方损失函数权重更新过慢的问题,具有“误差大的时候,权重更新快;误差小的时候,权重更新慢”的良好性质。

相关高频问题:

(1)交叉熵函数与最大似然函数的联系和区别?

区别:交叉熵函数使用来描述模型预测值和真实值的差距大小,越大代表越不相近;似然函数的本质就是衡量在某个参数下,整体的估计和真实的情况一样的概率,越大代表越相近。

联系:交叉熵函数可以由最大似然函数在伯努利分布的条件下推导出来,或者说最小化交叉熵函数的本质就是对数似然函数的最大化。

(2)在用sigmoid作为激活函数的时候,为什么要用交叉熵损失函数,而不用均方误差损失函数?

分析一下两个误差函数的参数更新过程就会发现原因了。

因为sigmoid的性质,导致 σ′(x) 在 z 取大部分值时会很小(如下图标出来的两端,几乎接近于平坦),这样会使得 η(a−y)σ′(z) 很小,导致参数 w 和 b 更新非常慢。

交叉熵损失函数在参数更新公式中没有 σ′(x) 这一项,权重的更新受 (a−y) 影响,受到误差的影响,所以当误差大的时候,权重更新快;当误差小的时候,权重更新慢。这是一个很好的性质。

均方差损失假设了误差服从高斯分布,在分类任务下这个假设没办法被满足,因此效果会很差。

为什么是交叉熵损失呢?有两个角度可以解释这个事情,一个角度从最大似然的角度,也就是我们上面的推导;另一个角度是可以用信息论来解释交叉熵损失

5合页损失函数Hinge

Hinge损失函数标准形式如下:L(y,f(x))=max(0,1−yf(x))

可以看到当 y 为正类时,模型输出负值会有较大的惩罚,当模型输出为正值且在 (0,1) 区间时还会有一个较小的惩罚。即合页损失不仅惩罚预测错的,并且对于预测对了但是置信度不高的也会给一个惩罚,只有置信度高的才会有零损失。使用合页损失直觉上理解是要找到一个决策边界,使得所有数据点被这个边界正确地、高置信地被分类。

特点:

(1)hinge损失函数表示如果被分类正确,损失为0,否则损失就为 1−yf(x) 。SVM就是使用这个损失函数。

(2)一般的 f(x) 是预测值,在-1到1之间,y 是目标值(-1或1)。其含义是,f(x) 的值在-1和+1之间就可以了,并不鼓励 |f(x)|>1 ,即并不鼓励分类器过度自信,让某个正确分类的样本距离分割线超过1并不会有任何奖励,从而使分类器可以更专注于整体的误差。

(3) 健壮性相对较高,对异常点、噪声不敏感,但它没太好的概率解释。

6、log对数损失函数

log对数损失函数的标准形式如下:L(Y,P(Y|X))=−logP(Y|X)

特点:

(1) log对数损失函数能非常好的表征概率分布,在很多场景尤其是多分类,如果需要知道结果属于每个类别的置信度,那它非常适合。

(2)健壮性不强,相比于hinge loss对噪声更敏感。

(3)逻辑回归的损失函数就是log对数损失函数。

7、指数损失函数(exponential loss)

指数损失函数的标准形式如下:L(Y|f(X))=exp[−yf(x)]

特点:对离群点、噪声非常敏感。经常用在AdaBoost算法中。

8、感知损失(perceptron loss)函数

感知损失函数的标准形式如下:L(y,f(x))=max(0,−f(x))

特点:是Hinge损失函数的一个变种,Hinge loss对判定边界附近的点(正确端)惩罚力度很高。而perceptron loss只要样本的判定类别正确的话,它就满意,不管其判定边界的距离。它比Hinge loss简单,因为不是max-margin boundary,所以模型的泛化能力没 hinge loss强。

梯度下降

批量梯度下降法(Batch Gradient Descent,BGD)就好比正常下山,而随机梯度下降法就好比蒙着眼睛下山,数学上的表达式为。

批量梯度下降法全部训练集上计算准确的梯度。为了获取准确的梯度,批量梯度下降法的每一步都把整个训练集载入进来进行计算,时间花费和内存开销都非常大,无法应用于大数据集、大模型的场景。

随机梯度下降法则采样单个样本来估计当前的梯度。随机梯度下降法则放弃了对梯度准确性的追求,每步仅仅随机采样一个(或少量)样本来估计当前梯度,计算速度快,内存开销小。但由于每步接受的信息量有限,随机梯度下降法对梯度的估计常常出现偏差,造成目标函数曲线收敛得很不稳定,伴有剧烈波动,有时甚至出现不收敛的情况。

批量梯度下降法稳定地逼近最低点,而随机梯度下降法的参数轨迹曲曲折折简直是“黄河十八弯"。

mini-batch梯度下降:

在每次更新时用b个样本,其实批量的梯度下降就是一种折中的方法,他用了一些小样本来近似全部的,其本质就是我1个指不定不太准,那我用个30个50个样本那比随机的要准不少了吧,而且批量的话还是非常可以反映样本的一个分布情况的。在深度学习中,这种方法用的是最多的,因为这个方法收敛也不会很慢,收敛的局部最优也是更多的可以接受!

在小批量梯度下降中,有三点需要注意的地方:

  1. 如何选择参数m?通常需要调参选取,一般取2的幂次时能充分利用矩阵运算操作。
  2. 如何挑选m个训练数据?为避免数据的特定顺序给算法收敛带来的影响,一般会在每次遍历数据之前,先对所有数据进行随机排序,然后在每次迭代时按顺序挑选m个训练数据直至遍历完所有的数据。
  3. 如何选取学习速率α?为了加快收敛速率,同时提高求解精度,通常采用衰减学习率的方案:一开始采用较大的学习速率,当误差曲线进入平台期后,减小学习速率做更精细的调整。最优的学习速率方案也通常需要调参才能得到。

深度学习中最常用的优化方法就是随机梯度下降法,但其偶尔也会失效。

随机梯度下降和批量梯度下降都会陷入局部最优的陷阱。对随机梯度下降法来说,最可怕的时山谷和鞍点两种地形。在梯度近乎为零的区域,随机梯度下降法无法准确察觉出梯度的微小变化,结果就停滞下来。

优化方法

优化方法大致分为两类:

  • 动量法(Momentum)

与随机梯度下降法(SDG)不同的是,它保存了历史的梯度,解决SDG方法在山谷震荡和鞍点停滞的问题。

用之前积累的动量来替代真正的梯度,每次迭代的梯度可以看做加速度。

加入动量因子可以减少偏移量。向下的力稳定不变,产生的动量不断累积,速度越来越快;左右的弹力总是在不停切换,动量累积的结果相互抵消,减弱了球的来回震荡。与SDG方法相比,动量方法的收敛速度更快,收敛曲线也更稳定。

  • 调整学习率:AdaGrad方法

常用的学习率调整方法包括学习率衰减、学习率预热、周期性学习率调整以及一些自适应调整学习率的方法,比如AdaGrad、RMSprop、AdaDelta。

惯性的力是基于历史的,我们还期待获得对周围环境的感知。希望更新频率低的参数可以拥有较大的更新步幅,而更新频率高的参数参数步幅可以减小。

AdaGrad方法采用“历史梯度平方和”来衡量不同参数的梯度的稀疏性,取值越小表明越稀疏。

AdaGrad方法采用所有历史梯度平方和作为分母,分母随时间单调递增,产生的自适应学习率随时间衰减的速度过于激进。

RMSProp算法不是像AdaGrad算法那样暴力直接的累加平方梯度,而是加了一个衰减系数来控制历史信息的获取多少。可以避免AdaGrad算法中学习率不断单调下降以至于过早衰减。

  • Adam算法:可以看做动量法和RMSprop算法的结合,不但用动量作为参数更新方向,而且可以自适应调整学习率。

将惯性保持和环境感知这两个优点集于一身。一方面记录梯度的一阶矩,即过往梯度与当前梯度的平均,保持了惯性;另一方面记录梯度的二阶矩,体现了环境感知能力,为不同参数产生自适应的学习速率。一阶矩和二阶矩采用类似于滑动窗口内求平均的思想进行融合。

过拟合和欠拟合

过拟合的原因:

  1. 模型过于复杂,将噪声数据特征也学习到模型中,导致泛化能力下降;
  2. 数据集规模太小

过拟合解决办法:

  • 获得更多的训练数据。

如果不是很容易,可以通过图像平移、旋转、缩放等,还可以使用迁移学习技术。

  • 降低模型复杂度

如决策树中降低树的高度、进行剪枝等。

  • 正则化方法

如L2将权值大小引入到损失函数中

添加BN层

使用dropout(dropout在训练时会随机隐藏一些神经元,导致训练过程不会每次都更新)

  • Early stopping

在模型对训练数据集迭代收敛之前停止迭代

具体做法:在一个epoch结束时计算validation data的accuracy,当其不再提高就停止训练。

  • 集成学习

就是把多个模型集成在一起。如Bagging,首先对原始m个训练样本进行有放回随机抽样,构建N组m个样本的数据集,用N组数据集训练网络,得到N组参数,进行加权平均。

但要花费更多时间和空间

  • 交叉检验

将数据切成S个互不相交大小相同的自己,用S-1子集的数据训练模型,余下的测试;将这一过程对可能的S中选择重复进行,选择S次当中平均测试误差最小的模型。

欠拟合的原因:

  1. 模型过于简单
  2. 提取的特征不好

欠拟合的解决办法:

  1. 增加模型复杂度,如线性模型改为非线性,增加网络层数或神经元个数,选择参数更多更先进的模型等。
  2. 增加新特征
  3. 如果损失函数增加了正则项,减小其系数

欠拟合会导致高 Bias ,过拟合会导致高 Variance,所以模型需要在 Bias 与 Variance 之间做出一个权衡。

正则化与稀疏项

为什么希望模型参数具有稀疏性?

相当于对模型进行了一次特征选择,只留下一些比较重要的特征,提高模型的泛化能力,降低过拟合的可能。

原理:在损失函数上加上某些限制,缩小解空间,从而减少求出过拟合解的可能性。

不同次方下的正则项(左:L2正则  右:L1正则)

机器学习/算法面试笔记1——损失函数、梯度下降、优化算法、过拟合和欠拟合、正则化与稀疏性、归一化、激活函数_第2张图片

二次正则项的优势,处处可导,方便计算。

L2正则化对于绝对值较大的权重予以很重的惩罚,对于绝对值很小的权重予以非常非常小的惩罚,当权重绝对值趋近于0时,基本不惩罚。这个性质与L2的平方项有关系,即越大的数,其平方越大,越小的数,比如小于1的数,其平方反而越小。

同时,他有另一个优势,在使用正规方程时,解析式中的逆始终存在的。

L2正则化只是使得模型的参数值趋近于0,而不是等于0,这样就无法丢掉模型里的任何一个特征,因此无法做到稀疏化。这时,L1的作用随之显现。L1正则化的作用是使得大部分模型参数的值等于0,这样一来,当模型训练好后,这些权值等于0的特征可以省去,从而达到稀疏化的目的,也节省了存储的空间。

L1在确实需要稀疏化模型的场景下,才能发挥很好的作用并且效果远胜于L2。在模型特征个数远大于训练样本数的情况下,如果我们事先知道模型的特征中只有少量相关特征(即参数值不为0),并且相关特征的个数少于训练样本数,那么L1的效果远好于L2。然而,需要注意的是,当相关特征数远大于训练样本数时,无论是L1还是L2,都无法取得很好的效果。

归一化

归一化的提出

机器学习领域,数据分布很重要。如果训练集和测试机分布很不相同,那可能训练好的模型在测试机上不奏效。

对神经网络来说,如果每层数据分布不一样,那么后一次网络要去学习适应迁移侧耳数据分布,加大了训练难度。

“Internal Covariate Shift”对于深度学习而言,会包含多个隐层结构,每一层隐层都有自己的输入,在训练过程中,隐层的输入分布经常发生变化。“Internal Covariate Shift”会导致模型的学习速率变慢,学习效果也可能会受到影响。

对于深层的神经网络而言,经过多层神经网络后,输出值往往会变大很多或者很小,如果激活函数是sigmoid的话,会导致梯度消失的情况。

基于以上两点(“Internal Covariate Shift”和梯度消失),则产生了归一化的需要。

BN特点:

强行将数据转为均值为0,方差为1的正态分布,使得数据分布一致,并且避免梯度消失。而梯度变大意味着学习收敛速度快,能够提高训练速度。

BN的好处:

  1. 防止网络梯度消失:结合sigmoid函数进行理解
  2. 加速训练,也允许更大的学习率

输出分布向着激活函数的上下限偏移,带来梯度的降低(如sigmoid),通过归一化,数据在一个合适的分布空间,通过激活函数仍能有不错的梯度。梯度好了自然加速训练。

  1. 降低参数初始化敏感
  2. 提高网络泛化能力防止过拟合。几乎可以替代dropout

在训练中,BN的使用使得一个mini-batch中的所有样本都被关联在了一起,因此网络不会从某一个训练样本中生成确定的结果。意思就是同样一个样本的输出不再仅仅取决于样本本身,也取决于跟这个样本属于同一个mini-batch的其它样本。

  1. 可以把训练数据彻底打乱

问题:

当batch size越小,BN表现越不好,因为计算过程中得到的均值方差不能代表全局。

BatchNormLayerNorm

Batch 顾名思义是对一个batch进行操作。假设我们有 10行 3列 的数据,即我们的batchsize = 10,每一行数据有三个特征,假设这三个特征是【身高、体重、年龄】。那么BN是针对每一列(特征)进行缩放,例如算出【身高】的均值与方差,再对身高这一列的10个数据进行缩放。体重和年龄同理。这是一种“列缩放”。

而layer方向相反,它针对的是每一行进行缩放。即只看一笔数据,算出这笔所有特征的均值与方差再缩放。这是一种“行缩放”。完全独立于batch size。

为什么要使用LN呢?因为NLP领域中,LN更为合适。

如果我们将一批文本组成一个batch,那么BN的操作方向是,对每句话的第一个词进行操作。但语言文本的复杂性是很高的,任何一个词都有可能放在初始位置,且词序可能并不影响我们对句子的理解。而BN是针对每个位置进行缩放,这不符合NLP的规律。

而LN则是针对一句话进行缩放的,且LN一般用在第三维度,如[batchsize, seq_len, dims]中的dims,一般为词向量的维度,或者是RNN的输出维度等等,这一维度各个特征的量纲应该相同。因此也不会遇到上面因为特征的量纲不同而导致的缩放问题。

小结:

BN 和 LN 都可以比较好的抑制梯度消失和梯度爆炸的情况。BN不适合RNN、transformer等序列网络,不适合文本长度不定和batchsize较小的情况,适合于CV中的CNN等网络;

而LN适合用于NLP中的RNN、transformer等网络,因为sequence的长度可能是不一致的。

(1)经过BN的归一化再输入激活函数,得到的值大部分会落入非线性函数的线性区,导数远离导数饱和区,避免了梯度消失,这样来加速训练收敛过程。

(2)归一化技术就是让每一层的分布稳定下来,让后面的层能在前面层的基础上“安心学习”。BatchNorm就是通过对batch size这个维度归一化来让分布稳定下来(但是BN没有解决ISC问题)。LayerNorm则是通过对Hidden size这个维度归一。

激活函数

为什么使用激活函数?

不使用激活函数,每一层输出都是上层输入的线性函数,无论神经网络有多少层,输出都是输入的线性组合。使用激活函数,能够给神经元引入非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络就可以利用到更多的非线性模型中。

总结:在神经网络中引入非线性因素,增加模型的拟合能力。

 激活函数需要具备以下几点性质: 非线性;计算简单;可微;单调

(1)连续并可导(允许少数点上不可导)的非线性函数。可导的激活函数可以直接利用数值优化的方法来学习网络参数。

(2)激活函数及其导函数要尽可能的简单,有利于提高网络计算效率。

(3)激活函数的导函数的值域要在一个合适的区间内,不能太大也不能太小,否则会影响训练的效率和稳定性。 

激活函数不会改变数据的维度,也就是输入和输出的维度是相同的。

机器学习/算法面试笔记1——损失函数、梯度下降、优化算法、过拟合和欠拟合、正则化与稀疏性、归一化、激活函数_第3张图片

1、相对于sigmoid函数,tanh激活函数关于零点对称的好处是什么?

sigmoid函数输出始终为正,在反向传播求导时,权重更新效率会降低,导致模型收敛速度变慢。

此外,sigmoid输出均大于0,作为下层神经元的输入会导致下层输入不是0均值的,随着网络加深可能导致原始数据分布发生变化。

Sigmoid函数输出在[0 , 1]之间,适合二分类问题。

2、RNN中为什么用tanh而不用RELU激活?

因为RELU的导数智能为0或1,导数为1时RNN很容易产生梯度爆炸。因为RNN中,每个神经元在不同时刻共享一个参数(而CNN每一次都是独立的参数),如果W大于1,进行连乘,就会出现梯度爆炸问题。

3、ReLU函数在0处不可导,为什么在深度学习网络中还这么常用?

可以设置一个伪梯度,如定义其在0处的导数为0。

RELU的好处:

形式简洁;

可以解决sigmoid的梯度消失问题;

RELU有单侧抑制,会使一部分神经元输出为0,造成了网络的稀疏性,缓和了过拟合问题;

计算速度快

RELU缺点:

导致神经元死亡,权重无法更新。

如果学习率没有设置好,更新权重输入是负值,那么这个含有RELU的神经节点就会死亡,不再被激活。

4、如何使用RELU神经元“死亡”问题(当有大梯度流入某个神经元后,导致神经元对其他梯度不敏感)

使用Leaky RELU等激活函数;Leaky RELU=max(ax, x),a是一个极小的系数,给负数区域一个很小的输出,不让其置0,从某种程度上避免了使部分神经元死掉的问题。

设置较小的学习率进行训练

使用momentun优化算法动态调整学习率

5、Gelu激活函数

gelu(gaussian error linear units)就是我们常说的高斯误差线性单元,它是一种高性能的神经网络激活函数,因为gelu的非线性变化是一种符合预期的随机正则变换方式。

对于是分类任务的输出层,二分类的输出层的激活函数常选择sigmoid函数;多分类就是softmax。对于隐藏层的激活函数通常会选择使用ReLU函数,保证学习效率。

第二期笔记打算整理一些典型的机器学习算法,下周(或者下下周)见~

你可能感兴趣的:(秋招算法,算法,面试)