7#ifndef XGBOOST_COMMON_HIST_UTIL_H_
8#define XGBOOST_COMMON_HIST_UTIL_H_
21#include "threading_utils.h"
26class GHistIndexMatrix;
38 bool has_categorical_{
false};
39 float max_cat_{-1.0f};
47 std::swap(has_categorical_, that.has_categorical_);
52 cut_values_.Resize(that.cut_values_.Size());
53 cut_ptrs_.Resize(that.cut_ptrs_.Size());
54 min_vals_.Resize(that.min_vals_.Size());
55 cut_values_.Copy(that.cut_values_);
56 cut_ptrs_.Copy(that.cut_ptrs_);
57 min_vals_.Copy(that.min_vals_);
58 has_categorical_ = that.has_categorical_;
59 max_cat_ = that.max_cat_;
72 this->Swap(std::forward<HistogramCuts>(that));
81 this->Swap(std::forward<HistogramCuts>(that));
86 return cut_ptrs_.ConstHostVector().at(feature + 1) - cut_ptrs_.ConstHostVector()[feature];
89 std::vector<uint32_t>
const& Ptrs()
const {
return cut_ptrs_.ConstHostVector(); }
90 std::vector<float>
const& Values()
const {
return cut_values_.ConstHostVector(); }
91 std::vector<float>
const& MinValues()
const {
return min_vals_.ConstHostVector(); }
93 [[nodiscard]]
bool HasCategorical()
const {
return has_categorical_; }
94 [[nodiscard]]
float MaxCategory()
const {
return max_cat_; }
102 has_categorical_ = has_cat;
106 [[nodiscard]]
bst_bin_t TotalBins()
const {
return cut_ptrs_.ConstHostVector().back(); }
111 std::vector<uint32_t>
const& ptrs,
112 std::vector<float>
const& values)
const {
113 auto end = ptrs[column_id + 1];
114 auto beg = ptrs[column_id];
115 auto it = std::upper_bound(values.cbegin() + beg, values.cbegin() + end, value);
116 auto idx = it - values.cbegin();
117 idx -= !!(idx == end);
122 return this->SearchBin(value, column_id, Ptrs(), Values());
133 std::vector<uint32_t>
const& ptrs,
134 std::vector<float>
const& vals)
const {
135 auto end = ptrs.at(fidx + 1) + vals.cbegin();
136 auto beg = ptrs[fidx] + vals.cbegin();
138 auto v =
static_cast<float>(common::AsCat(value));
139 auto bin_idx = std::lower_bound(beg, end, v) - vals.cbegin();
140 if (bin_idx == ptrs.at(fidx + 1)) {
146 auto const& ptrs = this->Ptrs();
147 auto const& vals = this->Values();
158 std::vector<float>
const& vals, std::vector<float>
const& mins,
160 auto lower =
static_cast<bst_bin_t>(ptrs[fidx]);
161 if (bin_idx == lower) {
164 return vals[bin_idx - 1];
175 bool use_sorted =
false, Span<float const> hessian = {});
177enum BinTypeSize : uint8_t {
178 kUint8BinsTypeSize = 1,
179 kUint16BinsTypeSize = 2,
180 kUint32BinsTypeSize = 4
186template <
typename Fn>
189 case kUint8BinsTypeSize: {
190 return fn(uint8_t{});
192 case kUint16BinsTypeSize: {
193 return fn(uint16_t{});
195 case kUint32BinsTypeSize: {
196 return fn(uint32_t{});
199 LOG(FATAL) <<
"Unreachable";
200 return fn(uint32_t{});
212 void SetBinTypeSize(BinTypeSize binTypeSize) {
213 binTypeSize_ = binTypeSize;
214 switch (binTypeSize) {
215 case kUint8BinsTypeSize:
216 func_ = &GetValueFromUint8;
218 case kUint16BinsTypeSize:
219 func_ = &GetValueFromUint16;
221 case kUint32BinsTypeSize:
222 func_ = &GetValueFromUint32;
225 CHECK(binTypeSize == kUint8BinsTypeSize || binTypeSize == kUint16BinsTypeSize ||
226 binTypeSize == kUint32BinsTypeSize);
237 template <
typename T>
239 uint32_t
const* offsets;
241 template <
typename Bin,
typename Feat>
242 auto operator()(Bin bin_idx, Feat fidx)
const {
243 return static_cast<T
>(bin_idx - offsets[fidx]);
247 template <
typename T>
249 uint32_t
const* offsets = this->Offset();
253 Index() { SetBinTypeSize(binTypeSize_); }
255 Index(Index
const& i) =
delete;
256 Index& operator=(Index
const& i) =
delete;
257 Index(Index&& i) =
delete;
269 this->SetBinTypeSize(bin_size);
272 uint32_t operator[](
size_t i)
const {
273 if (!bin_offset_.empty()) {
275 auto fidx = i % bin_offset_.size();
277 return func_(data_.data(), i) + bin_offset_[fidx];
279 return func_(data_.data(), i);
282 [[nodiscard]] BinTypeSize GetBinTypeSize()
const {
return binTypeSize_; }
283 template <
typename T>
284 T
const* data()
const {
285 return reinterpret_cast<T const*
>(data_.data());
287 template <
typename T>
289 return reinterpret_cast<T*
>(data_.data());
291 [[nodiscard]] std::uint32_t
const* Offset()
const {
return bin_offset_.data(); }
292 [[nodiscard]] std::size_t OffsetSize()
const {
return bin_offset_.size(); }
293 [[nodiscard]] std::size_t Size()
const {
return data_.size() / (binTypeSize_); }
296 void SetBinOffset(std::vector<uint32_t>
const& cut_ptrs) {
297 bin_offset_.resize(cut_ptrs.size() - 1);
298 std::copy_n(cut_ptrs.begin(), bin_offset_.size(), bin_offset_.begin());
304 return data_.data() + data_.size();
311 return data_.data() + data_.size();
316 static uint32_t GetValueFromUint8(uint8_t
const* t,
size_t i) {
return t[i]; }
317 static uint32_t GetValueFromUint16(uint8_t
const* t,
size_t i) {
318 return reinterpret_cast<uint16_t const*
>(t)[i];
320 static uint32_t GetValueFromUint32(uint8_t
const* t,
size_t i) {
321 return reinterpret_cast<uint32_t const*
>(t)[i];
324 using Func = uint32_t (*)(uint8_t
const*, size_t);
326 Span<std::uint8_t> data_;
329 std::vector<uint32_t> bin_offset_;
331 BinTypeSize binTypeSize_{kUint8BinsTypeSize};
335template <
typename GradientIndex>
336bst_bin_t XGBOOST_HOST_DEV_INLINE BinarySearchBin(std::size_t begin, std::size_t end,
337 GradientIndex
const& data,
340 size_t previous_middle = std::numeric_limits<size_t>::max();
341 while (end != begin) {
342 size_t middle = begin + (end - begin) / 2;
343 if (middle == previous_middle) {
346 previous_middle = middle;
349 auto gidx = data[middle];
351 if (gidx >= fidx_begin && gidx < fidx_end) {
353 return static_cast<int32_t
>(gidx);
354 }
else if (gidx < fidx_begin) {
364using GHistRow = Span<xgboost::GradientPairPrecise>;
365using ConstGHistRow = Span<xgboost::GradientPairPrecise const>;
370void IncrementHist(GHistRow dst, ConstGHistRow add, std::size_t begin, std::size_t end);
375void CopyHist(GHistRow dst,
const GHistRow src,
size_t begin,
size_t end);
380void SubtractionHist(GHistRow dst,
const GHistRow src1,
const GHistRow src2,
size_t begin,
390 constexpr uint32_t kMax = std::numeric_limits<uint32_t>::max();
391 const size_t id = row_ptr_.at(nid);
394 return {ptr, nbins_};
398 [[nodiscard]]
bool RowExists(
bst_uint nid)
const {
399 const uint32_t k_max = std::numeric_limits<uint32_t>::max();
400 return (nid < row_ptr_.size() && row_ptr_[nid] != k_max);
407 void Init(std::uint32_t n_total_bins) {
408 if (nbins_ != n_total_bins) {
409 nbins_ = n_total_bins;
419 constexpr uint32_t kMax = std::numeric_limits<uint32_t>::max();
420 if (nid >= row_ptr_.size()) {
421 row_ptr_.resize(nid + 1, kMax);
423 CHECK_EQ(row_ptr_[nid], kMax);
425 if (data_.size() < (nid + 1)) {
426 data_.resize((nid + 1));
429 row_ptr_[nid] = n_nodes_added_;
434 if (data_[row_ptr_[nid]].size() == 0) {
435 data_[row_ptr_[nid]].resize(nbins_, {0, 0});
443 uint32_t n_nodes_added_ = 0;
444 std::vector<std::vector<GradientPairPrecise>> data_;
447 std::vector<size_t> row_ptr_;
457 void Init(
size_t nbins) {
458 if (nbins != nbins_) {
459 hist_buffer_.
Init(nbins);
466 void Reset(
size_t nthreads,
size_t nodes,
const BlockedSpace2d& space,
467 const std::vector<GHistRow>& targeted_hists) {
468 hist_buffer_.
Init(nbins_);
469 tid_nid_to_hist_.clear();
470 threads_to_nids_map_.clear();
472 targeted_hists_ = targeted_hists;
474 CHECK_EQ(nodes, targeted_hists.size());
477 nthreads_ = nthreads;
479 MatchThreadsToNodes(space);
480 AllocateAdditionalHistograms();
481 MatchNodeNidPairToHist();
483 hist_was_used_.resize(nthreads * nodes_);
484 std::fill(hist_was_used_.begin(), hist_was_used_.end(),
static_cast<int>(
false));
488 GHistRow GetInitializedHist(
size_t tid,
size_t nid) {
489 CHECK_LT(nid, nodes_);
490 CHECK_LT(tid, nthreads_);
492 int idx = tid_nid_to_hist_.at({tid, nid});
494 hist_buffer_.AllocateData(idx);
496 GHistRow hist = idx == -1 ? targeted_hists_[nid] : hist_buffer_[idx];
498 if (!hist_was_used_[tid * nodes_ + nid]) {
500 hist_was_used_[tid * nodes_ + nid] =
static_cast<int>(
true);
507 void ReduceHist(
size_t nid,
size_t begin,
size_t end)
const {
508 CHECK_GT(end, begin);
509 CHECK_LT(nid, nodes_);
511 GHistRow dst = targeted_hists_[nid];
513 bool is_updated =
false;
514 for (
size_t tid = 0; tid < nthreads_; ++tid) {
515 if (hist_was_used_[tid * nodes_ + nid]) {
518 int idx = tid_nid_to_hist_.at({tid, nid});
519 GHistRow src = idx == -1 ? targeted_hists_[nid] : hist_buffer_[idx];
521 if (dst.data() != src.data()) {
534 const size_t space_size = space.Size();
535 const size_t chunck_size = space_size / nthreads_ + !!(space_size % nthreads_);
537 threads_to_nids_map_.resize(nthreads_ * nodes_,
false);
539 for (
size_t tid = 0; tid < nthreads_; ++tid) {
540 size_t begin = chunck_size * tid;
541 size_t end = std::min(begin + chunck_size, space_size);
543 if (begin < space_size) {
544 size_t nid_begin = space.GetFirstDimension(begin);
545 size_t nid_end = space.GetFirstDimension(end-1);
547 for (
size_t nid = nid_begin; nid <= nid_end; ++nid) {
549 threads_to_nids_map_[tid * nodes_ + nid] =
true;
555 void AllocateAdditionalHistograms() {
556 size_t hist_allocated_additionally = 0;
558 for (
size_t nid = 0; nid < nodes_; ++nid) {
559 int nthreads_for_nid = 0;
561 for (
size_t tid = 0; tid < nthreads_; ++tid) {
562 if (threads_to_nids_map_[tid * nodes_ + nid]) {
571 hist_allocated_additionally += std::max<int>(0, nthreads_for_nid - 1);
574 for (
size_t i = 0; i < hist_allocated_additionally; ++i) {
575 hist_buffer_.AddHistRow(i);
579 [[nodiscard]]
bst_bin_t TotalBins()
const {
return nbins_; }
582 void MatchNodeNidPairToHist() {
583 size_t hist_allocated_additionally = 0;
585 for (
size_t nid = 0; nid < nodes_; ++nid) {
586 bool first_hist =
true;
587 for (
size_t tid = 0; tid < nthreads_; ++tid) {
588 if (threads_to_nids_map_[tid * nodes_ + nid]) {
590 tid_nid_to_hist_[{tid, nid}] = -1;
593 tid_nid_to_hist_[{tid, nid}] = hist_allocated_additionally++;
603 size_t nthreads_ = 0;
613 std::vector<int> hist_was_used_;
616 std::vector<bool> threads_to_nids_map_;
618 std::vector<GHistRow> targeted_hists_;
623 std::map<std::pair<size_t, size_t>,
int> tid_nid_to_hist_;
627template <
bool any_missing>
Copyright 2020-2023, XGBoost Contributors.
Internal data structured used by XGBoost during training.
Definition data.h:509
preprocessed global index matrix, in CSR format.
Definition gradient_index.h:38
Definition host_device_vector.h:87
Definition threading_utils.h:74
histogram of gradient statistics for multiple nodes
Definition hist_util.h:386
void Init(std::uint32_t n_total_bins)
Initialize histogram collection.
Definition hist_util.h:407
Definition hist_util.h:37
void SetCategorical(bool has_cat, float max_cat)
Set meta info about categorical features.
Definition hist_util.h:101
static float NumericBinValue(std::vector< std::uint32_t > const &ptrs, std::vector< float > const &vals, std::vector< float > const &mins, bst_feature_t fidx, bst_bin_t bin_idx)
Return numerical bin value given bin index.
Definition hist_util.h:157
bst_bin_t SearchBin(Entry const &e) const
Search the bin index for numerical feature.
Definition hist_util.h:127
bst_bin_t SearchCatBin(float value, bst_feature_t fidx, std::vector< uint32_t > const &ptrs, std::vector< float > const &vals) const
Search the bin index for categorical feature.
Definition hist_util.h:132
Optionally compressed gradient index.
Definition hist_util.h:210
Index(Span< std::uint8_t > data, BinTypeSize bin_size)
Construct the index from data.
Definition hist_util.h:268
Index & operator=(Index &&i)=default
Move assignment for lazy initialization.
Stores temporary histograms to compute them in parallel Supports processing multiple tree-nodes for n...
Definition hist_util.h:455
span class implementation, based on ISO++20 span<T>. The interface should be the same.
Definition span.h:424
Copyright 2015-2023 by XGBoost Contributors.
Copyright 2015-2023 by XGBoost Contributors.
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition json.hpp:24418
auto DispatchBinType(BinTypeSize type, Fn &&fn)
Dispatch for bin type, fn is a function that accepts a scalar of the bin type.
Definition hist_util.h:187
HistogramCuts SketchOnDMatrix(Context const *ctx, DMatrix *m, bst_bin_t max_bins, bool use_sorted, Span< float const > hessian)
Run CPU sketching on DMatrix.
Definition hist_util.cc:32
void IncrementHist(GHistRow dst, ConstGHistRow add, std::size_t begin, std::size_t end)
Increment hist as dst += add in range [begin, end)
Definition hist_util.cc:73
void CopyHist(GHistRow dst, const GHistRow src, size_t begin, size_t end)
Copy hist from src to dst in range [begin, end)
Definition hist_util.cc:85
void SubtractionHist(GHistRow dst, const GHistRow src1, const GHistRow src2, size_t begin, size_t end)
Compute Subtraction: dst = src1 - src2 in range [begin, end)
Definition hist_util.cc:97
namespace of xgboost
Definition base.h:90
uint32_t bst_feature_t
Type for data column (feature) index.
Definition base.h:101
uint32_t bst_uint
unsigned integer type used for feature index.
Definition base.h:93
int32_t bst_bin_t
Type for histogram bin index.
Definition base.h:103
Copyright 2014-2023 by XGBoost Contributors.
Copyright 2021-2023 by Contributors.
Runtime context for XGBoost.
Definition context.h:84
Element from a sparse vector.
Definition data.h:216
Definition hist_util.h:238
data structure to store an instance set, a subset of rows (instances) associated with a particular no...
Definition row_set.h:30