"git@developer.sourcefind.cn:tianlh/lightgbm-dcu.git" did not exist on "432c8214698102d361ac03e82e436491dcf88b41"
binary_objective.hpp 4.34 KB
Newer Older
Guolin Ke's avatar
Guolin Ke committed
1
2
3
4
5
6
7
8
9
10
#ifndef LIGHTGBM_OBJECTIVE_BINARY_OBJECTIVE_HPP_
#define LIGHTGBM_OBJECTIVE_BINARY_OBJECTIVE_HPP_

#include <LightGBM/objective_function.h>

#include <cstring>
#include <cmath>

namespace LightGBM {
/*!
11
* \brief Objective function for binary classification
Guolin Ke's avatar
Guolin Ke committed
12
13
14
*/
class BinaryLogloss: public ObjectiveFunction {
public:
Guolin Ke's avatar
Guolin Ke committed
15
  explicit BinaryLogloss(const ObjectiveConfig& config, std::function<bool(float)> is_pos = nullptr) {
Guolin Ke's avatar
Guolin Ke committed
16
    is_unbalance_ = config.is_unbalance;
17
    sigmoid_ = static_cast<double>(config.sigmoid);
Guolin Ke's avatar
Guolin Ke committed
18
    if (sigmoid_ <= 0.0) {
19
      Log::Fatal("Sigmoid parameter %f should be greater than zero", sigmoid_);
Guolin Ke's avatar
Guolin Ke committed
20
    }
21
    scale_pos_weight_ = static_cast<double>(config.scale_pos_weight);
Guolin Ke's avatar
Guolin Ke committed
22
23
24
25
    is_pos_ = is_pos;
    if (is_pos_ == nullptr) {
      is_pos_ = [](float label) {return label > 0; };
    }
Guolin Ke's avatar
Guolin Ke committed
26
  }
Guolin Ke's avatar
Guolin Ke committed
27

Guolin Ke's avatar
Guolin Ke committed
28
  ~BinaryLogloss() {}
Guolin Ke's avatar
Guolin Ke committed
29

Guolin Ke's avatar
Guolin Ke committed
30
31
32
33
34
35
36
  void Init(const Metadata& metadata, data_size_t num_data) override {
    num_data_ = num_data;
    label_ = metadata.label();
    weights_ = metadata.weights();
    data_size_t cnt_positive = 0;
    data_size_t cnt_negative = 0;
    // count for positive and negative samples
37
    #pragma omp parallel for schedule(static) reduction(+:cnt_positive, cnt_negative)
Guolin Ke's avatar
Guolin Ke committed
38
    for (data_size_t i = 0; i < num_data_; ++i) {
Guolin Ke's avatar
Guolin Ke committed
39
      if (is_pos_(label_[i])) {
Guolin Ke's avatar
Guolin Ke committed
40
41
42
43
44
        ++cnt_positive;
      } else {
        ++cnt_negative;
      }
    }
45
46
47
48
49
    if (cnt_negative == 0 || cnt_positive == 0) {
      Log::Warning("Only contain one class.");
      // not need to boost.
      num_data_ = 0;
    }
ProtD's avatar
ProtD committed
50
    Log::Info("Number of positive: %d, number of negative: %d", cnt_positive, cnt_negative);
Guolin Ke's avatar
Guolin Ke committed
51
52
53
54
55
56
57
    // use -1 for negative class, and 1 for positive class
    label_val_[0] = -1;
    label_val_[1] = 1;
    // weight for label
    label_weights_[0] = 1.0f;
    label_weights_[1] = 1.0f;
    // if using unbalance, change the labels weight
58
    if (is_unbalance_ && cnt_positive > 0 && cnt_negative > 0) {
59
60
      if (cnt_positive > cnt_negative) {
        label_weights_[1] = 1.0f;
61
        label_weights_[0] = static_cast<double>(cnt_positive) / cnt_negative;
62
      } else {
63
        label_weights_[1] = static_cast<double>(cnt_negative) / cnt_positive;
64
65
        label_weights_[0] = 1.0f;
      }
Guolin Ke's avatar
Guolin Ke committed
66
    }
Guolin Ke's avatar
Guolin Ke committed
67
    label_weights_[1] *= scale_pos_weight_;
Guolin Ke's avatar
Guolin Ke committed
68
69
  }

70
  void GetGradients(const double* score, score_t* gradients, score_t* hessians) const override {
Guolin Ke's avatar
Guolin Ke committed
71
72
73
74
    if (weights_ == nullptr) {
      #pragma omp parallel for schedule(static)
      for (data_size_t i = 0; i < num_data_; ++i) {
        // get label and label weights
Guolin Ke's avatar
Guolin Ke committed
75
        const int is_pos = is_pos_(label_[i]);
Guolin Ke's avatar
Guolin Ke committed
76
77
        const int label = label_val_[is_pos];
        const double label_weight = label_weights_[is_pos];
Guolin Ke's avatar
Guolin Ke committed
78
        // calculate gradients and hessians
79
        const double response = -label * sigmoid_ / (1.0f + std::exp(label * sigmoid_ * score[i]));
80
81
        const double abs_response = fabs(response);
        gradients[i] = static_cast<score_t>(response * label_weight);
82
        hessians[i] = static_cast<score_t>(abs_response * (sigmoid_ - abs_response) * label_weight);
Guolin Ke's avatar
Guolin Ke committed
83
84
85
86
87
      }
    } else {
      #pragma omp parallel for schedule(static)
      for (data_size_t i = 0; i < num_data_; ++i) {
        // get label and label weights
Guolin Ke's avatar
Guolin Ke committed
88
        const int is_pos = is_pos_(label_[i]);
Guolin Ke's avatar
Guolin Ke committed
89
90
        const int label = label_val_[is_pos];
        const double label_weight = label_weights_[is_pos];
Guolin Ke's avatar
Guolin Ke committed
91
        // calculate gradients and hessians
92
        const double response = -label * sigmoid_ / (1.0f + std::exp(label * sigmoid_ * score[i]));
93
94
        const double abs_response = fabs(response);
        gradients[i] = static_cast<score_t>(response * label_weight  * weights_[i]);
95
        hessians[i] = static_cast<score_t>(abs_response * (sigmoid_ - abs_response) * label_weight * weights_[i]);
Guolin Ke's avatar
Guolin Ke committed
96
97
98
99
      }
    }
  }

Guolin Ke's avatar
Guolin Ke committed
100
101
  const char* GetName() const override {
    return "binary";
Guolin Ke's avatar
Guolin Ke committed
102
103
104
105
106
107
108
109
110
111
  }

private:
  /*! \brief Number of data */
  data_size_t num_data_;
  /*! \brief Pointer of label */
  const float* label_;
  /*! \brief True if using unbalance training */
  bool is_unbalance_;
  /*! \brief Sigmoid parameter */
112
  double sigmoid_;
Guolin Ke's avatar
Guolin Ke committed
113
114
115
  /*! \brief Values for positive and negative labels */
  int label_val_[2];
  /*! \brief Weights for positive and negative labels */
116
  double label_weights_[2];
Guolin Ke's avatar
Guolin Ke committed
117
118
  /*! \brief Weights for data */
  const float* weights_;
119
  double scale_pos_weight_;
Guolin Ke's avatar
Guolin Ke committed
120
  std::function<bool(float)> is_pos_;
Guolin Ke's avatar
Guolin Ke committed
121
122
123
};

}  // namespace LightGBM
Guolin Ke's avatar
Guolin Ke committed
124
#endif   // LightGBM_OBJECTIVE_BINARY_OBJECTIVE_HPP_