regression_objective.hpp 8.31 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,
Guolin Ke's avatar
Guolin Ke committed
26
    score_t* hessians) const override {
Guolin Ke's avatar
Guolin Ke committed
27
    if (weights_ == nullptr) {
Guolin Ke's avatar
Guolin Ke committed
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 {
Guolin Ke's avatar
Guolin Ke committed
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
54
  }

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
55
56
57
/*!
* \brief L1 regression loss
*/
58
59
class RegressionL1loss: public ObjectiveFunction {
public:
60
  explicit RegressionL1loss(const ObjectiveConfig& config) {
61
    eta_ = static_cast<double>(config.gaussian_eta);
62
  }
63
64
65
66
67
68
69
70
71

  ~RegressionL1loss() {}

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

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

  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_;
110
  /*! \brief a parameter to control the width of Gaussian function to approximate hessian */
111
  double eta_;
112
113
};

Guolin Ke's avatar
Guolin Ke committed
114
115
116
/*!
* \brief Huber regression loss
*/
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
117
class RegressionHuberLoss: public ObjectiveFunction {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
118
public:
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
119
  explicit RegressionHuberLoss(const ObjectiveConfig& config) {
120
121
    delta_ = static_cast<double>(config.huber_delta);
    eta_ = static_cast<double>(config.gaussian_eta);
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
122
123
  }

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
124
  ~RegressionHuberLoss() {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
125
126
127
128
129
130
131
132
  }

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

133
  void GetGradients(const double* score, score_t* gradients,
Guolin Ke's avatar
Guolin Ke committed
134
    score_t* hessians) const override {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
135
    if (weights_ == nullptr) {
Guolin Ke's avatar
Guolin Ke committed
136
#pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
137
      for (data_size_t i = 0; i < num_data_; ++i) {
138
        const double diff = score[i] - label_[i];
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
139

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
140
        if (std::abs(diff) <= delta_) {
141
          gradients[i] = static_cast<score_t>(diff);
Guolin Ke's avatar
Guolin Ke committed
142
          hessians[i] = 1.0f;
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
143
        } else {
Guolin Ke's avatar
Guolin Ke committed
144
          if (diff >= 0.0f) {
145
            gradients[i] = static_cast<score_t>(delta_);
Guolin Ke's avatar
Guolin Ke committed
146
          } else {
147
            gradients[i] = static_cast<score_t>(-delta_);
Guolin Ke's avatar
Guolin Ke committed
148
          }
149
          hessians[i] = static_cast<score_t>(Common::ApproximateHessianWithGaussian(score[i], label_[i], gradients[i], eta_));
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
150
151
152
        }
      }
    } else {
Guolin Ke's avatar
Guolin Ke committed
153
#pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
154
      for (data_size_t i = 0; i < num_data_; ++i) {
155
        const double diff = score[i] - label_[i];
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
156

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
157
        if (std::abs(diff) <= delta_) {
158
          gradients[i] = static_cast<score_t>(diff * weights_[i]);
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
159
160
          hessians[i] = weights_[i];
        } else {
Guolin Ke's avatar
Guolin Ke committed
161
          if (diff >= 0.0f) {
162
            gradients[i] = static_cast<score_t>(delta_ * weights_[i]);
Guolin Ke's avatar
Guolin Ke committed
163
          } else {
164
            gradients[i] = static_cast<score_t>(-delta_ * weights_[i]);
Guolin Ke's avatar
Guolin Ke committed
165
          }
166
          hessians[i] = static_cast<score_t>(Common::ApproximateHessianWithGaussian(score[i], label_[i], gradients[i], eta_, weights_[i]));
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
        }
      }
    }
  }

  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 */
184
  double delta_;
185
  /*! \brief a parameter to control the width of Gaussian function to approximate hessian */
186
  double eta_;
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
187
188
};

Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
189
190
191
192
193

// 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) {
194
    c_ = static_cast<double>(config.fair_c);
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
195
196
197
198
199
200
201
202
203
204
  }

  ~RegressionFairLoss() {}

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

205
  void GetGradients(const double* score, score_t* gradients,
Guolin Ke's avatar
Guolin Ke committed
206
    score_t* hessians) const override {
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
207
    if (weights_ == nullptr) {
Guolin Ke's avatar
Guolin Ke committed
208
#pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
209
      for (data_size_t i = 0; i < num_data_; ++i) {
210
211
212
        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
213
214
      }
    } else {
Guolin Ke's avatar
Guolin Ke committed
215
#pragma omp parallel for schedule(static)
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
216
      for (data_size_t i = 0; i < num_data_; ++i) {
217
218
219
        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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
      }
    }
  }

  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 */
236
  double c_;
Tsukasa OMOTO's avatar
Tsukasa OMOTO committed
237
238
};

239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

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

  ~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,
    score_t* hessians) const override {
    if (weights_ == nullptr) {
#pragma omp parallel for schedule(static)
      for (data_size_t i = 0; i < num_data_; ++i) {
        gradients[i] = score[i] - label_[i];
        hessians[i] = score[i] + max_delta_step_;
      }
    } else {
#pragma omp parallel for schedule(static)
      for (data_size_t i = 0; i < num_data_; ++i) {
        gradients[i] = (score[i] - label_[i]) * weights_[i];
        hessians[i] = (score[i] + max_delta_step_) * weights_[i];
      }
    }
  }

  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
289
}  // namespace LightGBM
Guolin Ke's avatar
Guolin Ke committed
290
#endif   // LightGBM_OBJECTIVE_REGRESSION_OBJECTIVE_HPP_