regression_objective.hpp 8.67 KB
Newer Older
Guolin Ke's avatar
Guolin Ke committed
1
2
3
4
#ifndef LIGHTGBM_OBJECTIVE_REGRESSION_OBJECTIVE_HPP_
#define LIGHTGBM_OBJECTIVE_REGRESSION_OBJECTIVE_HPP_

#include <LightGBM/objective_function.h>
5
#include <LightGBM/utils/common.h>
Guolin Ke's avatar
Guolin Ke committed
6
7
8

namespace LightGBM {
/*!
9
* \brief Objective function for regression
Guolin Ke's avatar
Guolin Ke committed
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
*/
class RegressionL2loss: public ObjectiveFunction {
public:
  explicit RegressionL2loss(const ObjectiveConfig&) {
  }

  ~RegressionL2loss() {
  }

  void Init(const Metadata& metadata, data_size_t num_data) override {
    num_data_ = num_data;
    label_ = metadata.label();
    weights_ = metadata.weights();
  }

25
  void GetGradients(const double* score, score_t* gradients,
26
                    score_t* hessians) const override {
Guolin Ke's avatar
Guolin Ke committed
27
    if (weights_ == nullptr) {
28
      #pragma omp parallel for schedule(static)
Guolin Ke's avatar
Guolin Ke committed
29
      for (data_size_t i = 0; i < num_data_; ++i) {
30
31
        gradients[i] = static_cast<score_t>(score[i] - label_[i]);
        hessians[i] = 1.0f;
Guolin Ke's avatar
Guolin Ke committed
32
33
      }
    } else {
34
      #pragma omp parallel for schedule(static)
Guolin Ke's avatar
Guolin Ke committed
35
      for (data_size_t i = 0; i < num_data_; ++i) {
36
        gradients[i] = static_cast<score_t>(score[i] - label_[i]) * weights_[i];
Guolin Ke's avatar
Guolin Ke committed
37
38
39
40
41
        hessians[i] = weights_[i];
      }
    }
  }

Guolin Ke's avatar
Guolin Ke committed
42
43
  const char* GetName() const override {
    return "regression";
Guolin Ke's avatar
Guolin Ke committed
44
45
  }

46
47
48
49
50
51
52
53
  bool IsConstantHessian() const override {
    if (weights_ == nullptr) {
      return true;
    } else {
      return false;
    }
  }

Guolin Ke's avatar
Guolin Ke committed
54
55
56
57
58
59
60
61
62
private:
  /*! \brief Number of data */
  data_size_t num_data_;
  /*! \brief Pointer of label */
  const float* label_;
  /*! \brief Pointer of weights */
  const float* weights_;
};

Guolin Ke's avatar
Guolin Ke committed
63
64
65
/*!
* \brief L1 regression loss
*/
66
67
class RegressionL1loss: public ObjectiveFunction {
public:
68
  explicit RegressionL1loss(const ObjectiveConfig& config) {
69
    eta_ = static_cast<double>(config.gaussian_eta);
70
  }
71
72
73
74
75
76
77
78
79

  ~RegressionL1loss() {}

  void Init(const Metadata& metadata, data_size_t num_data) override {
    num_data_ = num_data;
    label_ = metadata.label();
    weights_ = metadata.weights();
  }

80
  void GetGradients(const double* score, score_t* gradients,
81
                    score_t* hessians) const override {
82
    if (weights_ == nullptr) {
83
      #pragma omp parallel for schedule(static)
84
      for (data_size_t i = 0; i < num_data_; ++i) {
85
        const double diff = score[i] - label_[i];
Guolin Ke's avatar
Guolin Ke committed
86
87
        if (diff >= 0.0f) {
          gradients[i] = 1.0f;
88
        } else {
Guolin Ke's avatar
Guolin Ke committed
89
          gradients[i] = -1.0f;
90
        }
91
        hessians[i] = static_cast<score_t>(Common::ApproximateHessianWithGaussian(score[i], label_[i], gradients[i], eta_));
92
93
      }
    } else {
94
      #pragma omp parallel for schedule(static)
95
      for (data_size_t i = 0; i < num_data_; ++i) {
96
        const double diff = score[i] - label_[i];
Guolin Ke's avatar
Guolin Ke committed
97
        if (diff >= 0.0f) {
98
99
100
101
          gradients[i] = weights_[i];
        } else {
          gradients[i] = -weights_[i];
        }
102
        hessians[i] = static_cast<score_t>(Common::ApproximateHessianWithGaussian(score[i], label_[i], gradients[i], eta_, weights_[i]));
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
      }
    }
  }

