gbdt.cpp 34.2 KB
Newer Older
1
2
3
4
/*!
 * Copyright (c) 2016 Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License. See LICENSE file in the project root for license information.
 */
Guolin Ke's avatar
Guolin Ke committed
5
6
7
#include "gbdt.h"

#include <LightGBM/metric.h>
Guolin Ke's avatar
Guolin Ke committed
8
#include <LightGBM/network.h>
9
10
11
12
#include <LightGBM/objective_function.h>
#include <LightGBM/prediction_early_stop.h>
#include <LightGBM/utils/common.h>
#include <LightGBM/utils/openmp_wrapper.h>
13
#include <LightGBM/sample_strategy.h>
Guolin Ke's avatar
Guolin Ke committed
14

15
16
#include <chrono>
#include <ctime>
17
#include <queue>
18
19
#include <sstream>

Guolin Ke's avatar
Guolin Ke committed
20
21
namespace LightGBM {

22
23
Common::Timer global_timer;

24
25
26
int LGBM_config_::current_device = lgbm_device_cpu;
int LGBM_config_::current_learner = use_cpu_learner;

27
28
29
GBDT::GBDT()
    : iter_(0),
      train_data_(nullptr),
30
      config_(nullptr),
31
32
      objective_function_(nullptr),
      early_stopping_round_(0),
33
      early_stopping_min_delta_(0.0),
34
35
36
37
38
39
      es_first_metric_only_(false),
      max_feature_idx_(0),
      num_tree_per_iteration_(1),
      num_class_(1),
      num_iteration_for_pred_(0),
      shrinkage_rate_(0.1f),
40
      num_init_iteration_(0) {
Guolin Ke's avatar
Guolin Ke committed
41
  average_output_ = false;
Guolin Ke's avatar
Guolin Ke committed
42
  tree_learner_ = nullptr;
43
  linear_tree_ = false;
44
  data_sample_strategy_.reset(nullptr);
shiyu1994's avatar
shiyu1994 committed
45
46
47
  gradients_pointer_ = nullptr;
  hessians_pointer_ = nullptr;
  boosting_on_gpu_ = false;
Guolin Ke's avatar
Guolin Ke committed
48
49
50
51
52
}

GBDT::~GBDT() {
}

Guolin Ke's avatar
Guolin Ke committed
53
void GBDT::Init(const Config* config, const Dataset* train_data, const ObjectiveFunction* objective_function,
54
                const std::vector<const Metric*>& training_metrics) {
Nikita Titov's avatar
Nikita Titov committed
55
  CHECK_NOTNULL(train_data);
56
  train_data_ = train_data;
57
  if (!config->monotone_constraints.empty()) {
Nikita Titov's avatar
Nikita Titov committed
58
    CHECK_EQ(static_cast<size_t>(train_data_->num_total_features()), config->monotone_constraints.size());
Nikita Titov's avatar
Nikita Titov committed
59
  }
60
  if (!config->feature_contri.empty()) {
Nikita Titov's avatar
Nikita Titov committed
61
    CHECK_EQ(static_cast<size_t>(train_data_->num_total_features()), config->feature_contri.size());
62
  }
63
  iter_ = 0;
wxchan's avatar
wxchan committed
64
  num_iteration_for_pred_ = 0;
65
  max_feature_idx_ = 0;
wxchan's avatar
wxchan committed
66
  num_class_ = config->num_class;
Guolin Ke's avatar
Guolin Ke committed
67
68
  config_ = std::unique_ptr<Config>(new Config(*config));
  early_stopping_round_ = config_->early_stopping_round;
69
  early_stopping_min_delta_ = config->early_stopping_min_delta;
70
  es_first_metric_only_ = config_->first_metric_only;
Guolin Ke's avatar
Guolin Ke committed
71
  shrinkage_rate_ = config_->learning_rate;
72

73
  if (config_->device_type == std::string("cuda")) {
74
    LGBM_config_::current_learner = use_cuda_learner;
75
76
    #ifdef USE_CUDA
    if (config_->device_type == std::string("cuda")) {
77
78
79
      const int gpu_device_id = config_->gpu_device_id >= 0 ? config_->gpu_device_id : 0;
      CUDASUCCESS_OR_FATAL(cudaSetDevice(gpu_device_id));
    }
80
    #endif  // USE_CUDA
81
82
  }

83
  // load forced_splits file
84
85
86
87
88
  if (!config->forcedsplits_filename.empty()) {
    std::ifstream forced_splits_file(config->forcedsplits_filename.c_str());
    std::stringstream buffer;
    buffer << forced_splits_file.rdbuf();
    std::string err;
Guolin Ke's avatar
Guolin Ke committed
89
    forced_splits_json_ = Json::parse(buffer.str(), &err);
90
91
  }

92
93
94
  objective_function_ = objective_function;
  num_tree_per_iteration_ = num_class_;
  if (objective_function_ != nullptr) {
Guolin Ke's avatar
Guolin Ke committed
95
    num_tree_per_iteration_ = objective_function_->NumModelPerIteration();
96
97
98
    if (objective_function_->IsRenewTreeOutput() && !config->monotone_constraints.empty()) {
      Log::Fatal("Cannot use ``monotone_constraints`` in %s objective, please disable it.", objective_function_->GetName());
    }
99
100
  }

101
  data_sample_strategy_.reset(SampleStrategy::CreateSampleStrategy(config_.get(), train_data_, objective_function_, num_tree_per_iteration_));
102
103
  is_constant_hessian_ = GetIsConstHessian(objective_function);

104
105
106
  boosting_on_gpu_ = objective_function_ != nullptr && objective_function_->IsCUDAObjective() &&
                     !data_sample_strategy_->IsHessianChange();  // for sample strategy with Hessian change, fall back to boosting on CPU

107
  tree_learner_ = std::unique_ptr<TreeLearner>(TreeLearner::CreateTreeLearner(config_->tree_learner, config_->device_type,
shiyu1994's avatar
shiyu1994 committed
108
                                                                              config_.get(), boosting_on_gpu_));
109
110
111

  // init tree learner
  tree_learner_->Init(train_data_, is_constant_hessian_);
112
  tree_learner_->SetForcedSplit(&forced_splits_json_);
113
114
115
116
117
118
119
120

  // push training metrics
  training_metrics_.clear();
  for (const auto& metric : training_metrics) {
    training_metrics_.push_back(metric);
  }
  training_metrics_.shrink_to_fit();

121
122
  #ifdef USE_CUDA
  if (config_->device_type == std::string("cuda")) {
shiyu1994's avatar
shiyu1994 committed
123
    train_score_updater_.reset(new CUDAScoreUpdater(train_data_, num_tree_per_iteration_, boosting_on_gpu_));
124
  } else {
125
  #endif  // USE_CUDA
126
    train_score_updater_.reset(new ScoreUpdater(train_data_, num_tree_per_iteration_));
127
  #ifdef USE_CUDA
128
  }
129
  #endif  // USE_CUDA
130
131

  num_data_ = train_data_->num_data();
shiyu1994's avatar
shiyu1994 committed
132

133
134
135
136
137
138
139
  // get max feature index
  max_feature_idx_ = train_data_->num_total_features() - 1;
  // get label index
  label_idx_ = train_data_->label_idx();
  // get feature names
  feature_names_ = train_data_->feature_names();
  feature_infos_ = train_data_->feature_infos();
140
  monotone_constraints_ = config->monotone_constraints;
141
142
  // get parser config file content
  parser_config_str_ = train_data_->parser_config_str();
143

144
145
146
  // check that forced splits does not use feature indices larger than dataset size
  CheckForcedSplitFeatures();

147
  // if need bagging, create buffer
148
149
  data_sample_strategy_->ResetSampleConfig(config_.get(), true);
  ResetGradientBuffers();
150
151
152

  class_need_train_ = std::vector<bool>(num_tree_per_iteration_, true);
  if (objective_function_ != nullptr && objective_function_->SkipEmptyClass()) {
Nikita Titov's avatar
Nikita Titov committed
153
    CHECK_EQ(num_tree_per_iteration_, num_class_);
154
155
    for (int i = 0; i < num_class_; ++i) {
      class_need_train_[i] = objective_function_->ClassNeedTrain(i);
156
157
    }
  }
158
159
160
161

  if (config_->linear_tree) {
    linear_tree_ = true;
  }
wxchan's avatar
wxchan committed
162
163
}

164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
void GBDT::CheckForcedSplitFeatures() {
  std::queue<Json> forced_split_nodes;
  forced_split_nodes.push(forced_splits_json_);
  while (!forced_split_nodes.empty()) {
    Json node = forced_split_nodes.front();
    forced_split_nodes.pop();
    const int feature_index = node["feature"].int_value();
    if (feature_index > max_feature_idx_) {
      Log::Fatal("Forced splits file includes feature index %d, but maximum feature index in dataset is %d",
        feature_index, max_feature_idx_);
    }
    if (node.object_items().count("left") > 0) {
      forced_split_nodes.push(node["left"]);
    }
    if (node.object_items().count("right") > 0) {
      forced_split_nodes.push(node["right"]);
    }
  }
}

wxchan's avatar
wxchan committed
184
void GBDT::AddValidDataset(const Dataset* valid_data,
185
                           const std::vector<const Metric*>& valid_metrics) {
wxchan's avatar
wxchan committed
186
  if (!train_data_->CheckAlign(*valid_data)) {
187
    Log::Fatal("Cannot add validation data, since it has different bin mappers with training data");
188
  }
Guolin Ke's avatar
Guolin Ke committed
189
  // for a validation dataset, we need its score and metric
190
  auto new_score_updater =
191
192
    #ifdef USE_CUDA
    config_->device_type == std::string("cuda") ?
193
194
    std::unique_ptr<CUDAScoreUpdater>(new CUDAScoreUpdater(valid_data, num_tree_per_iteration_,
      objective_function_ != nullptr && objective_function_->IsCUDAObjective())) :
195
    #endif  // USE_CUDA
196
    std::unique_ptr<ScoreUpdater>(new ScoreUpdater(valid_data, num_tree_per_iteration_));
wxchan's avatar
wxchan committed
197
198
  // update score
  for (int i = 0; i < iter_; ++i) {
199
200
201
    for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
      auto curr_tree = (i + num_init_iteration_) * num_tree_per_iteration_ + cur_tree_id;
      new_score_updater->AddScore(models_[curr_tree].get(), cur_tree_id);
wxchan's avatar
wxchan committed
202
203
    }
  }
Guolin Ke's avatar
Guolin Ke committed
204
  valid_score_updater_.push_back(std::move(new_score_updater));
Guolin Ke's avatar
Guolin Ke committed
205
206
207
208
  valid_metrics_.emplace_back();
  for (const auto& metric : valid_metrics) {
    valid_metrics_.back().push_back(metric);
  }
Guolin Ke's avatar
Guolin Ke committed
209
  valid_metrics_.back().shrink_to_fit();
210

211
212
213
214
215
216
217
  if (early_stopping_round_ > 0) {
    auto num_metrics = valid_metrics.size();
    if (es_first_metric_only_) { num_metrics = 1; }
    best_iter_.emplace_back(num_metrics, 0);
    best_score_.emplace_back(num_metrics, kMinScore);
    best_msg_.emplace_back(num_metrics);
  }
Guolin Ke's avatar
Guolin Ke committed
218
219
}

