1、LightGBM介绍
LightGBM是一个梯度Boosting框架,使用基于决策树的学习算法。
LightGBM的优点:
1)更快的训练效率
2)低内存使用
3)更高的准确率
4)支持并行化学习
5)可以处理大规模数据
2、速度和内存使用的优化
许多增强工具使用基于预排序的算法[2,3](例如xgboost中的默认算法)用于决策树学习。这是一个简单的解决方案,但不容易优化。
LightGBM使用基于直方图的算法[4,5,6],它将连续特征(属性)值存储到离散区间。这加快了培训速度并减少了内存使用量。基于直方图的算法的优点包括:
- 降低计算每次拆分增益的成本
- 基于预排序的算法具有时间复杂性
O(#data)
- 计算直方图具有时间复杂度
O(#data)
,但这仅涉及快速的总结操作。构建直方图后,基于直方图的算法具有时间复杂度O(#bins)
,并且#bins
远小于#data
。
- 基于预排序的算法具有时间复杂性
- 使用直方图减法进一步加速
- 要在二叉树中获取一个叶子的直方图,请使用其父级及其邻居的直方图减法
- 因此,它需要仅为一个叶子构建直方图(小于
#data
其邻居)。然后它可以通过直方图减法获得其邻居的直方图,成本较低(O(#bins)
)
- 减少内存使用量
- 用离散箱替换连续值。如果
#bins
很小,可以使用小数据类型,例如uint8_t来存储训练数据 - 无需存储用于预排序特征值的其他信息
- 用离散箱替换连续值。如果
- 降低并行学习的通信成本
3、稀疏优化
- 只需要为稀疏特征构造直方图
O(2 * #non_zero_data)
4、精度优化
叶子(最好的)树生长
大多数决策树学习算法按级别(深度)逐级生成树,如下图所示:
LightGBM以叶子方式生长树木(最佳优先)[7]。它将选择具有最大增量损失的叶子来生长。保持#leaf
固定的叶子算法往往比水平算法实现更低的损失。
叶子方式可能会导致过度拟合#data
,因此LightGBM包含max_depth
限制树深度的参数。然而,即使max_depth
指定了树木,树木仍然会逐渐生长。
5、分类特征的最佳分割
通常使用单热编码来表示分类特征,但这种方法对于树学习者来说是次优的。特别是对于高基数分类特征,基于单热特征构建的树往往是不平衡的,并且需要非常深地生长以实现良好的准确性。
最佳解决方案是通过将其类别划分为2个子集来分割分类特征,而不是单热编码。如果该功能具有k
类别,则可能存在分区。但是回归树有一个有效的解决方案[8]。它需要找到最佳分区。2^(k-1) - 1
O(k * log(k))
基本思想是根据每次拆分的培训目标对类别进行排序。更具体地说,LightGBM根据其累积值()对直方图(对于分类特征)进行排序,然后在排序的直方图上找到最佳分割。sum_gradient / sum_hessian
6、网络通信的优化
它只需要在LightGBM的并行学习中使用一些集体通信算法,如“All reduce”,“All gather”和“Reduce scatter”。LightGBM实现了最先进的算法[9]。这些集体通信算法可以提供比点对点通信更好的性能。/
7、并行学习中的优化
LightGBM提供以下并行学习算法。
8、功能并行
传统算法
并行特征旨在并行化决策树中的“查找最佳拆分”。传统特征并行的过程是:
- 垂直分区数据(不同的机器具有不同的功能集)。
- 工作人员在本地功能集上找到本地最佳分割点{feature,threshold}。
- 彼此沟通本地最好的分裂,并获得最好的分裂。
- 具有最佳拆分的工作人员执行拆分,然后将拆分的数据结果发送给其他工作人员。
- 其他工作人员根据收到的数据分割数据。
传统功能并行的缺点:
- 有计算开销,因为它不能加速“时间复杂度”的“分裂”
O(#data)
。因此,并行特征在#data
大时不能很好地加速。 - 需要分割结果的通信,其成本约为(一个数据一位)。
O(#data / 8)
LightGBM中的并行特征
由于特征并行在#data
大的时候不能很好地加速,我们做了一点改变:不是垂直分割数据,而是每个工人都拥有完整的数据。因此,LightGBM不需要为分割数据结果进行通信,因为每个工作人员都知道如何分割数据。并且#data
不会更大,因此在每台机器中保存完整数据是合理的。
LightGBM中并行功能的过程:
- 工作人员在本地功能集上找到本地最佳分割点{feature,threshold}。
- 彼此沟通本地最好的分裂,并获得最好的分裂。
- 执行最佳分割。
然而,这个特征并行算法仍然会受到“分裂”时计算开销的影响#data
。因此,当#data
大的时候使用并行数据会更好。
9、数据并行
传统算法
数据并行旨在并行化整个决策学习。数据并行的过程是:
- 水平分区数据。
- 工人使用本地数据构建局部直方图。
- 合并来自所有局部直方图的全局直方图。
- 从合并的全局直方图中找到最佳拆分,然后执行拆分。
传统数据并行的缺点:
- 通信成本高。如果使用点对点通信算法,则一台机器的通信成本约为。如果使用集体通信算法(例如“All Reduce”),通信成本约为(在[9]的第4.5章中检查“All Reduce”的成本)。
O(#machine * #feature * #bin)
O(2 * #feature * #bin)
LightGBM中的数据并行
我们在LightGBM中降低了并行数据的通信成本:
- LightGBM使用“Reduce Scatter”来合并不同工人的不同(非重叠)特征的直方图,而不是“从所有局部直方图中合并全局直方图”。然后,工作人员在本地合并直方图上找到本地最佳分割,并同步全局最佳分割。
- 如前所述,LightGBM使用直方图减法来加速训练。基于此,我们可以仅为一个叶子传达直方图,并通过减法获得其邻居的直方图。
考虑到所有因素,LightGBM中的数据并行具有时间复杂性。O(0.5 * #feature * #bin)
10、投票并行
并行投票进一步降低了数据并行中的成本通信成本。它使用两阶段投票来降低特征直方图的通信成本[10]。/
11、GPU支持
感谢@ huanzhang12提供此功能。请阅读[11]以获取更多详细信息。
12、应用程序和指标
LightGBM支持以下应用程序:
- 回归,目标函数是L2损失
- 二进制分类,目标函数是logloss
- 多分类
- 交叉熵,目标函数是logloss,支持非二进制标签的训练
- lambdarank,目标函数是lambdarank与NDCG
LightGBM支持以下指标:
- L1损失
- L2损失
- 记录丢失
- 分类错误率
- AUC
- NDCG
- 地图
- 多级日志丢失
- 多级错误率
- 公平
- 胡伯
- 泊松
- 位数
- MAPE
- 库勒巴克-莱布勒
- 伽玛
- 特威迪
有关更多详细信息,请参阅参数。
13、其他功能
max_depth
树的限制,当生长树叶子时- 镖
- L1 / L2正则化
- 套袋
- 列(特征)子样本
- 继续列车输入GBDT模型
- 继续训练输入得分文件
- 加权培训
- 培训期间的验证度量输出
- 多验证数据
- 多指标
- 提前停止(训练和预测)
- 叶指数的预测
有关更多详细信息,请参阅参数。
14、参数设置:
task: 默认值=train,可选项=train,prediction;指定我们希望执行的任务,该任务有两种类型:训练 和 预测;
application: 默认值=regression,type=enum,options=options;
regression: 执行回归任务;
binary:二分类;
multiclass:多分类;
lambdarank:lambrank应用;
data: type=string;training data,LightGBM将从这些数据中进行训练;
num_iterations: 默认值为100,类型为int。表示提升迭代次数,也就是提升树的棵树;
num_leaves: 每个树上的叶子数,默认值为31,类型为int;
device: 默认值=cpu;可选项:cpu,gpu。也就是我们使用什么类型的设备去训练我们的模型。选择GPU会使得训练过程更快;
mindatain_leaf: 每个叶子上的最少数据;
feature_fraction: 默认值为1;指定每次迭代所需要的特征部分;
bagging_fraction: 默认值为1;指定每次迭代所需要的数据部分,并且它通常是被用来提升训练速度和避免过拟合的。
mingainto_split: 默认值为1;执行分裂的最小的信息增益;
max_bin: 最大的桶的数量,用来装数值的;
mindatain_bin: 每个桶内最少的数据量;
numthreads: 默认值为OpenMPdefault,类型为int。指定LightGBM算法运行时线程的数量;
label: 类型为string;指定标签列;
categorical_feature: 类型为string;指定我们想要进行模型训练所使用的特征类别;
num_class: 默认值为1,类型为int;仅仅需要在多分类的场合。
15、达观杯实践
import lightgbm as LGB
#训练LGB分类器
params = {
'boosting': 'gbdt',
'application': 'multiclassova',
'num_class': 19,
'learning_rate': 0.1,
'num_leaves': 31,
'max_depth': -1,
'lambda_l1': 0,
'lambda_l2': 0.5,
'bagging_fraction': 1.0,
}
bst = LGB.train(params, d_train, num_boost_round=800, valid_sets=d_vali, feval=f1_score_vali,
early_stopping_rounds=None,
verbose_eval=True)
joblib.dump(bst, model_path + "LGB_data_w_tfidf.m")
#对测试集进行预测;将预测结果转换为官方标准格式;并将结果保存至本地
y_proba = bst.predict(x_test)
y_test = np.argmax(y_proba, axis=1) + 1
df_result = pd.DataFrame(data={'id': range(102277), 'class': y_test.tolist()})
df_proba = pd.DataFrame(data={'id': range(102277), 'proba': y_proba.tolist()})
df_result.to_csv(result_path + 'LGB_data_w_tfidf_result.csv', index=False)
df_proba.to_csv(result_path + 'LGB_data_w_tfidf_proba.csv', index=False)
---------------------
本文参考链接及学习资料:
【1】https://blog.csdn.net/gulaixiangjuejue/article/details/89287997