gbdt.h 9.85 KB
Newer Older
Guolin Ke's avatar
Guolin Ke committed
1
2
3
4
5
6
7
8
9
#ifndef LIGHTGBM_BOOSTING_GBDT_H_
#define LIGHTGBM_BOOSTING_GBDT_H_

#include <LightGBM/boosting.h>
#include "score_updater.hpp"

#include <cstdio>
#include <vector>
#include <string>
10
#include <fstream>
Guolin Ke's avatar
Guolin Ke committed
11
#include <memory>
Guolin Ke's avatar
Guolin Ke committed
12
13
14
15
16
17
18
19
20
21

namespace LightGBM {
/*!
* \brief GBDT algorithm implementation. including Training, prediction, bagging.
*/
class GBDT: public Boosting {
public:
  /*!
  * \brief Constructor
  */
22
  GBDT();
Guolin Ke's avatar
Guolin Ke committed
23
24
25
26
27
  /*!
  * \brief Destructor
  */
  ~GBDT();
  /*!
Qiwei Ye's avatar
Qiwei Ye committed
28
  * \brief Initialization logic
Guolin Ke's avatar
Guolin Ke committed
29
30
31
32
33
34
  * \param config Config for boosting
  * \param train_data Training data
  * \param object_function Training objective function
  * \param training_metrics Training metrics
  * \param output_model_filename Filename of output model
  */
35
36
  void Init(const BoostingConfig* gbdt_config, const Dataset* train_data, const ObjectiveFunction* object_function,
                             const std::vector<const Metric*>& training_metrics)
Guolin Ke's avatar
Guolin Ke committed
37
                                                                       override;
38

Guolin Ke's avatar
Guolin Ke committed
39
40
41
42
43
  /*!
  * \brief Merge model from other boosting object
           Will insert to the front of current boosting object
  * \param other
  */
Guolin Ke's avatar
Guolin Ke committed
44
45
  void MergeFrom(const Boosting* other) override {
    auto other_gbdt = reinterpret_cast<const GBDT*>(other);
Guolin Ke's avatar
Guolin Ke committed
46
47
48
49
    // tmp move to other vector
    auto original_models = std::move(models_);
    models_ = std::vector<std::unique_ptr<Tree>>();
    // push model from other first
Guolin Ke's avatar
Guolin Ke committed
50
51
52
53
    for (const auto& tree : other_gbdt->models_) {
      auto new_tree = std::unique_ptr<Tree>(new Tree(*(tree.get())));
      models_.push_back(std::move(new_tree));
    }
Guolin Ke's avatar
Guolin Ke committed
54
55
56
57
58
59
60
    num_init_iteration_ = static_cast<int>(models_.size()) / num_class_;
    // push model in current object
    for (const auto& tree : original_models) {
      auto new_tree = std::unique_ptr<Tree>(new Tree(*(tree.get())));
      models_.push_back(std::move(new_tree));
    }
    num_iteration_for_pred_ = static_cast<int>(models_.size()) / num_class_;
Guolin Ke's avatar
Guolin Ke committed
61
62
  }

63
64
65
66
67
68
  /*!
  * \brief Reset training data for current boosting
  * \param train_data Training data
  * \param object_function Training objective function
  * \param training_metrics Training metric
  */
69
  void ResetTrainingData(const BoostingConfig* config, const Dataset* train_data, const ObjectiveFunction* object_function, const std::vector<const Metric*>& training_metrics) override;
70

71
72
73
74
75
76
77
78
  /*!
  * \brief Reset shrinkage_rate data for current boosting
  * \param shrinkage_rate Configs for boosting
  */
  void ResetShrinkageRate(double shrinkage_rate) override {
    shrinkage_rate_ = shrinkage_rate;
  }

Guolin Ke's avatar
Guolin Ke committed
79
  /*!
Qiwei Ye's avatar
Qiwei Ye committed
80
81
82
  * \brief Adding a validation dataset
  * \param valid_data Validation dataset
  * \param valid_metrics Metrics for validation dataset
Guolin Ke's avatar
Guolin Ke committed
83
  */
84
  void AddValidDataset(const Dataset* valid_data,
Guolin Ke's avatar
Guolin Ke committed
85
86
       const std::vector<const Metric*>& valid_metrics) override;
  /*!
Guolin Ke's avatar
Guolin Ke committed
87
88
89
  * \brief Training logic
  * \param gradient nullptr for using default objective, otherwise use self-defined boosting
  * \param hessian nullptr for using default objective, otherwise use self-defined boosting
Guolin Ke's avatar
Guolin Ke committed
90
  * \param is_eval true if need evaluation or early stop
Guolin Ke's avatar
Guolin Ke committed
91
  * \return True if meet early stopping or cannot boosting
Guolin Ke's avatar
Guolin Ke committed
92
  */
93
  virtual bool TrainOneIter(const score_t* gradient, const score_t* hessian, bool is_eval) override;
94

95
96
97
98
99
  /*!
  * \brief Rollback one iteration
  */
  void RollbackOneIter() override;

100
  int GetCurrentIteration() const override { return iter_ + num_init_iteration_; }
101

Guolin Ke's avatar
Guolin Ke committed
102
103
  bool EvalAndCheckEarlyStopping() override;

Guolin Ke's avatar
Guolin Ke committed
104
105
106
107
108
  /*!
  * \brief Get evaluation result at data_idx data
  * \param data_idx 0: training data, 1: 1st validation data
  * \return evaluation result
  */
109
  std::vector<double> GetEvalAt(int data_idx) const override;
110

Guolin Ke's avatar
Guolin Ke committed
111
112
  /*!
  * \brief Get current training score
Guolin Ke's avatar
Guolin Ke committed
113
  * \param out_len length of returned score
Guolin Ke's avatar
Guolin Ke committed
114
115
  * \return training score
  */
116
  virtual const score_t* GetTrainingScore(data_size_t* out_len) override;
117

Guolin Ke's avatar
Guolin Ke committed
118
119
120
121
122
123
  /*!
  * \brief Get prediction result at data_idx data
  * \param data_idx 0: training data, 1: 1st validation data
  * \param result used to store prediction result, should allocate memory before call this function
  * \param out_len lenght of returned score
  */
Guolin Ke's avatar
Guolin Ke committed
124
  void GetPredictAt(int data_idx, score_t* out_result, data_size_t* out_len) override;
Guolin Ke's avatar
Guolin Ke committed
125

Guolin Ke's avatar
Guolin Ke committed
126
  /*!
127
  * \brief Prediction for one record without sigmoid transformation
Guolin Ke's avatar
Guolin Ke committed
128
129
130
  * \param feature_values Feature value on this record
  * \return Prediction result for this record
  */
131
  std::vector<double> PredictRaw(const double* feature_values) const override;
Guolin Ke's avatar
Guolin Ke committed
132
133