Guolin Ke's avatar
Guolin Ke committed
220
void GBDT::Boosting() {
221
  Common::FunctionTimer fun_timer("GBDT::Boosting", global_timer);
Guolin Ke's avatar
Guolin Ke committed
222
  if (objective_function_ == nullptr) {
223
    Log::Fatal("No objective function provided");
Guolin Ke's avatar
Guolin Ke committed
224
225
226
227
  }
  // objective function will calculate gradients and hessians
  int64_t num_score = 0;
  objective_function_->
228
    GetGradients(GetTrainingScore(&num_score), gradients_pointer_, hessians_pointer_);
Guolin Ke's avatar
Guolin Ke committed
229
230
}

Guolin Ke's avatar
Guolin Ke committed
231
void GBDT::Train(int snapshot_freq, const std::string& model_output_path) {
232
  Common::FunctionTimer fun_timer("GBDT::Train", global_timer);
Guolin Ke's avatar
Guolin Ke committed
233
234
  bool is_finished = false;
  auto start_time = std::chrono::steady_clock::now();
Guolin Ke's avatar
Guolin Ke committed
235
  for (int iter = 0; iter < config_->num_iterations && !is_finished; ++iter) {
Guolin Ke's avatar
Guolin Ke committed
236
237
238
239
    is_finished = TrainOneIter(nullptr, nullptr);
    if (!is_finished) {
      is_finished = EvalAndCheckEarlyStopping();
    }
Guolin Ke's avatar
Guolin Ke committed
240
241
242
243
244
245
246
    auto end_time = std::chrono::steady_clock::now();
    // output used time per iteration
    Log::Info("%f seconds elapsed, finished iteration %d", std::chrono::duration<double,
              std::milli>(end_time - start_time) * 1e-3, iter + 1);
    if (snapshot_freq > 0
        && (iter + 1) % snapshot_freq == 0) {
      std::string snapshot_out = model_output_path + ".snapshot_iter_" + std::to_string(iter + 1);
247
      SaveModelToFile(0, -1, config_->saved_feature_importance_type, snapshot_out.c_str());
Guolin Ke's avatar
Guolin Ke committed
248
249
250
251
    }
  }
}

