1 /*!
2  * Copyright 2018 by Contributors
3  * \author Tianqi Chen, Rory Mitchell
4  */
5 
6 #include <xgboost/linear_updater.h>
7 #include "coordinate_common.h"
8 
9 namespace xgboost {
10 namespace linear {
11 
12 DMLC_REGISTRY_FILE_TAG(updater_shotgun);
13 
14 class ShotgunUpdater : public LinearUpdater {
15  public:
16   // set training parameter
Configure(Args const & args)17   void Configure(Args const& args) override {
18     param_.UpdateAllowUnknown(args);
19     if (param_.feature_selector != kCyclic &&
20         param_.feature_selector != kShuffle) {
21       LOG(FATAL) << "Unsupported feature selector for shotgun updater.\n"
22                  << "Supported options are: {cyclic, shuffle}";
23     }
24     selector_.reset(FeatureSelector::Create(param_.feature_selector));
25   }
LoadConfig(Json const & in)26   void LoadConfig(Json const& in) override {
27     auto const& config = get<Object const>(in);
28     FromJson(config.at("linear_train_param"), &param_);
29   }
SaveConfig(Json * p_out) const30   void SaveConfig(Json* p_out) const override {
31     auto& out = *p_out;
32     out["linear_train_param"] = ToJson(param_);
33   }
34 
Update(HostDeviceVector<GradientPair> * in_gpair,DMatrix * p_fmat,gbm::GBLinearModel * model,double sum_instance_weight)35   void Update(HostDeviceVector<GradientPair> *in_gpair, DMatrix *p_fmat,
36               gbm::GBLinearModel *model, double sum_instance_weight) override {
37     auto &gpair = in_gpair->HostVector();
38     param_.DenormalizePenalties(sum_instance_weight);
39     const int ngroup = model->learner_model_param->num_output_group;
40 
41     // update bias
42     for (int gid = 0; gid < ngroup; ++gid) {
43       auto grad = GetBiasGradientParallel(gid, ngroup,
44                                           in_gpair->ConstHostVector(), p_fmat);
45       auto dbias = static_cast<bst_float>(param_.learning_rate *
46                                CoordinateDeltaBias(grad.first, grad.second));
47       model->Bias()[gid] += dbias;
48       UpdateBiasResidualParallel(gid, ngroup, dbias, &in_gpair->HostVector(), p_fmat);
49     }
50 
51     // lock-free parallel updates of weights
52     selector_->Setup(*model, in_gpair->ConstHostVector(), p_fmat,
53                      param_.reg_alpha_denorm, param_.reg_lambda_denorm, 0);
54     for (const auto &batch : p_fmat->GetBatches<CSCPage>()) {
55       auto page = batch.GetView();
56       const auto nfeat = static_cast<bst_omp_uint>(batch.Size());
57       dmlc::OMPException exc;
58 #pragma omp parallel for schedule(static)
59       for (bst_omp_uint i = 0; i < nfeat; ++i) {
60         exc.Run([&]() {
61           int ii = selector_->NextFeature
62             (i, *model, 0, in_gpair->ConstHostVector(), p_fmat, param_.reg_alpha_denorm,
63             param_.reg_lambda_denorm);
64           if (ii < 0) return;
65           const bst_uint fid = ii;
66           auto col = page[ii];
67           for (int gid = 0; gid < ngroup; ++gid) {
68             double sum_grad = 0.0, sum_hess = 0.0;
69             for (auto& c : col) {
70               const GradientPair &p = gpair[c.index * ngroup + gid];
71               if (p.GetHess() < 0.0f) continue;
72               const bst_float v = c.fvalue;
73               sum_grad += p.GetGrad() * v;
74               sum_hess += p.GetHess() * v * v;
75             }
76             bst_float &w = (*model)[fid][gid];
77             auto dw = static_cast<bst_float>(
78                 param_.learning_rate *
79                 CoordinateDelta(sum_grad, sum_hess, w, param_.reg_alpha_denorm,
80                                 param_.reg_lambda_denorm));
81             if (dw == 0.f) continue;
82             w += dw;
83             // update grad values
84             for (auto& c : col) {
85               GradientPair &p = gpair[c.index * ngroup + gid];
86               if (p.GetHess() < 0.0f) continue;
87               p += GradientPair(p.GetHess() * c.fvalue * dw, 0);
88             }
89           }
90         });
91       }
92       exc.Rethrow();
93     }
94   }
95 
96  protected:
97   // training parameters
98   LinearTrainParam param_;
99 
100   std::unique_ptr<FeatureSelector> selector_;
101 };
102 
103 XGBOOST_REGISTER_LINEAR_UPDATER(ShotgunUpdater, "shotgun")
104     .describe(
105         "Update linear model according to shotgun coordinate descent "
106         "algorithm.")
__anon89e520760202() 107     .set_body([]() { return new ShotgunUpdater(); });
108 }  // namespace linear
109 }  // namespace xgboost
110