0.摘要
Gradient Boosting Decision Tree (GBDT)是一个非常流行的机器学习算法,却只有像XGBoost和pGBRT的一些实现。尽管许多工程上的优化方案已经在这些实现中应用了,但是当特征维度较高和数据量巨大的时候,仍然存在效率和可扩展性的问题。一个主要原因就是对于每一个特征的每一个分裂点,都需要遍历全部数据计算信息增益,这一过程非常耗时。针对这一问题,本文提出两种新方法:Gradient-based One-Side Sampling (GOSS) 和Exclusive Feature Bundling (EFB)(基于梯度的one-side采样和互斥的特征捆绑)。在GOSS中,我们排除了一部分重要的具有小梯度实例数据的比例,只用剩下的来估计信息增益。我们证明,这些梯度大的实例在计算信息增益中扮演重要角色,GOSS可以用更小的数据量对信息增益进行相当准确的估计。对于EFB,我们捆绑互斥的特征(例如,特征间很少同时非零的特征),来降低特征的个数。我们完美地证明了捆绑互斥特征是NP难的,但贪心算法能够实现相当好的逼近率,因此我们能够在不损害分割点准确率许多的情况下,有效减少特征的数量。(牺牲一点分割准确率降低特征数量),这一算法命名为LightGBM。我们在多个公共数据集实验证明,LightGBM加速了传统GBDT训练过程20倍以上,同时达到了几乎相同的精度。
- GBDT的实现只有XGBoost和pGBRT, 且在实现了在工程上的优化方案
- 特征维度高和数据量巨大时,效率以及扩展性存在问题(计算每个特征的分裂点非常耗时)
- Gradient-based One-Side Sampling (GOSS):排除小梯度的数据比例,减少数据量的同时保证准确性
- Exclusive Feature Bundling (EFB) 降低特征的个数,同时保证准确率
- LightGBM加速了传统GBDT训练过程20倍以上,同时达到了几乎相同的精度
1.引言
GBDT是一个广泛应用的机器学习算法,这得益于其本身的有效性、准确性、可解释性。GBDT在许多机器学习任务上均取得了最好的效果,例如多分类,点击预测,排序。但最近几年随着大数据的爆发(特征量和数据量),GBDT正在面临新的挑战,特别是在平衡准确率和效率的调整方面。常见的GBDT的实现,对于每个特征,都需要遍历全部数据来计算所有可能分裂点的信息增益。因此,其计算复杂度将受到特征数量和数据量双重影响,造成处理大数据时十分耗时。
- GBDT被广泛应用,这得益于其本身的有效性、准确性、可解释性,在许多任务中取得最好的效果
- 在数据量和特征量激增的情况下, GBDT面临巨大的挑战(准确率和效率)
为了解决这一问题,一个直接的方法就是减少特征量和数据量而且不影响精确度。然而,这将是非常重要的。例如,我们不清楚如何针对提升GBDT来进行数据抽样。而有部分工作根据数据权重采样来加速boosting的过程,它们不能直接地应用于GBDT,因为gbdt没有样本权重。在本文中,我们提出两种新方法实现此目标。
解决问题的想法:1.减少特征数 2.减少数据量
Gradient-based One-Side Sampling (GOSS)。尽管GBDT虽然没有数据样本权重,但每个数据样本有不同的梯度,从而在信息增益的计算中扮演不同的角色。特别地,根据计算信息增益的定义,梯度大的样本对信息增益有更大的影响。因此,在数据样本下采样时,为了保持信息增益预估的准确性,我们应该尽量保留梯度大的样本(预先设定阈值,或者最高百分位间),并且随机去掉梯度小的样本。我们证明此措施在相同的采样率下比随机采样获得更准确的结果,尤其是在信息增益范围较大时。
- Gradient-based One-Side Sampling (GOSS)
- 在数据样本下采样时,为了保持信息增益预估的准确性,应该尽量保留梯度大的样本
- 同时随机去掉梯度小的样本
Exclusive Feature Bundling (EFB)。通常在真实应用中,虽然特征量比较多,但是由于特征空间十分稀疏,那我们是否可以设计一种无损的方法来减少有效特征呢?特别在,稀疏特征空间上,许多特征几乎都是互斥的(例如像文本挖掘中的one-hot特征)。我们就可以捆绑这些互斥的特征。最后,我们设计了一个有效的算法,将捆绑问题简化成图着色问题(方法是将特征作为节点,在每两个不完全互斥的特征之间添加边),并且通过贪心算法可以求得近似解。
- Exclusive Feature Bundling (EFB)
- 捆绑互斥的特征
- 贪心算法可以求得近似解
我们将这种结合了 GOSS 和 EFB 的新 GBDT 算法称为LightGBM。我们在多个公开数据集上的实验结果证明了 LightGBM 在得到几乎相同准确率的情况下能够提升20倍的训练速度。
GOSS 和 EFB 的新 GBDT 算法称为LightGBM
这篇文章剩下的部分将按如下安排。首先,我们在第二部分回顾了 GBDT 算法和相关工作。然后,我们分别在第三和第四部分介绍了 GOSS 和 EFB 的详细内容。在第五部分,展示了我们在公共数据集上所做的关于 LightGBM 的实验结果。最后,我们在第六部分进行了总结。
2.预研
2.1 GBDT概述和复杂度分析
GBDT是一种集成模型的决策树,顺序训练决策树。每次迭代中,GBDT通过拟合负梯度(也被称为残差)来学习决策树。
学习决策树是GBDT主要的时间花销,而学习决策树中找到最优切分点最消耗时间。有一种最常用的预排序算法来找到最优切分点,这种方法会列举预排序中所有可能的切分点。这种算法虽然能够找到最优的切分点,但在训练速度和内存消耗上的效率都很低。另一种流行算法是直方图算法(histogram-based algorithm),如 Alg.1 所示。直方图算法并不通过特征排序找到最优的切分点,而是将连续的特征值抽象成离散的分箱,并使用这些分箱在训练过程中构建特征直方图。这种算法更加训练速度和内存消耗上都更加高效,lightGBM使用此种算法。
- GBDT:集成学习、boosting、拟合负梯度
- 预排序算法:枚举出所有可能的切分点(耗时长、效率低)
- 直方图算法
- 将连续的特征值抽象成离散的分箱,并使用这些分箱在训练过程中构建特征直方图
histogram-based算法通过直方图寻找最优切分点,其建直方图消耗 O ( # d a t a ∗ # f e a t u r e ) O(\#data * \#feature) O(#data∗#feature),寻找最优切分点消耗 O ( # b i n ∗ # f e a t u r e ) O(\#bin * \# feature) O(#bin∗#feature),而 # b i n \#bin #bin 的数量远小于 # d a t a \#data #data,所以建直方图为主要时间消耗。如果能够减少数据量或特征量,那么还能够够加速GBDT的训练。(寻找最优切分点已经进行了优化,那么我们现在应该对建直方图的时间进行优化)
- 建立直方图为主要时间开销
- 直方图: O ( # d a t a ∗ # f e a t u r e ) O(\#data * \#feature) O(#data∗#feature)
- 寻找最佳切分点: O ( # b i n ∗ # f e a t u r e ) O(\#bin* \# feature) O(#bin∗#feature)
2.2 相关工作
GBDT有许多实现,如XGBoost,PGBRT,Scikit-learn,gbm in R。Scikit-learn和gbm in R实现都用了预排序,pGBRT使用了直方图算法。XGBoost支持预排序和直方图算法,由于XGBoost胜过其他算法,我们用它作为实验的baseline。
实验的baseline:XGBoost
为了减小训练数据集,通常做法是下采样。例如过滤掉权重小于阈值的数据。SGB每次迭代中用随机子集训练弱学习器。或者采样率基于训练过程动态调整。然而,这些都是使用基于AdaBoost的SGB,其不能直接应用于GBDT是因为GBDT中没有原始的权重。虽然SGB也能间接应用于GBDT,但往往会影响精度。
SGB每次迭代中用随机子集训练弱学习器。或者采样率基于训练过程动态调整。但是不能直接应用于GBDT,原因是GBDT中没有原始权重
同样,可以考虑过滤掉弱特征(什么是弱特征)来减少特征量。通常用主成分分析或者投影法。当然,这些方法依赖于一个假设-特征有高冗余性,但实际中往往不是。(设计特征来自于其独特的贡献,移除任何一维度都可以某种程度上影响精度)。
考虑过滤掉弱特征(什么是弱特征)来减少特征量(注意只是考虑)
实际中大规模的数据集通常都是非常稀疏的,使用预排序算法的GBDT能够通过无视为0的特征来降低训练时间消耗。然而直方图算法没有优化稀疏的方案。因为直方图算法无论特征值是否为0,都需要为每个数据检索特征区间值。如果基于直方图的GBDT能够有效解决稀疏特征中的0值,并且这样将会有很好的性能。
直方图中没有优化稀疏的方案, 因为直方图算法无论特征是否为0度需要为每个数据检索特征区间值
为了解决前面工作的局限性,我们提出了两个全新的技术分别是 Gradient-based One-Side Sampling (GOSS) 和 Exclusive Feature Bundling (EFB)(基于梯度的one-side采样和互斥的特征捆绑)。跟多的细节会再下一部分介绍。
3.基于梯度的one-side采样
在这一部分,我们为 GBDT 提出了一个新的抽样方法, 这能够在减少数据样本量和保持学习到的决策树的准确度之间达到一个平衡。
3.1 算法描述
在AdaBoost中,样本权重是数据样本重要性的指标。然而在GBDT中没有原始样本权重,不能应用权重采样。幸运的事,我们观察到GBDT中每个数据都有不同的梯度值,对采样十分有用,即实例的梯度小,实例训练误差也就较小,已经被学习得很好了,直接想法就是丢掉这部分梯度小的数据。然而这样做会改变数据的分布,将会影响训练的模型的精确度,为了避免此问题,我们提出了GOSS。
GOSS保留所有的梯度较大的实例,在梯度小的实例上使用随机采样。为了抵消对数据分布的影响,计算信息增益的时候,GOSS对小梯度的数据引入常量乘数。GOSS首先根据数据的梯度绝对值排序,选取 t o p a ∗ 100 % top \ a * 100\% top a∗100%个样本。然后在剩余的数据中随机采样 b ∗ 100 % b*100\% b∗100%个样本。接着计算信息增益时为采样出的小梯度数据乘以 1 − a b \frac{1-a}{b} b1−a(即,小梯度样本总数/随机采样出的小梯度样本数量),这样算法就会更关注训练不足的实例,而不会过多改变原数据集的分布。
- 在AdaBoost中,样本权重是数据样本重要性的指标。然而在GBDT中没有原始样本权重,不能应用权重采样。
- GBDT中每个数据都有不同的梯度值,对采样十分有用,即实例的梯度小,实例训练误差也就较小,已经被学习得很好了,直接想法就是丢掉这部分梯度小的数据。然而这样做会改变数据的分布,将会影响训练的模型的精确度
- GOSS保留所有的梯度较大的实例,在梯度小的实例上使用随机采样
- 为了抵消对数据分布的影响,计算信息增益的时候,GOSS对小梯度的数据引入常量乘数。
- GOSS(基于梯度的边采样)的做法:
- 根据数据的梯度绝对值排序,选取 t o p a ∗ 100 % top\ a * 100\% top a∗100%个样本
- 在剩余的数据中随机采样 b ∗ 100 % b*100\% b∗100%个样本
- 计算信息增益时为采样出的小梯度数据乘以 1 − a b \frac{1-a}{b} b1−a(小梯度样本总数/随机采样出的小梯度样本数量)
3.2 理论分析
GBDT使用决策树,来学习获得一个将输入空间 χ s χ^s χs映射到梯度空间 G G G的函数。 设训练集有 n n n个样本 x 1 , … , x n x_1,…,x_n x1,…,xn,每个 x i x_i xi都是一个维度为 s s s的特征向量。每次迭代时,模型数据变量的损失函数的负梯度方向表示为 g 1 , … , g n g_1,…,g_n g1,…,gn,决策树通过最优切分点(最大信息增益点)将数据分到各个节点。对于GBDT,一般通过分割后的方差衡量信息增益,具体由下定义。
定义3.1:
O
O
O表示某个固定叶子节点的训练集,分割特征
j
j
j的分割点
d
d
d对应的方差增益定义为:
V
j
∣
O
(
d
)
=
1
n
O
(
(
∑
{
x
i
∈
O
:
x
i
j
≤
d
}
g
i
)
2
n
l
∣
O
j
(
d
)
+
(
∑
{
x
i
∈
O
:
x
i
j
≤
d
}
g
i
)
2
n
r
∣
O
j
(
d
)
)
\bold V_{j|O}(d) = \frac {1}{n_O}\Big(\frac{(\sum_{\{x_i \in O:x_{ij}≤d\}}g_i)^2}{n^j_{l|O}(d)} + \frac{(\sum_{\{x_i \in O:x_{ij}≤d\}}g_i)^2}{n^j_{r|O}(d)} \Big)
Vj∣O(d)=nO1(nl∣Oj(d)(∑{xi∈O:xij≤d}gi)2+nr∣Oj(d)(∑{xi∈O:xij≤d}gi)2)
其中
n
O
=
∑
I
[
x
i
∈
O
]
n_O=\sum I[x_i \in O]
nO=∑I[xi∈O] ,
n
l
∣
O
j
(
d
)
=
∑
I
[
x
i
∈
O
:
x
i
j
≤
d
]
n^j_{l|O}(d)=\sum I[x_i \in O:x_{ij}≤d]
nl∣Oj(d)=∑I[xi∈O:xij≤d] 和
n
r
∣
O
j
(
d
)
=
∑
I
[
x
i
∈
O
:
x
i
j
≤
d
]
n^j_{r|O}(d)=\sum I[x_i \in O:x_{ij}≤d]
nr∣Oj(d)=∑I[xi∈O:xij≤d] 对于特征
j
j
j,决策树算法选择
d
j
∗
=
a
r
g
m
a
x
d
V
j
(
d
)
d_j^* = argma x_d V_j(d)
dj∗=argmaxdVj(d) 并且计算最大信息增益并且计算最大信息增益
V
j
(
d
j
∗
)
V_j(d_j^*)
Vj(dj∗)。然后,数据集会根据特征。然后,数据集会根据特征
j
∗
j^*
j∗ 在分裂点
d
j
∗
d_j^*
dj∗分到左右子节点中去。
在我们所提出的GOSS方法中,首先,我们训练样本按照它们梯度的绝对值进行降序排列;第二,我们保留梯度最大的
t
o
p
−
a
∗
100
%
top-a * 100\%
top−a∗100% 个样本作为样本子集A;再者,对于剩下的包含
(
1
−
a
)
∗
100
%
(1-a) * 100\%
(1−a)∗100%个更小梯度样本的子集
A
c
A^c
Ac,我们进一步随机抽样一个大小为
b
∗
∣
A
c
∣
b*|A^c|
b∗∣Ac∣的子集B;最后,我们我们将样本实例按照下列公式在子集
A
∪
B
A∪B
A∪B上的方法增益估计值进行分割:
V
j
~
(
d
)
=
1
n
(
(
∑
x
i
∈
A
l
g
i
+
1
−
a
b
∑
x
i
∈
B
l
g
i
)
2
n
l
j
(
d
)
+
(
∑
x
i
∈
A
l
g
i
+
1
−
a
b
∑
x
i
∈
B
l
g
i
)
2
n
r
j
(
d
)
)
(
1
)
\tilde{\bold V_j}(d)=\frac{1}{n}\Big( \frac{(\sum_{x_i \in A_l}g_i+\frac{1-a}{b}\sum_{x_i \in B_l}g_i)^2}{n^j_{l}(d)} + \frac{(\sum_{x_i \in A_l}g_i+\frac{1-a}{b}\sum_{x_i \in B_l}g_i)^2}{n^j_{r}(d)}\Big) \qquad\qquad(1)
Vj~(d)=n1(nlj(d)(∑xi∈Algi+b1−a∑xi∈Blgi)2+nrj(d)(∑xi∈Algi+b1−a∑xi∈Blgi)2)(1)
其中
A
l
=
{
x
i
∈
A
:
x
i
j
≤
d
}
,
A
r
=
{
x
i
∈
A
:
x
i
j
≤
d
}
A_l=\{x_i\in A:x_{ij}≤d\}, A_r=\{x_i\in A:x_{ij}≤d\}
Al={xi∈A:xij≤d},Ar={xi∈A:xij≤d} 和
B
l
=
{
x
i
∈
A
:
x
i
j
≤
d
}
,
B
r
=
{
x
i
∈
A
:
x
i
j
≤
d
}
B_l=\{x_i\in A:x_{ij}≤d\}, B_r=\{x_i\in A:x_{ij}≤d\}
Bl={xi∈A:xij≤d},Br={xi∈A:xij≤d},并且系数
1
−
a
b
\frac{1-a}{b}
b1−a是用来将B上的梯度和归一化到
A
c
A^c
Ac的大小上去。
因此,在GOSS中,我们使用更小样本子集上的估计值 V ~ j ( d ) \widetilde {\bold V}_j(d) V j(d) 而不是使用所有的实样本集来计算精确的 V j ( d ) \bold V_j(d) Vj(d)来得到分裂点,并且这种计算成本也可以得到大大地降低。更重要的是,下列定理表名了GOSS不会损失更多的训练精度并且会优于随机抽样。由于空间限制,我们将定理的证明放在了补充材料中。
定理3.2 我们将GOSS的近似误差定义为 ε ( d ) = ∣ V ~ j ( d ) − V j ( d ) ∣ ε(d)=| \widetilde V_j(d)−V_j(d)| ε(d)=∣V j(d)−Vj(d)∣ and g ‾ l j ( d ) = ∑ x i ∈ ( A ∪ A c ) l ∣ g i ∣ n l j ( d ) \overline{g}^j_l(d)=\frac{\sum_{x_i} \in (A \cup A^c)_l|g_i|}{n^j_l(d)} glj(d)=nlj(d)∑xi∈(A∪Ac)l∣gi∣ 和 g ‾ l j ( d ) = ∑ x i ∈ ( A ∪ A c ) r n r j ( d ) \overline{g}^j_l(d)=\frac{\sum_{x_i} \in (A \cup A^c)_r}{n^j_r(d)} glj(d)=nrj(d)∑xi∈(A∪Ac)r。概率至少是 1 − δ 1−δ 1−δ,我们有
根据定理,我们可以得到以下结论:
- GOSS的渐进近似比率是 O ( 1 n l j ( d ) + 1 n r j ( d ) + 1 n ) O(\frac{1}{n^j_l(d)}+\frac{1}{n^j_r(d)}+\frac{1}{\sqrt n}) O(nlj(d)1+nrj(d)1+n1)。 如果分割的不是特别不平衡(即 n l j ( d ) ≥ O ( n ) n^j_l(d)≥O(\sqrt{n}) nlj(d)≥O(n) 且 n r j ( d ) ≥ O ( n ) n^j_r(d)≥O(\sqrt{n}) nrj(d)≥O(n)),近似误差可以由公式(2)中的第二项来表示,其中当 n → ∞ n→∞ n→∞时 O ( n ) O(\sqrt{n}) O(n)将趋向于0。这意味着当数据集个数很大的时候,近似值将是很准确的。
- 随机抽样是一个 a = 0 a=0 a=0时GOSS的特例。在许多案例中,GOSS都会表现地比随机抽样要好,在 C 0 , β > C a , β − a C_{0,β}>C_{a,β−a} C0,β>Ca,β−a条件下,这等价于 α a β > 1 − a β − α \frac{α_a}{\sqrt{β}} > \frac{1−a}{\sqrt{β−α}} βαa>β−α1−a 且有 α a = m a x x i ∈ A ∪ A c ∣ g i ∣ m a x x i ∈ A c ∣ g i ∣ α_a=max_{x_i \in {A∪A^c}} \frac{|gi|} {max_{x_i \in A^c} |gi|} αa=maxxi∈A∪Acmaxxi∈Ac∣gi∣∣gi∣。
下一步,我们分析了GOSS的泛化表现。我们考虑了GOSS的泛化误差 ε g e n G O S S ( d ) = ∣ V ~ j ( d ) − V ∗ ( d ) ∣ \varepsilon_{gen}^{GOSS} (d) = |\tilde V_j (d) - V_ *(d)| εgenGOSS(d)=∣V~j(d)−V∗(d)∣,这个值是由GOSS中抽样训练得到的方差增益和潜在分布的真实方差增益之间的差值。我们有,这个值是由GOSS中抽样训练得到的方差增益和潜在分布的真实方差增益之间的差值。我们有 ε g e n G O S S ( d ) ≤ ∣ V ~ j ( d ) − V j ( d ) ∣ + ∣ V j ( d ) − V ∗ ( d ) ∣ ≜ ε G O S S ( d ) + ε g e n ( d ) \varepsilon_{gen}^{GOSS} (d) \leq |\tilde V_j (d) - V_j (d)| + |V_j (d) - V_* (d)| \triangleq \varepsilon_{GOSS} (d) + \varepsilon_{gen} (d) εgenGOSS(d)≤∣V~j(d)−Vj(d)∣+∣Vj(d)−V∗(d)∣≜εGOSS(d)+εgen(d)。因此,如果GOSS近似是准确的,那么带GOSS的泛化误差是接近于使用全量数据集计算得结果。另一方面,抽样会增加基础学习器之间的多样性,这潜在地帮助提升了泛化的表现。
4.互斥特征捆绑
这一章,我们提出了一个全新的方法来有效地减少特征数量。
高维的数据通常是非常稀疏的。这种稀疏性启发我们可以设计一种无损地方法来减少特征的维度。特别地,在稀疏特征空间中,许多特征是完全互斥的,即它们从不同时为非零值。我们可以绑定互斥的特征为单一特征(这就是我们所说的互斥特征捆绑)。通过仔细设计特征扫描算法,我们从特征捆绑中构建了与单个特征相同的特征直方图。这种方式的构建直方图时间复杂度从 O ( # d a t a ∗ # f e a t u r e ) O(\# data * \#feature) O(#data∗#feature) 降到 O ( # d a t a ∗ # b u n d l e ) O(\#data* \#bundle) O(#data∗#bundle),由于 # b u n d l e < < # f e a t u r e \#bundle << \# feature #bundle<<#feature,我们能够极大地加速GBDT的训练过程而且不损失精度。(构造直方图的时候,遍历一个“捆绑的大特征”可以得到一组exclusive feature的直方图。这样只需要遍历这些“大特征”就可以获取到所有特征的直方图,降低了需要遍历的特征量。)在下面,我们将会展示如何实现这些方法的细节。
有两个问题需要被解决。第一个就是需要确定哪些特征后应该绑定在一起。第二个就是如何构造捆绑。
定理4.1 将特征分割为较小量的互斥特征群是NP难的
*证明:*将图着色问题归约为此问题。而图着色是NP难的,所以我们可以得到我们的结论。
给定图着色的一个实例 G = ( V , E ) G=(V, E) G=(V,E)。可以构建一个我们问题的一个实例如下所示。以 G G G的关联矩阵的每一行为特征,得到我们问题的一个实例有 ∣ V ∣ |V| ∣V∣个特征。 很容易看到,在我们的问题中,一个独特的特征捆绑与一组具有相同颜色的顶点相对应,反之亦然。
对于第1个问题,我们在定理4.1说明寻找一个最优的捆绑策略是NP难的,这就表明不可能找到一个能够在多项式时间内解决的办法。为了寻找好的近似算法,我们将最优捆绑问题归结为图着色问题,如果两个特征之间不是相互排斥,那么我们用一个边将他们连接,然后用合理的贪婪算法(具有恒定的近似比)用于图着色来做特征捆绑。 此外,我们注意到通常有很多特征,尽管不是100%相互排斥的,也很少同时取非零值。 如果我们的算法可以允许一小部分的冲突,我们可以得到更少的特征包,进一步提高计算效率。经过简单的计算,随机污染小部分特征值将影响精度最多为 O ( [ ( 1 − γ ) n ] − 2 3 ) O([(1−γ)n]^{−\frac{2}{3}}) O([(1−γ)n]−32)(参考文献【2】), γ \gamma γ 是每个绑定中的最大冲突比率。所以,如果我们能选择一个相对较小的 γ \gamma γ 时,能够完成精度和效率之间的平衡。
基于上述的讨论,我们针对互斥特征捆绑设计了一个算法如Alg.3所示。首先,我们建立一个图,每个点代表特征,每个边有权重,其权重和特征之间总体冲突相关。第二,我们按照降序排列图中点的度来排序特征。最后,我们检查排序之后的每个特征,对它进行特征绑定或者建立新的绑定使得操作之后的总体冲突最小(由 γ \gamma γ 控制)。算法3的时间复杂度是 O ( # f e a t u r e 2 ) O (\# feature ^2) O(#feature2),并且只在训练之前处理一次。其时间复杂度在特征不是特别多的情况下是可以接受的,但难以应对百万维的特征。为了继续提高效率,我们提出了一个更加高效的不用构建图的排序策略:将特征按照非零值个数排序,这和使用图节点的度排序相似,因为更多的非零值通常会导致冲突。新算法在算法3基础上只是改变了排序策略来避免重复。
对于第2个问题,我们需要一个好的办法合并同一个bundle的特征来降低训练时间复杂度。关键在于原始特征值可以从bundle中区分出来。鉴于直方图算法存储离散值而不是连续特征值,我们通过将互斥特征放在不同的箱中来构建bundle。这可以通过将偏移量添加到特征原始值中实现,例如,假设bundle中有两个特征,原始特征A取值[0, 10],B取值[0, 20]。我们添加偏移量10到B中,因此B取值[10, 30]。通过这种做法,就可以安全地将A、B特征合并,使用一个取值[0, 30]的特征取代A和B。算法见Alg.4。
EFB算法能够将许多互斥的特征变为低维稠密的特征,就能够有效的避免不必要0值特征的计算。实际,对每一个特征,建立一个记录数据中的非零值的表,通过用这个表,来忽略零值特征,达到优化基础的直方图算法的目的。通过扫描表中的数据,建直方图的时间复杂度将从 O ( # d a t a ) O(\#data) O(#data)降到 O ( # n o n _ z e r o _ d a t a ) O(\# non\_zero\_data) O(#non_zero_data)。当然,这种方法在构建树过程中需要而额外的内存和计算开销来维持这种表。我们在lightGBM中将此优化作为基本函数.因为当bundles是稀疏的时候,这个优化与EFB不冲突(可以用于EFB).
5.实验
在这一部分,我们汇报了我们提出的LightGBM算法的实验结果。我们使用五个不同的公开数据集。这些数据集的细节列在了表1中。在它们中,微软的排序数据集包含30K网站搜索请求数据。这个数据集中的特征大多是稠密数值特征。Allstate Insurance Claim和Flight Delay数据集都包含许多one-hot编码特征。并且最后两个数据集来自KDD CUP 2010 and KDD CUP 2012。我们直接地使用这些由获胜者NTU提供的特征,其中包含稠密特征和稀疏特征,并且这两个数据集非常大。这些数据集都是很大的,同时包含稀疏特征和稠密特征,并且涵盖了许多真实的任务。因此,我们直接地可以使用它们来测试我们的算法。
我们的实验环境是一个Linux服务器,包含两个E5-2670 v3 CPUs(总共24核)和256GB的内存。所有试验都是多线程运行并且线程的个数固定在16。
5.1 全部对比
我们在这一部分展示了所有的实验对比。XGBoost和不包含GOSS以及EFB(称为lgb_baseline)的LightGBM用作基准线。对于XGBoost,我们使用两个版本,xgb_exa(预排序算法)和xgb_his(基于直方图的算法)。对于xgb_his,lgb_baseline,和LightGBM,我们使用leaf-wise树增长方法。对于xgb_exa,因为它仅仅支持layer-wise增长策略,我们将xgb_exa的参数设成使其和其他方法增长相似的树。我们也可以通过调整参数使其在所有的数据集上能在速度和准确率上面达到平衡。我们在Allstate, KDD10 和 KDD12上设定 a = 0.05 , b = 0.05 a=0.05,b=0.05 a=0.05,b=0.05,并且在Flight Delay 和 LETOR上设定 a = 0.1 ; b = 0.1 a = 0.1; b = 0.1 a=0.1;b=0.1。我们对于EFB设定 γ = 0 \gamma=0 γ=0。所有的算法都运行固定的线程数,并且我们从迭代过程中获取最好的分数的准确率结果。
训练时间和测试准确率分别汇总在表2和表3中。从这些结果中,我们能够看到在于基准线保持几乎相同准确率的时候是最快速的。xgb_exa是基于预排序的算法,这相对于基于直方图的算法是非常慢的。相对于lgb_baseline,LightGBM在Allstate, Flight Delay, LETOR, KDD10 和 KDD12数据集上分别加速了21,6,1.6,14和13倍。因xgb_his非常消耗内存,导致其在KDD10 和 KDD12数据集上内存溢出而不能成功运行。在剩下的数据集上,LightGBM都是最快的,最高是在Allstate数据集上加速了9倍。由于所有的算法都在差不多的迭代次数后收敛了,所以加速是基于平均每次迭代时间计算得到的。为了展示整个训练过程,我们基于Flight Delay 和 LETOR的经过的时间也分别展示了训练曲线在图1和图2中。为了节省空间,我们将其他数据集的训练曲线放在了补充材料中。
在所有的数据集上,LightGBM都能够得到几乎和基准线一致的测试准确率。这表明GOSS和EFB都不会降低准确率并且能够带来显著地加速。这也与我们前面的理论分析保持一致。
LightGBM在不同的数据集上得到了不同的加速率。整体的加速结果是来自GOSS和EFB二者的联合,我们将下一部分分开讨论二者的贡献。
5.2 GOSS分析
首先,我们研究了GOSS的加速性能。从表2中LightGBM和EFB_only的对比来看,我们能够发现GOSS能够通过其自己在使用10%-20%的数据时候带来近2倍的加速。GOSS能够紧紧使用抽样数据进行学习树。然而,它依然保留了一些在全部数据集上的一些计算,例如预测和计算梯度。因此,我们能够发现整体的加速相对于抽样数据的百分比并不是线性的。然而,GOSS带来的加速又是非常显著地,并且这一技术可以普遍的应用在不同的数据集上。
第二,我们通过和SGB(随机梯度提升)对比评估了GOSS的准确率。为了没有泛化性的损失,我们使用LETOR数据集来进行测试。我们通过选择GOSS中不同的 a a a 和 b b b 值来设定抽样率,并且在SGB上使用同样的整体抽样率。我们使用这些设定运行并且使用early stopping直到其收敛。结果如表4所示。我们能够看到但我们使用相同的抽样率的时候GOSS的准确率总是比SGB要好。这一结果和我们3.2部分的讨论保持一致。所有的实验结果都表明了GOSS相比于随机抽样是一个更有效的抽样方法。
5.3 EFB分析
我们通过对比lgb_baseline和EFB_only来检测了EFB在加速方面的贡献。结果如表2所示。这里我们没有允许捆绑发现流程中冲突的存在(即 γ = 0 \gamma=0 γ=0)。我们发现EFB能够有助于在大规模数据集上获得显著性的加速。
请注意lgb_baseline已经在系数特征上进行了优化,且EFB依然能够在训练过程中进行加速。这是因为EFB将许多稀疏特征(one-hot编码的特征和一些潜在的互斥特征)合并成了很少的特征。基础的稀疏特征优化包含在了捆绑程序中。然而,EFB在树训练过程中为每个特征维持非零数据表上没有额外的成本。而且,由于许多预先独立出的特征捆绑到了一起,它能够增加本地空间并且能够显著地改善缓存冲击率。因此,在效率上的整体改进是显著地。基于上述分析,EFB是一个非常有效能够在基于直方图的算法中充分利用稀疏性的算法,并且它能够再GBDT训练过程中带来显著性加速。
6.结论
在这篇文章中,我们提出了全新的GBDT算法叫做LightGBM,它包含了连个新颖的技术:Gradient-based One-Side Sampling (GOSS) 和Exclusive Feature Bundling (EFB)(基于梯度的one-side采样和互斥的特征捆绑)分别来处理大数据量和高维特征的场景。我们在理论分析和实验研究表明,得益于GOSS和EFB,LightGBM在计算速度和内存消耗上明显优于XGBoost和SGB。未来工作中,我们将研究在GOSS中选择a,b值的优化方案,并且继续提高EFB在高维特征上的性能,无论其是否是稀疏的。
7.思考题
1.偏差 vs 方差?
- 偏差是指由有所采样得到的大小为m的训练数据集,训练出的所有模型的输出的平均值和真实模型输出之间的偏差。
- 通常是由对学习算法做了错误的假设导致的
- 描述模型输出结果的期望与样本真实结果的差距。分类器表达能力有限导致的系统性错误,表现在训练误差不收敛
- 方差是指有所有采样得到的大小为m的训练数据集,训练出的所有模型的输出的方差
- 描述模型对于给定值的输出稳定性。分类器对样本分布过于敏感,到指在训练样本较少的时候,出现过拟合
- boosting方法通过逐步聚焦分类器分错的样本,减少集成分类器的偏差
- Bagging采用分而治之的策略,通过对样本多次采样,分别训练多个模型,减少方差
2.什么是LightGBM?
先得说说XGBoost:
- xgboost是属于boosting家族,是GBDT算法的一个工程实现
- 在模型的训练过程中是聚焦残差,在目标函数中使用了二阶泰勒展开并加入了正则,在决策树的生成过程中采用了精确贪心的思路,寻找最佳分裂点的时候,使用了预排序算法, 对所有特征都按照特征的数值进行预排序, 然后遍历所有特征上的所有分裂点位,计算按照这些候选分裂点位分裂后的全部样本的目标函数增益,找到最大的那个增益对应的特征和候选分裂点位,从而进行分裂。这样一层一层的完成建树过程
- xgboost训练的时候,是通过加法的方式进行训练,也就是每一次通过聚焦残差训练一棵树出来, 最后的预测结果是所有树的加和表示。
- xgboost寻找最佳分裂点的复杂度=特征数量 × 分裂点数量 × 样本的数量
- Lightgbm里面的直方图算法就是为了减少分裂点的数量, Lightgbm里面的单边梯度抽样算法就是为了减少样本的数量, 而Lightgbm里面的互斥特征捆绑算法就是为了减少特征的数量。并且后面两个是Lightgbm的亮点所在。
3. 什么是LightGBM的直方图算法?
- LightGBM的直方图算法是代替Xgboost的预排序算法的
- 直方图算法说白了就是把连续的浮点特征离散化为k个整数(也就是分桶bins的思想), 比如[0, 0.1) ->0, [0.1, 0.3)->1。
- 并根据特征所在的bin对其进行梯度累加和个数统计,在遍历数据的时候,根据离散化后的值作为索引在直方图中累积统计量,当遍历一次数据后,直方图累积了需要的统计量,然后根据直方图的离散值,遍历寻找最优的分割点。
这样在遍历到该特征的时候,只需要根据直方图的离散值,遍历寻找最优的分割点即可,由于bins的数量是远小于样本不同取值的数量的,所以分桶之后要遍历的分裂点的个数会少了很多,这样就可以减少计算量。
g)]
XGBoost 在进行预排序时只考虑非零值进行加速,而 LightGBM 也采用类似策略:只用非零特征构建直方图。这种离散化分桶思路其实有很多优点的, 首先最明显就是内存消耗的降低,xgboost需要用32位的浮点数去存储特征值, 并用32位的整型去存储索引,而Lightgbm的直方图算法不仅不需要额外存储预排序的结果,而且可以只保存特征离散化后的值,而这个值一般用8位整型存储就足够了,内存消耗可以降低为原来的1/8。
然后在计算上的代价也大幅降低,预排序算法每遍历一个特征值就需要计算一次分裂的增益,而Lightgbm直方图算法只需要计算k次
直方图作差加速
当节点分裂成两个时,右边的子节点的直方图其实等于其父节点的直方图减去左边子节点的直方图:
通过这种直方图加速的方式,又可以使得Lightgbm的速度快进一步啦。
4.什么是LightGBM的GOSS 和 EFB?
1.GOSS-单边梯度抽样算法
单边梯度抽样算法(Gradient-based One-Side Sampling)是从减少样本的角度出发, 排除大部分权重小的样本,仅用剩下的样本计算信息增益,它是一种在减少数据和保证精度上平衡的算法。
GOSS 算法保留了梯度大的样本,并对梯度小的样本进行随机抽样,为了不改变样本的数据分布,在计算增益时为梯度小的样本引入一个常数进行平衡。首先将要进行分裂的特征的所有取值按照绝对值大小降序排序(xgboost也进行了排序,但是LightGBM不用保存排序后的结果),然后拿到前a% 的梯度大的样本,和剩下样本的b%,在计算增益时,后面的这b%通过乘上 1 − a b \frac{1-a}{b} b1−a来放大梯度小的样本的权重。一方面算法将更多的注意力放在训练不足的样本上,另一方面通过乘上权重来防止采样对原始数据分布造成太大的影响。
通过上面,我们就通过采样的方式,选出了我们的样本,两个梯度大的6号和7号,然后又从剩下的样本里面随机选了2个梯度小的,4号和2号,这时候我们重点看看基于采样样本的估计直方图长什么样子,毕竟我们从8个里面选出了四个,如果直接把另外四个给删掉的话,这时候会改变数据的分布,但应该怎么做呢?也就是乘上 1 − a b \frac{1-a}{b} b1−a来放大梯度小的样本的权重到底是怎么算的?看下图:
梯度小的样本乘上相应的权重之后,我们在基于采样样本的估计直方图中可以发现Ni的总个数依然是8个, 虽然6个梯度小的样本中去掉了4个,留下了两个。但是这2个样本在梯度上和个数上都进行了3倍的放大,所以可以防止采样对原数数据分布造成太大的影响, 这也就是论文里面说的将更多的注意力放在训练不足的样本上的原因。
GOSS的感觉就好像一个公寓里本来住了10个人,感觉太挤了,赶走了6个人,但是剩下的人要分摊他们6个人的房租。
2.EFB-互斥特征捆绑算法
高维度的数据往往是稀疏的,这种稀疏性启发我们设计一种无损的方法来减少特征的维度。通常被捆绑的特征都是互斥的(即特征不会同时为非零值,像one-hot),这样两个特征捆绑起来才不会丢失信息。如果两个特征并不是完全互斥(部分情况下两个特征都是非零值),可以用一个指标对特征不互斥程度进行衡量,称之为冲突比率,当这个值较小时,我们可以选择把不完全互斥的两个特征捆绑,而不影响最后的精度。
看到上面的这些特征够稀疏了吧(大部分都是0),而每一个特征都只有一个训练样本是非0且都不是同一个训练样本,这样的话特征之间也没有冲突了。这样的情况就可以把这四个特征捆绑成一个,这样是不是维度就减少 。
所以互斥特征捆绑算法(Exclusive Feature Bundling)是从减少特征的角度去帮助Lightgbm更快, 它指出如果将一些特征进行融合绑定,则可以降低特征数量。
3.怎么判定哪些特征应该绑在一起?
- 首先将所有的特征看成图的各个顶点,将不相互独立的特征用一条边连起来,边的权重就是两个相连接的特征的总冲突值(也就是这两个特征上不同时为0的样本个数)。
- 然后按照节点的度对特征降序排序, 度越大,说明与其他特征的冲突越大
- 对于每一个特征, 遍历已有的特征簇,如果发现该特征加入到特征簇中的矛盾数不超过某一个阈值,则将该特征加入到该簇中。如果该特征不能加入任何一个已有的特征簇,则新建一个簇,将该特征加入到新建的簇中。
上面这个过程的时间复杂度其实是KaTeX parse error: Expected 'EOF', got '#' at position 3: O(#̲features^2)的,因为要遍历特征,每个特征还要遍历所有的簇, 在特征不多的情况下还行,但是如果特征维度很大,就不好使了。所以为了改善效率,可以不建立图,而是将特征按照非零值个数进行排序,因为更多的非零值的特征会导致更多的冲突,所以跳过了上面的第一步,直接排序然后第三步分簇。
4.特征绑在一起之后,特征值应该如何确定呢?
关键就是原始特征能从合并的特征中分离出来
绑定几个特征在同一个bundle里需要保证绑定前的原始特征的值可以在bundle里面进行识别,考虑到直方图算法将连续的值保存为离散的bins,我们可以使得不同特征的值分到簇中的不同bins里面去,这可以通过在特征值中加入一个偏置常量来解决。
比如,我们把特征A和B绑定到了同一个bundle里面, A特征的原始取值区间[0,10), B特征原始取值区间[0,20), 这样如果直接绑定,那么会发现我从bundle里面取出一个值5, 就分不出这个5到底是来自特征A还是特征B了。所以我们可以再B特征的取值上加一个常量10转换为[10, 30),这样绑定好的特征取值就是[0,30), 我如果再从bundle里面取出5, 就一下子知道这个是来自特征A的。这样就可以放心的融合特征A和特征B了。看下图:
5. LightGBM的生长策略(Leaf-wise)?
XGBoost 在树的生成过程中采用 Level-wise 的增长策略,该策略遍历一次数据可以同时分裂同一层的叶子,容易进行多线程优化,也好控制模型复杂度,不容易过拟合。但实际上Level-wise是一种低效的算法,因为它不加区分的对待同一层的叶子,实际上很多叶子的分裂增益较低,没必要进行搜索和分裂,因此带来了很多没必要的计算开销(一层一层的走,不管它效果到底好不好)
Leaf-wise 则是一种更为高效的策略,每次从当前所有叶子中,找到分裂增益最大的一个叶子,然后分裂,如此循环。因此同 Level-wise 相比,在分裂次数相同的情况下,Leaf-wise 可以降低更多的误差,得到更好的精度。Leaf-wise 的缺点是可能会长出比较深的决策树,产生过拟合。因此 LightGBM 在 Leaf-wise 之上增加了一个最大深度的限制,在保证高效率的同时防止过拟合。(最大信息增益的优先, 我才不管层不层呢)
Leaf-wise vs Level-wise
- Level-wise的做法会产生一些低信息增益的节点,浪费运算资源,但是这个对于防止过拟合挺有用。
- Leaf-wise能够追求更好的精度,降低误差,但是会带来过拟合问题。( 数据合并,直方图和GOSS等各个操作的时候,其实都有天然正则化的作用)
6.LightGBM的优点
- 内存更小
- XGBoost 使用预排序后需要记录特征值及其对应样本的统计值的索引,而 LightGBM 使用了直方图算法将特征值转变为 bin 值,且不需要记录特征到样本的索引,将空间复杂度从 O(2*#data) 降低为 O(#bin) ,极大的减少了内存消耗;
- LightGBM 采用了直方图算法将存储特征值转变为存储 bin 值,降低了内存消耗;
- LightGBM 在训练过程中采用互斥特征捆绑算法减少了特征数量,降低了内存消耗。
- 速度更快
- LightGBM 采用了直方图算法将遍历样本转变为遍历直方图,极大的降低了时间复杂度;
- LightGBM 在训练过程中采用单边梯度算法过滤掉梯度小的样本,减少了大量的计算;
- LightGBM 采用了基于 Leaf-wise 算法的增长策略构建树,减少了很多不必要的计算量;
- LightGBM 采用优化后的特征并行、数据并行方法加速计算,当数据量非常大的时候还可以采用投票并行的策略;
- LightGBM 对缓存也进行了优化,增加了 Cache hit 的命中率。