  /*!
134
  * \brief Prediction for one record with sigmoid transformation if enabled
Guolin Ke's avatar
Guolin Ke committed
135
136
137
  * \param feature_values Feature value on this record
  * \return Prediction result for this record
  */
138
  std::vector<double> Predict(const double* feature_values) const override;
139

wxchan's avatar
wxchan committed
140
  /*!
141
  * \brief Prediction for one record with leaf index
wxchan's avatar
wxchan committed
142
143
144
  * \param feature_values Feature value on this record
  * \return Predicted leaf index for this record
  */
145
  std::vector<int> PredictLeafIndex(const double* value) const override;
146

Guolin Ke's avatar
Guolin Ke committed
147
  /*!
Guolin Ke's avatar
Guolin Ke committed
148
  * \brief save model to file
Guolin Ke's avatar
Guolin Ke committed
149
  * \param num_iterations Iterations that want to save, -1 means save all
Guolin Ke's avatar
Guolin Ke committed
150
  * \param filename filename that want to save to
Guolin Ke's avatar
Guolin Ke committed
151
  */
Guolin Ke's avatar
Guolin Ke committed
152
153
  virtual void SaveModelToFile(int num_iterations, const char* filename) const override ;

Guolin Ke's avatar
Guolin Ke committed
154
155
156
  /*!
  * \brief Restore from a serialized string
  */
Guolin Ke's avatar
Guolin Ke committed
157
  void LoadModelFromString(const std::string& model_str) override;
Guolin Ke's avatar
Guolin Ke committed
158
159
160
161
162
  /*!
  * \brief Get max feature index of this model
  * \return Max feature index of this model
  */
  inline int MaxFeatureIdx() const override { return max_feature_idx_; }
Guolin Ke's avatar
Guolin Ke committed
163
164
165
166
167
168
169