  const char* GetName() const override {
    return "regression_l1";
  }

private:
  /*! \brief Number of data */
  data_size_t num_data_;
  /*! \brief Pointer of label */
  const float* label_;
  /*! \brief Pointer of weights */
  const float* weights_;
118
  /*! \brief a parameter to control the width of Gaussian function to approximate hessian */
119
  double eta_;
120
121
};

Guolin Ke's avatar
Guolin Ke committed
122
123
124
/*!
* \brief Huber regression loss
*/
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
125
class RegressionHuberLoss: public ObjectiveFunction {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
126
public:
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
127
  explicit RegressionHuberLoss(const ObjectiveConfig& config) {
128
129
    delta_ = static_cast<double>(config.huber_delta);
    eta_ = static_cast<double>(config.gaussian_eta);
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
130
131
  }

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
132
  ~RegressionHuberLoss() {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
133
134
135
136
137
138
139
140
  }

  void Init(const Metadata& metadata, data_size_t num_data) override {
    num_data_ = num_data;
    label_ = metadata.label();
    weights_ = metadata.weights();
  }

141
  void GetGradients(const double* score, score_t* gradients,
142
                    score_t* hessians) const override {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
143
    if (weights_ == nullptr) {
144
      #pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
145
      for (data_size_t i = 0; i < num_data_; ++i) {
146
        const double diff = score[i] - label_[i];
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
147

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
148
        if (std::abs(diff) <= delta_) {
149
          gradients[i] = static_cast<score_t>(diff);
Guolin Ke's avatar
Guolin Ke committed
150
          hessians[i] = 1.0f;
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
151
        } else {
Guolin Ke's avatar
Guolin Ke committed
152
          if (diff >= 0.0f) {
153
            gradients[i] = static_cast<score_t>(delta_);
Guolin Ke's avatar
Guolin Ke committed
154
          } else {
155
            gradients[i] = static_cast<score_t>(-delta_);
Guolin Ke's avatar
Guolin Ke committed
156
          }
157
          hessians[i] = static_cast<score_t>(Common::ApproximateHessianWithGaussian(score[i], label_[i], gradients[i], eta_));
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
158
159
160
        }
      }
    } else {
161
      #pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
162
      for (data_size_t i = 0; i < num_data_; ++i) {
163
        const double diff = score[i] - label_[i];
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
164

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
165
        if (std::abs(diff) <= delta_) {
166
          gradients[i] = static_cast<score_t>(diff * weights_[i]);
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
167
168
          hessians[i] = weights_[i];
        } else {
Guolin Ke's avatar
Guolin Ke committed
169
          if (diff >= 0.0f) {
170
            gradients[i] = static_cast<score_t>(delta_ * weights_[i]);
Guolin Ke's avatar
Guolin Ke committed
171
          } else {
172
            gradients[i] = static_cast<score_t>(-delta_ * weights_[i]);
Guolin Ke's avatar
Guolin Ke committed
173
          }
174
          hessians[i] = static_cast<score_t>(Common::ApproximateHessianWithGaussian(score[i], label_[i], gradients[i], eta_, weights_[i]));
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
        }
      }
    }
  }

  const char* GetName() const override {
    return "huber";
  }

private:
  /*! \brief Number of data */
  data_size_t num_data_;
  /*! \brief Pointer of label */
  const float* label_;
  /*! \brief Pointer of weights */
  const float* weights_;
  /*! \brief delta for Huber loss */
192
  double delta_;
193
  /*! \brief a parameter to control the width of Gaussian function to approximate hessian */
194
  double eta_;
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
195
196
};

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
197
198
199
200
201

// http://research.microsoft.com/en-us/um/people/zhang/INRIA/Publis/Tutorial-Estim/node24.html
class RegressionFairLoss: public ObjectiveFunction {
public:
  explicit RegressionFairLoss(const ObjectiveConfig& config) {
202
    c_ = static_cast<double>(config.fair_c);
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
203
204
205
206
207
208
209
210
211
212
  }

