Skip to content

Commit

Permalink
multi target.
Browse files Browse the repository at this point in the history
  • Loading branch information
trivialfis committed Feb 12, 2022
1 parent 07bd80b commit d7bb90d
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 51 deletions.
22 changes: 9 additions & 13 deletions src/objective/regression_obj.cu
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ namespace {
void CheckRegInputs(MetaInfo const& info, HostDeviceVector<bst_float> 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.";
Expand Down Expand Up @@ -80,20 +79,13 @@ class RegLossObj : public ObjFunction {
void GetGradient(const HostDeviceVector<bst_float>& preds,
const MetaInfo &info, int,
HostDeviceVector<GradientPair>* 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;
Expand Down Expand Up @@ -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;
}
});
Expand Down Expand Up @@ -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};
});
}
Expand Down
135 changes: 97 additions & 38 deletions tests/cpp/objective/test_regression_obj.cc
Original file line number Diff line number Diff line change
Expand Up @@ -355,12 +355,14 @@ TEST(Objective, DeclareUnifiedTest(TweedieRegressionBasic)) {
}

TEST(Objective, DeclareUnifiedTest(RegularizedClassification)) {
GenericParameter lparam = CreateEmptyGenericParam(GPUIDX);
Args args{{"fairness", "0.0"}};
std::unique_ptr<ObjFunction> 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<ObjFunction> obj{ObjFunction::Create("binary:regularized", &ctx)};
obj->Configure(args);
CheckConfigReload(obj, "binary:regularized");
}

MetaInfo info;
info.num_row_ = 16;
Expand All @@ -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<GradientPair> reg_gpair;

info.labels = linalg::Tensor<float, 2>{{info.num_row_, static_cast<uint64_t>(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<float> const& predts,
HostDeviceVector<GradientPair>* reg_gpair) {
std::unique_ptr<ObjFunction> 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<float> 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<ObjFunction> logistic{ObjFunction::Create("binary:logistic", &ctx)};
logistic->Configure({});

HostDeviceVector<GradientPair> reg_gpair;
obj->GetGradient(predts, info, 0, &reg_gpair);
auto const& h_reg = reg_gpair.ConstHostVector();
HostDeviceVector<GradientPair> logistic_gpair;
logistic->GetGradient(predts, info, 0, &logistic_gpair);
auto const& h_logistic = logistic_gpair.ConstHostVector();

// fairness == 0 means unbiased
std::unique_ptr<ObjFunction> logistic{ObjFunction::Create("binary:logistic", &lparam)};
logistic->Configure({});
HostDeviceVector<GradientPair> 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<float> const& predts,
HostDeviceVector<GradientPair>* reg_gpair) {
std::unique_ptr<ObjFunction> obj{ObjFunction::Create("binary:regularized", &ctx)};
obj->Configure({{"fairness", "1.0"}});
obj->GetGradient(predts, info, 0, &reg_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<float, 2>{{info.num_row_, static_cast<uint64_t>(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<float> 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, &reg_gpair);
info.weights_.Resize(info.num_row_, 1.0);
test_unbiased(predts, &reg_gpair);

info.weights_.Resize(0);
test_regularized(predts, &reg_gpair);
info.weights_.Resize(info.num_row_, 1.0);
test_regularized(predts, &reg_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<float> 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, &reg_gpair);
info.weights_.Resize(info.num_row_, 1.0);
test_unbiased(predts, &reg_gpair);

info.weights_.Resize(0);
test_regularized(predts, &reg_gpair);
info.weights_.Resize(info.num_row_, 1.0);
test_regularized(predts, &reg_gpair);
}
}

// CoxRegression not implemented in GPU code, no need for testing.
Expand Down

0 comments on commit d7bb90d

Please sign in to comment.