一直搞不清楚损失函数和优化函数的区别,现在我们对它们俩进行分析。
在机器学习中,损失函数是代价函数的一部分,而代价函数则是目标函数的一种类型。
损失函数是用于衡量模型所作出的预测离真实值(Ground Truth)之间的偏离程度。 通常,我们都会最小化目标函数,最常用的算法便是“梯度下降法”(Gradient Descent)。
俗话说,任何事情必然有它的两面性,因此,并没有一种万能的损失函数能够适用于所有的机器学习任务,所以在这里我们需要知道每一种损失函数的优点和局限性,才能更好的利用它们去解决实际的问题。损失函数大致可分为两种:
L1 Loss也称为Mean Absolute Error,即平均绝对误差(MAE),它衡量的是预测值与真实值之间距离的平均误差幅度,作用范围为 [ 0 , + ∞ ] [0, +\infty] [0,+∞]。
L 1 = ∑ i = 1 n ∣ y i − f ( x i ) ∣ L_1= \sum^n_{i=1}|y_i-f(x_i)| L1=i=1∑n∣yi−f(xi)∣
d L 1 ( x ) d x = { 1 , x ≥ 0 − 1 , o t h e r w i s e \frac{\mathrm{d}L_1(x)}{\mathrm{d}x}= \begin{cases} 1, & x\ge0 \\ -1, & \mathrm{otherwise} \end{cases} dxdL1(x)={1,−1,x≥0otherwise
优点: 对离群点(Outliers)或者异常值更具有鲁棒性。
缺点: 由图可知其在0点处的导数不连续,使得求解效率低下,导致收敛速度慢;而对于较小的损失值,其梯度也同其他区间损失值的梯度一样大,所以不利于网络的学习。
L2 Loss也称为Mean Squred Error,即均方差(MSE),它衡量的是预测值与真实值之间距离的平方和,作用范围同为 [ 0 , + ∞ ] [0, +\infty] [0,+∞] 。
L 2 = ∑ i = 1 n ( y i − f ( x i ) ) 2 L_2 = \sum^n_{i=1}(y_i-f(x_i))^2 L2=i=1∑n(yi−f(xi))2
d L 2 ( x ) d x = 2 x \frac{\mathrm{d}L_2(x)}{\mathrm{d}x}= 2x dxdL2(x)=2x
优点: 收敛速度快,能够对梯度给予合适的惩罚权重,而不是“一视同仁”,使梯度更新的方向可以更加精确。
缺点: 对异常值十分敏感,梯度更新的方向很容易受离群点所主导,不具备鲁棒性。
对于L1范数和L2范数,如果异常值对于实际业务非常重要,我们可以使用MSE作为我们的损失函数;另一方面,如果异常值仅仅表示损坏的数据,那我们应该选择MAE作为损失函数。此外,考虑到收敛速度,在大多数的卷积神经网络中(CNN)中,我们通常会选择L2损失。
因为这个差异要被平方放大,所以就会表现出越小的距离( − 1 ≤ x ≤ 1 -1\le x\le1 −1≤x≤1 ),对于大的平方后就会放大。
Smooth L1 Loss即为平滑的L1损失(SLL),出自Fast RCNN。SLL通过综合L1和L2损失的优点,在0点处附近采用了L2损失中的平方函数,解决了L1损失在0点处梯度不可导的问题,使其更加平滑易于收敛。此外,在 ∣ x ∣ > 1 |x|>1 ∣x∣>1 的区间上,它又采用了L1损失中的线性函数,使得梯度能够快速下降。
s m o o t h L 1 ( x ) = { 0.5 x 2 , ∣ x ∣ < 1 ∣ x ∣ − 0.5 , o t h e r w i s e \mathrm{smooth_{L_1}}(x)= \begin{cases} 0.5x^2,&|x|<1 \\ |x|-0.5,&\mathrm{otherwise} \end{cases} smoothL1(x)={0.5x2,∣x∣−0.5,∣x∣<1otherwise
d s m o o t h L 1 d x = { x , ∣ x ∣ < 1 ± 1 , o t h e r w i s e \frac{\mathrm{d \ smooth_{L_1}}}{\mathrm{d}x} = \begin{cases} x, & |x|<1 \\ ±1, & \mathrm{otherwise} \end{cases} dxd smoothL1={x,±1,∣x∣<1otherwise
通过对这三个损失函数进行求导可以发现,L1损失的导数为常数,如果不及时调整学习率,那么当值过小时,会导致模型很难收敛到一个较高的精度,而是趋向于一个固定值附近波动。反过来,对于L2损失来说,由于在训练初期值较大时,其导数值也会相应较大,导致训练不稳定。最后,可以发现Smooth L1在训练初期输入数值较大时能够较为稳定在某一个数值,而在后期趋向于收敛时也能够加速梯度的回传,很好的解决了前面两者所存在的问题。
Entropy即为“熵”,熵的概念最早起源于物理学,用于度量一个热力学系统的无序程度。但更常见的,在信息论里面, 熵是用于描述对不确定性的度量。所以,这个概念可以延伸到深度神经网络中,比如我们的模型在做分类时,其实也是在做一个判断一个物体到底是不是属于某个类别。因此,在正式介绍分类损失函数时,我们必须先了解熵的概念。
数字化时代,信息都是由bit(0和1)组成的。在通信时,有些位是有用(useful)的信息,有些位则是冗余(redundant)的信息,有些位甚至是错误(error)的信息,等等。当我们传达信息时,我们希望尽可能多地向接收者传递有用的信息。
传输1比特的信息意味着将接收者的不确定性降低2倍。 —— 香农
如何理解香农的这句话,1bit意味着只有两种情况。对于一件事情发的概率,加入只有两种情况:
- 发生了
- 没有发生
那么我们的猜对的概率就是50%,也就是不确定性有50%。
这时如果传输过来1bit的数据,那么这意味着这件事情的概率我们是已知的,即事情的不确定性从50%降低为了0%,确定性从原来的50%上升到100%,100% / 50%=2,即我们的确定性上升了2倍,也就意味着不确定性降低了2倍。
下面以一个天气预报的例子为例,形象化的讲解熵到底尤为何物?假设一个地方的天气是随机的,每天有50%的机会是晴天或雨天。
现在,如果气象站告诉您明天将要下雨,那么这个消息将不确定性降低了2倍。
这里和香农的那句话是一个道理
起初,有两种同样可能的可能性,但是在收到气象站的更新信息后,我们只有一种 。 在这里,气象站向我们发送了一点有用的信息,无论他们如何编码这些信息,这都是事实。即使发送的消息是雨天的,每个字符占一个字节,消息的总大小为40位,但它们仍然只通信1位的有用信息。
现在,我们假设天气有8种可能状态,且都是等可能的。
那么,当气象站为您提供第二天的天气时,它们会将您的不确定性降低了8倍(告诉了我们明天会下雨,所以下雨成了一个确定性的概率1)。由于每个事件的发生几率为1/8,因此降低因子为8。
但如果这些可能性不是等概率的呢?比如,75%的机会是晴天,25%的机会是雨天。
现在,如果气象台说第二天会下雨,那么你的不确定性就降低了4倍,也就是2比特的信息。
不确定性的减少就是事件概率的倒数(因为一个事件发生的概率被确定为1,那么不发生的概率就确定为0)。
在这种情况下,25%的倒数是4, log 2 4 = 2 \log_24=2 log24=2 。因此,我们得到了2bit有用的信息。
这个有用信息是一个固定公式计算得到的,这里不用纠结。
如果气象站说第二天是晴天,那么不确定性就降低了 1 0.75 \frac{1}{0.75} 0.751,那么我们得到 log 2 1 0.75 = 0.4150 \log_2\frac{1}{0.75}=0.4150 log20.751=0.4150 bit的有用信息。
那么,我们平均能从气象站得到多少信息呢?明天是晴天的概率是75%这就给了你0.41比特的信息而明天是雨天的概率是25%这就给了你2比特的信息,这就对应我们平均每天从气象站得到0.81比特的信息,计算如下图:
我们刚刚所计算出来的就叫做熵(Entropy),它可以很好地描述事件的不确定性。它是由以下公式给出:
E n t r o p y , H ( p ) = − ∑ p ( i ) ∗ log ( p ( i ) ) \mathrm{Entropy}, H(p) = - \sum p(i) * \log(p(i)) Entropy,H(p)=−∑p(i)∗log(p(i))
它衡量的是你每天了解天气情况时所得到的平均信息量。一般来说,它给出了给定概率分布 p p p中样本值的平均信息量,并且它还会告诉我们概率分布有多不可预测。
如果我们住在沙漠中央,那里每天都是阳光灿烂的,平均来说,我们不会每天从气象站得到很多信息,熵会接近于零。另一方面,如果天气变化很大,熵就会大得多。
意思就是说,如果一个事件可预测性很低,那么给这个事件一个确定性,则这个确定性会携带大量的信息量。
就好比,1+1=2,这件事情所包含的信息量是0,因为它对于每个人来说,1+1就是等于2,你杠你说的对。
总的来说:
现在,让我们讨论一下交叉熵。它指的是平均信息长度。考虑同样的例子,8种可能的天气条件,所有都是等可能的,每一种都可以用3位编码即 2 3 = 8 2^3=8 23=8。
现在,假设你住在一个阳光充足的地区,那里的天气概率分布是这样的:
即每天有35%的机会出现晴天,只有1%的机会出现雷雨。我们可以计算这个概率分布的熵,我们得到2.23bits的熵,具体计算公式如下:
E n t r o p y , H ( p ) = − ∑ p ( i ) ∗ log ( p ( i ) ) = − ( 0.35 × log 0.35 + 0.35 × log 0.35 + 0.1 × log 0.1 + 0.1 × log 0.1 + 0.04 × log 0.04 + 0.04 × log 0.04 + 0.01 × log 0.01 + 0.01 × log 0.01 ) = 2.23 b i t \begin{aligned} \mathrm{Entropy}, H(p) & = - \sum p(i) * \log(p(i)) \\ & = -( 0.35 \times \log0.35 + 0.35 \times \log0.35 + 0.1 \times \log0.1 + 0.1 \times \log0.1 +\\& 0.04 \times \log0.04 + 0.04 \times \log0.04 + 0.01 \times \log0.01 + 0.01 \times \log0.01 ) \\ & =2.23 \ \mathrm{bit} \end{aligned} Entropy,H(p)=−∑p(i)∗log(p(i))=−(0.35×log0.35+0.35×log0.35+0.1×log0.1+0.1×log0.1+0.04×log0.04+0.04×log0.04+0.01×log0.01+0.01×log0.01)=2.23 bit
所以,平均来说,气象站发送了3个bits,但接收者只得到2.23个bits有用的信息。
我们可以做得更好,例如更改编码方式:
现在,我们只使用2bit用于表示晴天或部分晴天,使用3bit用于多云和大部分多云,使用4bit用于表示中雨和小雨,使用5bit用于大雨和雷暴。天气的编码方式是明确的,并且如果你链接多条消息,则只有一种方法可以解释位的顺序。 例如,01100只能表示部分晴天(01),然后是小雨(100)。 因此,如果我们计算该站每天发送的平均比特数,则可以得出:
E n t r o p y , H ( p ) = − ∑ p ( i ) ∗ log ( p ( i ) ) = − ( 0.35 × log 4 + 0.35 × log 4 + 0.1 × log 8 + 0.1 × log 8 + 0.04 × log 16 + 0.04 × log 16 + 0.01 × log 32 + 0.01 × log 32 ) = 0.35 × 2 + 0.35 × 2 + 0.1 × 3 + 0.1 × 3 + 0.04 × 4 + 0.04 × 4 + 0.01 × 5 + 0.01 × 5 = 2.42 b i t \begin{aligned} \mathrm{Entropy}, H(p) & = - \sum p(i) * \log(p(i)) \\ & = -( 0.35 \times \log4 + 0.35 \times \log4 + 0.1 \times \log8 + 0.1 \times \log8 +\\ & 0.04 \times \log16 + 0.04 \times \log16 + 0.01 \times \log32 + 0.01 \times \log32 ) \\ & = 0.35 \times2 + 0.35 \times 2+ 0.1 \times 3 + 0.1 \times 3 +\\ & 0.04 \times 4 + 0.04 \times 4 + 0.01 \times 5 + 0.01 \times 5 \\ & = 2.42 \ \mathrm{bit} \end{aligned} Entropy,H(p)=−∑p(i)∗log(p(i))=−(0.35×log4+0.35×log4+0.1×log8+0.1×log8+0.04×log16+0.04×log16+0.01×log32+0.01×log32)=0.35×2+0.35×2+0.1×3+0.1×3+0.04×4+0.04×4+0.01×5+0.01×5=2.42 bit
我们将得到4.58bit。大约是熵的两倍。 平均而言,该站发送4.58位,但只有2.23位对接收者有用。 每条消息发送的信息量是必要信息的两倍。 这是因为我们使用的编码对天气分布做出了一些隐含的假设。
例如,当我们在晴天使用2bit消息时,我们隐式地预测晴天的概率为25%。以同样的方式,我们计算所有天气情况:
分母中2的幂对应于用于传输消息的比特数。很明显,预测分布 q q q和 真实分布 p p p有很大不同。现在我们可以把交叉熵表示成真实概率分布 p p p 的函数和预测概率分布 q q q 的函数:
E n t r o p y , H ( p , q ) = − ∑ p ( i ) ∗ log ( q ( i ) ) \mathrm{Entropy}, H(p,q) = - \sum p(i) * \log(q(i)) Entropy,H(p,q)=−∑p(i)∗log(q(i))
log的底数为2
K-L Divergence即KL散度。对于交叉熵损失,除了我们在这里使用预测概率的对数 log ( q ( i ) ) \log(q(i)) log(q(i)) 外,它看起来与上面熵的方程非常相似。如果我们的预测是完美的,那就是预测分布等于真实分布,此时交叉熵就等于熵。 但是,如果分布不同,则交叉熵将比熵大一些位数。 交叉熵超过熵的量称为相对熵,或更普遍地称为库尔贝克-莱布里埃发散度(KL Divergence)。
K-L散度是衡量预测分布和真实分布之间的差异
总结如下:
C r o s s E n t r o p y = E n t r o p y + K L − D i v e r g e n c e \mathrm{CrossEntropy} = \mathrm{Entropy + KL - Divergence} CrossEntropy=Entropy+KL−Divergence
D K L ( p ∣ ∣ q ) = H ( p , q ) − H ( p ) = − ∑ i p i log ( q i ) − ( − ∑ i p i log ( p i ) ) = − ∑ i p i log ( q i ) + ∑ i p i log ( p i ) = ∑ i p i log p i q i \begin{aligned} \\ D_{KL}(p||q) & = H(p, q) - H(p) \\ & = -\sum_i p_i \log(q_i)-(-\sum_i p_i \log(p_i)) \\ & = -\sum_i p_i \log(q_i)+ \sum_i p_i \log(p_i) \\ & = \sum_i p_i \log\frac{p_i}{q_i} \end{aligned} DKL(p∣∣q)=H(p,q)−H(p)=−i∑pilog(qi)−(−i∑pilog(pi))=−i∑pilog(qi)+i∑pilog(pi)=i∑pilogqipi
接上面的例子,我们便可以顺便算出: KL散度 = 交叉熵 - 熵 = 4.58 - 2.23 = 2.35(Bits)。
在统计学意义上来说,KL散度可以用来衡量两个分布之间的差异程度。
通常来说,一般分类损失最常用的损失函数之一便是交叉熵损失。
假设我们当前做一个3个类别的图像分类任务,如猫、狗、猪。给定一张输入图片其真实类别是猫,模型通过训练用Softmax分类后的输出结果为:{“cat”: 0.3, “dog”: 0.45, “pig”: 0.25},那么此时交叉熵为:
E n t r o p y , H ( p , q ) = − ∑ p ( i ) ∗ log ( q ( i ) ) = − 1 × log ( 0.3 ) = 1.203 \mathrm{Entropy}, H(p,q) = - \sum p(i) * \log(q(i)) \\ = -1 \times \log(0.3) = 1.203 Entropy,H(p,q)=−∑p(i)∗log(q(i))=−1×log(0.3)=1.203
当输出结果为:{“cat”: 0.5, “dog”: 0.3, “pig”: 0.2}时,交叉熵为:
E n t r o p y , H ( p , q ) = − ∑ p ( i ) ∗ log ( q ( i ) ) = − 1 × log ( 0.5 ) = 0.301 \mathrm{Entropy}, H(p,q) = - \sum p(i) * \log(q(i)) \\ = -1 \times \log(0.5) = 0.301 Entropy,H(p,q)=−∑p(i)∗log(q(i))=−1×log(0.5)=0.301
可以发现,
这也就是为什么要使用交叉熵作为损失函数,原因有二:
Dice Loss即骰子损失,它是一种用于评估两个样本之间相似性度量的函数,取值范围为 [ 0 , 1 ] [0, 1] [0,1] ,值越大表示两个值的相似度越高(和余弦相似性是类似的),其基本定义(二分类)如下:
L d i c e = 1 − 2 ⋅ ∣ X ∩ Y ∣ ∣ X ∣ − ∣ Y ∣ = 1 − 2 ⋅ T P 2 ⋅ T P + F P + F N L_{\mathrm{dice}} = 1 - \frac{2 \cdot |X \cap Y|}{|X| - |Y|} = 1 - \frac{2 \cdot TP}{2 \cdot TP + FP + FN} Ldice=1−∣X∣−∣Y∣2⋅∣X∩Y∣=1−2⋅TP+FP+FN2⋅TP
其中, ∣ X ∩ Y ∣ |X∩Y| ∣X∩Y∣ 表示 X X X和 Y Y Y之间的交集, ∣ X ∣ |X| ∣X∣ 和 ∣ Y ∣ |Y| ∣Y∣ 分别表示集合 X X X 和 Y Y Y 中像素点的个数,分子乘于2保证值域范围在 [ 0 , 1 ] [0, 1] [0,1]之间,因为分母相加时会计算多一次重叠区间,如下图
从右边公式也可以看出,其实Dice系数是等价于F1分数的,优化Dice等价于优化F1值,F1计算如下:
F 1 = 2 P R P + R F_1 = 2 \frac{PR}{P + R} F1=2P+RPR
此外,为了防止dice loss的分母项为0,一般我们会在分子和分母处同时加入一个很小的数作为平滑系数,也称为拉普拉斯平滑项。Dice损失由以下两个主要特性:
所以一般来说,我们都会结合交叉熵损失或者其他分类损失一同进行优化。
Focal Loss(焦点损失),出自何凯明的《Focal Loss for Dense Object Detection》,出发点是解决目标检测领域中one-stage算法如YOLO系列算法准确率不高的问题。作者认为样本的类别不均衡(比如前景和背景)是导致这个问题的主要原因。
比如在很多输入图片中,我们利用网格去划分小窗口,大多数的窗口是不包含目标的。如此一来,如果我们直接运用原始的交叉熵损失,那么负样本所占比例会非常大,主导梯度的优化方向,即网络会偏向于将前景预测为背景。即使我们可以使用OHEM(在线困难样本挖掘)算法来处理不均衡的问题,虽然其增加了误分类样本的权重,但也容易忽略掉易分类样本。
而Focal loss则是聚焦于训练一个困难样本的稀疏集,通过直接在标准的交叉熵损失基础上做改进,引进了两个惩罚因子,来减少易分类样本的权重,使得模型在训练过程中更专注于困难样本。其Focal Loss (FL)基本定义如下:
F L ( p , p ^ ) = − ( α ( 1 − p ^ ) γ p log ( p ^ ) + ( 1 − α ) p ^ γ ( 1 − p ) log ( 1 − p ^ ) ) \mathrm{FL}(p, \hat{p}) = -( \alpha(1-\hat{p})^\gamma p \log(\hat{p}) + (1-\alpha)\hat{p}^{\gamma}(1-p)\log(1-\hat{p}) ) FL(p,p^)=−(α(1−p^)γplog(p^)+(1−α)p^γ(1−p)log(1−p^))
其中:
实验中,作者取 α = 0.25 , γ = 0.2 α=0.25, γ=0.2 α=0.25,γ=0.2 的效果最好,具体还需要根据任务的情况调整。
由此可见,Focal Loss引入两个超参数需要调整,而一般来说很需要经验才能调好。
Tversky loss,特沃斯基损失,发表于CVPR 2018上的一篇《Tversky loss function for image segmentation using 3D fully convolutional deep networks》文章,是根据 Tversky 等人于1997年发表的《Features of Similarity》文章所提出的Tversky指数所改造的。Tversky系数主要用于描述两个特征(集合)之间的相似度,其定义如下:
T ( A , B ) = ∣ A ∩ B ∣ ∣ A ∩ B ∣ + α ∣ A − B ∣ + β ∣ B − A ∣ T(A, B) = \frac{|A \cap B|}{|A \cap B| + \alpha|A-B| + \beta|B-A|} T(A,B)=∣A∩B∣+α∣A−B∣+β∣B−A∣∣A∩B∣
由上可知,它是结合了Dice系数(F1-score)以及Jaccard系数(IoU)的一种广义形式,如:
因此,我们只需控制 α \alpha α 和 β \beta β 便可以控制假阴性(FN)和假阳性(FP)之间的平衡。
比如在医学领域我们要检测肿瘤时,更多时候我们是希望Recall值(查全率,也称为灵敏度或召回率)更高,因为我们不希望说将肿瘤检测为非肿瘤,即假阴性。因此,我们可以通过增大 β \beta β 的取值,来提高网络对肿瘤检测的灵敏度。其中, α + β 的取值我们一般会令其1。
给定两个集合A,B,Jaccard 系数定义为A与B交集的大小与A与B并集的大小的比值,定义如下:
J ( A , B ) = ∣ A ∩ B ∣ ∣ A ∪ B ∣ = ∣ A ∩ B ∣ ∣ A ∣ + ∣ B ∣ − ∣ A ∩ B ∣ J(A, B) = \frac{|A \cap B|}{|A \cup B|} = \frac{|A \cap B|}{|A| + |B| - |A \cap B|} J(A,B)=∣A∪B∣∣A∩B∣=∣A∣+∣B∣−∣A∩B∣∣A∩B∣
当集合A,B都为空时, J ( A , B ) J(A,B) J(A,B) 定义为1。
与Jaccard 系数相关的指标叫做 Jaccard 距离,用于描述集合之间的不相似度。Jaccard 距离越大,样本相似度越低。公式定义如下:
d j ( A , B ) = 1 − J ( A , B ) = ∣ A ∪ B ∣ − ∣ A ∩ B ∣ ∣ A ∪ B ∣ = A Δ B ∣ A ∪ B ∣ d_j(A, B) = 1 - J(A, B) = \frac{|A \cup B| - |A \cap B|}{|A \cup B|} = \frac{A \Delta B}{|A \cup B|} dj(A,B)=1−J(A,B)=∣A∪B∣∣A∪B∣−∣A∩B∣=∣A∪B∣AΔB
其中对称差(symmetric difference) A Δ B = ∣ A ∪ B ∣ − ∣ A ∩ B ∣ A \Delta B = |A \cup B| - |A \cap B| AΔB=∣A∪B∣−∣A∩B∣。
J ( A , B ) ∈ [ 0 , 1 ] J(A, B) \in [0, 1] J(A,B)∈[0,1]
总的来说,损失函数的形式千变万化,但追究溯源还是万变不离其宗。其本质便是给出一个能较全面合理的描述两个特征或集合之间的相似性度量或距离度量,针对某些特定的情况,如类别不平衡等,给予适当的惩罚因子进行权重的加减。大多数的损失都是基于最原始的损失一步步改进的,或提出更一般的形式,或提出更加具体实例化的形式。
定义:在利用损失函数(Loss Function)计算出模型的损失值之后,接下来需要利用损失值进行模型参数的优化,这个过程使用的函数就是优化函数。
模型内部有些参数,是用来计算测试集中目标值 Y Y Y 的真实值和预测值 Y ^ \hat Y Y^ 的偏差程度的,基于这些参数,就形成了损失函数 J ( x ) J(x) J(x)。
比如说,权重( W W W)和偏差( b b b)就是这样的内部参数,一般用于计算输出值,在训练神经网络模型时起到主要作用。
在有效地训练模型并产生准确结果时,模型的内部参数起到了非常重要的作用。这也是为什么我们应该用各种优化策略和算法,来更新和计算影响模型训练和模型输出的网络参数,使其逼近或达到最优值。
在实践操作最常用到的是一阶优化函数。包括
一阶优化函数在优化过程中求解的是参数的一阶导数,这些一阶导数的值就是模型中参数的微调值。
梯度下降(Gradient Descent)是参数优化的基础方法。虽然已广泛应用,但是其自身存在许多不足,所以在其基础上改进的优化函数也非常多。
全局梯度下降的参数更新公式如下:
θ j = θ j − η × ∂ J ( θ j ) ∂ θ j \theta_j = \theta_j - \eta \times \frac{\partial J(\theta_j)}{\partial \theta_j} θj=θj−η×∂θj∂J(θj)
其中, θ \theta θ 为需要更新的参数,训练样本总数为 n n n , j = 0 , 1 , 2 , . . . , n j=0, 1, 2, ..., n j=0,1,2,...,n 是我们优化的参数对象, η \eta η 是学习速率, J ( θ ) J(\theta) J(θ) 是损失函数, ∂ J ( θ j ) ∂ θ j \frac{\partial J(\theta_j)}{\partial \theta_j} ∂θj∂J(θj) 是根据损失函数 J ( θ j ) J(\theta_j) J(θj) 来计算 θ \theta θ 的梯度。
计算损失值的时间成本和模型训练过程中的复杂度呈正相关 -> 模型越复杂,求梯度所花费时间越长。
假设划分出来的batch size为 m m m (即 j ∈ [ 0 , m − 1 ] j\in[0, m-1] j∈[0,m−1] ),其中的一个batch包含batch size个数据样本,那么一个batch的梯度下降的参数更新公式如下:
θ j = θ j − η × ∂ J b a t c h ( θ j ) ∂ θ j \theta_j = \theta_j - \eta \times \frac{\partial J_{\mathrm{batch}}(\theta_j)}{\partial \theta_j} θj=θj−η×∂θj∂Jbatch(θj)
容易导致优化函数的最终结果是局部最优解。
前者可以看成是batch_size = 1的Batch GD
假设我们随机选取的一部分数据集包含stochastic(随机的)个数据样本,那么随机梯度下降的参数更新公式如下:
θ j = θ j − η × ∂ J s t o c h a s t i c ( θ j ) ∂ θ j \theta_j = \theta_j - \eta \times \frac{\partial J_{\mathrm{stochastic}}(\theta_j)}{\partial \theta_j} θj=θj−η×∂θj∂Jstochastic(θj)
随机梯度下降算法和批量梯度下降的不同点在于其梯度是根据随机选取的训练集样本来决定的,其每次对 θ \theta θ 的更新,都是针对单个样本数据,并没有遍历完整的参数。 当样本数据很大时,可能到迭代完成,也只不过遍历了样本中的一小部分。因此,其速度较快,但是其每次的优化方向不一定是全局最优的,最终的结果是在全局最优解的附近。
虽然BGD可以让参数达到全局最低点并且停止,而SGD可能会让参数达到局部最优,但是仍然会波动,甚至在训练过程中让参数会朝一个更好的更有潜力的方向更新。众多的实验表明,当我们逐渐减少学习速率时,SGD和BGD会达到一样的全局最优点。
训练速度快,避免了BGD更新过程中的计算冗余问题,对于很大的数据集,也能够以较快的速度收敛。
那么这样一来,学习率 η \eta η 如何衰减就成了问题。如果要保证SGD收敛,应该满足如下两个要求:
而在实际操作中,一般是进行线性衰减,即:
η k = ( 1 − α ) η 0 + α η τ α = k τ \eta_k = (1-\alpha) \eta_0 + \alpha \eta_\tau \\ \alpha = \frac{k}{\tau} ηk=(1−α)η0+αητα=τk
其中 η 0 \eta_0 η0 是初始学习率, η τ \eta_{\tau} ητ 是最后一次迭代的学习率, τ \tau τ 自然代表迭代次数。
一般来说, η τ \eta_\tau ητ 设为 η 0 \eta_0 η0 的 1 % 1\% 1% 比较合适。而 τ \tau τ 一般设为让训练集中的每个数据都输入模型上百次比较合适。那么初始学习率 η 0 \eta_0 η0 怎么设置呢?书上说,你先用固定的学习速率迭代100次,找出效果最好的学习速率,然后 η 0 \eta_0 η0 设为比它大一点就可以了。
另外,需要注意的是因为存在样本选择的随机性,所以在梯度下降过程中会存在较大的噪声,因此学习速率应该要逐渐减小,来寻找一个相对全局最优的方向。
同时也考虑到每次只选择一个样本进行梯度更新存在较大的噪声,学者们开始尝试每次选择一小批样本进行梯度更新,在降低噪声的同时提高速度,因此就有了下面的MBGD(Mini-Batch Gradient Descent)小批量梯度下降法。
为了综合上述两种方法,提出了小批量梯度下降。
在每次迭代时考虑一小部分样本,比如考虑10个样本,同时计算在这10个样本点上的每个参数的偏导数,对于每个优化参数,将该参数在这10个样本点的偏导数求和。
但是,需要注意的是因为这里也存在样本选择的随机性,学习速率应该要逐渐减小,同时上述方法并不能保证好的收敛性。
基于上述问题,又有了如下更多的优化策略!
上述SGD和MBGD算法都存在样本选择的随机性,因此含有较多的噪声,而momentum能解决上述噪声问题,尤其在面对小而较多噪声的梯度时,它往往能加速学习速率。
Momentum借用了物理中的动量概念,即前几次的梯度也会参与运算。为了表示动量,引入了一个新的变量 v v v (velocity,速度)。 v v v 是之前的梯度的累加,但是每回合都有一定的衰减。
其中参数 α \alpha α 表示每回合速率 v v v 的衰减程度。同时也可以推断得到:如果每次迭代得到的梯度都是 g g g ,那么最后得到的 v v v 的稳定值为 η ∣ ∣ g ∣ ∣ 1 − α \frac{\eta ||g||}{1-\alpha} 1−αη∣∣g∣∣。
也就是说,Momentum最好情况下能够将学习速率加速 1 1 − α \frac{1}{1-\alpha} 1−α1 倍。一般 α \alpha α 的取值为0.9或者更小。
当然,也可以让 α \alpha α 的值随着时间而变化:一开始小点,后来再加大。不过这样一来,又会引进新的参数。
本质上来说,就和我们把球从山上退下来一样,球的速度会越来越快。和我们的参数更新一样:
即:
仅仅有一个追求速度的球往山下滚是不能令人满意的,我们需要一个球,它能知道往前一步的信息,并且当山坡再次变陡时他能够减速。因此,带有nesterov的出现了!
momentum:
nesterov momentum:
这是对之前的Momentum的一种改进,大概思路就是,先对参数进行估计(先往前看一步,探路),然后使用估计后的参数来计算误差。
注意在估算 g ^ \hat{g} g^ 的时候,参数变成了 θ + α v θ+αv θ+αv 而不是之前的 θ \theta θ 。
AdaGrad可以自动变更学习速率,只是需要设定一个全局的学习速率 η \eta η,但是这并非是实际学习速率。实际的速率是与以往参数的模之和的开方成反比的。也许说起来有点绕口,不过用公式来表示就直白的多:
η n = η δ + ∑ i = 1 n − 1 g i ⊙ g i \eta_n = \frac{\eta}{\delta+\sqrt{\sum_{i=1}^{n-1}}g_i \odot g_i} ηn=δ+∑i=1n−1gi⊙giη
其中 δ \delta δ 是一个很小的常量,大概在 1 0 − 7 10^{-7} 10−7 ,防止出现除以 0 0 0的情况。
对于频繁出现的参数使用更小的更新速率,对于不频繁出现的参数使用更大的更新速率。
正因为如此,该优化函数较适用于稀疏的数据,比如在Google从YouTube视频上识别猫时,该优化函数大大提升了SGD的鲁棒性。在训练GloVe词向量时该优化函数更加适用。
在SGD中,我们对所有参数进行同时更新,这些参数都使用同样的学习速率。比如用 g t , i g_{t,i} gt,i 表示在 t t t 时间点,对 i i i 参数求得的偏导。
g t , i = Δ θ J ( θ i ) g_{t, i} = \Delta_\theta J(\theta_i) gt,i=ΔθJ(θi)
那么在SGD中就会用同一个学习速率对 i i i 参数进行更新:
θ t + 1 , i = θ t , i − η ⋅ g t , i \theta_{t+1, i} = \theta_{t, i} - \eta \cdot g_{t, i} θt+1,i=θt,i−η⋅gt,i
但是在AdaGrad里,会综合考虑 i i i 之前的所有梯度值来更新学习速率:
θ t + 1 , i = θ t , i − η G t , i i + ϵ ⋅ g t , i \theta_{t+1, i} = \theta_{t, i} - \frac{\eta}{\sqrt{G_{t, ii}+\epsilon}} \cdot g_{t, i} θt+1,i=θt,i−Gt,ii+ϵη⋅gt,i
其中 G t , i i G_{t,ii} Gt,ii 是一个对角矩阵, i i i 行 i i i 列存储了目前时间点为止的所有 i i i参数的偏导的平方和。后面的项是一个很小的值(1e−8),为了防止除 0 0 0错误。
能够实现学习率的自动更改。如果这次梯度大,那么学习速率衰减的就快一些;如果这次梯度小,那么学习速率衰减的就慢一些。
最大的缺点在于分母中那个 G G G是偏导的累积,随着时间的推移,分母会不断的变大,最后会使得学习速率变的非常小,而此时会使得模型不再具备学习其他知识的能力。
经验表明,在普通算法中也许效果不错,但在深度学习中,深度过深时会造成训练提前结束。因为它到后面的衰减可能越来越慢,然后就提前结束了。为了解决提前结束的问题,引入了如下的算法:Adadelta, RMSprop。
AdaDelta是AdaGrad的延伸,不同于AdaDelta将以前所有的偏导都累加起来,AdaDelta控制了累加的范围到一定的窗口中。
但是,并非简单的将窗口大小设置并且存储,我们是通过下式动态改变的上述的 G G G:
E [ g 2 ] t = γ E [ g 2 ] t − 1 + ( 1 − γ ) g t 2 E[g^2]_t = \gamma E[g^2]_{t-1} + (1-\gamma)g_t^2 E[g2]t=γE[g2]t−1+(1−γ)gt2
这里面的 γ \gamma γ类似于momentum里面的项( α \alpha α通常取值0.9),用来控制更新的权重。
因此以前的:
θ t + 1 = θ t − η G t + ϵ ⊙ g t \theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{G_t+\epsilon}} \odot g_t θt+1=θt−Gt+ϵη⊙gt
将被改变为:
θ t = − η E [ g 2 ] t + ϵ g t \theta_{t} = - \frac{\eta}{\sqrt{E[g^2]_t+\epsilon}} \ g_t θt=−E[g2]t+ϵη gt
RMSProp通过引入一个衰减系数,让 r r r 每回合都衰减一定比例,类似于Momentum中的做法。
和Adadelta没啥区别
算法的提出者建议如上式所示, γ \gamma γ取0.9,学习速率为0.001
Adam自适应时刻估计方法(Adaptive Moment Estimation),一个比较智能的优化函数方法。它在模型训练优化的过程中通过让每个参数获得自适应的学习率,来达到优化质量和速度的双重提升。现在一般都选择用这个方法。
Adam(Adaptive Moment Estimation)是另外一种给每个参数计算不同更新速率的方法,其本质上是带有动量项的RMSprop,它利用梯度的一阶矩估计和二阶矩估计动态调整每个参数的学习率。
主要在于经过偏置校正后,每一次迭代学习率都有个确定范围,使得参数比较平稳。它和上述的adadelta和RMSprop一样,都存储了以前的偏导平方衰减平均值,此外,它还存储以前的偏导衰减平均值。
其中几个取值一般为:
δ = 1 0 − 8 , ρ 1 = 0.9 , ρ 2 = 0.999 \delta=10^{−8}, \rho_1=0.9, \rho_2=0.999 δ=10−8,ρ1=0.9,ρ2=0.999
中间变量:一阶动量 s s s ,二阶动量 r r r 都初始化为0
其中的 m t m_t mt 和 v t v_t vt 分别表示平均值角度和非中心方差角度的偏导。
m t ^ = m t 1 − β 1 t v t ^ = v t 1 − β 2 t θ t + 1 = θ t − η v t ^ + ϵ m t ^ \begin{aligned} & \hat{m_t} = \frac{m_t}{1-\beta_1^t} \\ & \hat{v_t} = \frac{v_t}{1-\beta_2^t} \\ & \theta_{t+1} = \theta_t - \frac{\eta}{\sqrt{\hat{v_t}}+\epsilon}\hat{m_t} \end{aligned} mt^=1−β1tmtvt^=1−β2tvtθt+1=θt−vt^+ϵηmt^
Adam作者建议: β 1 = 0.9 , β 2 = 0.999 , ϵ = 1 0 − 8 \beta_1=0.9, \beta_2=0.999, \epsilon=10^{-8} β1=0.9,β2=0.999,ϵ=10−8 ,并且声称Adam在实践中比其他的自适应算法有更好的表现。
综上,RMSprop、Adadelta、Adam都是类似的。