regression_objective.hpp 9.88 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
*/
class RegressionL2loss: public ObjectiveFunction {
public:
  explicit RegressionL2loss(const ObjectiveConfig&) {
  }

16
17
18
19
  explicit RegressionL2loss(const std::vector<std::string>&) {

  }

Guolin Ke's avatar
Guolin Ke committed
20
21
22
23
24
25
26
27
28
  ~RegressionL2loss() {
  }

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

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

Guolin Ke's avatar
Guolin Ke committed
46
47
  const char* GetName() const override {
    return "regression";
Guolin Ke's avatar
Guolin Ke committed
48
49
  }

50
51
52
53
54
55
  std::string ToString() const override {
    std::stringstream str_buf;
    str_buf << GetName();
    return str_buf.str();
  }

56
57
58
59
60
61
62
63
  bool IsConstantHessian() const override {
    if (weights_ == nullptr) {
      return true;
    } else {
      return false;
    }
  }

64
65
  bool BoostFromAverage() const override { return true; }

Guolin Ke's avatar
Guolin Ke committed
66
67
68
69
70
71
72
73
74
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
75
76
77
/*!
* \brief L1 regression loss
*/
78
79
class RegressionL1loss: public ObjectiveFunction {
public:
80
  explicit RegressionL1loss(const ObjectiveConfig& config) {
81
    eta_ = static_cast<double>(config.gaussian_eta);
82
  }
83

84
85
86
87
  explicit RegressionL1loss(const std::vector<std::string>&) {

  }

88
89
90
91
92
93
94
95
  ~RegressionL1loss() {}

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

Guolin Ke's avatar
Guolin Ke committed
96
97
  void GetGradients(const double* score, float* gradients,
                    float* hessians) const override {
98
    if (weights_ == nullptr) {
99
      #pragma omp parallel for schedule(static)
100
      for (data_size_t i = 0; i < num_data_; ++i) {
101
        const double diff = score[i] - label_[i];
Guolin Ke's avatar
Guolin Ke committed
102
103
        if (diff >= 0.0f) {
          gradients[i] = 1.0f;
104
        } else {
Guolin Ke's avatar
Guolin Ke committed
105
          gradients[i] = -1.0f;
106
        }
Guolin Ke's avatar
Guolin Ke committed
107
        hessians[i] = static_cast<float>(Common::ApproximateHessianWithGaussian(score[i], label_[i], gradients[i], eta_));
108
109
      }
    } else {
110
      #pragma omp parallel for schedule(static)
111
      for (data_size_t i = 0; i < num_data_; ++i) {
112
        const double diff = score[i] - label_[i];
Guolin Ke's avatar
Guolin Ke committed
113
        if (diff >= 0.0f) {
114
115
116
117
          gradients[i] = weights_[i];
        } else {
          gradients[i] = -weights_[i];
        }
Guolin Ke's avatar
Guolin Ke committed
118
        hessians[i] = static_cast<float>(Common::ApproximateHessianWithGaussian(score[i], label_[i], gradients[i], eta_, weights_[i]));
119
120
121
122
123
124
125
126
      }
    }
  }

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

127
128
129
130
131
132
133
134
  std::string ToString() const override {
    std::stringstream str_buf;
    str_buf << GetName();
    return str_buf.str();
  }

  bool BoostFromAverage() const override { return true; }

135
136
137
138
139
140
141
private:
  /*! \brief Number of data */
  data_size_t num_data_;
  /*! \brief Pointer of label */
  const float* label_;
  /*! \brief Pointer of weights */
  const float* weights_;
142
  /*! \brief a parameter to control the width of Gaussian function to approximate hessian */
143
  double eta_;
144
145
};

Guolin Ke's avatar
Guolin Ke committed
146
147
148
/*!
* \brief Huber regression loss
*/
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
149
class RegressionHuberLoss: public ObjectiveFunction {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
150
public:
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
151
  explicit RegressionHuberLoss(const ObjectiveConfig& config) {
152
153
    delta_ = static_cast<double>(config.huber_delta);
    eta_ = static_cast<double>(config.gaussian_eta);
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
154
155
  }

156
157
158
159
  explicit RegressionHuberLoss(const std::vector<std::string>&) {

  }

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
160
  ~RegressionHuberLoss() {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
161
162
163
164
165
166
167
168
  }

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

Guolin Ke's avatar
Guolin Ke committed
169
170
  void GetGradients(const double* score, float* gradients,
                    float* hessians) const override {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
171
    if (weights_ == nullptr) {
172
      #pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
173
      for (data_size_t i = 0; i < num_data_; ++i) {
174
        const double diff = score[i] - label_[i];
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
175

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
176
        if (std::abs(diff) <= delta_) {
Guolin Ke's avatar
Guolin Ke committed
177
          gradients[i] = static_cast<float>(diff);
Guolin Ke's avatar
Guolin Ke committed
178
          hessians[i] = 1.0f;
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
179
        } else {
Guolin Ke's avatar
Guolin Ke committed
180
          if (diff >= 0.0f) {
Guolin Ke's avatar
Guolin Ke committed
181
            gradients[i] = static_cast<float>(delta_);
Guolin Ke's avatar
Guolin Ke committed
182
          } else {
Guolin Ke's avatar
Guolin Ke committed
183
            gradients[i] = static_cast<float>(-delta_);
Guolin Ke's avatar
Guolin Ke committed
184
          }
Guolin Ke's avatar
Guolin Ke committed
185
          hessians[i] = static_cast<float>(Common::ApproximateHessianWithGaussian(score[i], label_[i], gradients[i], eta_));
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
186
187
188
        }
      }
    } else {
189
      #pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
190
      for (data_size_t i = 0; i < num_data_; ++i) {
191
        const double diff = score[i] - label_[i];
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
192

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
193
        if (std::abs(diff) <= delta_) {
Guolin Ke's avatar
Guolin Ke committed
194
          gradients[i] = static_cast<float>(diff * weights_[i]);
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
195
196
          hessians[i] = weights_[i];
        } else {
Guolin Ke's avatar
Guolin Ke committed
197
          if (diff >= 0.0f) {
Guolin Ke's avatar
Guolin Ke committed
198
            gradients[i] = static_cast<float>(delta_ * weights_[i]);
Guolin Ke's avatar
Guolin Ke committed
199
          } else {
Guolin Ke's avatar
Guolin Ke committed
200
            gradients[i] = static_cast<float>(-delta_ * weights_[i]);
Guolin Ke's avatar
Guolin Ke committed
201
          }
Guolin Ke's avatar
Guolin Ke committed
202
          hessians[i] = static_cast<float>(Common::ApproximateHessianWithGaussian(score[i], label_[i], gradients[i], eta_, weights_[i]));
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
203
204
205
206
207
208
209
210
211
        }
      }
    }
  }

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

212
213
214
215
216
217
218
219
  std::string ToString() const override {
    std::stringstream str_buf;
    str_buf << GetName();
    return str_buf.str();
  }

