From d7bb90d0c11f2f6b84d71c7d824f8c28441e3ad6 Mon Sep 17 00:00:00 2001 From: fis Date: Fri, 11 Feb 2022 17:44:11 +0800 Subject: [PATCH] multi target. --- src/objective/regression_obj.cu | 22 ++-- tests/cpp/objective/test_regression_obj.cc | 135 +++++++++++++++------ 2 files changed, 106 insertions(+), 51 deletions(-) diff --git a/src/objective/regression_obj.cu b/src/objective/regression_obj.cu index 7ea6635e3bce..c46637b818a9 100644 --- a/src/objective/regression_obj.cu +++ b/src/objective/regression_obj.cu @@ -34,7 +34,6 @@ namespace { void CheckRegInputs(MetaInfo const& info, HostDeviceVector const& preds) { CHECK_EQ(info.labels.Shape(0), info.num_row_) << "Invalid shape of labels."; CHECK_EQ(info.labels.Size(), preds.Size()) << "Invalid shape of labels."; - CHECK_EQ(info.labels.Shape(1), 1); if (!info.weights_.Empty()) { CHECK_EQ(info.weights_.Size(), info.num_row_) << "Number of weights should be equal to number of data points."; @@ -80,20 +79,13 @@ class RegLossObj : public ObjFunction { void GetGradient(const HostDeviceVector& preds, const MetaInfo &info, int, HostDeviceVector* out_gpair) override { - CHECK_EQ(preds.Size(), info.labels.Size()) - << " " << "labels are not correctly provided" - << "preds.size=" << preds.Size() << ", label.size=" << info.labels.Size() << ", " - << "Loss: " << Loss::Name(); + CheckRegInputs(info, preds); size_t const ndata = preds.Size(); out_gpair->Resize(ndata); auto device = ctx_->gpu_id; additional_input_.HostVector().begin()[0] = 1; // Fill the label_correct flag bool is_null_weight = info.weights_.Size() == 0; - if (!is_null_weight) { - CHECK_EQ(info.weights_.Size(), info.labels.Shape(0)) - << "Number of weights should be equal to number of data points."; - } auto scale_pos_weight = param_.scale_pos_weight; additional_input_.HostVector().begin()[1] = scale_pos_weight; additional_input_.HostVector().begin()[2] = is_null_weight; @@ -233,7 +225,8 @@ class RegularizedClassification : public ObjFunction { if (!LogisticClassification::CheckLabel(y)) { vflag[0] = 1; } - if (!LogisticClassification::CheckLabel(sensitive(i))) { + auto sample_id = std::get<0>(linalg::UnravelIndex(i, labels.Shape())); + if (!LogisticClassification::CheckLabel(sensitive(sample_id))) { vflag[0] = 1; } }); @@ -269,22 +262,25 @@ class RegularizedClassification : public ObjFunction { auto labels = info.labels.View(ctx_->gpu_id); auto sensitive = info.sensitive_features.View(ctx_->gpu_id); + out_gpair->SetDevice(ctx_->gpu_id); - out_gpair->Resize(info.num_row_); + out_gpair->Resize(info.labels.Size()); auto gpair = linalg::MakeVec(out_gpair); preds.SetDevice(ctx_->gpu_id); auto predt = linalg::MakeVec(&preds); + info.weights_.SetDevice(ctx_->gpu_id); common::OptionalWeights weight{ctx_->IsCPU() ? info.weights_.ConstHostSpan() : info.weights_.ConstDeviceSpan()}; linalg::ElementWiseKernel(ctx_, labels, [=] XGBOOST_DEVICE(size_t i, float const y) mutable { + auto sample_id = std::get<0>(linalg::UnravelIndex(i, labels.Shape())); auto p = common::Sigmoid(predt(i)); - auto sf = sensitive(i); + auto sf = sensitive(sample_id); auto grad = (p - y) + (fairness * (sf - p)); auto hess = (1.0f - fairness) * p * (1.0f - p); - auto w = weight[std::get<0>(linalg::UnravelIndex(i, labels.Shape()))]; + auto w = weight[sample_id]; gpair(i) = {grad * w, hess * w}; }); } diff --git a/tests/cpp/objective/test_regression_obj.cc b/tests/cpp/objective/test_regression_obj.cc index 8639d24a394c..de386015fbe5 100644 --- a/tests/cpp/objective/test_regression_obj.cc +++ b/tests/cpp/objective/test_regression_obj.cc @@ -355,12 +355,14 @@ TEST(Objective, DeclareUnifiedTest(TweedieRegressionBasic)) { } TEST(Objective, DeclareUnifiedTest(RegularizedClassification)) { - GenericParameter lparam = CreateEmptyGenericParam(GPUIDX); - Args args{{"fairness", "0.0"}}; - std::unique_ptr obj{ObjFunction::Create("binary:regularized", &lparam)}; + GenericParameter ctx = CreateEmptyGenericParam(GPUIDX); - obj->Configure(args); - CheckConfigReload(obj, "binary:regularized"); + { + Args args{{"fairness", "0.0"}}; + std::unique_ptr obj{ObjFunction::Create("binary:regularized", &ctx)}; + obj->Configure(args); + CheckConfigReload(obj, "binary:regularized"); + } MetaInfo info; info.num_row_ = 16; @@ -369,47 +371,104 @@ TEST(Objective, DeclareUnifiedTest(RegularizedClassification)) { for (size_t i = 0; i < h_sf.size(); ++i) { h_sf[i] = i % 2 == 0; } + HostDeviceVector reg_gpair; - info.labels = linalg::Tensor{{info.num_row_, static_cast(1)}, GPUIDX}; - auto& h_y = info.labels.Data()->HostVector(); - for (size_t i = 0; i < h_y.size(); ++i) { - h_y[i] = i % 2 != 0; - } + // fairness == 0 means unbiased + auto test_unbiased = [&](HostDeviceVector const& predts, + HostDeviceVector* reg_gpair) { + std::unique_ptr obj{ObjFunction::Create("binary:regularized", &ctx)}; + obj->Configure({{"fairness", "0.0"}}); + obj->GetGradient(predts, info, 0, reg_gpair); + auto const& h_reg = reg_gpair->ConstHostVector(); - HostDeviceVector predts; - predts.SetDevice(GPUIDX); - predts.Resize(info.num_row_); - auto& h_predts = predts.HostVector(); - for (size_t i = 0; i < h_y.size(); ++i) { - h_predts[i] = i % 2 != 0; - } + std::unique_ptr logistic{ObjFunction::Create("binary:logistic", &ctx)}; + logistic->Configure({}); - HostDeviceVector reg_gpair; - obj->GetGradient(predts, info, 0, ®_gpair); - auto const& h_reg = reg_gpair.ConstHostVector(); + HostDeviceVector logistic_gpair; + logistic->GetGradient(predts, info, 0, &logistic_gpair); + auto const& h_logistic = logistic_gpair.ConstHostVector(); - // fairness == 0 means unbiased - std::unique_ptr logistic{ObjFunction::Create("binary:logistic", &lparam)}; - logistic->Configure({}); - HostDeviceVector logistic_gpair; - obj->GetGradient(predts, info, 0, &logistic_gpair); - auto const& h_logistic = logistic_gpair.ConstHostVector(); - for (size_t i = 0; i < h_reg.size(); ++i) { - ASSERT_EQ(h_logistic[i], h_reg[i]); - } + for (size_t i = 0; i < h_reg.size(); ++i) { + ASSERT_EQ(h_logistic[i], h_reg[i]); + } + }; - auto test_regularized = [&]() { + auto test_regularized = [&](HostDeviceVector const& predts, + HostDeviceVector* reg_gpair) { + std::unique_ptr obj{ObjFunction::Create("binary:regularized", &ctx)}; obj->Configure({{"fairness", "1.0"}}); - obj->GetGradient(predts, info, 0, ®_gpair); - auto const& h_reg = reg_gpair.ConstHostVector(); - for (size_t i = 0; i < h_reg.size(); ++i) { - ASSERT_EQ(h_reg[i].GetHess(), 0.0f); - ASSERT_EQ(h_reg[i].GetGrad(), i % 2 == 0 ? 1.0 : -1.0); + obj->GetGradient(predts, info, 0, reg_gpair); + auto const& h_reg = reg_gpair->ConstHostVector(); + auto h_y = info.labels.HostView(); + size_t strides[] = {h_y.Stride(0), h_y.Stride(1)}; + + for (size_t i = 0; i < info.labels.Shape(1); ++i) { + for (size_t j = 0; j < info.labels.Shape(0); ++j) { + auto offset = linalg::detail::Offset<0ul>(strides, 0ul, j, i); + + ASSERT_EQ(h_reg[offset].GetHess(), 0.0f); + ASSERT_EQ(h_reg[offset].GetGrad(), j % 2 == 0 ? 1.0 : -1.0); + } } }; - test_regularized(); - info.weights_.Resize(info.num_row_, 1.0); - test_regularized(); + + { + info.labels = linalg::Tensor{{info.num_row_, static_cast(1)}, GPUIDX}; + auto& h_y = info.labels.Data()->HostVector(); + for (size_t i = 0; i < h_y.size(); ++i) { + h_y[i] = i % 2 != 0; + } + + HostDeviceVector predts; + predts.SetDevice(GPUIDX); + predts.Resize(info.num_row_); + auto& h_predts = predts.HostVector(); + for (size_t i = 0; i < h_y.size(); ++i) { + h_predts[i] = i % 2 != 0; + } + + info.weights_.Resize(0); + test_unbiased(predts, ®_gpair); + info.weights_.Resize(info.num_row_, 1.0); + test_unbiased(predts, ®_gpair); + + info.weights_.Resize(0); + test_regularized(predts, ®_gpair); + info.weights_.Resize(info.num_row_, 1.0); + test_regularized(predts, ®_gpair); + } + + { + /** + * multi-target, change the shape of labels and predictions. + */ + size_t n_targets = 4; + info.labels.Reshape(info.num_row_, n_targets); + auto h_y = info.labels.HostView(); + + HostDeviceVector predts; + predts.SetDevice(GPUIDX); + predts.Resize(info.labels.Size()); + auto& h_predts = predts.HostVector(); + for (size_t i = 0; i < n_targets; ++i) { + for (size_t j = 0; j < info.num_row_; ++j) { + h_y(j, i) = j % 2 != 0; + size_t strides[] = {h_y.Stride(0), h_y.Stride(1)}; + auto offset = linalg::detail::Offset<0ul>(strides, 0ul, j, i); + h_predts[offset] = j % 2 != 0; + } + } + + info.weights_.Resize(0); + test_unbiased(predts, ®_gpair); + info.weights_.Resize(info.num_row_, 1.0); + test_unbiased(predts, ®_gpair); + + info.weights_.Resize(0); + test_regularized(predts, ®_gpair); + info.weights_.Resize(info.num_row_, 1.0); + test_regularized(predts, ®_gpair); + } } // CoxRegression not implemented in GPU code, no need for testing.