Multi-target support for L1 error. (#8652)
- Add matrix support to the median function. - Iterate through each target for quantile computation.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Copyright 2022 by XGBoost Contributors
|
||||
/**
|
||||
* Copyright 2022-2023 by XGBoost Contributors
|
||||
*/
|
||||
#include "adaptive.h"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "../common/stats.h"
|
||||
#include "../common/threading_utils.h"
|
||||
#include "../common/transform_iterator.h" // MakeIndexTransformIter
|
||||
#include "xgboost/linalg.h"
|
||||
#include "xgboost/tree_model.h"
|
||||
|
||||
namespace xgboost {
|
||||
@@ -66,8 +67,8 @@ void EncodeTreeLeafHost(RegTree const& tree, std::vector<bst_node_t> const& posi
|
||||
}
|
||||
|
||||
void UpdateTreeLeafHost(Context const* ctx, std::vector<bst_node_t> const& position,
|
||||
MetaInfo const& info, HostDeviceVector<float> const& predt, float alpha,
|
||||
RegTree* p_tree) {
|
||||
std::int32_t group_idx, MetaInfo const& info,
|
||||
HostDeviceVector<float> const& predt, float alpha, RegTree* p_tree) {
|
||||
auto& tree = *p_tree;
|
||||
|
||||
std::vector<bst_node_t> nidx;
|
||||
@@ -88,6 +89,9 @@ void UpdateTreeLeafHost(Context const* ctx, std::vector<bst_node_t> const& posit
|
||||
auto const& h_node_idx = nidx;
|
||||
auto const& h_node_ptr = nptr;
|
||||
CHECK_LE(h_node_ptr.back(), info.num_row_);
|
||||
auto h_predt = linalg::MakeTensorView(predt.ConstHostSpan(),
|
||||
{info.num_row_, predt.Size() / info.num_row_}, ctx->gpu_id);
|
||||
|
||||
// loop over each leaf
|
||||
common::ParallelFor(quantiles.size(), ctx->Threads(), [&](size_t k) {
|
||||
auto nidx = h_node_idx[k];
|
||||
@@ -95,14 +99,13 @@ void UpdateTreeLeafHost(Context const* ctx, std::vector<bst_node_t> const& posit
|
||||
CHECK_LT(k + 1, h_node_ptr.size());
|
||||
size_t n = h_node_ptr[k + 1] - h_node_ptr[k];
|
||||
auto h_row_set = common::Span<size_t const>{ridx}.subspan(h_node_ptr[k], n);
|
||||
// multi-target not yet supported.
|
||||
auto h_labels = info.labels.HostView().Slice(linalg::All(), 0);
|
||||
auto const& h_predt = predt.ConstHostVector();
|
||||
CHECK_LE(group_idx, info.labels.Shape(1));
|
||||
auto h_labels = info.labels.HostView().Slice(linalg::All(), group_idx);
|
||||
auto h_weights = linalg::MakeVec(&info.weights_);
|
||||
|
||||
auto iter = common::MakeIndexTransformIter([&](size_t i) -> float {
|
||||
auto row_idx = h_row_set[i];
|
||||
return h_labels(row_idx) - h_predt[row_idx];
|
||||
return h_labels(row_idx) - h_predt(row_idx, group_idx);
|
||||
});
|
||||
auto w_it = common::MakeIndexTransformIter([&](size_t i) -> float {
|
||||
auto row_idx = h_row_set[i];
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
/*!
|
||||
* Copyright 2022 by XGBoost Contributors
|
||||
/**
|
||||
* Copyright 2022-2023 by XGBoost Contributors
|
||||
*/
|
||||
#include <thrust/sort.h>
|
||||
|
||||
#include <cstdint> // std::int32_t
|
||||
#include <cub/cub.cuh>
|
||||
|
||||
#include "../common/cuda_context.cuh" // CUDAContext
|
||||
#include "../common/device_helpers.cuh"
|
||||
#include "../common/stats.cuh"
|
||||
#include "adaptive.h"
|
||||
#include "xgboost/context.h"
|
||||
|
||||
namespace xgboost {
|
||||
namespace obj {
|
||||
@@ -55,13 +58,13 @@ void EncodeTreeLeafDevice(Context const* ctx, common::Span<bst_node_t const> pos
|
||||
|
||||
size_t nbytes{0};
|
||||
auto begin_it = sorted_position.begin() + beg_pos;
|
||||
dh::safe_cuda(cub::DeviceRunLengthEncode::Encode(nullptr, nbytes, begin_it,
|
||||
unique_out.data().get(), counts_out.data().get(),
|
||||
d_num_runs_out.data(), n_samples - beg_pos));
|
||||
dh::safe_cuda(cub::DeviceRunLengthEncode::Encode(
|
||||
nullptr, nbytes, begin_it, unique_out.data().get(), counts_out.data().get(),
|
||||
d_num_runs_out.data(), n_samples - beg_pos, ctx->CUDACtx()->Stream()));
|
||||
dh::TemporaryArray<char> temp(nbytes);
|
||||
dh::safe_cuda(cub::DeviceRunLengthEncode::Encode(temp.data().get(), nbytes, begin_it,
|
||||
unique_out.data().get(), counts_out.data().get(),
|
||||
d_num_runs_out.data(), n_samples - beg_pos));
|
||||
dh::safe_cuda(cub::DeviceRunLengthEncode::Encode(
|
||||
temp.data().get(), nbytes, begin_it, unique_out.data().get(), counts_out.data().get(),
|
||||
d_num_runs_out.data(), n_samples - beg_pos, ctx->CUDACtx()->Stream()));
|
||||
|
||||
dh::PinnedMemory pinned_pool;
|
||||
auto pinned = pinned_pool.GetSpan<char>(sizeof(size_t) + sizeof(bst_node_t));
|
||||
@@ -138,8 +141,8 @@ void EncodeTreeLeafDevice(Context const* ctx, common::Span<bst_node_t const> pos
|
||||
}
|
||||
|
||||
void UpdateTreeLeafDevice(Context const* ctx, common::Span<bst_node_t const> position,
|
||||
MetaInfo const& info, HostDeviceVector<float> const& predt, float alpha,
|
||||
RegTree* p_tree) {
|
||||
std::int32_t group_idx, MetaInfo const& info,
|
||||
HostDeviceVector<float> const& predt, float alpha, RegTree* p_tree) {
|
||||
dh::safe_cuda(cudaSetDevice(ctx->gpu_id));
|
||||
dh::device_vector<size_t> ridx;
|
||||
HostDeviceVector<size_t> nptr;
|
||||
@@ -154,19 +157,24 @@ void UpdateTreeLeafDevice(Context const* ctx, common::Span<bst_node_t const> pos
|
||||
|
||||
HostDeviceVector<float> quantiles;
|
||||
predt.SetDevice(ctx->gpu_id);
|
||||
auto d_predt = predt.ConstDeviceSpan();
|
||||
auto d_labels = info.labels.View(ctx->gpu_id);
|
||||
|
||||
auto d_predt = linalg::MakeTensorView(predt.ConstDeviceSpan(),
|
||||
{info.num_row_, predt.Size() / info.num_row_}, ctx->gpu_id);
|
||||
CHECK_LT(group_idx, d_predt.Shape(1));
|
||||
auto t_predt = d_predt.Slice(linalg::All(), group_idx);
|
||||
auto d_labels = info.labels.View(ctx->gpu_id).Slice(linalg::All(), group_idx);
|
||||
|
||||
auto d_row_index = dh::ToSpan(ridx);
|
||||
auto seg_beg = nptr.DevicePointer();
|
||||
auto seg_end = seg_beg + nptr.Size();
|
||||
auto val_beg = dh::MakeTransformIterator<float>(thrust::make_counting_iterator(0ul),
|
||||
[=] XGBOOST_DEVICE(size_t i) {
|
||||
auto predt = d_predt[d_row_index[i]];
|
||||
float p = t_predt(d_row_index[i]);
|
||||
auto y = d_labels(d_row_index[i]);
|
||||
return y - predt;
|
||||
return y - p;
|
||||
});
|
||||
auto val_end = val_beg + d_labels.Size();
|
||||
CHECK_EQ(d_labels.Shape(0), position.size());
|
||||
auto val_end = val_beg + d_labels.Shape(0);
|
||||
CHECK_EQ(nidx.Size() + 1, nptr.Size());
|
||||
if (info.weights_.Empty()) {
|
||||
common::SegmentedQuantile(ctx, alpha, seg_beg, seg_end, val_beg, val_end, &quantiles);
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/*!
|
||||
* Copyright 2022 by XGBoost Contributors
|
||||
/**
|
||||
* Copyright 2022-2023 by XGBoost Contributors
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint> // std::int32_t
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
@@ -32,7 +33,7 @@ inline void FillMissingLeaf(std::vector<bst_node_t> const& maybe_missing,
|
||||
}
|
||||
}
|
||||
|
||||
inline void UpdateLeafValues(std::vector<float>* p_quantiles, std::vector<bst_node_t> const nidx,
|
||||
inline void UpdateLeafValues(std::vector<float>* p_quantiles, std::vector<bst_node_t> const& nidx,
|
||||
RegTree* p_tree) {
|
||||
auto& tree = *p_tree;
|
||||
auto& quantiles = *p_quantiles;
|
||||
@@ -73,12 +74,12 @@ inline void UpdateLeafValues(std::vector<float>* p_quantiles, std::vector<bst_no
|
||||
}
|
||||
|
||||
void UpdateTreeLeafDevice(Context const* ctx, common::Span<bst_node_t const> position,
|
||||
MetaInfo const& info, HostDeviceVector<float> const& predt, float alpha,
|
||||
RegTree* p_tree);
|
||||
std::int32_t group_idx, MetaInfo const& info,
|
||||
HostDeviceVector<float> const& predt, float alpha, RegTree* p_tree);
|
||||
|
||||
void UpdateTreeLeafHost(Context const* ctx, std::vector<bst_node_t> const& position,
|
||||
MetaInfo const& info, HostDeviceVector<float> const& predt, float alpha,
|
||||
RegTree* p_tree);
|
||||
std::int32_t group_idx, MetaInfo const& info,
|
||||
HostDeviceVector<float> const& predt, float alpha, RegTree* p_tree);
|
||||
} // namespace detail
|
||||
} // namespace obj
|
||||
} // namespace xgboost
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
/*!
|
||||
* Copyright 2015-2022 by XGBoost Contributors
|
||||
/**
|
||||
* Copyright 2015-2023 by XGBoost Contributors
|
||||
* \file regression_obj.cu
|
||||
* \brief Definition of single-value regression and classification objectives.
|
||||
* \author Tianqi Chen, Kailong Chen
|
||||
*/
|
||||
#include <dmlc/omp.h>
|
||||
#include <xgboost/logging.h>
|
||||
#include <xgboost/objective.h>
|
||||
#include <xgboost/tree_model.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdint> // std::int32_t
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@@ -25,12 +24,15 @@
|
||||
#include "adaptive.h"
|
||||
#include "xgboost/base.h"
|
||||
#include "xgboost/context.h"
|
||||
#include "xgboost/data.h"
|
||||
#include "xgboost/data.h" // MetaInfo
|
||||
#include "xgboost/host_device_vector.h"
|
||||
#include "xgboost/json.h"
|
||||
#include "xgboost/linalg.h"
|
||||
#include "xgboost/logging.h"
|
||||
#include "xgboost/objective.h" // ObjFunction
|
||||
#include "xgboost/parameter.h"
|
||||
#include "xgboost/span.h"
|
||||
#include "xgboost/tree_model.h" // RegTree
|
||||
|
||||
#if defined(XGBOOST_USE_CUDA)
|
||||
#include "../common/device_helpers.cuh"
|
||||
@@ -703,6 +705,9 @@ class MeanAbsoluteError : public ObjFunction {
|
||||
public:
|
||||
void Configure(Args const&) override {}
|
||||
ObjInfo Task() const override { return {ObjInfo::kRegression, true, true}; }
|
||||
bst_target_t Targets(MetaInfo const& info) const override {
|
||||
return std::max(static_cast<size_t>(1), info.labels.Shape(1));
|
||||
}
|
||||
|
||||
void GetGradient(HostDeviceVector<bst_float> const& preds, const MetaInfo& info, int /*iter*/,
|
||||
HostDeviceVector<GradientPair>* out_gpair) override {
|
||||
@@ -724,7 +729,7 @@ class MeanAbsoluteError : public ObjFunction {
|
||||
return (x > static_cast<decltype(x)>(0)) - (x < static_cast<decltype(x)>(0));
|
||||
};
|
||||
auto sample_id = std::get<0>(linalg::UnravelIndex(i, labels.Shape()));
|
||||
auto grad = sign(predt(i) - y) * weight[i];
|
||||
auto grad = sign(predt(i) - y) * weight[sample_id];
|
||||
auto hess = weight[sample_id];
|
||||
gpair(i) = GradientPair{grad, hess};
|
||||
});
|
||||
@@ -732,8 +737,7 @@ class MeanAbsoluteError : public ObjFunction {
|
||||
|
||||
void InitEstimation(MetaInfo const& info, linalg::Tensor<float, 1>* base_margin) const override {
|
||||
CheckInitInputs(info);
|
||||
base_margin->Reshape(1);
|
||||
auto out = base_margin->HostView();
|
||||
base_margin->Reshape(this->Targets(info));
|
||||
|
||||
double w{0.0};
|
||||
if (info.weights_.Empty()) {
|
||||
@@ -743,11 +747,18 @@ class MeanAbsoluteError : public ObjFunction {
|
||||
}
|
||||
|
||||
if (info.num_row_ == 0) {
|
||||
auto out = base_margin->HostView();
|
||||
out(0) = 0;
|
||||
} else {
|
||||
// weighted avg
|
||||
out(0) = common::Median(ctx_, info.labels, info.weights_) * w;
|
||||
linalg::Vector<float> temp;
|
||||
common::Median(ctx_, info.labels, info.weights_, &temp);
|
||||
common::Mean(ctx_, temp, base_margin);
|
||||
}
|
||||
CHECK_EQ(base_margin->Size(), 1);
|
||||
auto out = base_margin->HostView();
|
||||
// weighted avg
|
||||
std::transform(linalg::cbegin(out), linalg::cend(out), linalg::begin(out),
|
||||
[w](float v) { return v * w; });
|
||||
|
||||
collective::Allreduce<collective::Operation::kSum>(out.Values().data(), out.Values().size());
|
||||
collective::Allreduce<collective::Operation::kSum>(&w, 1);
|
||||
@@ -763,15 +774,16 @@ class MeanAbsoluteError : public ObjFunction {
|
||||
}
|
||||
|
||||
void UpdateTreeLeaf(HostDeviceVector<bst_node_t> const& position, MetaInfo const& info,
|
||||
HostDeviceVector<float> const& prediction, RegTree* p_tree) const override {
|
||||
HostDeviceVector<float> const& prediction, std::int32_t group_idx,
|
||||
RegTree* p_tree) const override {
|
||||
if (ctx_->IsCPU()) {
|
||||
auto const& h_position = position.ConstHostVector();
|
||||
detail::UpdateTreeLeafHost(ctx_, h_position, info, prediction, 0.5, p_tree);
|
||||
detail::UpdateTreeLeafHost(ctx_, h_position, group_idx, info, prediction, 0.5, p_tree);
|
||||
} else {
|
||||
#if defined(XGBOOST_USE_CUDA)
|
||||
position.SetDevice(ctx_->gpu_id);
|
||||
auto d_position = position.ConstDeviceSpan();
|
||||
detail::UpdateTreeLeafDevice(ctx_, d_position, info, prediction, 0.5, p_tree);
|
||||
detail::UpdateTreeLeafDevice(ctx_, d_position, group_idx, info, prediction, 0.5, p_tree);
|
||||
#else
|
||||
common::AssertGPUSupport();
|
||||
#endif // defined(XGBOOST_USE_CUDA)
|
||||
|
||||
Reference in New Issue
Block a user