树类算法之---lightGBM使⽤与调参
1. 说明
lightGBM是⼀个基于树模型的分布式Boosting算法,该算法是有微软开源贡献,说到tree-based模型⼀般都会想到XGBOOST算法,毕竟也是曾经的⼤杀器,那下⾯就把这两个算法进⾏⼀些对⽐。
2.Xgboost的优缺点
优点:(不详细说了,默认有树模型基础)
1.Xgboost利⽤的⼆阶梯度,相对于lightGBM在进⾏节点划分的时候,会有更⾼的精度
2.利⽤局部近似算法,对分裂节点的贪⼼算法进⾏优化,取适当的收益时,可以提⾼算法的性能和训练速度。
3.在损失函数中加⼊L1和L2正则化,降低模型的复杂度,提⾼模型的适⽤性,鲁棒性。
4.提供并⾏计算能⼒,主要是在树节点求不同的候选的分裂点的Gain Infomation(分裂后,损失函数的差值)。
5.Tree Shrinkage,column subsampling等不同的处理细节。
缺点:
1.需要对特征值进⾏预排序,这样会消耗很多的内存空间。(2 *data * features,索引和值)
2.数据分割点上,由于xgboost对不同的特征进⾏了预排序,所以不同的特征的排序顺序是不同的,所以在分割时,要对每个特征的每
个值进⾏单独的分割,遍历次数为data * features,以此将所有的数据分配到左右⼦⽀。
3.尽管使⽤了局部近似算法,但是分割的粒度依然很细
4.由于做了预排序的处理,在寻特征分裂点是(level - wise),会产⽣⼤量的cache随机访问。
3.lightGBM相应的改进
1.LightGBM基于histogram算法代替pre-sorted所构建的数据结构,利⽤histogram后,会有很多有⽤的tricks。例如histogram做
差,提⾼了cache命中率(主要是因为使⽤了leaf-wise)。
2.在机器学习当中,我们⾯对⼤数据量时候都会使⽤采样的⽅式(根据样本权值)来提⾼训练速度。⼜或者在训练的时候赋予样本权值
来关于于某⼀类样本(如Adaboost)。LightGBM利⽤了GOSS来做采样算法。
3.由于histogram算法对稀疏数据的处理时间复杂度没有pre-sorted好。因为histogram并不管特征值是否为0。因此我们采⽤了EFB
来预处理稀疏数据。
3.1 Histogram Algorithm(直⽅图)
相对于pre-sorted算法,它的内存空间需要相对⼩很多。因为pre-sorted算法需要保存起来每⼀个特征的排序结构,所以其需要的内存⼤⼩是2 * #data * #feature * 4Bytes(⽽histogram只需保存离散值bin value(EFB会谈到bin)⽽且我们不需要原始的feature value,所以占⽤的内存⼤⼩为:#data * # feature * 1Byte,因为离散值bin value使⽤uint8_t已经⾜够了。另外对于求⼦节点相应的feature histogram时,我们只需构造⼀个⼦节点的feature histogram,另外⼀个⼦节点的feature histogram我们⽤⽗节点的histogram减去刚构造出来的⼦节点的histogram便可,时间复杂度就压缩到O(k),k为histogram的桶数。这是⼀个很巧妙的做差法。
直⽅图优化⽰意图
针对特征值划分出bin,这样就可以将连续的特征值压缩到K个bin中
内存优化⽰意图
左边图是xgboost的内存使⽤情况,需要存储排序的索引Sorted_Indices和特征值Features_Values,并且全部是使⽤的4Byte 右边图是lightGBM的内存使⽤情况,不需要存储索引,仅仅需要存储bin的值就可以了,并且存储使⽤的是单字节1Byte
3.2 Gradient-based One-Side Sampling(GOSS)
其中⽂为梯度单边采样。⼤致的意思是根据样本某⼀特征上的单梯度作为样本的权值进⾏训练。其采样的⽅式有点巧妙:
1.选取前a%个较⼤梯度的值作为⼤梯度值的训练样本。
2.从剩余的1 - a%个较⼩梯度的值中,我们随机选取其中的b%个作为⼩梯度值的训练样本。
3.对于较⼩梯度的样本,也就是b% * (1 - 1%) * #samples,我们在计算信息增益时将其放⼤(1 - a) / b倍。
Q>>>::这么做有什么好处呢?
enum类型如何使用1.总的来说就是a% * #samples + b% * (1 - a%) * #samples个样本作为训练样本。
2.这样的构造是为了尽可能保持与总的数据分布⼀致,并且保证⼩梯度值的样本得到训练。
3.3 Exclusive Feature Bundling
EFB中⽂名叫独⽴特征合并,顾名思义它就是将若⼲个特征合并在⼀起。使⽤这个算法的原因是因为我们要解决数据稀疏的问题。在很多时候,数据通常都是⼏千万维的稀疏数据。因此我们对不同维度的数据合并⼀起使得⼀个稀疏矩阵变成⼀个稠密矩阵。
这⾥就有两个问题:
1.如何确定哪些特征⽤于融合且效果为较好。
2.如何将这些特征合并到⼀齐。
注意:这⼀部分在官⽹我没看到,不确定是怎么使⽤的。
3.4 Leaf-wise (Best-first) Tree Growth
⼤多树的决策树⽣长⽅式是按照level - wise⽅式进⾏⽣长的,⼤概是按照下⾯这种:
lightGBM的决策树⽣长⽅式是按照leaf - wise⽅式进⾏⽣长,⼤概是按照下⾯这种:
那么两者有什么区别呢?
LightGBM对于树的⽣长使⽤的是Leaf-wise,⽽不是Level-wise。这样的做法主要是因为LightGBM认为Level-wise的做法会产⽣⼀些低信息增益的节点,浪费运算资源。其实通常来说,Level-wise对于防⽌过拟合还是很有作⽤的,所以⼤家都⽐较青睐与它相⽐与Leaf-wise。作者认为Leaf-wise能够追求更好的精度,让产⽣更好精度的节点做分裂。但这样带来过拟合的问题,所以作者使⽤的max_depth来控制它的最⼤⾼度。还有原因是因为LightGBM在做数据合并,Histogram Algorithm和GOSS等各个操作,其实都有天然正则化的作⽤,所以使⽤Leaf-wise来提⾼精度是⼀个很不错的选择。
对⽐项⽬leaf - wise level - wise
应⽤lightGBM xgboost
资源使⽤低⾼
分裂⽅式选择增益最⼤全部节点进⾏分裂
精度⾼低
过拟合风险⾼低
过拟合控制最⼤深度风险较低
3.5 其他性能对⽐
对⽐项⽬xgboost LightGBM
正则项L1、L2L1、L2
列采样yes yes
Exact Gradient yes yes
近似算法yes no
稀疏数据yes yes
对⽐项⽬xgboost LightGBM
分布式并⾏yes yes
缓存yes no
out of core yes no
加权数据yes yes
树⽣长⽅式level-wise leaf-wise
最⼤深度控制⽆有
基于算法pre-sorted histgram
dropout no yes
bagging yes yes
应⽤回归、分类、rank回归、分类、lambdrank
GPU⽀持no yes
⽹络通信point-to-point collective-communication Categorical Features⽆优化有优化Continued train with input GBDT model no yes
Continued train with input no yes Early Stopping(both training and prediction)no yes
4.LightGBM的重要参数
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;仅仅需要在多分类的场合。
def train(params, # 参数设置,格式为字典格式
train_set, # 训练集,或者测试集
num_boost_round=100, # 迭代次数
valid_sets=None, # 交叉验证集
valid_names=None, # 交叉验证集的名字
fobj=None, # ⾃定义⽬标函数
feval=None, # ⾃定义评估函数,需要设置两个参数:preds, train_data,
init_model=None,# LightGBM模型或者其他Booster模型的⽂件名字,可⽤于加载模型
feature_name='auto', # 特征名字,如果是‘auto’就会⾃动识别DataFrame数据格式的列名
categorical_feature='auto', # 可以是"int"或者"string"类型的⼀个列表
early_stopping_rounds=None, # 可以是"int"类型的值,如果验证集上在这个数的范围内分数不再提⾼,就会⾃动停⽌训练。
evals_result=None, # ⽤来存储在验证集上每次迭代产⽣的结果
verbose_eval=True, # 控制台打印,如果为TRUE,就每次都打印;如果是5,就5次打印⼀次
learning_rates=None, # 学习率
keep_training_booster=False, # 是否返回⼀个Booster被⽤于继续训练,如果设置为False,返回值在返回前将会被转化成⼀个"_InnerPredictor",可以使⽤这个"_InnerPredictor"作为"init_model"。⽤于今后的模型训练。
callbacks=None)
5.参数调优
LightGBM使⽤基于depth-wise的分裂的leaf-wise分裂算法,这使得它能够更快地收敛。但是,它也会导致过拟合。因此,这⾥给出⼀个LightGBM参数调优的快速指南。
5.1 控制过拟合
numleaves:这个参数是⽤来设置组成每棵树的叶⼦的数量。numleaves 和 maxdepth理论上的联系是: numleaves =
2^(maxdepth)。然⽽,但是如果使⽤LightGBM的情况下,这种估计就不正确了:因为它使⽤了leafwise⽽不是level-wise分裂叶⼦节点。因此,numleaves必须设置为⼀个⼩于2^(maxdepth)的值。否则,他将
可能会导致过拟合。LightGBM的numleave和max_depth这两个参数之间没有直接的联系。因此,我们⼀定不要把两者联系在⼀起。
mindatain_leaf : 它也是⼀个⽤来解决过拟合的⾮常重要的参数。把它的值设置的特别⼩可能会导致过拟合,因此,我们需要对其进⾏相应的设置。因此,对于⼤数据集来说,我们应该把它的值设置为⼏百到⼏千。
max_depth: 它指定了每棵树的最⼤深度或者它能够⽣长的层数上限。
5.2 提升速度
bagging_fraction : 它被⽤来执⾏更快的结果装袋;
feature_fraction : 设置每⼀次迭代所使⽤的特征⼦集;
maxbin : maxbin的值越⼩越能够节省更多的时间:当它将特征值分桶装进不同的桶中的时候,这在计算上是很便宜的
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论