(作者:陈玓玏)
1、 源码文件夹结构
文件夹的结构如下,其中build文件夹、lib文件夹以及最后一个xgboost可执行文件是在编译之后才生成的。我们在读源码过程中主要是看include文件夹以及src文件夹中的内容。
2、 主流程
2.1 main函数
src/cli_main.cc文件中
先找到main函数,从main函数开始跟踪整个流程。Main函数调用了xgboost这个命名空间下的CLIRunTask函数,因此找到CLIRunTask:这个函数输入参数是整型argc以及字符串的指针argv。我们在运行源码的过程中可以通过demo文件夹下各类实例中的.conf文件来传入这两个参数。
Main
CLIRunTask
--判断argc参数的合法性,如果小于2则直接退出。
// rabit是分布式通信库,这里的功能是初始化整个框架的分布特性
--rabit::Init(argc, argv);
//生成一个cfg向量,cfg实际是用来配置模型参数的
--std::vector<std::pair<std::string, std::string> > cfg;
//通过cfg初始化CLIParam对象,这些参数后面用到的地方很多
--param.Configure(cfg);
//判断当前是执行什么任务,有三种可能,训练、加载模型、预测
-- switch (param.task) {
case kTrain: CLITrain(param); break;
case kDumpModel: CLIDumpModel(param); break;
case kPredict: CLIPredict(param); break;
}
Main函数的大体流程就是这样,所以关键在于,怎么训练、预测。
2.2 训练
src/cli_main.cc文件中
建树过程最重要的就是PredictRaw、GetGradient和DoBoost这三个函数,除了并行之外,大部分代码都在实现这三个函数。
//传入的参数是模型参数的引用,也就是传入了参数的地址
CLITrain
//加载数据,数据会转换成DMatrix类,这个类的定义在include/xgboost/data.h文件中
-- DMatrix::Load(param.train_path, param.silent != 0, param.dsplit == 2)
//根据之前由DMatrix生成的cache_mats向量初始化学习器,学习器定义在include/xgboost/learner.h文件中
-- Learner::Create(cache_mats)
//根据实际情况配置模型,并加载模型或者初始化模型
-- learner->Load(fi.get());
-- learner->Configure(param.cfg);
-- learner->InitModel();
//一次训练完成后,更新迭代器,这是模型的主要过程,所以内容也是最多的
//可以看到基本上都在操作learner这个类,我们调用的很多函数都定义在这个类里,而这个类里主要的函数的具体写法都定义在Src/learner.cc文件中
-- learner->UpdateOneIter(i, dtrain.get());
// monitor是用来记录整个建模过程的时间的,通用函数
-- monitor_.Start("UpdateOneIter");
// LazyInitDMatrix根据树的生成方式和结构来确定是否需要初始化列接口,其实也就是判断是离散型还是连续型
-- this->LazyInitDMatrix(train);
// 预测训练数据
-- this->PredictRaw(train, &preds_);
//PredictBatch函数在两个文件中有定义,分别是src/gbm/gbtree.cc以及src/gbm/gblinear.cc,并且这个函数在gbtree中有两种定义,分别是剪枝和不剪枝,不过xgboost本身有前剪枝,所以这种后剪枝用得并不多
-- gbm_->PredictBatch(data, out_preds, ntree_limit);
//剪枝gbtree中调用,剪枝又分两种方式,按照一定比例剪枝以及按照权重来剪
-- DropTrees(ntree_limit);
//无论是否剪枝,都是调用这个函数做预测
-- PredLoopInternal<Dart>();
-- PredLoopSpecalize<Derived>()
//预测每个样本的值,并计算树的叶子节点权重和
-- self->PredValue()
// gblinear用下面这个函数预测
-- PredictBatchInternal(p_fmat, &out_preds->HostVector());
//gblinear的预测过程和逻辑回归是类似的,直接用特征矩阵*权重向量求得
-- Pred()
//执行完预测后求解梯度向量,包括一阶导和二阶导
//这个函数共有八种定义,针对不同的目标函数有不同的求解结果
//分别在src/objective文件夹的regression_obj.cc、hinge.cc、rank_obj.cc、multiclass_obj.cc四个文件中
-- obj_->GetGradient(preds_, train->Info(), iter, &gpair_);
//开始建树,DoBoost过程也分为两种,一种是gbtree的boost过程,一种是gblinear的boost过程,分别在Src/gbm文件夹的gblinear.cc文件以及gbtree.cc文件
-- gbm_->DoBoost(train, &gpair_, obj_.get());
//初始化接口
-- p_fmat->InitColAccess()
//初始化模型
-- model_.LazyInitModel();
//计算权重和
-- this->LazySumWeights(p_fmat);
//更新树,gblinear的update函数也分两种,一种是linear_updater,另一种是ShotgunUpdater
-- updater_->Update()
//---------这一部分是gblinear的linear_updater函数
//计算L1、L2惩罚项,其值为 惩罚因子*权重和
-- param.DenormalizePenalties(sum_instance_weight);
//计算截距项的梯度向量
-- GetBiasGradientParallel();
//更新截距项梯度向量
-- UpdateBiasResidualParallel()
//获取非截距项的梯度向量
-- GetGradientParallel()
-- CoordinateDelta()
-- this->UpdateFeature()
//---------这一部分是gbtree的更新
-- BoostNewTrees()
//初始化更新器,默认的更新器的树更新顺序是:先生成,后修剪
-- this->InitUpdater();
//初始化模型
-- ptr->InitModel();
//gbtree的更新有八种方式,其中五种是树的更新,三种是辅助更新
-- Update(gpair, p_fmat, new_trees);
//------------下面以update_colmaker为例
//检查训练数据信息的完备性
-- CheckInfo(dmat->Info());
//调整学习率,为后面的树留出提升空间
-- param_.learning_rate = lr / trees.size();
//构建build类建树,并update,build类有两个重要的输入参数:
//训练参数及SplitEvaluator类向量,update代码到此已经结束,
//重要的是它的SplitEvaluator类。其中定义计算分割点增益,计算节点权重等内容,具体的计算分割点的方法有精确查找和基于//权重的分位点算法。
-- Builder builder();
-- builder.Update(gpair->ConstHostVector(), dmat, tree);
//提交模型
-- this->CommitModel(std::move(new_trees));
//评估本轮的模型效果
//针对不同的损失函数,xgboost定义了不同的评估函数
-- learner->EvalOneIter(i, eval_datasets, eval_data_names);
//保存模型
-- learner->Save(fo.get());
2.3 模型加载
src/cli_main.cc文件中
CLIDumpModel
//读取文件
-- dmlc::Stream::Create(param.name_fmap.c_str(), "r"))
//创建学习器/加载模型
-- Learner::Create({})
//配置模型
-- learner->Configure(param.cfg);
//加载模型
-- learner->Load(fi.get());
//加载数据
-- learner->DumpModel(fmap, param.dump_stats, param.dump_format);
2.4 预测
src/cli_main.cc文件中
CLIPredict
//加载数据,数据会转换成DMatrix类,这个类的定义在include/xgboost/data.h文件中
-- DMatrix::Load(param.train_path, param.silent != 0, param.dsplit == 2)
//根据之前由DMatrix生成的cache_mats向量初始化学习器,学习器定义在include/xgboost/learner.h文件中
-- Learner::Create(cache_mats)
//加载模型
-- learner->Load(fi.get());
//配置模型
-- learner->Configure(param.cfg);
//预测
-- learner->Predict(dtest.get(), param.pred_margin, &preds, param.ntree_limit);