252
253
254
255
256
void GBDT::RefitTree(const int* tree_leaf_prediction, const size_t nrow, const size_t ncol) {
  CHECK_GT(nrow * ncol, 0);
  CHECK_EQ(static_cast<size_t>(num_data_), nrow);
  CHECK_EQ(models_.size(), ncol);

257
258
  int num_iterations = static_cast<int>(models_.size() / num_tree_per_iteration_);
  std::vector<int> leaf_pred(num_data_);
259
260
  if (linear_tree_) {
    std::vector<int> max_leaves_by_thread = std::vector<int>(OMP_NUM_THREADS(), 0);
261
    #pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static)
262
    for (int i = 0; i < static_cast<int>(nrow); ++i) {
263
      int tid = omp_get_thread_num();
264
265
      for (size_t j = 0; j < ncol; ++j) {
        max_leaves_by_thread[tid] = std::max(max_leaves_by_thread[tid], tree_leaf_prediction[i * ncol + j]);
266
267
268
269
270
271
      }
    }
    int max_leaves = *std::max_element(max_leaves_by_thread.begin(), max_leaves_by_thread.end());
    max_leaves += 1;
    tree_learner_->InitLinear(train_data_, max_leaves);
  }
272

273
274
275
276
  for (int iter = 0; iter < num_iterations; ++iter) {
    Boosting();
    for (int tree_id = 0; tree_id < num_tree_per_iteration_; ++tree_id) {
      int model_index = iter * num_tree_per_iteration_ + tree_id;
277
      #pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static)
278
      for (int i = 0; i < num_data_; ++i) {
279
        leaf_pred[i] = tree_leaf_prediction[i * ncol + model_index];
Nikita Titov's avatar
Nikita Titov committed
280
        CHECK_LT(leaf_pred[i], models_[model_index]->num_leaves());
281
      }
282
      size_t offset = static_cast<size_t>(tree_id) * num_data_;
283
284
      auto grad = gradients_pointer_ + offset;
      auto hess = hessians_pointer_ + offset;
285
286
287
288
289
290
291
      auto new_tree = tree_learner_->FitByExistingTree(models_[model_index].get(), leaf_pred, grad, hess);
      train_score_updater_->AddScore(tree_learner_.get(), new_tree, tree_id);
      models_[model_index].reset(new_tree);
    }
  }
}

Andrew Ziem's avatar
Andrew Ziem committed
292
/* If the custom "average" is implemented it will be used in place of the label average (if enabled)
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
*
* An improvement to this is to have options to explicitly choose
* (i) standard average
* (ii) custom average if available
* (iii) any user defined scalar bias (e.g. using a new option "init_score" that overrides (i) and (ii) )
*
* (i) and (ii) could be selected as say "auto_init_score" = 0 or 1 etc..
*
*/
double ObtainAutomaticInitialScore(const ObjectiveFunction* fobj, int class_id) {
  double init_score = 0.0;
  if (fobj != nullptr) {
    init_score = fobj->BoostFromScore(class_id);
  }
  if (Network::num_machines() > 1) {
    init_score = Network::GlobalSyncUpByMean(init_score);
  }
  return init_score;
}

Guolin Ke's avatar
Guolin Ke committed
313
double GBDT::BoostFromAverage(int class_id, bool update_scorer) {
314
  Common::FunctionTimer fun_timer("GBDT::BoostFromAverage", global_timer);
315
  // boosting from average label; or customized "average" if implemented for the current objective
316
317
318
  if (models_.empty() && !train_score_updater_->has_init_score() && objective_function_ != nullptr) {
    if (config_->boost_from_average || (train_data_ != nullptr && train_data_->num_features() == 0)) {
      double init_score = ObtainAutomaticInitialScore(objective_function_, class_id);
319
      if (std::fabs(init_score) > kEpsilon) {
Guolin Ke's avatar
Guolin Ke committed
320
321
322
323
324
        if (update_scorer) {
          train_score_updater_->AddScore(init_score, class_id);
          for (auto& score_updater : valid_score_updater_) {
            score_updater->AddScore(init_score, class_id);
          }
325
326
327
        }
        Log::Info("Start training from score %lf", init_score);
        return init_score;
Guolin Ke's avatar
Guolin Ke committed
328
      }
329
330
331
    } else if (std::string(objective_function_->GetName()) == std::string("regression_l1")
               || std::string(objective_function_->GetName()) == std::string("quantile")
               || std::string(objective_function_->GetName()) == std::string("mape")) {
332
      Log::Warning("Disabling boost_from_average in %s may cause the slow convergence", objective_function_->GetName());
333
    }
334
  }
Guolin Ke's avatar
Guolin Ke committed
335
336
  return 0.0f;
}
Guolin Ke's avatar
Guolin Ke committed
337

