22 sigmoid_ =
static_cast<double>(config.sigmoid);
23 label_gain_ = config.label_gain;
25 DCGCalculator::DefaultLabelGain(&label_gain_);
28 optimize_pos_at_ = config.max_position;
29 sigmoid_table_.clear();
30 inverse_max_dcgs_.clear();
31 if (sigmoid_ <= 0.0) {
32 Log::Fatal(
"Sigmoid param %f should be greater than zero", sigmoid_);
44 label_ = metadata.
label();
50 if (query_boundaries_ ==
nullptr) {
51 Log::Fatal(
"Lambdarank tasks require query information");
55 inverse_max_dcgs_.resize(num_queries_);
56#pragma omp parallel for schedule(static)
59 label_ + query_boundaries_[i],
60 query_boundaries_[i + 1] - query_boundaries_[i]);
62 if (inverse_max_dcgs_[i] > 0.0) {
63 inverse_max_dcgs_[i] = 1.0f / inverse_max_dcgs_[i];
67 ConstructSigmoidTable();
71 score_t* hessians)
const override {
72 #pragma omp parallel for schedule(guided)
74 GetGradientsForOneQuery(score, gradients, hessians, i);
78 inline void GetGradientsForOneQuery(
const double* score,
81 const data_size_t start = query_boundaries_[query_id];
83 query_boundaries_[query_id + 1] - query_boundaries_[query_id];
85 const double inverse_max_dcg = inverse_max_dcgs_[query_id];
87 const label_t* label = label_ + start;
97 std::vector<data_size_t> sorted_idx;
99 sorted_idx.emplace_back(i);
101 std::stable_sort(sorted_idx.begin(), sorted_idx.end(),
104 const double best_score = score[sorted_idx[0]];
106 if (worst_idx > 0 && score[sorted_idx[worst_idx]] == kMinScore) {
109 const double wrost_score = score[sorted_idx[worst_idx]];
113 const int high_label =
static_cast<int>(label[high]);
114 const double high_score = score[high];
115 if (high_score == kMinScore) {
continue; }
116 const double high_label_gain = label_gain_[high_label];
118 double high_sum_lambda = 0.0;
119 double high_sum_hessian = 0.0;
122 if (i == j) {
continue; }
125 const int low_label =
static_cast<int>(label[low]);
126 const double low_score = score[low];
128 if (high_label <= low_label || low_score == kMinScore) {
continue; }
130 const double delta_score = high_score - low_score;
132 const double low_label_gain = label_gain_[low_label];
135 const double dcg_gap = high_label_gain - low_label_gain;
137 const double paired_discount = fabs(high_discount - low_discount);
139 double delta_pair_NDCG = dcg_gap * paired_discount * inverse_max_dcg;
141 if (high_label != low_label && best_score != wrost_score) {
142 delta_pair_NDCG /= (0.01f + fabs(delta_score));
145 double p_lambda = GetSigmoid(delta_score);
146 double p_hessian = p_lambda * (2.0f - p_lambda);
148 p_lambda *= -delta_pair_NDCG;
149 p_hessian *= 2 * delta_pair_NDCG;
150 high_sum_lambda += p_lambda;
151 high_sum_hessian += p_hessian;
152 lambdas[low] -=
static_cast<score_t>(p_lambda);
153 hessians[low] +=
static_cast<score_t>(p_hessian);
156 lambdas[high] +=
static_cast<score_t>(high_sum_lambda);
157 hessians[high] +=
static_cast<score_t>(high_sum_hessian);
160 if (weights_ !=
nullptr) {
162 lambdas[i] =
static_cast<score_t>(lambdas[i] * weights_[start + i]);
163 hessians[i] =
static_cast<score_t>(hessians[i] * weights_[start + i]);
169 inline double GetSigmoid(
double score)
const {
170 if (score <= min_sigmoid_input_) {
172 return sigmoid_table_[0];
173 }
else if (score >= max_sigmoid_input_) {
175 return sigmoid_table_[_sigmoid_bins - 1];
177 return sigmoid_table_[
static_cast<size_t>((score - min_sigmoid_input_) * sigmoid_table_idx_factor_)];
181 void ConstructSigmoidTable() {
183 min_sigmoid_input_ = min_sigmoid_input_ / sigmoid_ / 2;
184 max_sigmoid_input_ = -min_sigmoid_input_;
185 sigmoid_table_.resize(_sigmoid_bins);
187 sigmoid_table_idx_factor_ =
188 _sigmoid_bins / (max_sigmoid_input_ - min_sigmoid_input_);
190 for (
size_t i = 0; i < _sigmoid_bins; ++i) {
191 const double score = i / sigmoid_table_idx_factor_ + min_sigmoid_input_;
192 sigmoid_table_[i] = 2.0f / (1.0f + std::exp(2.0f * score * sigmoid_));
196 const char* GetName()
const override {
200 std::string ToString()
const override {
201 std::stringstream str_buf;
202 str_buf << GetName();
203 return str_buf.str();
210 std::vector<double> label_gain_;
212 std::vector<double> inverse_max_dcgs_;
216 int optimize_pos_at_;
228 std::vector<double> sigmoid_table_;
230 size_t _sigmoid_bins = 1024 * 1024;
232 double min_sigmoid_input_ = -50;
234 double max_sigmoid_input_ = 50;
236 double sigmoid_table_idx_factor_;