xgboost C++源码主要函数

(作者:陈玓玏)

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);

猜你喜欢

转载自blog.csdn.net/weixin_39750084/article/details/83244191
今日推荐