Guolin Ke's avatar
Guolin Ke committed
338
bool GBDT::TrainOneIter(const score_t* gradients, const score_t* hessians) {
339
  Common::FunctionTimer fun_timer("GBDT::TrainOneIter", global_timer);
340
  std::vector<double> init_scores(num_tree_per_iteration_, 0.0);
Guolin Ke's avatar
Guolin Ke committed
341
  // boosting first
Guolin Ke's avatar
Guolin Ke committed
342
  if (gradients == nullptr || hessians == nullptr) {
343
    for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
Guolin Ke's avatar
Guolin Ke committed
344
      init_scores[cur_tree_id] = BoostFromAverage(cur_tree_id, true);
345
    }
Guolin Ke's avatar
Guolin Ke committed
346
    Boosting();
347
348
349
    gradients = gradients_pointer_;
    hessians = hessians_pointer_;
  } else {
shiyu1994's avatar
shiyu1994 committed
350
    // use customized objective function
351
    // the check below fails unless objective=custom is provided in the parameters on Booster creation
shiyu1994's avatar
shiyu1994 committed
352
    CHECK(objective_function_ == nullptr);
353
    if (data_sample_strategy_->IsHessianChange()) {
shiyu1994's avatar
shiyu1994 committed
354
355
      // need to copy customized gradients when using GOSS
      int64_t total_size = static_cast<int64_t>(num_data_) * num_tree_per_iteration_;
356
      #pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static)
shiyu1994's avatar
shiyu1994 committed
357
358
359
360
361
362
      for (int64_t i = 0; i < total_size; ++i) {
        gradients_[i] = gradients[i];
        hessians_[i] = hessians[i];
      }
      CHECK_EQ(gradients_pointer_, gradients_.data());
      CHECK_EQ(hessians_pointer_, hessians_.data());
363
364
365
366
367
      gradients = gradients_pointer_;
      hessians = hessians_pointer_;
    }
  }

368
  // bagging logic
369
370
371
372
  data_sample_strategy_->Bagging(iter_, tree_learner_.get(), gradients_.data(), hessians_.data());
  const bool is_use_subset = data_sample_strategy_->is_use_subset();
  const data_size_t bag_data_cnt = data_sample_strategy_->bag_data_cnt();
  const std::vector<data_size_t, Common::AlignmentAllocator<data_size_t, kAlignedSize>>& bag_data_indices = data_sample_strategy_->bag_data_indices();
Guolin Ke's avatar
Guolin Ke committed
373

374
375
  if (objective_function_ == nullptr && is_use_subset && bag_data_cnt < num_data_ && !boosting_on_gpu_ && !data_sample_strategy_->IsHessianChange()) {
    ResetGradientBuffers();
shiyu1994's avatar
shiyu1994 committed
376
377
  }

Guolin Ke's avatar
Guolin Ke committed
378
  bool should_continue = false;
379
  for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
380
    const size_t offset = static_cast<size_t>(cur_tree_id) * num_data_;
381
    std::unique_ptr<Tree> new_tree(new Tree(2, false, false));
382
    if (class_need_train_[cur_tree_id] && train_data_->num_features() > 0) {
383
384
      auto grad = gradients + offset;
      auto hess = hessians + offset;
Guolin Ke's avatar
Guolin Ke committed
385
      // need to copy gradients for bagging subset.
386
387
388
389
      if (is_use_subset && bag_data_cnt < num_data_ && !boosting_on_gpu_) {
        for (int i = 0; i < bag_data_cnt; ++i) {
          gradients_pointer_[offset + i] = grad[bag_data_indices[i]];
          hessians_pointer_[offset + i] = hess[bag_data_indices[i]];
Guolin Ke's avatar
Guolin Ke committed
390
        }
391
392
        grad = gradients_pointer_ + offset;
        hess = hessians_pointer_ + offset;
Guolin Ke's avatar
Guolin Ke committed
393
      }
394
395
      bool is_first_tree = models_.size() < static_cast<size_t>(num_tree_per_iteration_);
      new_tree.reset(tree_learner_->Train(grad, hess, is_first_tree));
396
    }
Guolin Ke's avatar
Guolin Ke committed
397

Guolin Ke's avatar
Guolin Ke committed
398
    if (new_tree->num_leaves() > 1) {
Guolin Ke's avatar
Guolin Ke committed
399
      should_continue = true;
400
      auto score_ptr = train_score_updater_->score() + offset;
401
402
      auto residual_getter = [score_ptr](const label_t* label, int i) {return static_cast<double>(label[i]) - score_ptr[i]; };
      tree_learner_->RenewTreeOutput(new_tree.get(), objective_function_, residual_getter,
403
                                     num_data_, bag_data_indices.data(), bag_data_cnt, train_score_updater_->score());
Guolin Ke's avatar
Guolin Ke committed
404
405
406
      // shrinkage by learning rate
      new_tree->Shrinkage(shrinkage_rate_);
      // update score
407
      UpdateScore(new_tree.get(), cur_tree_id);
408
409
      if (std::fabs(init_scores[cur_tree_id]) > kEpsilon) {
        new_tree->AddBias(init_scores[cur_tree_id]);
Guolin Ke's avatar
Guolin Ke committed
410
      }
411
412
    } else {
      // only add default score one-time
413
      if (models_.size() < static_cast<size_t>(num_tree_per_iteration_)) {
414
415
416
417
418
419
        if (objective_function_ != nullptr && !config_->boost_from_average && !train_score_updater_->has_init_score()) {
          init_scores[cur_tree_id] = ObtainAutomaticInitialScore(objective_function_, cur_tree_id);
          // updates scores
          train_score_updater_->AddScore(init_scores[cur_tree_id], cur_tree_id);
          for (auto& score_updater : valid_score_updater_) {
            score_updater->AddScore(init_scores[cur_tree_id], cur_tree_id);
420
          }
421
        }
422
        new_tree->AsConstantTree(init_scores[cur_tree_id]);
423
424
      }
    }
Guolin Ke's avatar
Guolin Ke committed
425
426
427
    // add model
    models_.push_back(std::move(new_tree));
  }
Guolin Ke's avatar
Guolin Ke committed
428

Guolin Ke's avatar
Guolin Ke committed
429
  if (!should_continue) {
430
    Log::Warning("Stopped training because there are no more leaves that meet the split requirements");
431
432
433
434
    if (models_.size() > static_cast<size_t>(num_tree_per_iteration_)) {
      for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
        models_.pop_back();
      }
Guolin Ke's avatar
Guolin Ke committed
435
436
437
    }
    return true;
  }
438

Guolin Ke's avatar
Guolin Ke committed
439
440
  ++iter_;
  return false;
Guolin Ke's avatar
Guolin Ke committed
441
}
442