  bool BoostFromAverage() const override { return true; }

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
220
221
222
223
224
225
226
227
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 */
228
  double delta_;
229
  /*! \brief a parameter to control the width of Gaussian function to approximate hessian */
230
  double eta_;
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
231
232
};

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
233
234
235
236
237

// 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) {
238
    c_ = static_cast<double>(config.fair_c);
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
239
240
  }

241
242
243
244
  explicit RegressionFairLoss(const std::vector<std::string>&) {

  }

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
245
246
247
248
249
250
251
252
  ~RegressionFairLoss() {}

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

Guolin Ke's avatar
Guolin Ke committed
253
254
  void GetGradients(const double* score, float* gradients,
                    float* hessians) const override {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
255
    if (weights_ == nullptr) {
256
      #pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
257
      for (data_size_t i = 0; i < num_data_; ++i) {
258
        const double x = score[i] - label_[i];
Guolin Ke's avatar
Guolin Ke committed
259
260
        gradients[i] = static_cast<float>(c_ * x / (std::fabs(x) + c_));
        hessians[i] = static_cast<float>(c_ * c_ / ((std::fabs(x) + c_) * (std::fabs(x) + c_)));
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
261
262
      }
    } else {
263
      #pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
264
      for (data_size_t i = 0; i < num_data_; ++i) {
265
        const double x = score[i] - label_[i];
Guolin Ke's avatar
Guolin Ke committed
266
267
        gradients[i] = static_cast<float>(c_ * x / (std::fabs(x) + c_) * weights_[i]);
        hessians[i] = static_cast<float>(c_ * c_ / ((std::fabs(x) + c_) * (std::fabs(x) + c_)) * weights_[i]);
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
268
269
270
271
272
273
274
275
      }
    }
  }

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

276
277
278
279
280
281
282
283
  std::string ToString() const override {
    std::stringstream str_buf;
    str_buf << GetName();
    return str_buf.str();
  }

  bool BoostFromAverage() const override { return true; }

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
284
285
286
287
288
289
290
291
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 */
292
  double c_;
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
293
294
};

295
296
297
298
299
300
301

/*!
* \brief Objective function for Poisson regression
*/
class RegressionPoissonLoss: public ObjectiveFunction {
public:
  explicit RegressionPoissonLoss(const ObjectiveConfig& config) {
302
    max_delta_step_ = static_cast<double>(config.poisson_max_delta_step);
303
304
  }

305
306
307
308
  explicit RegressionPoissonLoss(const std::vector<std::string>&) {

  }

309
310
311
312
313
314
315
316
  ~RegressionPoissonLoss() {}

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

Guolin Ke's avatar
Guolin Ke committed
317
318
  void GetGradients(const double* score, float* gradients,
                    float* hessians) const override {
319
    if (weights_ == nullptr) {
320
      #pragma omp parallel for schedule(static)
321
      for (data_size_t i = 0; i < num_data_; ++i) {
Guolin Ke's avatar
Guolin Ke committed
322
323
        gradients[i] = static_cast<float>(score[i] - label_[i]);
        hessians[i] = static_cast<float>(score[i] + max_delta_step_);
324
325
      }
    } else {
326
      #pragma omp parallel for schedule(static)
327
      for (data_size_t i = 0; i < num_data_; ++i) {
Guolin Ke's avatar
Guolin Ke committed
328
329
        gradients[i] = static_cast<float>((score[i] - label_[i]) * weights_[i]);
        hessians[i] = static_cast<float>((score[i] + max_delta_step_) * weights_[i]);
330
331
332
333
334
335
336
337
      }
    }
  }

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

338
339
340
341
342
343
344
345
  std::string ToString() const override {
    std::stringstream str_buf;
    str_buf << GetName();
    return str_buf.str();
  }

  bool BoostFromAverage() const override { return true; }

346
347
348
349
350
351
352
353
354
355
356
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
357
}  // namespace LightGBM
Guolin Ke's avatar
Guolin Ke committed
358
#endif   // LightGBM_OBJECTIVE_REGRESSION_OBJECTIVE_HPP_