最近看到集成学习的部分,觉得推导有点难,稍微写一写,推荐看看原论文或李宏毅老师的深度学习2019课程和周志华老师的《机器学习》,这里只关注Gradient Boosting 和 AdaBoost 的推导,综合了三部分内容,理清一下思路。
Gradient Boosting 本身是一个 general 的算法,使用不同的学习器和损失函数可以导出不同的具体的算法。这里换一个角度将整个框架搭建起来。首先,集成学习需要训练 T 个基学习器,然后用某种方法把这些基学习器的结果综合起来作为输出,就会是这样子:
For t = 1 to T:
\space \space \space \space \space \space train ft(x)
Output: F( f1(x), f2(x),…,fT(x) )
我们的目标很清晰,最终就是要得到一个强学习器,需要思考的是如何训练基学习器和如何整合起来。我们先略过构造的部分抽象的建模 G(x),这里的 G(x) 有点特别,它是很多个模型的综合,理论上这些模型都可能是不同质的:
Init G(x) = 0
For t = 1 to T:
\space \space \space \space \space \space train ft(x)
G(x) = F( f1(x), f2(x),…,fT(x) )
Output: sign(G(x))
从这里出发,或许可以产生许多种集成学习的思路,Gradient Boosting 假设各个学习器是弱学习器,后面训练的弱学习器的目标是校正前面训练的弱学习器的缺点,如果从模型 G(x) 的角度来看,每训练出一个模型,G(x) 的效果就会变好,所以整体上是一种提升算法:
Init G0(x) = 0
For t = 1 to T:
\space \space \space \space \space \space train ft(x)
\space \space \space \space \space \space update Gt(x) using Gt-1(x) and ft(x)
Output: sign(GT(x))
事实上,Gradient Boosting 采用加性模型,训练后面的基学习器时会固定住前面的基学习器,然后做简单的相加,注意到基学习器的训练过程是有序的,所以 Gradient Boosting 的基学习器的训练不能并行:
Init G0(x) = 0
For t = 1 to T:
\space \space \space \space \space \space train ft(x)
\space \space \space \space \space \space Gt(x) = Gt-1(x) + at · ft(x)
Output: sign(GT(x))
接下来需要细化提升的过程,所谓的提升一定是相对于某个损失而言的,因此我们需要选择适当的损失函数为整个算法提供方向。注意一下这里是第一个可以选择的地方:
target m i n i m i z e L ( G ) = ∑ i = 1 N L ( y i , G ( x i ) ) minimize \ \mathcal L(G) = \sum^{N}_{i=1} L(y^i, G(x^i)) minimize L(G)=∑i=1NL(yi,G(xi))
Init G0(x) = 0
For t = 1 to T:
\space \space \space \space \space \space train ft(x)
\space \space \space \space \space \space Gt(x) = Gt-1(x) + at · ft(x)
Output: sign(GT(x))
为了做到在 T 个学习器训练完成后整个模型的损失降到最小,我们观察 G(x) 的更新过程。如果训练的基学习器 ft(x) 正好是一个类似负梯度的东西,那就可以保证每一个学习器都有往正确的方向做贡献,再来,如果每一个 at 都选择得恰到好处,那就能达到类似线性搜索的效果,整个优化过程就是最佳的,这正是我们需要构造的两部分:
target m i n i m i z e L ( G ) = ∑ i = 1 N L ( y i , G ( x i ) ) minimize \ \mathcal L(G) = \sum^{N}_{i=1} L(y^i, G(x^i)) minimize L(G)=∑i=1NL(yi,G(xi))
Init G0(x) = 0
For t = 1 to T:
\space \space \space \space \space \space ft(x) = − ∂ L ( y , G t − 1 ( x ) ) ∂ G t − 1 ( x ) -\frac{ \partial L(y, G_{t-1}(x)) }{\partial G_{t-1}(x)} −∂Gt−1(x)∂L(y,Gt−1(x))
\space \space \space \space \space \space ρ \rho ρt = a r g m i n ρ ∑ i = 1 N L ( y i , G t − 1 ( x i ) + ρ argmin_\rho \sum^{N}_{i=1}L(y^i,G_{t-1}(x^i)+\rho argminρ∑i=1NL(yi,Gt−1(xi)+ρ · ft ( x i ) ) (x^i)) (xi))
\space \space \space \space \space \space Gt(x) = Gt-1(x) + ρ \rho ρt · ft(x)
Output: sign(GT(x))
ρ \rho ρt 的选择不必多讲,在最小化 Gt(x) 损失的过程中选择,就是选择最合适的步长,有问题的是训练 ft(x) 的过程。细心的你可能会发现,ft(x) 要逼近的梯度是一个对函数的偏导,在原论文中称为函数空间的梯度,计算的方法和对参数的偏导相同,简单的将函数看成是 vector 就可以了。但是,之所以说是逼近,是因为 ft(x) 是在有限的样本中训练出来的,只能是对真实函数的估计,一定会有偏差,所以实际上这里不能取等号,我们把它改成逼近的过程(后面略去 target ):
Init G0(x) = a r g m i n ρ ∑ i = 1 N L ( y i , ρ ) argmin_\rho \sum^{N}_{i=1}L(y^i,\rho) argminρ∑i=1NL(yi,ρ)
For t = 1 to T:
\space \space \space \space \space \space y ~ i \tilde y^i y~i = [ − ∂ L ( y i , G ( x i ) ) ∂ G ( x i ) ] G ( x ) = G x − 1 ( x ) , i = 1 , N [-\frac{ \partial L(y^i, G(x^i)) }{\partial G(x^i)}]_{G(x) =G_{x-1}(x)}\space,\space i=1,N [−∂G(xi)∂L(yi,G(xi))]G(x)=Gx−1(x) , i=1,N
\space \space \space \space \space \space ft(x) = a r g m i n f ∑ i = 1 N [ y ~ i − f ( x i ) ] 2 argmin_{f}\sum^{N}_{i=1}[\tilde y^i\space-\space f(x^i)]^2 argminf∑i=1N[y~i − f(xi)]2
\space \space \space \space \space \space ρ \rho ρt = a r g m i n ρ ∑ i = 1 N L ( y i , G t − 1 ( x i ) + ρ argmin_\rho \sum^{N}_{i=1}L(y^i,G_{t-1}(x^i)+\rho argminρ∑i=1NL(yi,Gt−1(xi)+ρ · ft ( x i ) ) (x^i)) (xi))
\space \space \space \space \space \space Gt(x) = Gt-1(x) + ρ \rho ρt · ft(x)
Output: sign(GT(x))
不用担心太复杂。这里的 y ~ \tilde y y~ 就是上面的负梯度,写成带有上标的形式只是为后面的书写方便而已,这里 ft(x) 向负梯度的逼近也是一个最小化损失的过程,损失函数选择平方损失,这里是第二个可以选择的地方,实际上基学习器选择怎么样子的,这里的损失函数要跟着修改,有时还要做一些变换,为了让训练第一个学习器时就能算梯度,修改了一下 G(x) 的初始化。到了这一步,看起来已经非常完善了,只是还有一个细节需要补充。注意到这里 ft(x) 的最小化过程,这里实际上最小化的是 x 和 y ~ \tilde y y~ 的联合概率的期望,与上一段同样的问题,对联合概率的估计只能是在有限的样本中完成,一定会有偏差,为了弥补这一段偏差,我们稍微修改一下最小化的过程:
Init G0(x) = a r g m i n ρ ∑ i = 1 N L ( y i , ρ ) argmin_\rho \sum^{N}_{i=1}L(y^i,\rho) argminρ∑i=1NL(yi,ρ)
For t = 1 to T:
\space \space \space \space \space \space y ~ i \tilde y^i y~i = [ − ∂ L ( y i , G ( x i ) ) ∂ G ( x i ) ] G ( x ) = G x − 1 ( x ) , i = 1 , N [-\frac{ \partial L(y^i, G(x^i)) }{\partial G(x^i)}]_{G(x) =G_{x-1}(x)}\space,\space i=1,N [−∂G(xi)∂L(yi,G(xi))]G(x)=Gx−1(x) , i=1,N
\space \space \space \space \space \space ft(x) = a r g m i n β ⋅ f ∑ i = 1 N [ y ~ i − β ⋅ f ( x i ) ] 2 argmin_{\beta ·f}\sum^{N}_{i=1}[\tilde y^i\space-\space \beta \space·f(x^i)]^2 argminβ⋅f∑i=1N[y~i − β ⋅f(xi)]2
\space \space \space \space \space \space ρ \rho ρt = a r g m i n ρ ∑ i = 1 N L ( y i , G t − 1 ( x i ) + ρ argmin_\rho \sum^{N}_{i=1}L(y^i,G_{t-1}(x^i)+\rho argminρ∑i=1NL(yi,Gt−1(xi)+ρ · ft ( x i ) ) (x^i)) (xi))
\space \space \space \space \space \space Gt(x) = Gt-1(x) + ρ \rho ρt · ft(x)
Output: sign(GT(x))
加入 β \beta β 的修正向后,最小化的过程会更准确一些,到这里再换一个更好看的书写方式就得到了与原论文相同的算法流程,非常经典:
Init G0(x) = a r g m i n ρ ∑ i = 1 N L ( y i , ρ ) argmin_\rho \sum^{N}_{i=1}L(y^i,\rho) argminρ∑i=1NL(yi,ρ)
For t = 1 to T:
\space \space \space \space \space \space y ~ i \tilde y^i y