wxchan's avatar
wxchan committed
443
void GBDT::RollbackOneIter() {
444
  if (iter_ <= 0) { return; }
wxchan's avatar
wxchan committed
445
  // reset score
446
  for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
Guolin Ke's avatar
Guolin Ke committed
447
    auto curr_tree = models_.size() - num_tree_per_iteration_ + cur_tree_id;
wxchan's avatar
wxchan committed
448
    models_[curr_tree]->Shrinkage(-1.0);
449
    train_score_updater_->AddScore(models_[curr_tree].get(), cur_tree_id);
wxchan's avatar
wxchan committed
450
    for (auto& score_updater : valid_score_updater_) {
451
      score_updater->AddScore(models_[curr_tree].get(), cur_tree_id);
wxchan's avatar
wxchan committed
452
453
454
    }
  }
  // remove model
455
  for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
wxchan's avatar
wxchan committed
456
457
458
459
460
    models_.pop_back();
  }
  --iter_;
}

Guolin Ke's avatar
Guolin Ke committed
461
bool GBDT::EvalAndCheckEarlyStopping() {
462
463
  bool is_met_early_stopping = false;
  // print message for metric
Guolin Ke's avatar
Guolin Ke committed
464
  auto best_msg = OutputMetric(iter_);
Guolin Ke's avatar
Guolin Ke committed
465
466


Guolin Ke's avatar
Guolin Ke committed
467
  is_met_early_stopping = !best_msg.empty();
468
469
  if (is_met_early_stopping) {
    Log::Info("Early stopping at iteration %d, the best iteration round is %d",
470
              iter_, iter_ - early_stopping_round_);
Guolin Ke's avatar
Guolin Ke committed
471
    Log::Info("Output of best iteration round:\n%s", best_msg.c_str());
472
    // pop last early_stopping_round_ models
473
    for (int i = 0; i < early_stopping_round_ * num_tree_per_iteration_; ++i) {
474
475
476
477
      models_.pop_back();
    }
  }
  return is_met_early_stopping;
Guolin Ke's avatar
Guolin Ke committed
478
479
}

480
void GBDT::UpdateScore(const Tree* tree, const int cur_tree_id) {
481
  Common::FunctionTimer fun_timer("GBDT::UpdateScore", global_timer);
Guolin Ke's avatar
Guolin Ke committed
482
  // update training score
483
  if (!data_sample_strategy_->is_use_subset()) {
484
    train_score_updater_->AddScore(tree_learner_.get(), tree, cur_tree_id);
Guolin Ke's avatar
Guolin Ke committed
485

486
    const data_size_t bag_data_cnt = data_sample_strategy_->bag_data_cnt();
Guolin Ke's avatar
Guolin Ke committed
487
    // we need to predict out-of-bag scores of data for boosting
488
    if (num_data_ - bag_data_cnt > 0) {
489
490
      #ifdef USE_CUDA
      if (config_->device_type == std::string("cuda")) {
491
        train_score_updater_->AddScore(tree, data_sample_strategy_->cuda_bag_data_indices().RawData() + bag_data_cnt, num_data_ - bag_data_cnt, cur_tree_id);
492
      } else {
493
      #endif  // USE_CUDA
494
        train_score_updater_->AddScore(tree, data_sample_strategy_->bag_data_indices().data() + bag_data_cnt, num_data_ - bag_data_cnt, cur_tree_id);
495
      #ifdef USE_CUDA
496
      }
497
      #endif  // USE_CUDA
Guolin Ke's avatar
Guolin Ke committed
498
499
    }

Guolin Ke's avatar
Guolin Ke committed
500
  } else {
501
    train_score_updater_->AddScore(tree, cur_tree_id);
Guolin Ke's avatar
Guolin Ke committed
502
  }
Guolin Ke's avatar
Guolin Ke committed
503
504


Guolin Ke's avatar
Guolin Ke committed
505
  // update validation score
Guolin Ke's avatar
Guolin Ke committed
506
  for (auto& score_updater : valid_score_updater_) {
507
    score_updater->AddScore(tree, cur_tree_id);
Guolin Ke's avatar
Guolin Ke committed
508
509
510
  }
}

