Support categorical data for dask functional interface and DQM. (#7043)
* Support categorical data for dask functional interface and DQM. * Implement categorical data support for GPU GK-merge. * Add support for dask functional interface. * Add support for DQM. * Get newer cupy.
This commit is contained in:
@@ -134,17 +134,20 @@ struct WriteCompressedEllpackFunctor {
|
||||
const common::CompressedBufferWriter& writer,
|
||||
AdapterBatchT batch,
|
||||
EllpackDeviceAccessor accessor,
|
||||
common::Span<FeatureType const> feature_types,
|
||||
const data::IsValidFunctor& is_valid)
|
||||
: d_buffer(buffer),
|
||||
writer(writer),
|
||||
batch(std::move(batch)),
|
||||
accessor(std::move(accessor)),
|
||||
feature_types(std::move(feature_types)),
|
||||
is_valid(is_valid) {}
|
||||
|
||||
common::CompressedByteT* d_buffer;
|
||||
common::CompressedBufferWriter writer;
|
||||
AdapterBatchT batch;
|
||||
EllpackDeviceAccessor accessor;
|
||||
common::Span<FeatureType const> feature_types;
|
||||
data::IsValidFunctor is_valid;
|
||||
|
||||
using Tuple = thrust::tuple<size_t, size_t, size_t>;
|
||||
@@ -154,7 +157,12 @@ struct WriteCompressedEllpackFunctor {
|
||||
// -1 because the scan is inclusive
|
||||
size_t output_position =
|
||||
accessor.row_stride * e.row_idx + out.get<1>() - 1;
|
||||
auto bin_idx = accessor.SearchBin(e.value, e.column_idx);
|
||||
uint32_t bin_idx = 0;
|
||||
if (common::IsCat(feature_types, e.column_idx)) {
|
||||
bin_idx = accessor.SearchBin<true>(e.value, e.column_idx);
|
||||
} else {
|
||||
bin_idx = accessor.SearchBin<false>(e.value, e.column_idx);
|
||||
}
|
||||
writer.AtomicWriteSymbol(d_buffer, bin_idx, output_position);
|
||||
}
|
||||
return 0;
|
||||
@@ -184,8 +192,9 @@ class TypedDiscard : public thrust::discard_iterator<T> {
|
||||
// Here the data is already correctly ordered and simply needs to be compacted
|
||||
// to remove missing data
|
||||
template <typename AdapterBatchT>
|
||||
void CopyDataToEllpack(const AdapterBatchT& batch, EllpackPageImpl* dst,
|
||||
int device_idx, float missing) {
|
||||
void CopyDataToEllpack(const AdapterBatchT &batch,
|
||||
common::Span<FeatureType const> feature_types,
|
||||
EllpackPageImpl *dst, int device_idx, float missing) {
|
||||
// Some witchcraft happens here
|
||||
// The goal is to copy valid elements out of the input to an ELLPACK matrix
|
||||
// with a given row stride, using no extra working memory Standard stream
|
||||
@@ -220,7 +229,8 @@ void CopyDataToEllpack(const AdapterBatchT& batch, EllpackPageImpl* dst,
|
||||
|
||||
// We redirect the scan output into this functor to do the actual writing
|
||||
WriteCompressedEllpackFunctor<AdapterBatchT> functor(
|
||||
d_compressed_buffer, writer, batch, device_accessor, is_valid);
|
||||
d_compressed_buffer, writer, batch, device_accessor, feature_types,
|
||||
is_valid);
|
||||
TypedDiscard<Tuple> discard;
|
||||
thrust::transform_output_iterator<
|
||||
WriteCompressedEllpackFunctor<AdapterBatchT>, decltype(discard)>
|
||||
@@ -263,22 +273,22 @@ template <typename AdapterBatch>
|
||||
EllpackPageImpl::EllpackPageImpl(AdapterBatch batch, float missing, int device,
|
||||
bool is_dense, int nthread,
|
||||
common::Span<size_t> row_counts_span,
|
||||
common::Span<FeatureType const> feature_types,
|
||||
size_t row_stride, size_t n_rows, size_t n_cols,
|
||||
common::HistogramCuts const& cuts) {
|
||||
dh::safe_cuda(cudaSetDevice(device));
|
||||
|
||||
*this = EllpackPageImpl(device, cuts, is_dense, row_stride, n_rows);
|
||||
CopyDataToEllpack(batch, this, device, missing);
|
||||
CopyDataToEllpack(batch, feature_types, this, device, missing);
|
||||
WriteNullValues(this, device, row_counts_span);
|
||||
}
|
||||
|
||||
#define ELLPACK_BATCH_SPECIALIZE(__BATCH_T) \
|
||||
template EllpackPageImpl::EllpackPageImpl( \
|
||||
__BATCH_T batch, float missing, int device, \
|
||||
bool is_dense, int nthread, \
|
||||
common::Span<size_t> row_counts_span, \
|
||||
size_t row_stride, size_t n_rows, size_t n_cols, \
|
||||
common::HistogramCuts const& cuts);
|
||||
#define ELLPACK_BATCH_SPECIALIZE(__BATCH_T) \
|
||||
template EllpackPageImpl::EllpackPageImpl( \
|
||||
__BATCH_T batch, float missing, int device, bool is_dense, int nthread, \
|
||||
common::Span<size_t> row_counts_span, \
|
||||
common::Span<FeatureType const> feature_types, size_t row_stride, \
|
||||
size_t n_rows, size_t n_cols, common::HistogramCuts const &cuts);
|
||||
|
||||
ELLPACK_BATCH_SPECIALIZE(data::CudfAdapterBatch)
|
||||
ELLPACK_BATCH_SPECIALIZE(data::CupyAdapterBatch)
|
||||
@@ -467,11 +477,17 @@ size_t EllpackPageImpl::MemCostBytes(size_t num_rows, size_t row_stride,
|
||||
return compressed_size_bytes;
|
||||
}
|
||||
|
||||
EllpackDeviceAccessor EllpackPageImpl::GetDeviceAccessor(int device) const {
|
||||
EllpackDeviceAccessor EllpackPageImpl::GetDeviceAccessor(
|
||||
int device, common::Span<FeatureType const> feature_types) const {
|
||||
gidx_buffer.SetDevice(device);
|
||||
return EllpackDeviceAccessor(
|
||||
device, cuts_, is_dense, row_stride, base_rowid, n_rows,
|
||||
common::CompressedIterator<uint32_t>(gidx_buffer.ConstDevicePointer(),
|
||||
NumSymbols()));
|
||||
return {device,
|
||||
cuts_,
|
||||
is_dense,
|
||||
row_stride,
|
||||
base_rowid,
|
||||
n_rows,
|
||||
common::CompressedIterator<uint32_t>(gidx_buffer.ConstDevicePointer(),
|
||||
NumSymbols()),
|
||||
feature_types};
|
||||
}
|
||||
} // namespace xgboost
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "../common/compressed_iterator.h"
|
||||
#include "../common/device_helpers.cuh"
|
||||
#include "../common/hist_util.h"
|
||||
#include "../common/categorical.h"
|
||||
#include <thrust/binary_search.h>
|
||||
|
||||
namespace xgboost {
|
||||
@@ -31,13 +32,17 @@ struct EllpackDeviceAccessor {
|
||||
/*! \brief Histogram cut values. Size equals to (bins per feature * number of features). */
|
||||
common::Span<const bst_float> gidx_fvalue_map;
|
||||
|
||||
common::Span<const FeatureType> feature_types;
|
||||
|
||||
EllpackDeviceAccessor(int device, const common::HistogramCuts& cuts,
|
||||
bool is_dense, size_t row_stride, size_t base_rowid,
|
||||
size_t n_rows,common::CompressedIterator<uint32_t> gidx_iter)
|
||||
size_t n_rows,common::CompressedIterator<uint32_t> gidx_iter,
|
||||
common::Span<FeatureType const> feature_types)
|
||||
: is_dense(is_dense),
|
||||
row_stride(row_stride),
|
||||
base_rowid(base_rowid),
|
||||
n_rows(n_rows) ,gidx_iter(gidx_iter){
|
||||
n_rows(n_rows) ,gidx_iter(gidx_iter),
|
||||
feature_types{feature_types} {
|
||||
cuts.cut_values_.SetDevice(device);
|
||||
cuts.cut_ptrs_.SetDevice(device);
|
||||
cuts.min_vals_.SetDevice(device);
|
||||
@@ -64,12 +69,23 @@ struct EllpackDeviceAccessor {
|
||||
return gidx;
|
||||
}
|
||||
|
||||
template <bool is_cat>
|
||||
__device__ uint32_t SearchBin(float value, size_t column_id) const {
|
||||
auto beg = feature_segments[column_id];
|
||||
auto end = feature_segments[column_id + 1];
|
||||
auto it =
|
||||
thrust::upper_bound(thrust::seq, gidx_fvalue_map.cbegin()+ beg, gidx_fvalue_map.cbegin() + end, value);
|
||||
uint32_t idx = it - gidx_fvalue_map.cbegin();
|
||||
uint32_t idx = 0;
|
||||
if (is_cat) {
|
||||
auto it = dh::MakeTransformIterator<bst_cat_t>(
|
||||
gidx_fvalue_map.cbegin(), [](float v) { return common::AsCat(v); });
|
||||
idx = thrust::lower_bound(thrust::seq, it + beg, it + end,
|
||||
common::AsCat(value)) -
|
||||
it;
|
||||
} else {
|
||||
auto it = thrust::upper_bound(thrust::seq, gidx_fvalue_map.cbegin() + beg,
|
||||
gidx_fvalue_map.cbegin() + end, value);
|
||||
idx = it - gidx_fvalue_map.cbegin();
|
||||
}
|
||||
|
||||
if (idx == end) {
|
||||
idx -= 1;
|
||||
}
|
||||
@@ -134,10 +150,12 @@ class EllpackPageImpl {
|
||||
explicit EllpackPageImpl(DMatrix* dmat, const BatchParam& parm);
|
||||
|
||||
template <typename AdapterBatch>
|
||||
explicit EllpackPageImpl(AdapterBatch batch, float missing, int device, bool is_dense, int nthread,
|
||||
explicit EllpackPageImpl(AdapterBatch batch, float missing, int device,
|
||||
bool is_dense, int nthread,
|
||||
common::Span<size_t> row_counts_span,
|
||||
common::Span<FeatureType const> feature_types,
|
||||
size_t row_stride, size_t n_rows, size_t n_cols,
|
||||
common::HistogramCuts const& cuts);
|
||||
common::HistogramCuts const &cuts);
|
||||
|
||||
/*! \brief Copy the elements of the given ELLPACK page into this page.
|
||||
*
|
||||
@@ -176,7 +194,9 @@ class EllpackPageImpl {
|
||||
* not found). */
|
||||
size_t NumSymbols() const { return cuts_.TotalBins() + 1; }
|
||||
|
||||
EllpackDeviceAccessor GetDeviceAccessor(int device) const;
|
||||
EllpackDeviceAccessor
|
||||
GetDeviceAccessor(int device,
|
||||
common::Span<FeatureType const> feature_types = {}) const;
|
||||
|
||||
private:
|
||||
/*!
|
||||
|
||||
@@ -148,9 +148,13 @@ void IterativeDeviceDMatrix::Initialize(DataIterHandle iter_handle, float missin
|
||||
return GetRowCounts(value, row_counts_span, get_device(), missing);
|
||||
});
|
||||
auto is_dense = this->IsDense();
|
||||
|
||||
proxy->Info().feature_types.SetDevice(get_device());
|
||||
auto d_feature_types = proxy->Info().feature_types.ConstDeviceSpan();
|
||||
auto new_impl = Dispatch(proxy, [&](auto const &value) {
|
||||
return EllpackPageImpl(value, missing, get_device(), is_dense, nthread,
|
||||
row_counts_span, row_stride, rows, cols, cuts);
|
||||
return EllpackPageImpl(value, missing, get_device(), is_dense, nthread,
|
||||
row_counts_span, d_feature_types, row_stride, rows,
|
||||
cols, cuts);
|
||||
});
|
||||
size_t num_elements = page_->Impl()->Copy(get_device(), &new_impl, offset);
|
||||
offset += num_elements;
|
||||
|
||||
Reference in New Issue
Block a user