regression_objective.hpp 8.4 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

/*!
* \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) {
Guolin Ke's avatar
Guolin Ke committed
262
263
        gradients[i] = static_cast<score_t>(score[i] - label_[i]);
        hessians[i] = static_cast<score_t>(score[i] + max_delta_step_);
264
265
266
267
      }
    } else {
#pragma omp parallel for schedule(static)
      for (data_size_t i = 0; i < num_data_; ++i) {
Guolin Ke's avatar
Guolin Ke committed
268
269
        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]);
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
      }
    }
  }

  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_