  ~RegressionFairLoss() {}

  void Init(const Metadata& metadata, data_size_t num_data) override {
    num_data_ = num_data;
    label_ = metadata.label();
    weights_ = metadata.weights();
  }

213
  void GetGradients(const double* score, score_t* gradients,
214
                    score_t* hessians) const override {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
215
    if (weights_ == nullptr) {
216
      #pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
217
      for (data_size_t i = 0; i < num_data_; ++i) {
218
219
220
        const double x = score[i] - label_[i];
        gradients[i] = static_cast<score_t>(c_ * x / (std::fabs(x) + c_));
        hessians[i] = static_cast<score_t>(c_ * c_ / ((std::fabs(x) + c_) * (std::fabs(x) + c_)));
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
221
222
      }
    } else {
223
      #pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
224
      for (data_size_t i = 0; i < num_data_; ++i) {
225
226
227
        const double x = score[i] - label_[i];
        gradients[i] = static_cast<score_t>(c_ * x / (std::fabs(x) + c_) * weights_[i]);
        hessians[i] = static_cast<score_t>(c_ * c_ / ((std::fabs(x) + c_) * (std::fabs(x) + c_)) * weights_[i]);
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
      }
    }
  }

  const char* GetName() const override {
    return "fair";
  }

private:
  /*! \brief Number of data */
  data_size_t num_data_;
  /*! \brief Pointer of label */
  const float* label_;
  /*! \brief Pointer of weights */
  const float* weights_;
  /*! \brief c for Fair loss */
244
  double c_;
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
245
246
};

247
248
249
250
251
252
253

/*!
* \brief Objective function for Poisson regression
*/
class RegressionPoissonLoss: public ObjectiveFunction {
public:
  explicit RegressionPoissonLoss(const ObjectiveConfig& config) {
254
    max_delta_step_ = static_cast<double>(config.poisson_max_delta_step);
255
256
257
258
259
260
261
262
263
264
265
  }

  ~RegressionPoissonLoss() {}

  void Init(const Metadata& metadata, data_size_t num_data) override {
    num_data_ = num_data;
    label_ = metadata.label();
    weights_ = metadata.weights();
  }

  void GetGradients(const double* score, score_t* gradients,
266
                    score_t* hessians) const override {
267
    if (weights_ == nullptr) {
268
      #pragma omp parallel for schedule(static)
269
      for (data_size_t i = 0; i < num_data_; ++i) {
Guolin Ke's avatar
Guolin Ke committed
270
271
        gradients[i] = static_cast<score_t>(score[i] - label_[i]);
        hessians[i] = static_cast<score_t>(score[i] + max_delta_step_);
272
273
      }
    } else {
274
      #pragma omp parallel for schedule(static)
275
      for (data_size_t i = 0; i < num_data_; ++i) {
Guolin Ke's avatar
Guolin Ke committed
276
277
        gradients[i] = static_cast<score_t>((score[i] - label_[i]) * weights_[i]);
        hessians[i] = static_cast<score_t>((score[i] + max_delta_step_) * weights_[i]);
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
      }
    }
  }

  const char* GetName() const override {
    return "poisson";
  }

private:
  /*! \brief Number of data */
  data_size_t num_data_;
  /*! \brief Pointer of label */
  const float* label_;
  /*! \brief Pointer of weights */
  const float* weights_;
  /*! \brief used to safeguard optimization */
  double max_delta_step_;
};

Guolin Ke's avatar
Guolin Ke committed
297
}  // namespace LightGBM
Guolin Ke's avatar
Guolin Ke committed
298
#endif   // LightGBM_OBJECTIVE_REGRESSION_OBJECTIVE_HPP_