511
#ifdef USE_CUDA
512
513
514
std::vector<double> GBDT::EvalOneMetric(const Metric* metric, const double* score, const data_size_t num_data) const {
#else
std::vector<double> GBDT::EvalOneMetric(const Metric* metric, const double* score, const data_size_t /*num_data*/) const {
515
516
#endif  // USE_CUDA
  #ifdef USE_CUDA
517
  const bool evaluation_on_cuda = metric->IsCUDAMetric();
shiyu1994's avatar
shiyu1994 committed
518
  if ((boosting_on_gpu_ && evaluation_on_cuda) || (!boosting_on_gpu_ && !evaluation_on_cuda)) {
519
  #endif  // USE_CUDA
520
    return metric->Eval(score, objective_function_);
521
  #ifdef USE_CUDA
shiyu1994's avatar
shiyu1994 committed
522
  } else if (boosting_on_gpu_ && !evaluation_on_cuda) {
523
    const size_t total_size = static_cast<size_t>(num_data) * static_cast<size_t>(num_tree_per_iteration_);
524
525
526
527
528
529
    if (total_size > host_score_.size()) {
      host_score_.resize(total_size, 0.0f);
    }
    CopyFromCUDADeviceToHost<double>(host_score_.data(), score, total_size, __FILE__, __LINE__);
    return metric->Eval(host_score_.data(), objective_function_);
  } else {
530
    const size_t total_size = static_cast<size_t>(num_data) * static_cast<size_t>(num_tree_per_iteration_);
531
532
533
534
535
536
    if (total_size > cuda_score_.Size()) {
      cuda_score_.Resize(total_size);
    }
    CopyFromHostToCUDADevice<double>(cuda_score_.RawData(), score, total_size, __FILE__, __LINE__);
    return metric->Eval(cuda_score_.RawData(), objective_function_);
  }
537
  #endif  // USE_CUDA
Guolin Ke's avatar
Guolin Ke committed
538
539
}

Guolin Ke's avatar
Guolin Ke committed
540
std::string GBDT::OutputMetric(int iter) {
Guolin Ke's avatar
Guolin Ke committed
541
  bool need_output = (iter % config_->metric_freq) == 0;
Guolin Ke's avatar
Guolin Ke committed
542
543
  std::string ret = "";
  std::stringstream msg_buf;
544
  std::vector<std::pair<size_t, size_t>> meet_early_stopping_pairs;
Guolin Ke's avatar
Guolin Ke committed
545
  // print training metric
Guolin Ke's avatar
Guolin Ke committed
546
  if (need_output) {
547
548
    for (auto& sub_metric : training_metrics_) {
      auto name = sub_metric->GetName();
549
      auto scores = EvalOneMetric(sub_metric, train_score_updater_->score(), train_score_updater_->num_data());
Guolin Ke's avatar
Guolin Ke committed
550
      for (size_t k = 0; k < name.size(); ++k) {
Guolin Ke's avatar
Guolin Ke committed
551
552
553
554
555
556
        std::stringstream tmp_buf;
        tmp_buf << "Iteration:" << iter
          << ", training " << name[k]
          << " : " << scores[k];
        Log::Info(tmp_buf.str().c_str());
        if (early_stopping_round_ > 0) {
557
          msg_buf << tmp_buf.str() << '\n';
Guolin Ke's avatar
Guolin Ke committed
558
        }
559
      }
560
    }
Guolin Ke's avatar
Guolin Ke committed
561
562
  }
  // print validation metric
Guolin Ke's avatar
Guolin Ke committed
563
  if (need_output || early_stopping_round_ > 0) {
564
565
    for (size_t i = 0; i < valid_metrics_.size(); ++i) {
      for (size_t j = 0; j < valid_metrics_[i].size(); ++j) {
566
        auto test_scores = EvalOneMetric(valid_metrics_[i][j], valid_score_updater_[i]->score(), valid_score_updater_[i]->num_data());
Guolin Ke's avatar
Guolin Ke committed
567
568
569
570
571
572
573
574
575
576
        auto name = valid_metrics_[i][j]->GetName();
        for (size_t k = 0; k < name.size(); ++k) {
          std::stringstream tmp_buf;
          tmp_buf << "Iteration:" << iter
            << ", valid_" << i + 1 << " " << name[k]
            << " : " << test_scores[k];
          if (need_output) {
            Log::Info(tmp_buf.str().c_str());
          }
          if (early_stopping_round_ > 0) {
577
            msg_buf << tmp_buf.str() << '\n';
578
          }
wxchan's avatar
wxchan committed
579
        }
580
        if (es_first_metric_only_ && j > 0) { continue; }
Guolin Ke's avatar
Guolin Ke committed
581
        if (ret.empty() && early_stopping_round_ > 0) {
582
          auto cur_score = valid_metrics_[i][j]->factor_to_bigger_better() * test_scores.back();
583
          if (cur_score - best_score_[i][j] > early_stopping_min_delta_) {
584
            best_score_[i][j] = cur_score;
585
            best_iter_[i][j] = iter;
Guolin Ke's avatar
Guolin Ke committed
586
            meet_early_stopping_pairs.emplace_back(i, j);
587
          } else {
Guolin Ke's avatar
Guolin Ke committed
588
            if (iter - best_iter_[i][j] >= early_stopping_round_) { ret = best_msg_[i][j]; }
589
          }
wxchan's avatar
wxchan committed
590
591
        }
      }
Guolin Ke's avatar
Guolin Ke committed
592
593
    }
  }
Guolin Ke's avatar
Guolin Ke committed
594
595
596
  for (auto& pair : meet_early_stopping_pairs) {
    best_msg_[pair.first][pair.second] = msg_buf.str();
  }
wxchan's avatar
wxchan committed
597
  return ret;
Guolin Ke's avatar
Guolin Ke committed
598
599
}

600
/*! \brief Get eval result */
601
std::vector<double> GBDT::GetEvalAt(int data_idx) const {
Guolin Ke's avatar
Guolin Ke committed
602
  CHECK(data_idx >= 0 && data_idx <= static_cast<int>(valid_score_updater_.size()));
603
604
  std::vector<double> ret;
  if (data_idx == 0) {
605
    for (auto& sub_metric : training_metrics_) {
606
      auto scores = EvalOneMetric(sub_metric, train_score_updater_->score(), train_score_updater_->num_data());
607
608
609
      for (auto score : scores) {
        ret.push_back(score);
      }
610
    }
611
  } else {
612
613
    auto used_idx = data_idx - 1;
    for (size_t j = 0; j < valid_metrics_[used_idx].size(); ++j) {
614
      auto test_scores = EvalOneMetric(valid_metrics_[used_idx][j], valid_score_updater_[used_idx]->score(), valid_score_updater_[used_idx]->num_data());
615
616
617
      for (auto score : test_scores) {
        ret.push_back(score);
      }
618
619
620
621
622
    }
  }
  return ret;
}

Guolin Ke's avatar
Guolin Ke committed
623
/*! \brief Get training scores result */
624
const double* GBDT::GetTrainingScore(int64_t* out_len) {
625
  *out_len = static_cast<int64_t>(train_score_updater_->num_data()) * num_class_;
Guolin Ke's avatar
Guolin Ke committed
626
  return train_score_updater_->score();
627
628
}

629
void GBDT::PredictContrib(const double* features, double* output) const {
630
  // set zero
Guolin Ke's avatar
Guolin Ke committed
631
632
  const int num_features = max_feature_idx_ + 1;
  std::memset(output, 0, sizeof(double) * num_tree_per_iteration_ * (num_features + 1));
633
634
  const int end_iteration_for_pred = start_iteration_for_pred_ + num_iteration_for_pred_;
  for (int i = start_iteration_for_pred_; i < end_iteration_for_pred; ++i) {
635
636
    // predict all the trees for one iteration
    for (int k = 0; k < num_tree_per_iteration_; ++k) {
Guolin Ke's avatar
Guolin Ke committed
637
      models_[i * num_tree_per_iteration_ + k]->PredictContrib(features, num_features, output + k*(num_features + 1));
638
    }
639
640
641
642
643
644
  }
}

void GBDT::PredictContribByMap(const std::unordered_map<int, double>& features,
                               std::vector<std::unordered_map<int, double>>* output) const {
  const int num_features = max_feature_idx_ + 1;
645
646
  const int end_iteration_for_pred = start_iteration_for_pred_ + num_iteration_for_pred_;
  for (int i = start_iteration_for_pred_; i < end_iteration_for_pred; ++i) {
647
648
649
    // predict all the trees for one iteration
    for (int k = 0; k < num_tree_per_iteration_; ++k) {
      models_[i * num_tree_per_iteration_ + k]->PredictContribByMap(features, num_features, &((*output)[k]));
650
651
652
653
    }
  }
}

Guolin Ke's avatar
Guolin Ke committed
654
655
void GBDT::GetPredictAt(int data_idx, double* out_result, int64_t* out_len) {
  CHECK(data_idx >= 0 && data_idx <= static_cast<int>(valid_score_updater_.size()));
Guolin Ke's avatar
Guolin Ke committed
656

657
  const double* raw_scores = nullptr;
Guolin Ke's avatar
Guolin Ke committed
658
659
  data_size_t num_data = 0;
  if (data_idx == 0) {
wxchan's avatar
wxchan committed
660
    raw_scores = GetTrainingScore(out_len);
Guolin Ke's avatar
Guolin Ke committed
661
662
663
664
665
    num_data = train_score_updater_->num_data();
  } else {
    auto used_idx = data_idx - 1;
    raw_scores = valid_score_updater_[used_idx]->score();
    num_data = valid_score_updater_[used_idx]->num_data();
666
    *out_len = static_cast<int64_t>(num_data) * num_class_;
Guolin Ke's avatar
Guolin Ke committed
667
  }
668
  #ifdef USE_CUDA
669
670
671
672
673
674
  std::vector<double> host_raw_scores;
  if (boosting_on_gpu_) {
    host_raw_scores.resize(static_cast<size_t>(*out_len), 0.0);
    CopyFromCUDADeviceToHost<double>(host_raw_scores.data(), raw_scores, static_cast<size_t>(*out_len), __FILE__, __LINE__);
    raw_scores = host_raw_scores.data();
  }
675
  #endif  // USE_CUDA
Guolin Ke's avatar
Guolin Ke committed
676
  if (objective_function_ != nullptr) {
677
    #pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static)
Guolin Ke's avatar
Guolin Ke committed
678
    for (data_size_t i = 0; i < num_data; ++i) {
Guolin Ke's avatar
Guolin Ke committed
679
      std::vector<double> tree_pred(num_tree_per_iteration_);
680
      for (int j = 0; j < num_tree_per_iteration_; ++j) {
Guolin Ke's avatar
Guolin Ke committed
681
        tree_pred[j] = raw_scores[j * num_data + i];
682
      }
Guolin Ke's avatar
Guolin Ke committed
683
684
      std::vector<double> tmp_result(num_class_);
      objective_function_->ConvertOutput(tree_pred.data(), tmp_result.data());
Guolin Ke's avatar
Guolin Ke committed
685
      for (int j = 0; j < num_class_; ++j) {
686
        out_result[j * num_data + i] = static_cast<double>(tmp_result[j]);
Guolin Ke's avatar
Guolin Ke committed
687
688
      }
    }
689
  } else {
690
    #pragma omp parallel for num_threads(OMP_NUM_THREADS()) schedule(static)
Guolin Ke's avatar
Guolin Ke committed
691
    for (data_size_t i = 0; i < num_data; ++i) {
692
      for (int j = 0; j < num_tree_per_iteration_; ++j) {
Guolin Ke's avatar
Guolin Ke committed
693
        out_result[j * num_data + i] = static_cast<double>(raw_scores[j * num_data + i]);
Guolin Ke's avatar
Guolin Ke committed
694
695
696
697
698
      }
    }
  }
}

699
700
double GBDT::GetUpperBoundValue() const {
  double max_value = 0.0;
Nikita Titov's avatar
Nikita Titov committed
701
  for (const auto &tree : models_) {
702
703
704
705
706
707
708
    max_value += tree->GetUpperBoundValue();
  }
  return max_value;
}

double GBDT::GetLowerBoundValue() const {
  double min_value = 0.0;
Nikita Titov's avatar
Nikita Titov committed
709
  for (const auto &tree : models_) {
710
711
712
713
714
    min_value += tree->GetLowerBoundValue();
  }
  return min_value;
}

Guolin Ke's avatar
Guolin Ke committed
715
716
717
void GBDT::ResetTrainingData(const Dataset* train_data, const ObjectiveFunction* objective_function,
                             const std::vector<const Metric*>& training_metrics) {
  if (train_data != train_data_ && !train_data_->CheckAlign(*train_data)) {
718
    Log::Fatal("Cannot reset training data, since new training data has different bin mappers");
wxchan's avatar
wxchan committed
719
720
  }

Guolin Ke's avatar
Guolin Ke committed
721
  objective_function_ = objective_function;
722
  data_sample_strategy_->UpdateObjectiveFunction(objective_function);
Guolin Ke's avatar
Guolin Ke committed
723
  if (objective_function_ != nullptr) {
Nikita Titov's avatar
Nikita Titov committed
724
    CHECK_EQ(num_tree_per_iteration_, objective_function_->NumModelPerIteration());
725
726
727
    if (objective_function_->IsRenewTreeOutput() && !config_->monotone_constraints.empty()) {
      Log::Fatal("Cannot use ``monotone_constraints`` in %s objective, please disable it.", objective_function_->GetName());
    }
728
  }
729
  is_constant_hessian_ = GetIsConstHessian(objective_function);
730

Guolin Ke's avatar
Guolin Ke committed
731
732
733
734
  // push training metrics
  training_metrics_.clear();
  for (const auto& metric : training_metrics) {
    training_metrics_.push_back(metric);
735
  }
Guolin Ke's avatar
Guolin Ke committed
736
  training_metrics_.shrink_to_fit();
737

738
  #ifdef USE_CUDA
739
740
  boosting_on_gpu_ = objective_function_ != nullptr && objective_function_->IsCUDAObjective() &&
                    !data_sample_strategy_->IsHessianChange();  // for sample strategy with Hessian change, fall back to boosting on CPU
shiyu1994's avatar
shiyu1994 committed
741
  tree_learner_->ResetBoostingOnGPU(boosting_on_gpu_);
742
  #endif  // USE_CUDA
743

Guolin Ke's avatar
Guolin Ke committed
744
745
  if (train_data != train_data_) {
    train_data_ = train_data;
746
    data_sample_strategy_->UpdateTrainingData(train_data);
Guolin Ke's avatar
Guolin Ke committed
747
748
    // not same training data, need reset score and others
    // create score tracker
749
750
    #ifdef USE_CUDA
    if (config_->device_type == std::string("cuda")) {
shiyu1994's avatar
shiyu1994 committed
751
      train_score_updater_.reset(new CUDAScoreUpdater(train_data_, num_tree_per_iteration_, boosting_on_gpu_));
752
    } else {
753
    #endif  // USE_CUDA
754
      train_score_updater_.reset(new ScoreUpdater(train_data_, num_tree_per_iteration_));
755
    #ifdef USE_CUDA
756
    }
757
    #endif  // USE_CUDA
758

Guolin Ke's avatar
Guolin Ke committed
759
760
761
762
763
764
    // update score
    for (int i = 0; i < iter_; ++i) {
      for (int cur_tree_id = 0; cur_tree_id < num_tree_per_iteration_; ++cur_tree_id) {
        auto curr_tree = (i + num_init_iteration_) * num_tree_per_iteration_ + cur_tree_id;
        train_score_updater_->AddScore(models_[curr_tree].get(), cur_tree_id);
      }
765
766
    }

Guolin Ke's avatar
Guolin Ke committed
767
    num_data_ = train_data_->num_data();
768

769
    ResetGradientBuffers();
770

Guolin Ke's avatar
Guolin Ke committed
771
772
773
774
    max_feature_idx_ = train_data_->num_total_features() - 1;
    label_idx_ = train_data_->label_idx();
    feature_names_ = train_data_->feature_names();
    feature_infos_ = train_data_->feature_infos();
775
    parser_config_str_ = train_data_->parser_config_str();
776

777
    tree_learner_->ResetTrainingData(train_data, is_constant_hessian_);
778
    data_sample_strategy_->ResetSampleConfig(config_.get(), true);
779
780
  } else {
    tree_learner_->ResetIsConstantHessian(is_constant_hessian_);
781
  }
782
783
}

Guolin Ke's avatar
Guolin Ke committed
784
785
void GBDT::ResetConfig(const Config* config) {
  auto new_config = std::unique_ptr<Config>(new Config(*config));
786
  if (!config->monotone_constraints.empty()) {
Nikita Titov's avatar
Nikita Titov committed
787
    CHECK_EQ(static_cast<size_t>(train_data_->num_total_features()), config->monotone_constraints.size());
788
789
  }
  if (!config->feature_contri.empty()) {
Nikita Titov's avatar
Nikita Titov committed
790
    CHECK_EQ(static_cast<size_t>(train_data_->num_total_features()), config->feature_contri.size());
791
  }
792
793
794
  if (objective_function_ != nullptr && objective_function_->IsRenewTreeOutput() && !config->monotone_constraints.empty()) {
    Log::Fatal("Cannot use ``monotone_constraints`` in %s objective, please disable it.", objective_function_->GetName());
  }
Guolin Ke's avatar
Guolin Ke committed
795
796
797
  early_stopping_round_ = new_config->early_stopping_round;
  shrinkage_rate_ = new_config->learning_rate;
  if (tree_learner_ != nullptr) {
Guolin Ke's avatar
Guolin Ke committed
798
    tree_learner_->ResetConfig(new_config.get());
799
  }
shiyu1994's avatar
shiyu1994 committed
800

801
802
  boosting_on_gpu_ = objective_function_ != nullptr && objective_function_->IsCUDAObjective() &&
                    !data_sample_strategy_->IsHessianChange();  // for sample strategy with Hessian change, fall back to boosting on CPU
shiyu1994's avatar
shiyu1994 committed
803
804
  tree_learner_->ResetBoostingOnGPU(boosting_on_gpu_);

Guolin Ke's avatar
Guolin Ke committed
805
  if (train_data_ != nullptr) {
806
807
808
809
810
    data_sample_strategy_->ResetSampleConfig(new_config.get(), false);
    if (data_sample_strategy_->NeedResizeGradients()) {
      // resize gradient vectors to copy the customized gradients for goss or bagging with subset
      ResetGradientBuffers();
    }
811
  }
812
  if (config_.get() != nullptr && config_->forcedsplits_filename != new_config->forcedsplits_filename) {
813
814
815
816
817
818
819
    // load forced_splits file
    if (!new_config->forcedsplits_filename.empty()) {
      std::ifstream forced_splits_file(
          new_config->forcedsplits_filename.c_str());
      std::stringstream buffer;
      buffer << forced_splits_file.rdbuf();
      std::string err;
Guolin Ke's avatar
Guolin Ke committed
820
      forced_splits_json_ = Json::parse(buffer.str(), &err);
821
822
823
824
825
826
      tree_learner_->SetForcedSplit(&forced_splits_json_);
    } else {
      forced_splits_json_ = Json();
      tree_learner_->SetForcedSplit(nullptr);
    }
  }
Guolin Ke's avatar
Guolin Ke committed
827
  config_.reset(new_config.release());
Guolin Ke's avatar
Guolin Ke committed
828
829
}

830
831
832
833
void GBDT::ResetGradientBuffers() {
  const size_t total_size = static_cast<size_t>(num_data_) * num_tree_per_iteration_;
  const bool is_use_subset = data_sample_strategy_->is_use_subset();
  const data_size_t bag_data_cnt = data_sample_strategy_->bag_data_cnt();
Guolin Ke's avatar
Guolin Ke committed
834
  if (objective_function_ != nullptr) {
835
836
    #ifdef USE_CUDA
    if (config_->device_type == std::string("cuda") && boosting_on_gpu_) {
837
838
839
      if (cuda_gradients_.Size() < total_size) {
        cuda_gradients_.Resize(total_size);
        cuda_hessians_.Resize(total_size);
Guolin Ke's avatar
Guolin Ke committed
840
      }
841
842
843
      gradients_pointer_ = cuda_gradients_.RawData();
      hessians_pointer_ = cuda_hessians_.RawData();
    } else {
844
    #endif  // USE_CUDA
845
      if (gradients_.size() < total_size) {
shiyu1994's avatar
shiyu1994 committed
846
847
        gradients_.resize(total_size);
        hessians_.resize(total_size);
848
      }
849
850
      gradients_pointer_ = gradients_.data();
      hessians_pointer_ = hessians_.data();
851
    #ifdef USE_CUDA
852
    }
853
    #endif  // USE_CUDA
854
855
856
857
858
859
860
  } else if (data_sample_strategy_->IsHessianChange() || (is_use_subset && bag_data_cnt < num_data_ && !boosting_on_gpu_)) {
    if (gradients_.size() < total_size) {
      gradients_.resize(total_size);
      hessians_.resize(total_size);
    }
    gradients_pointer_ = gradients_.data();
    hessians_pointer_ = hessians_.data();
861
  }
wxchan's avatar
wxchan committed
862
863
}

Guolin Ke's avatar
Guolin Ke committed
864
}  // namespace LightGBM