XGBoost源码分析之单机多线程的实现

上篇文章主要通过论文阅读、数学推导,基本掌握了XGBoost的原理。于是开始阅读XGBoost源码,并总结了几处自己认为比较重要的方面。如有错误,请指正:

 

1. 总体框架:


cli_main.cc 是程序的入口,main函数所在的文件。除了有main函数以外,还有训练参数的结构体。如模型保存路径,数据路径,迭代次数等。这个源码注释的很清楚,不再赘述。

通过调用main() -> CLIRunTask() -> CLITrain(),这里我们主要看函数CLITrain()的流程

 

CLITrain主要分了几步:

1.加载数据

2.初始化learner

3.调用learner->InitModel()、learner->Configure初始化Model,确定目标函数和模型,初始化目标函数结构体和模型

4.根据模型参数param.num_round迭代调用UpdateOneIter()来建树


2.learner

上一节,在learner中初始化目标函数和模型,主要赋值给了这两个变量。

/include/xgboost/learner.h

  /*! \brief objective function */
  std::unique_ptr<ObjFunction> obj_;
  /*! \brief The gradient booster used by the model*/
  std::unique_ptr<GradientBooster> gbm_;

ObjFunction是基类,定义了很多虚函数。类RegLossObj等都继承于此类,主要实现了根据不同的模型和loss,将一阶二阶导数计算出来。


以线性回归模型为例

src\objective\regression_obj.cc

定义平方损失函数:

// linear regression
struct LinearSquareLoss {
  static bst_float PredTransform(bst_float x) { return x; }
  static bool CheckLabel(bst_float x) { return true; }
  static bst_float FirstOrderGradient(bst_float predt, bst_float label) { return predt - label; }
  static bst_float SecondOrderGradient(bst_float predt, bst_float label) { return 1.0f; }
  static bst_float ProbToMargin(bst_float base_score) { return base_score; }
  static const char* LabelErrorMsg() { return ""; }
  static const char* DefaultEvalMetric() { return "rmse"; }
}


class RegLossObj : public ObjFunction{
...
void GetGradient(const std::vector<bst_float> &preds,
                   const MetaInfo &info,
                   int iter,
                   std::vector<bst_gpair> *out_gpair) override {
...
    out_gpair->resize(preds.size());
    // check if label in range
    bool label_correct = true;
    // start calculating gradient
    const omp_ulong ndata = static_cast<omp_ulong>(preds.size());
    #pragma omp parallel for schedule(static)
    for (omp_ulong i = 0; i < ndata; ++i) {
      bst_float p = Loss::PredTransform(preds[i]);
      bst_float w = info.GetWeight(i);
      if (info.labels[i] == 1.0f) w *= param_.scale_pos_weight;
      if (!Loss::CheckLabel(info.labels[i])) label_correct = false;
      out_gpair->at(i) = bst_gpair(Loss::FirstOrderGradient(p, info.labels[i]) * w,
                                   Loss::SecondOrderGradient(p, info.labels[i]) * w);
    
    }
...
}
可以发现在计算一阶导和二阶导的时候,采用了并行处理。以一条数据作为一个粒度。


GradientBooster是基类,有两个模型继承于此类。XGBoost中除了有Tree模型(GBTree),同时也实现了线性模型(GBLinear)。与梯度下降和牛顿法不同的是,在每次迭代的过程中,每个属性单独计算,采用类似于一维的牛顿法来更新一个属性。这里不是重点,有兴趣的同学可以看\src\gbm\gblinear.cc。


3.UpdateOneIter


这里可以看出每次迭代的操作,主要有:

  void UpdateOneIter(int iter, DMatrix* train) override {
  	
    this->LazyInitDMatrix(train);
    this->PredictRaw(train, &preds_);                                   //获取上一轮预测值
    obj_->GetGradient(preds_, tr
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值