无论是gbdt还是xgboost,以前我纠结拟合的是啥,后来才明白,优化才是核心。
拟合是外在,优化是核心
GBDT也好,XGBOOST也好,目标就是寻找多棵树的预测结果,合起来比如简单求和、加权求和,与实际值尽量接近(损失函数最小)。
本质工作就是最小化损失函数,使得预测值与实际值尽量接近
1.以GBDT来看树的生成
拿起笔,拿一张纸,边写边画,门槛不高,易懂,还是会损失一些严谨性。
既然目标是找到多棵树(树是二叉树,多叉树可等价为一个多层的二叉树),合起来(比如求和)后,样本的预测值与实际值尽量接近,那么我们首先来解决一个问题:
1.1 叶子节点值如何确定:损失函数求最优
假设已经存在了 t − 1 t-1 t−1棵树,如何设计第 t t t棵树,使得经过第 t t t棵树后,整体样本的预测值与实际值尽量接近?
- 假设已经存在了 t − 1 t-1 t−1棵树( t = 1 t=1 t=1时,就是GBDT/XgBoost的初始状态), m m m个样本,每个样本的实际值也就是label为 y i r y^r_i yir,其中 i = 1 , 2 , 3... m i=1,2,3...m i=1,2,3...m;
- 每个样本第 k k k棵树的预测值(叶子节点值)为 w i k w^k_i wik,其中 k = 1 , 2... t − 1 k=1,2...t-1 k=1,2...t−1, i = 1 , 2 , 3... m i=1,2,3...m i=1,2,3...m;
- 每个样本前面 t − 1 t-1 t−1棵树的预测值之和 y i t − 1 = ∑ k = 1 t − 1 w i k y^{t-1}_i = \sum_{k=1}^{t-1}w_i^k yit−1=∑k=1t−1wik, i = 1 , 2 , 3... m i=1,2,3...m i=1,2,3...m;
- 对于第 t t t棵树,先假设这棵树不分裂,只有一个根节点、也是叶子节点,那么这m个样本都分配到这个节点,那么m个样本在这颗树的预测值 w i t w^t_i wit是相等的,即 w 1 t = w 2 t = . . . = w m t {w^t_1}={w^t_2}=...={w^t_m} w1t=w2t=...=wmt,那么,请问 w i t w^t_i wit取值多少时能使得m个样本的 y i t y^{t}_i yit与label值 y i r y^r_i yir整体最接近?;
- 首先,如何衡量m个样本的 y i t y^{t}_i yit与label值 y i r y^r_i yir的整体接近程度呢,构建一个损失函数 L = 1 / m ∗ ∑ i = 1 m l ( y i t , y i r ) L=1/m*\sum_{i=1}^ml(y^{t}_i,y^r_i) L=1/m∗∑i=1ml(yit,yir),当 L L L越小时,m个样本的 y i t y^{t}_i yit与label值 y i r y^r_i yir的整体越接近;
- 先做一个简单的,假设使用平方损失函数也就是 L = 1 / m ∗ ∑ i = 1 m ( y i t − y i r ) 2 L=1/m*\sum_{i=1}^m(y^{t}_i-y^r_i)^2 L=1/m∗∑i=1m(yit−yir)2,代入3的公式得到 L = 1 / m ∗ ∑ i = 1 m ( y i t − 1 + w i t − y i r ) 2 L=1/m*\sum_{i=1}^m(y^{t-1}_i+w^t_i-y^r_i)^2 L=1/m∗∑i=1m(yit−1+wit−yir)2,对于构建 t t t棵树的时候,前面 t − 1 t-1 t−1棵树已经生成,所以 y i t − 1 y^{t-1}_i yit−1可以看做常数, y i r y^r_i yir本来也是固定的,所以可以假设这么一个常数 c i t − 1 = y i r − y i t − 1 c^{t-1}_i=y^r_i-y^{t-1}_i cit−1=yir−yit−1, L L L可以变为 L = 1 / m ∗ ∑ i = 1 m ( y i t − 1 + w i t − y i r ) 2 = 1 / m ∗ ∑ i = 1 m ( w i t − c i t − 1 ) 2 L=1/m*\sum_{i=1}^m(y^{t-1}_i+w^t_i-y^r_i)^2=1/m*\sum_{i=1}^m(w^t_i-c^{t-1}_i)^2 L=1/m∗∑i=1m(yit−1+wit−yir)2=1/m∗∑i=1m(wit−cit−1)2;
- 进一步,利用4中 w i t w^t_i wit都相等,设为 x x x,对于 L L L换个高中就熟悉的形式 L = 1 / m ∗ ∑ i = 1 m ( x − c i t − 1 ) 2 L=1/m*\sum_{i=1}^m(x-c^{t-1}_i)^2 L=1/m∗∑i=1m(x−cit−1)2,是不是很熟悉了, L L L是关于 x x x的二次函数,二次函数求最值,很简单吧;
- 恩,二次函数求极值会发现 x = 1 / m ∗ ∑ i = 1 m c i t − 1 x=1/m*\sum_{i=1}^mc^{t-1}_i x=1/m∗∑i=1mcit−1,是不是就是 m m m个样本在 t − 1 t-1 t−1树后残差 y i r − y i t − 1 y^r_i-y^{t-1}_i yir−yit−1的平均值;
- 所以,在损失函数为平方损失的时候,会发现第 t t t棵树学习的恰好是前 t − 1 t-1 t−1棵树的残差,这是损失函数最小化时的表象。
1.2 一次分裂的分裂点选择:枚举选最优
前面考虑的是第 t t t棵树不分裂,只有一个根节点,现在要求第 t t t棵树分裂1次,使得经过第 t t t棵树后,整体样本的预测值与实际值尽量接近?
- 继续画一画, m m m个样本有 j j j个特征,每个特征分裂点个数为 a j a_j aj,那么枚举的话,可以生成 ∑ i = 1 j a i \sum_{i=1}^ja_i ∑i=1jai种二叉树;从中,随便拿一个二叉树 T r e e s Tree_s Trees;
- 按照该树选择的特征和分裂点,一部分样本分配到左节点 N l e f t {N}_{left} Nleft,叶子节点取值为 w s , l e f t w_{s,left} ws,left,另一部分样本分配到右节点 N r i g h t {N}_{right} Nright,叶子节点取值为 w s , r i g h t w_{s,right} ws,right,这个时候 w s , l e f t w_{s,left} ws,left和 w s , r i g h t w_{s,right} ws,right的取值不用再说了吧,为使得损失函数 L s L_s Ls最小,继续上面的最优化求解,结果为这个叶子节点下样本残差的均值,此时的 L s L_s Ls也是 T r e e s Tree_s Trees对应的最优值;
- 在 ∑ i = 1 j a i \sum_{i=1}^ja_i ∑i=1jai种二叉树中,哪一棵树的 L s L_s Ls最小,就是这一轮分裂枚举的最优二叉树。
1.3 多次分裂的分裂点选择:复杂度计算+贪婪策略
进一步,前面考虑的是要求第 t t t棵树只分裂1次,使得经过第 t t t棵树后,整体样本的预测值与实际值尽量接近,那么现在要求分裂2次、3次、 h h h次、任意次呢,怎么做?
答案:大家都知道,用的贪婪策略,也就是先第一层遍历特征和分裂点,寻找最优的分裂点和叶子节点值;然后下一层也如此,一层一层下去。
现在我们来想想为什么选择这个策略:
- 先看看决策树生成的复杂度,第一层根节点最优分裂,对于 m m m个样本,有 j j j维特征,每个特征可分裂点数为 a j a_j aj,必然存在 a j ≤ m a_j\leq m aj≤m,那么第一层枚举特征、分裂点的种类数为 s 1 = ( ∑ i = 1 j a i ) ≤ j ∗ m s_1=(\sum_{i=1}^ja_i)\leq j*m s1=(∑i=1jai)≤j∗m,也就是说,枚举特征、特征分割点,需要遍历 s 1 s_1 s1次,取 L s L_s Ls最小的作为这一轮分裂选择;如果计算一次 L s L_s Ls的时间成本为 T c o n s T_{cons} Tcons,那么这一层枚举寻优时间消耗为 s 1 ∗ T c o n s ≤ j ∗ m ∗ T c o n s s_1*T_{cons}\leq j*m*T_{cons} s1∗Tcons≤j∗m∗Tcons;
- 第1层根节点分裂后,第2层左节点样本数为 m 2 , l m_{2,l} m2,l,右节点样本数为 m 2 , r m_{2,r} m2,r,满足 m 2 , l + m 2 , r = m m_{2,l}+m_{2,r}=m m2,l+m2,r=m,第2层左节点寻找最优分裂,枚举次数为 s 2 , l ≤ j ∗ m 2 , l s_{2,l}\leq j*m_{2,l} s2,l≤j∗m2,l,同样,右侧节点寻找最有分裂,枚举次数为 s 2 , r ≤ j ∗ m 2 , r s_{2,r}\leq j*m_{2,r} s2,r≤j∗m2,r,整体的枚举次数 s 2 = s 2 , l + s 2 , r ≤ j ∗ m 2 , l + j ∗ m 2 , r = j ∗ m s_2=s_{2,l}+s_{2,r}\leq j*m_{2,l}+j*m_{2,r}=j*m s2=s2,l+s2,r≤j∗m2,l+j∗m2,r=j∗m;这一层枚举寻优时间消耗为 s 2 ∗ T c o n s ≤ j ∗ m ∗ T c o n s s_2*T_{cons}\leq j*m*T_{cons} s2∗Tcons≤j∗m∗Tcons
- 你会发现,每一次层枚举次数的上边界值为 j ∗ m j*m j∗m,当然这只是边界值,实际的情况应该是 j ∗ 10 j*10 j∗10或者 j ∗ 100 j*100 j∗100这种,就是把特征按照分位点或者什么规则分成10个区间、100个区间等,就不细究了。这里重点就是,每一层的枚举花费时间都是一个级别,都是 j ∗ m ∗ T c o n s j*m*T_{cons} j∗m∗Tcons这个级别
- 关键点来了:对于深度为D层的树,你要找到数的最优结构,枚举次数是 ( j ∗ m ) D (j*m)^D (j∗m)D,到这里,你发现了,枚举最优树结构的复杂度是指数级别,因此选择贪婪策略是妥协选择。
- 贪婪做法:先遍历第1层选最优,再到第2层选最优…然后到D层,复杂度变为 ( j ∗ m ) ∗ D (j*m)*D (j∗m)∗D,哦豁,相对来说是线性级别。当然,贪婪的结果就是得到的结果是局部最优,不一定是全局最优。
- 这就是实际情况,并不一定需要全局最优,局部最优也够解决问题了
2.再看Xgboost损失函数
2.1 损失函数一般化,后面寻优策略本质未变
损失函数一般化,二阶近似,加上考虑模型复杂度的正则项。
一步步来,我们先搬出来上面的旧损失函数:
L = ∑ i = 1 m l ( y i t , y i r ) L=\sum_{i=1}^ml(y^{t}_i,y^r_i) L=∑i=1ml(yit,yir)
当时 l ( y i t , y i r ) l(y^{t}_i,y^r_i) l(yit,yir)假设为平方损失,后面就是一个一般的函数。
同样,与咱们上面的「1.1 叶子节点值如何确定」一样,仍然先考虑第 t t t棵树不分裂节点,样本都在这个节点下,预测值 w i t w_i^t wit都相等,原来的损失函数改一下到xgboost论文里的函数:
L = ∑ i = 1 m l ( y i t , y i r ) + γ ∗ T + 1 2 ∗ ( w i t ) 2 L=\sum_{i=1}^ml(y^{t}_i,y^r_i)+\gamma *T +\frac{1}{2}* (w_i^t)^2 L=∑i=1ml(yit,yir)+γ∗T+21∗(wit)2
后面的2项我在以前的博客说过啦:
我们重点来聊聊
l
(
y
i
t
,
y
i
r
)
l(y^{t}_i,y^r_i)
l(yit,yir),按照上文可以写成:
l ( y i t , y i r ) = l ( y i t − 1 + w i t , y i r ) l(y^{t}_i,y^r_i)=l(y^{t-1}_i+w^t_i,y^r_i) l(yit,yir)=l(yit−1+wit,yir)
我先假设一下,大家的数学水平在多年社会毒打后,停留在高中、大一这个层次,印象中留下的只有导数这么点感觉,我们把上面的形式换一个熟悉一点的情况:
l ( y i t , y i r ) = l ( y i t − 1 + w i t , y i r ) → l ( x 0 + Δ x , c ) l(y^{t}_i,y^r_i)=l(y^{t-1}_i+w^t_i,y^r_i)\rightarrow l(x_0+\Delta x,c) l(yit,yir)=l(yit−1+wit,yir)→l(x0+Δx,c)
然后,设计到泰勒展开式,这个呢,你可以百度一下,意思就是在 x = x 0 x=x_0 x=x0处用一个多项式 f m u l t i ( x 0 ) f_{multi}(x_0) fmulti(x0)来近似表示原函数,要求这个新的多项式函数在 x = x 0 x=x_0 x=x0处的函数值、1阶导、各级导数都与原函数相等:
l ( x 0 + Δ x , c ) ≈ l ( x 0 , c ) + ∂ l ( x , c ) ∂ x x = x 0 ∗ Δ x + 1 2 ∗ ∂ l 2 ( x , c ) ∂ x 2 x = x 0 ∗ Δ x 2 l(x_0+\Delta x,c) \approx l(x_0,c)+\frac{\partial l(x,c)}{\partial x}_{x=x_0}*\Delta x+\frac{1}{2}*\frac{\partial l^2(x,c)}{\partial x^2}_{x=x_0}*\Delta x^2 l(x0+Δx,c)≈l(x0,c)+∂x∂l(x,c)x=x0∗Δx+21∗∂x2∂l2(x,c)x=x0∗Δx2
写到这里,把 x 0 x_0 x0换回去 y i t − 1 y^{t-1}_i yit−1, Δ x \Delta x Δx换回去 w i t w^t_i wit,然后细品一下,细细品:
l ( y i t − 1 + w i t , y i r ) ≈ 1 2 a i ∗ ( w i t ) 2 + b i ∗ ( w i t ) + c i l(y^{t-1}_i+w^t_i,y^r_i) \approx \frac{1}{2}a_i*(w^t_i)^2+b_i*(w^t_i)+c_i l(yit−1+wit,yir)≈21ai∗(wit)2+bi∗(wit)+ci
其中 a i = ∂ l 2 ( x , c ) ∂ x 2 x = x 0 a_i=\frac{\partial l^2(x,c)}{\partial x^2}_{x=x_0} ai=∂x2∂l2(x,c)x=x0, b i = ∂ l ( x , c ) ∂ x x = x 0 b_i=\frac{\partial l(x,c)}{\partial x}_{x=x_0} bi=∂x∂l(x,c)x=x0, c i = l ( x 0 , c ) c_i=l(x_0,c) ci=l(x0,c)
(这里采用的符号、变量名很业余,很不严谨,只是方便回忆起高中数学、大学数学的感觉,好理解,理解是目的,形式咱先忍一忍…)
到这里,是不是发现损失函数也是一个二次函数,继续重新走上面的路「1.以GBDT来看树的生成:1.1叶子节点值如何确定;1.2一次分裂的分裂点选择;1.3 多次分裂的分裂点选择」,是不是又是二次函数求最值、枚举取最优,完事儿?
ps:还记得平方损失时,叶子节点数值 w i t w_i^t wit是节点样本的均值,那么看看上面新的损失函数二次近似以后叶子节点值是多少:
以节点不分离为例,此时 T = 1 T=1 T=1,
L = ∑ i = 1 m ( 1 2 a i ∗ ( w i t ) 2 + b i ∗ ( w i t ) + c i ) + γ + 1 2 ∗ ( w i t ) 2 L=\sum_{i=1}^m(\frac{1}{2}a_i*(w^t_i)^2+b_i*(w^t_i)+c_i)+\gamma +\frac{1}{2}* (w_i^t)^2 L=∑i=1m(21ai∗(wit)2+bi∗(wit)+ci)+γ+21∗(wit)2
二次函数求最值,不多说,还是如此的简单:
w i t ∗ = − ∑ 1 m b i γ + ∑ 1 m a i {w_i^t}^*=-\frac{\sum_1^mb_i}{\gamma+\sum_1^ma_i} wit∗=−γ+∑1mai∑1mbi
虽说后面的部分有工程上的细节优化,但是不改贪婪+枚举寻优的本质?
2.2 看下正则和二阶近似
1.正则提高泛化能力
实话说,原理上我也没仔细研究过,暂时贴一下人家的回答,我有空回头研究,https://www.zhihu.com/question/20700829:
看见没,人家这叫专业!
2.为啥是二阶近似,而不是一阶,为了快?
这个话题太专业了,看看人家的回答吧。
借用https://www.jiqizhixin.com/articles/2020-02-27-5的说法:
(1)直观感觉上
假设如果我们希望找到
L
L
L的「谷底」:
采用一阶梯度,也就是坡度的陡和缓来确定步子要迈多大;
而坡度本身也是有变化的,即逐渐变陡或变缓;
之前我们可以慢慢多走几步,就能根据坡度的变化直接调整;
如果能用二阶梯度,相当于梯度的梯度,那么也就知道坡度变化的趋势,因此一步就能走的更精准。
(2) 二阶优化,就是单次计迭代计算量增加了,但是每一步走得更精准,因而迭代步数更少,这是二阶梯度算法 Shampoo 表现
(3) 举一个不恰当,但是很直观的例子,拿二次函数寻最优来看,按一阶优化,要走几步才能到最低点,每一步计算下一阶导数就行;按二阶优化牛顿法,一步到位,但是要计算一阶导数和二阶导数,牛顿法我就不写公式了,看下这里https://blog.csdn.net/Im_Chenxi/article/details/80546742。
3.接着看Xgboost性能加速(待填坑)
4.看lightGBM性能加速(待填坑)
小结
xgboost果然是加强版的gbdt,工程上的优化先不说,损失函数一般化,这不就是明显的个例到一般的升华么?
另外,上次我说判断力最重要,后来想想也不对,还是执行力在前面,只敢想不敢做,哪来的经验积累,哪来的样本训练判断力,都是空想了。
「小时候自己十分好奇,同样是主角,为什么永远都是太一的亚古兽先进化。直到长大后才明白,都是因为:只有拥有了勇气,才会有友情,爱心,纯真,诚实,知识,光明,最后才会充满希望。」