  /*!
  * \brief Get index of label column
  * \return index of label column
  */
  inline int LabelIdx() const override { return label_idx_; }

Guolin Ke's avatar
Guolin Ke committed
170

Guolin Ke's avatar
Guolin Ke committed
171
172
173
174
  /*!
  * \brief Get number of weak sub-models
  * \return Number of weak sub-models
  */
Guolin Ke's avatar
Guolin Ke committed
175
  inline int NumberOfTotalModel() const override { return static_cast<int>(models_.size()); }
Guolin Ke's avatar
Guolin Ke committed
176

177
178
179
180
  /*!
  * \brief Get number of classes
  * \return Number of classes
  */
Guolin Ke's avatar
Guolin Ke committed
181
  inline int NumberOfClasses() const override { return num_class_; }
182
183

  /*!
Guolin Ke's avatar
Guolin Ke committed
184
  * \brief Set number of iterations for prediction
185
  */
Guolin Ke's avatar
Guolin Ke committed
186
187
188
189
190
  inline void SetNumIterationForPred(int num_iteration) override {
    if (num_iteration > 0) {
      num_iteration_for_pred_ = num_iteration;
    } else {
      num_iteration_for_pred_ = static_cast<int>(models_.size()) / num_class_;
191
    }
192
193
    num_iteration_for_pred_ = std::min(num_iteration_for_pred_, 
      static_cast<int>(models_.size()) / num_class_);
194
  }
195

196
197
198
  /*!
  * \brief Get Type name of this boosting object
  */
199
  virtual const char* Name() const override { return "gbdt"; }
200

201
protected:
Guolin Ke's avatar
Guolin Ke committed
202
203
204
  /*!
  * \brief Implement bagging logic
  * \param iter Current interation
205
  * \param curr_class Current class for multiclass training
Guolin Ke's avatar
Guolin Ke committed
206
  */
207
  void Bagging(int iter, const int curr_class);
Guolin Ke's avatar
Guolin Ke committed
208
  /*!
Qiwei Ye's avatar
Qiwei Ye committed
209
210
  * \brief updating score for out-of-bag data.
  *        Data should be update since we may re-bagging data on training
Guolin Ke's avatar
Guolin Ke committed
211
  * \param tree Trained tree of this iteration
212
  * \param curr_class Current class for multiclass training
Guolin Ke's avatar
Guolin Ke committed
213
  */
214
  void UpdateScoreOutOfBag(const Tree* tree, const int curr_class);
Guolin Ke's avatar
Guolin Ke committed
215
216
217
218
219
  /*!
  * \brief calculate the object function
  */
  void Boosting();
  /*!
Qiwei Ye's avatar
Qiwei Ye committed
220
  * \brief updating score after tree was trained
Guolin Ke's avatar
Guolin Ke committed
221
  * \param tree Trained tree of this iteration
222
  * \param curr_class Current class for multiclass training
Guolin Ke's avatar
Guolin Ke committed
223
  */
224
  virtual void UpdateScore(const Tree* tree, const int curr_class);
Guolin Ke's avatar
Guolin Ke committed
225
  /*!
Hui Xue's avatar
Hui Xue committed
226
  * \brief Print metric result of current iteration
Guolin Ke's avatar
Guolin Ke committed
227
228
  * \param iter Current interation
  */
wxchan's avatar
wxchan committed
229
  bool OutputMetric(int iter);
wxchan's avatar
wxchan committed
230
231
232
233
  /*!
  * \brief Calculate feature importances
  * \param last_iter Last tree use to calculate
  */
234
235
236
  std::string FeatureImportance() const;
  /*! \brief current iteration */
  int iter_;
Guolin Ke's avatar
Guolin Ke committed
237
238
239
  /*! \brief Pointer to training data */
  const Dataset* train_data_;
  /*! \brief Config of gbdt */
Guolin Ke's avatar
Guolin Ke committed
240
  const BoostingConfig* gbdt_config_;
Hui Xue's avatar
Hui Xue committed
241
  /*! \brief Tree learner, will use this class to learn trees */
Guolin Ke's avatar
Guolin Ke committed
242
  std::vector<std::unique_ptr<TreeLearner>> tree_learner_;
Guolin Ke's avatar
Guolin Ke committed
243
244
  /*! \brief Objective function */
  const ObjectiveFunction* object_function_;
Hui Xue's avatar
Hui Xue committed
245
  /*! \brief Store and update training data's score */
Guolin Ke's avatar
Guolin Ke committed
246
  std::unique_ptr<ScoreUpdater> train_score_updater_;
Guolin Ke's avatar
Guolin Ke committed
247
248
249
  /*! \brief Metrics for training data */
  std::vector<const Metric*> training_metrics_;
  /*! \brief Store and update validation data's scores */
Guolin Ke's avatar
Guolin Ke committed
250
  std::vector<std::unique_ptr<ScoreUpdater>> valid_score_updater_;
Guolin Ke's avatar
Guolin Ke committed
251
252
  /*! \brief Metric for validation data */
  std::vector<std::vector<const Metric*>> valid_metrics_;
wxchan's avatar
wxchan committed
253
254
  /*! \brief Number of rounds for early stopping */
  int early_stopping_round_;
wxchan's avatar
wxchan committed
255
256
  /*! \brief Best score(s) for early stopping */
  std::vector<std::vector<int>> best_iter_;
257
  std::vector<std::vector<double>> best_score_;
Guolin Ke's avatar
Guolin Ke committed
258
  /*! \brief Trained models(trees) */
Guolin Ke's avatar
Guolin Ke committed
259
  std::vector<std::unique_ptr<Tree>> models_;
Guolin Ke's avatar
Guolin Ke committed
260
261
262
  /*! \brief Max feature index of training data*/
  int max_feature_idx_;
  /*! \brief First order derivative of training data */
Guolin Ke's avatar
Guolin Ke committed
263
  std::vector<score_t> gradients_;
Guolin Ke's avatar
Guolin Ke committed
264
  /*! \brief Secend order derivative of training data */
Guolin Ke's avatar
Guolin Ke committed
265
  std::vector<score_t> hessians_;
Guolin Ke's avatar
Guolin Ke committed
266
  /*! \brief Store the data indices of out-of-bag */
Guolin Ke's avatar
Guolin Ke committed
267
  std::vector<data_size_t> out_of_bag_data_indices_;
Guolin Ke's avatar
Guolin Ke committed
268
269
270
  /*! \brief Number of out-of-bag data */
  data_size_t out_of_bag_data_cnt_;
  /*! \brief Store the indices of in-bag data */
Guolin Ke's avatar
Guolin Ke committed
271
  std::vector<data_size_t> bag_data_indices_;
Guolin Ke's avatar
Guolin Ke committed
272
273
  /*! \brief Number of in-bag data */
  data_size_t bag_data_cnt_;
274
  /*! \brief Number of training data */
Guolin Ke's avatar
Guolin Ke committed
275
  data_size_t num_data_;
276
277
  /*! \brief Number of classes */
  int num_class_;
Guolin Ke's avatar
Guolin Ke committed
278
279
280
281
  /*! \brief Random generator, used for bagging */
  Random random_;
  /*!
  *   \brief Sigmoid parameter, used for prediction.
282
  *          if > 0 means output score will transform by sigmoid function
Guolin Ke's avatar
Guolin Ke committed
283
  */
284
  double sigmoid_;
Guolin Ke's avatar
Guolin Ke committed
285
286
  /*! \brief Index of label column */
  data_size_t label_idx_;
287
  /*! \brief number of used model */
Guolin Ke's avatar
Guolin Ke committed
288
  int num_iteration_for_pred_;
Guolin Ke's avatar
Guolin Ke committed
289
290
  /*! \brief Shrinkage rate for one iteration */
  double shrinkage_rate_;
Guolin Ke's avatar
Guolin Ke committed
291
  /*! \brief Number of loaded initial models */
292
  int num_init_iteration_;
Guolin Ke's avatar
Guolin Ke committed
293
294
295
};

}  // namespace LightGBM
Guolin Ke's avatar
Guolin Ke committed
296
#endif   // LightGBM_BOOSTING_GBDT_H_