From 0057de363587dc2e4480731f66b34aa7ecf4f182 Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Thu, 2 Jul 2026 15:50:23 +0200 Subject: [PATCH 01/14] Use standard lower_bound for RF bin lookup --- .../kernels/builder_kernels.cuh | 20 ------ .../kernels/builder_kernels_impl.cuh | 14 ++++- cpp/tests/sg/rf_test.cu | 62 ------------------- 3 files changed, 11 insertions(+), 85 deletions(-) diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh index c0181fbaec..92cfc01527 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh @@ -122,26 +122,6 @@ void launchLeafKernel(ObjectiveT objective, int batch_size, size_t smem_size, cudaStream_t builder_stream); -// Returns the lowest index in `array` whose value is greater or equal to `element`. -// Values outside the quantile range are clamped to the edge bins: values below the -// first quantile return 0, and values above the last quantile return len - 1. -template -HDI IdxT lower_bound(DataT* array, IdxT len, DataT element) -{ - IdxT start = 0; - IdxT end = len - 1; - IdxT mid; - while (start < end) { - mid = (start + end) / 2; - if (array[mid] < element) { - start = mid + 1; - } else { - end = mid; - } - } - return start; -} - template void launchComputeSplitKernel(typename ObjectiveT::BinT* histograms, IdxT n_bins, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh index fb7c70e9c1..abb953457e 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh @@ -14,7 +14,8 @@ #include #include -#include +#include +#include #include #include #include @@ -323,8 +324,15 @@ static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, auto data = dataset.data[row + col_offset]; auto label = dataset.labels[row]; - // `start` is lowest index such that data <= shared_quantiles[start] - IdxT start = lower_bound(shared_quantiles, n_bins, data); + // Search bin indices so lower_bound uses 32-bit distance and advance arithmetic. + auto bin_begin = cuda::counting_iterator(0); + auto bin_end = bin_begin + n_bins; + auto bin_it = + ::cuda::std::lower_bound(bin_begin, bin_end, data, [shared_quantiles](int bin, DataT value) { + return shared_quantiles[bin] < value; + }); + int bin = bin_it == bin_end ? n_bins - 1 : *bin_it; + IdxT start = static_cast(bin); // ++shared_histogram[start] objective.IncrementHistogram(shared_histogram, n_bins, start, label, dataset, row); } diff --git a/cpp/tests/sg/rf_test.cu b/cpp/tests/sg/rf_test.cu index a2a08572d4..1914df0026 100644 --- a/cpp/tests/sg/rf_test.cu +++ b/cpp/tests/sg/rf_test.cu @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -977,57 +976,6 @@ struct QuantileTestParameters { uint64_t seed; }; -template -class RFQuantileBinsLowerBoundTest : public ::testing::TestWithParam { - public: - void SetUp() override - { - auto params = ::testing::TestWithParam::GetParam(); - - thrust::device_vector data(params.n_rows); - thrust::host_vector h_data(params.n_rows); - thrust::host_vector h_quantiles(params.max_n_bins); - raft::random::Rng r(8); - r.normal(data.data().get(), data.size(), T(0.0), T(2.0), nullptr); - auto stream_pool = std::make_shared(1); - raft::handle_t handle(rmm::cuda_stream_per_thread, stream_pool); - - // computing the quantiles - auto quantile_result = - DT::computeQuantiles(handle, data.data().get(), params.max_n_bins, params.n_rows, 1); - auto quantiles = quantile_result.view(); - - raft::update_host( - h_quantiles.data(), quantiles.quantiles_array, params.max_n_bins, handle.get_stream()); - - int n_unique_bins; - raft::copy(&n_unique_bins, quantiles.n_bins_array, 1, handle.get_stream()); - if (n_unique_bins < params.max_n_bins) { - return; // almost impossible that this happens, skip if so - } - - h_data = data; - for (std::size_t i = 0; i < h_data.size(); ++i) { - auto d = h_data[i]; - // golden lower bound from thrust - auto golden_lb = - thrust::lower_bound( - thrust::seq, h_quantiles.data(), h_quantiles.data() + params.max_n_bins, d) - - h_quantiles.data(); - // lower bound from custom lower_bound impl - auto lb = DT::lower_bound(h_quantiles.data(), params.max_n_bins, d); - if (golden_lb == params.max_n_bins) { - ASSERT_EQ(lb, params.max_n_bins - 1) - << "custom lower_bound should clamp values above the last quantile to the last bin" - << std::endl; - continue; - } - ASSERT_EQ(golden_lb, lb) - << "custom lower_bound method is inconsistent with thrust::lower_bound" << std::endl; - } - } -}; - template class RFQuantileTest : public ::testing::TestWithParam { public: @@ -1451,16 +1399,6 @@ typedef RFQuantileTest RFQuantileTestD; TEST_P(RFQuantileTestD, test) {} INSTANTIATE_TEST_CASE_P(RfTests, RFQuantileTestD, ::testing::ValuesIn(inputs)); -// float type quantile bins lower bounds test -typedef RFQuantileBinsLowerBoundTest RFQuantileBinsLowerBoundTestF; -TEST_P(RFQuantileBinsLowerBoundTestF, test) {} -INSTANTIATE_TEST_CASE_P(RfTests, RFQuantileBinsLowerBoundTestF, ::testing::ValuesIn(inputs)); - -// double type quantile bins lower bounds test -typedef RFQuantileBinsLowerBoundTest RFQuantileBinsLowerBoundTestD; -TEST_P(RFQuantileBinsLowerBoundTestD, test) {} -INSTANTIATE_TEST_CASE_P(RfTests, RFQuantileBinsLowerBoundTestD, ::testing::ValuesIn(inputs)); - // float type quantile variable binning test typedef RFQuantileVariableBinsTest RFQuantileVariableBinsTestF; TEST_P(RFQuantileVariableBinsTestF, test) {} From 8658088031410f950e4ae6b7204ab1f2b7a7b364 Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Thu, 2 Jul 2026 16:03:17 +0200 Subject: [PATCH 02/14] Use int for RF internal index types --- .../batched-levelalgo/builder.cuh | 159 +++++++++-------- .../decisiontree/batched-levelalgo/dataset.h | 14 +- .../kernels/builder_kernels.cuh | 85 +++++---- .../kernels/builder_kernels_impl.cuh | 162 +++++++++--------- .../kernels/classification-double.cu | 27 ++- .../kernels/classification-float.cu | 27 ++- .../batched-levelalgo/kernels/node-split.cu | 65 ++++--- .../kernels/regression-double.cu | 27 ++- .../kernels/regression-float.cu | 27 ++- .../kernels/weighted-classification-double.cu | 27 ++- .../kernels/weighted-classification-float.cu | 27 ++- .../kernels/weighted-regression-double.cu | 27 ++- .../kernels/weighted-regression-float.cu | 27 ++- .../batched-levelalgo/objectives.cuh | 68 ++++---- .../batched-levelalgo/quantiles.cuh | 4 +- .../batched-levelalgo/quantiles.h | 6 +- .../decisiontree/batched-levelalgo/split.cuh | 45 +++-- cpp/src/decisiontree/decisiontree.cuh | 107 ++++++------ cpp/tests/sg/rf_test.cu | 123 +++++++------ 19 files changed, 513 insertions(+), 541 deletions(-) diff --git a/cpp/src/decisiontree/batched-levelalgo/builder.cuh b/cpp/src/decisiontree/batched-levelalgo/builder.cuh index 25a151fb92..b436aa412f 100644 --- a/cpp/src/decisiontree/batched-levelalgo/builder.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/builder.cuh @@ -140,12 +140,11 @@ template struct Builder { typedef typename ObjectiveT::DataT DataT; typedef typename ObjectiveT::LabelT LabelT; - typedef typename ObjectiveT::IdxT IdxT; typedef typename ObjectiveT::BinT BinT; - typedef SparseTreeNode NodeT; - typedef Split SplitT; - typedef Dataset DatasetT; - typedef Quantiles QuantilesT; + typedef SparseTreeNode NodeT; + typedef Split SplitT; + typedef Dataset DatasetT; + typedef Quantiles QuantilesT; /** default threads per block for most kernels in here */ static constexpr int TPB_DEFAULT = 128; @@ -160,11 +159,11 @@ struct Builder { /** quantiles */ QuantilesT quantiles; /** Tree index */ - IdxT treeid; + int treeid; /** Seed used for randomization */ uint64_t seed; /** number of nodes created in the current batch */ - IdxT* n_nodes; + int* n_nodes; /** buffer of segmented histograms*/ BinT* histograms; /** threadblock arrival count */ @@ -176,9 +175,9 @@ struct Builder { /** current batch of nodes */ NodeWorkItem* d_work_items; /** device AOS to map CTA blocks along dimx to nodes of a batch */ - WorkloadInfo* workload_info; + WorkloadInfo* workload_info; /** host AOS to map CTA blocks along dimx to nodes of a batch */ - WorkloadInfo* h_workload_info; + WorkloadInfo* h_workload_info; /** maximum CTA blocks along dimx */ int max_blocks_dimx = 0; /** host array of splits */ @@ -187,9 +186,9 @@ struct Builder { int n_blks_for_cols = 10; /** Memory alignment value */ const size_t align_value = 512; - IdxT* column_samples; + int* column_samples; /** temporary row IDs for row-wise out-of-place partitioning */ - IdxT* partition_row_ids; + int* partition_row_ids; /** rmm device workspace buffer */ rmm::device_uvector d_buff; /** pinned host buffer to store the trained nodes */ @@ -197,16 +196,16 @@ struct Builder { Builder(const raft::handle_t& handle, cudaStream_t s, - IdxT treeid, + int treeid, uint64_t seed, const DecisionTreeParams& p, const DataT* data, const LabelT* labels, const double* sample_weight, - IdxT n_rows, - IdxT n_cols, - rmm::device_uvector* row_ids, - IdxT n_classes, + int n_rows, + int n_cols, + rmm::device_uvector* row_ids, + int n_classes, const QuantilesT& q) : handle(handle), builder_stream(s), @@ -219,7 +218,7 @@ struct Builder { n_rows, n_cols, int(row_ids->size()), - max(1, IdxT(params.max_features * n_cols)), + max(1, int(params.max_features * n_cols)), row_ids->data(), n_classes}, quantiles(q), @@ -275,21 +274,21 @@ struct Builder { size_t max_len_histograms = max_batch * params.max_n_bins * n_blks_for_cols * dataset.num_outputs; - d_wsize += calculateAlignedBytes(sizeof(IdxT)); // n_nodes + d_wsize += calculateAlignedBytes(sizeof(int)); // n_nodes d_wsize += calculateAlignedBytes(sizeof(BinT) * max_len_histograms); // histograms d_wsize += calculateAlignedBytes(sizeof(int) * max_batch * n_blks_for_cols); // done_count d_wsize += calculateAlignedBytes(sizeof(int) * max_batch); // mutex d_wsize += calculateAlignedBytes(sizeof(SplitT) * max_batch); // splits d_wsize += calculateAlignedBytes(sizeof(NodeWorkItem) * max_batch); // d_work_Items d_wsize += // workload_info - calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); d_wsize += - calculateAlignedBytes(sizeof(IdxT) * max_batch * dataset.n_sampled_cols); // column_samples - d_wsize += calculateAlignedBytes(sizeof(IdxT) * dataset.n_sampled_rows); // partition row IDs + calculateAlignedBytes(sizeof(int) * max_batch * dataset.n_sampled_cols); // column_samples + d_wsize += calculateAlignedBytes(sizeof(int) * dataset.n_sampled_rows); // partition row IDs // all nodes in the tree h_wsize += // h_workload_info - calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); h_wsize += calculateAlignedBytes(sizeof(SplitT) * max_batch); // splits return std::make_pair(d_wsize, h_wsize); @@ -311,8 +310,8 @@ struct Builder { size_t max_len_histograms = max_batch * (params.max_n_bins) * n_blks_for_cols * dataset.num_outputs; // device - n_nodes = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(IdxT)); + n_nodes = reinterpret_cast(d_wspace); + d_wspace += calculateAlignedBytes(sizeof(int)); histograms = reinterpret_cast(d_wspace); d_wspace += calculateAlignedBytes(sizeof(BinT) * max_len_histograms); done_count = reinterpret_cast(d_wspace); @@ -323,20 +322,20 @@ struct Builder { d_wspace += calculateAlignedBytes(sizeof(SplitT) * max_batch); d_work_items = reinterpret_cast(d_wspace); d_wspace += calculateAlignedBytes(sizeof(NodeWorkItem) * max_batch); - workload_info = reinterpret_cast*>(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); - column_samples = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(IdxT) * max_batch * dataset.n_sampled_cols); - partition_row_ids = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(IdxT) * dataset.n_sampled_rows); + workload_info = reinterpret_cast(d_wspace); + d_wspace += calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + column_samples = reinterpret_cast(d_wspace); + d_wspace += calculateAlignedBytes(sizeof(int) * max_batch * dataset.n_sampled_cols); + partition_row_ids = reinterpret_cast(d_wspace); + d_wspace += calculateAlignedBytes(sizeof(int) * dataset.n_sampled_rows); RAFT_CUDA_TRY( cudaMemsetAsync(done_count, 0, sizeof(int) * max_batch * n_col_blks, builder_stream)); RAFT_CUDA_TRY(cudaMemsetAsync(mutex, 0, sizeof(int) * max_batch, builder_stream)); // host - h_workload_info = reinterpret_cast*>(h_wspace); - h_wspace += calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + h_workload_info = reinterpret_cast(h_wspace); + h_wspace += calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); h_splits = reinterpret_cast(h_wspace); h_wspace += calculateAlignedBytes(sizeof(SplitT) * max_batch); } @@ -389,20 +388,20 @@ struct Builder { { raft::common::nvtx::range fun_scope("Builder::doSplit @builder.cuh [batched-levelalgo]"); // start fresh on the number of *new* nodes created in this batch - RAFT_CUDA_TRY(cudaMemsetAsync(n_nodes, 0, sizeof(IdxT), builder_stream)); + RAFT_CUDA_TRY(cudaMemsetAsync(n_nodes, 0, sizeof(int), builder_stream)); - const IdxT original_n_sampled_cols = dataset.n_sampled_cols; + const int original_n_sampled_cols = dataset.n_sampled_cols; ASSERT(original_n_sampled_cols > 0 && original_n_sampled_cols <= dataset.N, "n_sampled_cols must be in [1, n_cols]"); const std::size_t max_sampling_rounds = std::size_t((dataset.N + original_n_sampled_cols - 1) / original_n_sampled_cols); struct HostSplit { DataT quesval; - IdxT colid; + int colid; DataT best_metric_val; int nLeft; - IdxT split_start; - IdxT split_end; + int split_start; + int split_end; }; static_assert(sizeof(HostSplit) == sizeof(SplitT)); static_assert(alignof(HostSplit) == alignof(SplitT)); @@ -424,7 +423,7 @@ struct Builder { // Match sklearn's behavior of searching beyond max_features when the // sampled features do not yield a valid split. for (std::size_t round = 0; !active_items.empty() && round < max_sampling_rounds; ++round) { - IdxT sample_offset = IdxT(round) * original_n_sampled_cols; + int sample_offset = int(round) * original_n_sampled_cols; dataset.n_sampled_cols = std::min(original_n_sampled_cols, dataset.N - sample_offset); computeBestSplits(active_items, seed, sample_offset); @@ -461,15 +460,15 @@ struct Builder { raft::update_device(d_work_items, work_items.data(), work_items.size(), builder_stream); const auto partition_workload = this->updateWorkloadInfo(work_items); raft::common::nvtx::push_range("nodeSplitKernel @builder.cuh [batched-levelalgo]"); - launchNodeSplitKernel(params.min_samples_leaf, - params.min_impurity_decrease, - dataset, - d_work_items, - splits, - workload_info, - partition_workload.first, - partition_row_ids, - builder_stream); + launchNodeSplitKernel(params.min_samples_leaf, + params.min_impurity_decrease, + dataset, + d_work_items, + splits, + workload_info, + partition_workload.first, + partition_row_ids, + builder_stream); RAFT_CUDA_TRY(cudaPeekAtLastError()); raft::common::nvtx::pop_range(); raft::update_host(h_splits, splits, work_items.size(), builder_stream); @@ -479,9 +478,9 @@ struct Builder { void computeBestSplits(const std::vector& work_items, uint64_t sampling_seed, - IdxT sample_offset) + int sample_offset) { - initSplit(splits, work_items.size(), builder_stream); + initSplit(splits, work_items.size(), builder_stream); RAFT_CUDA_TRY(cudaMemsetAsync( done_count, 0, sizeof(int) * params.max_batch_size * n_blks_for_cols, builder_stream)); RAFT_CUDA_TRY(cudaMemsetAsync(mutex, 0, sizeof(int) * params.max_batch_size, builder_stream)); @@ -490,7 +489,7 @@ struct Builder { sampleFeatures(work_items, sampling_seed, sample_offset); - for (IdxT c = 0; c < dataset.n_sampled_cols; c += n_blks_for_cols) { + for (int c = 0; c < dataset.n_sampled_cols; c += n_blks_for_cols) { computeSplit(c, n_blocks_dimx, n_large_nodes); RAFT_CUDA_TRY(cudaPeekAtLastError()); } @@ -500,18 +499,18 @@ struct Builder { void sampleFeatures(const std::vector& work_items, uint64_t sampling_seed, - IdxT sample_offset) + int sample_offset) { raft::common::nvtx::range fun_scope("feature-sampling"); - sample_features(column_samples, - d_work_items, - work_items.size(), - treeid, - sampling_seed, - sample_offset, - dataset.N, - dataset.n_sampled_cols, - builder_stream); + sample_features(column_samples, + d_work_items, + work_items.size(), + treeid, + sampling_seed, + sample_offset, + dataset.N, + dataset.n_sampled_cols, + builder_stream); RAFT_CUDA_TRY(cudaPeekAtLastError()); } @@ -542,7 +541,7 @@ struct Builder { return dynamic_smem_size; } - void computeSplit(IdxT col, size_t n_blocks_dimx, size_t n_large_nodes) + void computeSplit(int col, size_t n_blocks_dimx, size_t n_large_nodes) { // if no instances to split, return if (n_blocks_dimx == 0) return; @@ -562,25 +561,25 @@ struct Builder { ObjectiveT objective(dataset.num_outputs, params.min_samples_leaf, params.split_criterion); // call the computeSplitKernel raft::common::nvtx::range kernel_scope("computeSplitKernel @builder.cuh [batched-levelalgo]"); - launchComputeSplitKernel(histograms, - params.max_n_bins, - params.min_samples_split, - params.max_leaves, - dataset, - quantiles, - d_work_items, - col, - column_samples, - done_count, - mutex, - splits, - objective, - treeid, - workload_info, - seed, - grid, - smem_size, - builder_stream); + launchComputeSplitKernel(histograms, + params.max_n_bins, + params.min_samples_split, + params.max_leaves, + dataset, + quantiles, + d_work_items, + col, + column_samples, + done_count, + mutex, + splits, + objective, + treeid, + workload_info, + seed, + grid, + smem_size, + builder_stream); } // Set the leaf value predictions in batch diff --git a/cpp/src/decisiontree/batched-levelalgo/dataset.h b/cpp/src/decisiontree/batched-levelalgo/dataset.h index 8f12152ce6..d3f55ea1b1 100644 --- a/cpp/src/decisiontree/batched-levelalgo/dataset.h +++ b/cpp/src/decisiontree/batched-levelalgo/dataset.h @@ -8,7 +8,7 @@ namespace ML { namespace DT { -template +template struct Dataset { /** input dataset (assumed to be col-major) */ const DataT* data; @@ -17,17 +17,17 @@ struct Dataset { /** optional input sample weights */ const double* sample_weight; /** total rows in dataset */ - IdxT M; + int M; /** total cols in dataset */ - IdxT N; + int N; /** total sampled rows in dataset */ - IdxT n_sampled_rows; + int n_sampled_rows; /** total sampled cols in dataset */ - IdxT n_sampled_cols; + int n_sampled_cols; /** indices of sampled rows */ - IdxT* row_ids; + int* row_ids; /** Number of classes or regression outputs*/ - IdxT num_outputs; + int num_outputs; }; } // namespace DT diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh index 92cfc01527..9fcfc3f821 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh @@ -38,27 +38,27 @@ struct NodeWorkItem { * This struct has information about workload of a single threadblock of * computeSplit kernels of classification and regression */ -template struct WorkloadInfo { - IdxT nodeid; // Node in the batch on which the threadblock needs to work - IdxT large_nodeid; // counts only large nodes (nodes that require more than one block along x-dim - // for histogram calculation) - IdxT offset_blockid; // Offset threadblock id among all the blocks that are - // working on this node - IdxT num_blocks; // Total number of blocks that are working on the node + int nodeid; // Node in the batch on which the threadblock needs to work + int large_nodeid; // counts only large nodes (nodes that require more than one block along x-dim + // for histogram calculation) + int offset_blockid; // Offset threadblock id among all the blocks that are + // working on this node + int num_blocks; // Total number of blocks that are working on the node }; -template -HDI bool SplitPartitionNotValid(const SplitT& split, IdxT min_samples_leaf, std::size_t num_rows) +template +HDI bool SplitPartitionNotValid(const SplitT& split, int min_samples_leaf, std::size_t num_rows) { - return split.colid == IdxT(-1) || split.nLeft < min_samples_leaf || - (IdxT(num_rows) - split.nLeft) < min_samples_leaf; + auto n_left = static_cast(split.nLeft); + return split.colid == -1 || split.nLeft < min_samples_leaf || n_left > num_rows || + num_rows - n_left < static_cast(min_samples_leaf); } -template +template HDI bool SplitNotValid(const SplitT& split, DataT min_impurity_decrease, - IdxT min_samples_leaf, + int min_samples_leaf, std::size_t num_rows) { return split.best_metric_val <= min_impurity_decrease || @@ -72,16 +72,15 @@ DI OutT* alignPointer(InT dataset) return reinterpret_cast(raft::alignTo(reinterpret_cast(dataset), sizeof(OutT))); } -template -void sample_features(IdxT* column_samples, - const NodeWorkItem* work_items, - size_t work_items_size, - IdxT treeid, - uint64_t seed, - IdxT sample_offset, - IdxT n, - IdxT k, - cudaStream_t stream) +inline void sample_features(int* column_samples, + const NodeWorkItem* work_items, + size_t work_items_size, + int treeid, + uint64_t seed, + int sample_offset, + int n, + int k, + cudaStream_t stream) { auto n_column_samples = work_items_size * size_t(k); auto counting = thrust::make_counting_iterator(0); @@ -90,27 +89,27 @@ void sample_features(IdxT* column_samples, counting, counting + n_column_samples, [=] __device__(size_t sample_idx) { - auto node_idx = sample_idx / size_t(k); - IdxT column_index = static_cast(sample_idx % size_t(k)); + auto node_idx = sample_idx / size_t(k); + int column_index = static_cast(sample_idx % size_t(k)); const uint32_t nodeid = work_items[node_idx].idx; uint32_t rng_seed = fnv1a32_hash(seed, treeid, nodeid); - cuda::shuffle_iterator shuffled_features( + cuda::shuffle_iterator shuffled_features( n, cuda::std::minstd_rand(rng_seed), sample_offset); column_samples[sample_idx] = shuffled_features[column_index]; }); } -template -void launchNodeSplitKernel(const IdxT min_samples_leaf, +template +void launchNodeSplitKernel(const int min_samples_leaf, const DataT min_impurity_decrease, - const Dataset& dataset, + const Dataset& dataset, const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, + const Split* splits, + const WorkloadInfo* workload_info, size_t n_blocks_dimx, - IdxT* partition_row_ids, + int* partition_row_ids, cudaStream_t builder_stream); template @@ -122,22 +121,22 @@ void launchLeafKernel(ObjectiveT objective, int batch_size, size_t smem_size, cudaStream_t builder_stream); -template +template void launchComputeSplitKernel(typename ObjectiveT::BinT* histograms, - IdxT n_bins, - IdxT min_samples_split, - IdxT max_leaves, - const Dataset& dataset, - const Quantiles& quantiles, + int n_bins, + int min_samples_split, + int max_leaves, + const Dataset& dataset, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + int colStart, + const int* column_samples, int* done_count, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - IdxT treeid, - const WorkloadInfo* workload_info, + int treeid, + const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, size_t smem_size, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh index abb953457e..ed04c616aa 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh @@ -30,17 +30,15 @@ namespace DT { static constexpr int TPB_DEFAULT = 128; -template struct NodeSplitPartitionState { - IdxT left_count; + int left_count; bool valid_row; bool goes_left; }; -template struct NodeSplitPartitionScanOp { - __host__ __device__ NodeSplitPartitionState operator()( - const NodeSplitPartitionState& lhs, const NodeSplitPartitionState& rhs) const + __host__ __device__ NodeSplitPartitionState operator()(const NodeSplitPartitionState& lhs, + const NodeSplitPartitionState& rhs) const { return {lhs.left_count + rhs.left_count, rhs.valid_row, rhs.goes_left}; } @@ -50,16 +48,15 @@ struct NodeSplitPartitionScanOp { // inclusive left count and current row side for each logical row slot in its // node segment; this writer uses that state to place the row into the temporary // partition buffer. -template +template struct NodeSplitPartitionWriter { - Dataset dataset; + Dataset dataset; const NodeWorkItem* work_items; - const Split* splits; - const WorkloadInfo* workload_info; - IdxT* partition_row_ids; + const Split* splits; + const WorkloadInfo* workload_info; + int* partition_row_ids; - __host__ __device__ void operator()(std::ptrdiff_t index, - NodeSplitPartitionState state) const + __host__ __device__ void operator()(std::ptrdiff_t index, NodeSplitPartitionState state) const { if (!state.valid_row) { return; } @@ -74,7 +71,7 @@ struct NodeSplitPartitionWriter { const auto row = dataset.row_ids[range_start + range_pos]; const auto rank = - state.goes_left ? state.left_count - IdxT(1) : IdxT(range_pos) - state.left_count; + state.goes_left ? state.left_count - int(1) : int(range_pos) - state.left_count; const auto out_idx = range_start + (state.goes_left ? rank : split.nLeft + rank); partition_row_ids[out_idx] = row; } @@ -82,14 +79,14 @@ struct NodeSplitPartitionWriter { // Copy back only ranges for nodes that actually split. Leaf/invalid nodes keep // their existing row-id order because the scan writer skips them too. -template -static __global__ void nodeSplitCopyBackKernel(const IdxT min_samples_leaf, +template +static __global__ void nodeSplitCopyBackKernel(const int min_samples_leaf, const DataT min_impurity_decrease, - const Dataset dataset, + const Dataset dataset, const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, - const IdxT* partition_row_ids) + const Split* splits, + const WorkloadInfo* workload_info, + const int* partition_row_ids) { const auto workload_info_cta = workload_info[blockIdx.x]; const auto nid = workload_info_cta.nodeid; @@ -108,15 +105,15 @@ static __global__ void nodeSplitCopyBackKernel(const IdxT min_samples_leaf, } } -template -void launchNodeSplitKernel(const IdxT min_samples_leaf, +template +void launchNodeSplitKernel(const int min_samples_leaf, const DataT min_impurity_decrease, - const Dataset& dataset, + const Dataset& dataset, const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, + const Split* splits, + const WorkloadInfo* workload_info, size_t n_blocks_dimx, - IdxT* partition_row_ids, + int* partition_row_ids, cudaStream_t builder_stream) { if (n_blocks_dimx == 0) return; @@ -136,18 +133,18 @@ void launchNodeSplitKernel(const IdxT min_samples_leaf, const auto work_item = work_items[nid]; const auto split = splits[nid]; if (SplitNotValid(split, min_impurity_decrease, min_samples_leaf, work_item.instances.count)) { - return NodeSplitPartitionState{IdxT(0), false, false}; + return NodeSplitPartitionState{int(0), false, false}; } const auto range_pos = std::size_t(workload_info_cta.offset_blockid) * TPB + slot % TPB; if (range_pos >= work_item.instances.count) { - return NodeSplitPartitionState{IdxT(0), false, false}; + return NodeSplitPartitionState{int(0), false, false}; } const auto row = dataset.row_ids[work_item.instances.begin + range_pos]; const auto col_idx = std::size_t(split.colid) * dataset.M + row; const auto goes_left = dataset.data[col_idx] <= split.quesval; - return NodeSplitPartitionState{goes_left ? IdxT(1) : IdxT(0), true, goes_left}; + return NodeSplitPartitionState{goes_left ? int(1) : int(0), true, goes_left}; }; // The scan input is a stream of per-slot partition states keyed by node id. @@ -156,18 +153,18 @@ void launchNodeSplitKernel(const IdxT min_samples_leaf, auto node_keys = thrust::make_transform_iterator(slots_begin, node_key); auto partition_states = thrust::make_transform_iterator(slots_begin, partition_state); auto partition_writer = - thrust::make_tabulate_output_iterator(NodeSplitPartitionWriter{ + thrust::make_tabulate_output_iterator(NodeSplitPartitionWriter{ dataset, work_items, splits, workload_info, partition_row_ids}); thrust::inclusive_scan_by_key(exec_policy, node_keys, node_keys + n_slots, partition_states, partition_writer, - thrust::equal_to{}, - NodeSplitPartitionScanOp{}); + thrust::equal_to{}, + NodeSplitPartitionScanOp{}); // The original row_ids buffer remains the source during the scan, so copy back after it finishes. - nodeSplitCopyBackKernel + nodeSplitCopyBackKernel <<>>(min_samples_leaf, min_impurity_decrease, dataset, @@ -230,8 +227,8 @@ void launchLeafKernel(ObjectiveT objective, * @return The total sum aggregated over the sumscan, * as well as the modified cdf-histogram pointer */ -template -DI BinT pdf_to_cdf(BinT* shared_histogram, IdxT n_bins) +template +DI BinT pdf_to_cdf(BinT* shared_histogram, int n_bins) { // Blockscan instance preparation typedef cub::BlockScan BlockScan; @@ -240,7 +237,7 @@ DI BinT pdf_to_cdf(BinT* shared_histogram, IdxT n_bins) // variable to accumulate aggregate of sumscans of previous iterations BinT total_aggregate = BinT(); - for (IdxT tix = threadIdx.x; tix < raft::ceildiv(n_bins, TPB) * TPB; tix += blockDim.x) { + for (int tix = threadIdx.x; tix < raft::ceildiv(n_bins, TPB) * TPB; tix += blockDim.x) { BinT result; BinT block_aggregate; BinT element = tix < n_bins ? shared_histogram[tix] : BinT(); @@ -253,46 +250,46 @@ DI BinT pdf_to_cdf(BinT* shared_histogram, IdxT n_bins) return total_aggregate; } -template +template static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, - IdxT max_n_bins, - IdxT min_samples_split, - IdxT max_leaves, - const Dataset dataset, - const Quantiles quantiles, + int max_n_bins, + int min_samples_split, + int max_leaves, + const Dataset dataset, + const Quantiles quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + int colStart, + const int* column_samples, int* done_count, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT objective, - IdxT treeid, - const WorkloadInfo* workload_info, + int treeid, + const WorkloadInfo* workload_info, uint64_t seed) { using BinT = typename ObjectiveT::BinT; // dynamic shared memory extern __shared__ char smem[]; constexpr int n_split_warps = (TPB + raft::WarpSize - 1) / raft::WarpSize; - __shared__ __align__(alignof(Split)) unsigned char - split_scratch_storage[sizeof(Split) * n_split_warps]; - auto* split_scratch = reinterpret_cast*>(split_scratch_storage); + __shared__ __align__(alignof( + Split)) unsigned char split_scratch_storage[sizeof(Split) * n_split_warps]; + auto* split_scratch = reinterpret_cast*>(split_scratch_storage); // Read workload info for this block - WorkloadInfo workload_info_cta = workload_info[blockIdx.x]; - IdxT nid = workload_info_cta.nodeid; - IdxT large_nid = workload_info_cta.large_nodeid; - const auto work_item = work_items[nid]; - auto range_start = work_item.instances.begin; - auto range_len = work_item.instances.count; + WorkloadInfo workload_info_cta = workload_info[blockIdx.x]; + int nid = workload_info_cta.nodeid; + int large_nid = workload_info_cta.large_nodeid; + const auto work_item = work_items[nid]; + auto range_start = work_item.instances.begin; + auto range_len = work_item.instances.count; - IdxT offset_blockid = workload_info_cta.offset_blockid; - IdxT num_blocks = workload_info_cta.num_blocks; + int offset_blockid = workload_info_cta.offset_blockid; + int num_blocks = workload_info_cta.num_blocks; // obtaining the feature to test split on - IdxT colIndex = colStart + blockIdx.y; - IdxT col = column_samples[nid * dataset.n_sampled_cols + colIndex]; + int colIndex = colStart + blockIdx.y; + int col = column_samples[nid * dataset.n_sampled_cols + colIndex]; // getting the n_bins for that feature int n_bins = quantiles.n_bins_array[col]; @@ -302,13 +299,13 @@ static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, auto* shared_histogram = alignPointer(smem); auto* shared_quantiles = alignPointer(shared_histogram + shared_histogram_len); auto* shared_done = alignPointer(shared_quantiles + n_bins); - IdxT stride = blockDim.x * num_blocks; - IdxT tid = threadIdx.x + offset_blockid * blockDim.x; + int stride = blockDim.x * num_blocks; + int tid = threadIdx.x + offset_blockid * blockDim.x; // populating shared memory with initial values - for (IdxT i = threadIdx.x; i < shared_histogram_len; i += blockDim.x) + for (int i = threadIdx.x; i < shared_histogram_len; i += blockDim.x) shared_histogram[i] = BinT(); - for (IdxT b = threadIdx.x; b < n_bins; b += blockDim.x) + for (int b = threadIdx.x; b < n_bins; b += blockDim.x) shared_quantiles[b] = quantiles.quantiles_array[max_n_bins * col + b]; // synchronizing above changes across block @@ -331,8 +328,8 @@ static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, ::cuda::std::lower_bound(bin_begin, bin_end, data, [shared_quantiles](int bin, DataT value) { return shared_quantiles[bin] < value; }); - int bin = bin_it == bin_end ? n_bins - 1 : *bin_it; - IdxT start = static_cast(bin); + int bin = bin_it == bin_end ? n_bins - 1 : *bin_it; + int start = static_cast(bin); // ++shared_histogram[start] objective.IncrementHistogram(shared_histogram, n_bins, start, label, dataset, row); } @@ -343,7 +340,7 @@ static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, // update the corresponding global location auto histograms_offset = ((large_nid * gridDim.y) + blockIdx.y) * max_n_bins * objective.NumClasses(); - for (IdxT i = threadIdx.x; i < shared_histogram_len; i += blockDim.x) { + for (int i = threadIdx.x; i < shared_histogram_len; i += blockDim.x) { BinT::AtomicAdd(histograms + histograms_offset + i, shared_histogram[i]); } @@ -357,17 +354,17 @@ static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, if (!last) return; // store the complete global histogram in shared memory of last block - for (IdxT i = threadIdx.x; i < shared_histogram_len; i += blockDim.x) + for (int i = threadIdx.x; i < shared_histogram_len; i += blockDim.x) shared_histogram[i] = histograms[histograms_offset + i]; __syncthreads(); } // PDF to CDF inplace in `shared_histogram` - for (IdxT c = 0; c < objective.NumClasses(); ++c) { + for (int c = 0; c < objective.NumClasses(); ++c) { // left to right scan operation for scanning // "lesser-than-or-equal" counts - BinT total_sum = pdf_to_cdf(shared_histogram + n_bins * c, n_bins); + BinT total_sum = pdf_to_cdf(shared_histogram + n_bins * c, n_bins); // now, `shared_histogram[n_bins * c + i]` will have count of datapoints of class `c` // that are less than or equal to `shared_quantiles[i]`. } @@ -376,8 +373,7 @@ static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, // calculate the best candidate bins (one for each thread in the block) in current feature and // corresponding information gain for splitting - Split sp = - objective.Gain(shared_histogram, shared_quantiles, col, range_len, n_bins); + Split sp = objective.Gain(shared_histogram, shared_quantiles, col, range_len, n_bins); __syncthreads(); @@ -387,28 +383,28 @@ static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, sp.evalBestSplit(split_scratch, splits + nid, mutex + nid, shared_quantiles, n_bins); } -template +template void launchComputeSplitKernel(typename ObjectiveT::BinT* histograms, - IdxT max_n_bins, - IdxT min_samples_split, - IdxT max_leaves, - const Dataset& dataset, - const Quantiles& quantiles, + int max_n_bins, + int min_samples_split, + int max_leaves, + const Dataset& dataset, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + int colStart, + const int* column_samples, int* done_count, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - IdxT treeid, - const WorkloadInfo* workload_info, + int treeid, + const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, size_t smem_size, cudaStream_t builder_stream) { - computeSplitKernel + computeSplitKernel <<>>(histograms, max_n_bins, min_samples_split, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu index e050054f26..a7ab7de6b9 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu @@ -11,11 +11,10 @@ namespace ML { namespace DT { using DataT = double; using LabelT = int; -using IdxT = int; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using DatasetT = Dataset; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -29,22 +28,22 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernel( +template void launchComputeSplitKernel( BinT* histograms, - IdxT n_bins, - IdxT min_samples_split, - IdxT max_leaves, + int n_bins, + int min_samples_split, + int max_leaves, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + int colStart, + const int* column_samples, int* done_count, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - IdxT treeid, - const WorkloadInfo* workload_info, + int treeid, + const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, size_t smem_size, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu index 6278efd092..bd60a5a9c0 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu @@ -11,11 +11,10 @@ namespace ML { namespace DT { using DataT = float; using LabelT = int; -using IdxT = int; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using DatasetT = Dataset; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -29,22 +28,22 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernel( +template void launchComputeSplitKernel( BinT* histograms, - IdxT n_bins, - IdxT min_samples_split, - IdxT max_leaves, + int n_bins, + int min_samples_split, + int max_leaves, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + int colStart, + const int* column_samples, int* done_count, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - IdxT treeid, - const WorkloadInfo* workload_info, + int treeid, + const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, size_t smem_size, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu index 3ecb93c143..bdf6c2c6aa 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu @@ -9,49 +9,46 @@ namespace ML { namespace DT { // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel( - const int min_samples_leaf, - const float min_impurity_decrease, - const Dataset& dataset, - const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, - size_t n_blocks_dimx, - int* partition_row_ids, - cudaStream_t builder_stream); +template void launchNodeSplitKernel(const int min_samples_leaf, + const float min_impurity_decrease, + const Dataset& dataset, + const NodeWorkItem* work_items, + const Split* splits, + const WorkloadInfo* workload_info, + size_t n_blocks_dimx, + int* partition_row_ids, + cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel( - const int min_samples_leaf, - const double min_impurity_decrease, - const Dataset& dataset, - const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, - size_t n_blocks_dimx, - int* partition_row_ids, - cudaStream_t builder_stream); +template void launchNodeSplitKernel(const int min_samples_leaf, + const double min_impurity_decrease, + const Dataset& dataset, + const NodeWorkItem* work_items, + const Split* splits, + const WorkloadInfo* workload_info, + size_t n_blocks_dimx, + int* partition_row_ids, + cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel( - const int min_samples_leaf, - const float min_impurity_decrease, - const Dataset& dataset, - const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, - size_t n_blocks_dimx, - int* partition_row_ids, - cudaStream_t builder_stream); +template void launchNodeSplitKernel(const int min_samples_leaf, + const float min_impurity_decrease, + const Dataset& dataset, + const NodeWorkItem* work_items, + const Split* splits, + const WorkloadInfo* workload_info, + size_t n_blocks_dimx, + int* partition_row_ids, + cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel( +template void launchNodeSplitKernel( const int min_samples_leaf, const double min_impurity_decrease, - const Dataset& dataset, + const Dataset& dataset, const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, + const Split* splits, + const WorkloadInfo* workload_info, size_t n_blocks_dimx, int* partition_row_ids, cudaStream_t builder_stream); diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu index e42c1bd0cd..9b08772359 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu @@ -11,11 +11,10 @@ namespace ML { namespace DT { using DataT = double; using LabelT = double; -using IdxT = int; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using DatasetT = Dataset; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -29,22 +28,22 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernel( +template void launchComputeSplitKernel( BinT* histograms, - IdxT n_bins, - IdxT min_samples_split, - IdxT max_leaves, + int n_bins, + int min_samples_split, + int max_leaves, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + int colStart, + const int* column_samples, int* done_count, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - IdxT treeid, - const WorkloadInfo* workload_info, + int treeid, + const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, size_t smem_size, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu index 42780bd796..05b88c76b3 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu @@ -11,11 +11,10 @@ namespace ML { namespace DT { using DataT = float; using LabelT = float; -using IdxT = int; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using DatasetT = Dataset; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -29,22 +28,22 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernel( +template void launchComputeSplitKernel( BinT* histograms, - IdxT n_bins, - IdxT min_samples_split, - IdxT max_leaves, + int n_bins, + int min_samples_split, + int max_leaves, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + int colStart, + const int* column_samples, int* done_count, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - IdxT treeid, - const WorkloadInfo* workload_info, + int treeid, + const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, size_t smem_size, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu index 69e8d3af1c..ceb7943372 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu @@ -11,11 +11,10 @@ namespace ML { namespace DT { using DataT = double; using LabelT = int; -using IdxT = int; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using DatasetT = Dataset; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -29,22 +28,22 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernel( +template void launchComputeSplitKernel( BinT* histograms, - IdxT n_bins, - IdxT min_samples_split, - IdxT max_leaves, + int n_bins, + int min_samples_split, + int max_leaves, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + int colStart, + const int* column_samples, int* done_count, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - IdxT treeid, - const WorkloadInfo* workload_info, + int treeid, + const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, size_t smem_size, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu index 0cb06c3e01..fe4bf612ef 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu @@ -11,11 +11,10 @@ namespace ML { namespace DT { using DataT = float; using LabelT = int; -using IdxT = int; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using DatasetT = Dataset; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -29,22 +28,22 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernel( +template void launchComputeSplitKernel( BinT* histograms, - IdxT n_bins, - IdxT min_samples_split, - IdxT max_leaves, + int n_bins, + int min_samples_split, + int max_leaves, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + int colStart, + const int* column_samples, int* done_count, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - IdxT treeid, - const WorkloadInfo* workload_info, + int treeid, + const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, size_t smem_size, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu index c735997614..bb8f00f2b1 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu @@ -11,11 +11,10 @@ namespace ML { namespace DT { using DataT = double; using LabelT = double; -using IdxT = int; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using DatasetT = Dataset; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -29,22 +28,22 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernel( +template void launchComputeSplitKernel( BinT* histograms, - IdxT n_bins, - IdxT min_samples_split, - IdxT max_leaves, + int n_bins, + int min_samples_split, + int max_leaves, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + int colStart, + const int* column_samples, int* done_count, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - IdxT treeid, - const WorkloadInfo* workload_info, + int treeid, + const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, size_t smem_size, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu index 11015f4da0..61336064f2 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu @@ -11,11 +11,10 @@ namespace ML { namespace DT { using DataT = float; using LabelT = float; -using IdxT = int; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using DatasetT = Dataset; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -29,22 +28,22 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernel( +template void launchComputeSplitKernel( BinT* histograms, - IdxT n_bins, - IdxT min_samples_split, - IdxT max_leaves, + int n_bins, + int min_samples_split, + int max_leaves, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + int colStart, + const int* column_samples, int* done_count, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - IdxT treeid, - const WorkloadInfo* workload_info, + int treeid, + const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, size_t smem_size, diff --git a/cpp/src/decisiontree/batched-levelalgo/objectives.cuh b/cpp/src/decisiontree/batched-levelalgo/objectives.cuh index 6d3284e3cb..eaaa467504 100644 --- a/cpp/src/decisiontree/batched-levelalgo/objectives.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/objectives.cuh @@ -16,30 +16,29 @@ namespace ML { namespace DT { -template +template class ClassificationObjectiveFunction { public: using DataT = DataT_; using LabelT = LabelT_; - using IdxT = IdxT_; using BinT = std::conditional_t; static constexpr bool weighted = weighted_; private: - IdxT nclasses; - IdxT min_samples_leaf; + int nclasses; + int min_samples_leaf; CRITERION criterion; - HDI double WeightAt(BinT const* hist, IdxT i, IdxT n_bins) const + HDI double WeightAt(BinT const* hist, int i, int n_bins) const { double weight = 0.0; - for (IdxT j = 0; j < nclasses; ++j) { + for (int j = 0; j < nclasses; ++j) { weight += hist[n_bins * j + i].Weight(); } return weight; } - HDI DataT GiniGain(BinT const* hist, IdxT i, IdxT n_bins, IdxT, IdxT, IdxT) const + HDI DataT GiniGain(BinT const* hist, int i, int n_bins, int, int, int) const { constexpr DataT One = DataT(1.0); auto total_weight = WeightAt(hist, n_bins - 1, n_bins); @@ -54,7 +53,7 @@ class ClassificationObjectiveFunction { auto invRight = One / DataT(right_weight); auto gain = DataT(0.0); - for (IdxT j = 0; j < nclasses; ++j) { + for (int j = 0; j < nclasses; ++j) { double val_i = 0.0; auto lval_i = hist[n_bins * j + i].Weight(); auto lval = DataT(lval_i); @@ -74,7 +73,7 @@ class ClassificationObjectiveFunction { return gain; } - HDI DataT EntropyGain(BinT const* hist, IdxT i, IdxT n_bins, IdxT, IdxT, IdxT) const + HDI DataT EntropyGain(BinT const* hist, int i, int n_bins, int, int, int) const { auto total_weight = WeightAt(hist, n_bins - 1, n_bins); auto left_weight = WeightAt(hist, i, n_bins); @@ -87,7 +86,7 @@ class ClassificationObjectiveFunction { auto invLeft{DataT(1.0) / DataT(left_weight)}; auto invRight{DataT(1.0) / DataT(right_weight)}; auto invLen{DataT(1.0) / DataT(total_weight)}; - for (IdxT c = 0; c < nclasses; ++c) { + for (int c = 0; c < nclasses; ++c) { double val_i = 0.0; auto lval_i = hist[n_bins * c + i].Weight(); if (lval_i != 0) { @@ -114,8 +113,7 @@ class ClassificationObjectiveFunction { } public: - HDI DataT - GainPerSplit(BinT const* hist, IdxT i, IdxT n_bins, IdxT len, IdxT nLeft, IdxT nRight) const + HDI DataT GainPerSplit(BinT const* hist, int i, int n_bins, int len, int nLeft, int nRight) const { if (nLeft < min_samples_leaf || nRight < min_samples_leaf) return -std::numeric_limits::max(); @@ -127,16 +125,16 @@ class ClassificationObjectiveFunction { } } - HDI ClassificationObjectiveFunction(IdxT nclasses, IdxT min_samples_leaf, CRITERION criterion) + HDI ClassificationObjectiveFunction(int nclasses, int min_samples_leaf, CRITERION criterion) : nclasses(nclasses), min_samples_leaf(min_samples_leaf), criterion(criterion) { } - DI IdxT NumClasses() const { return nclasses; } + DI int NumClasses() const { return nclasses; } template DI void IncrementHistogram( - BinT* histogram, IdxT n_bins, IdxT bin, LabelT label, const DatasetT& dataset, IdxT row) const + BinT* histogram, int n_bins, int bin, LabelT label, const DatasetT& dataset, int row) const { double weight = 1.0; if constexpr (weighted) { @@ -145,11 +143,11 @@ class ClassificationObjectiveFunction { BinT::IncrementHistogram(histogram, n_bins, bin, label, weight); } - DI Split Gain( - BinT const* shist, DataT const* squantiles, IdxT col, IdxT len, IdxT n_bins) const + DI Split Gain( + BinT const* shist, DataT const* squantiles, int col, int len, int n_bins) const { - Split sp; - for (IdxT i = threadIdx.x; i < n_bins; i += blockDim.x) { + Split sp; + for (int i = threadIdx.x; i < n_bins; i += blockDim.x) { auto nLeft = detail::CountLeft(shist, i, n_bins, nclasses); auto nRight = len - nLeft; auto gain = -std::numeric_limits::max(); @@ -180,21 +178,20 @@ class ClassificationObjectiveFunction { } }; -template +template class RegressionObjectiveFunction { public: using DataT = DataT_; using LabelT = LabelT_; - using IdxT = IdxT_; using BinT = std::conditional_t; static constexpr bool weighted = weighted_; private: - IdxT min_samples_leaf; + int min_samples_leaf; CRITERION criterion; static constexpr auto eps_ = 10 * std::numeric_limits::epsilon(); - HDI DataT MSEGain(BinT const* hist, IdxT i, IdxT n_bins, IdxT, IdxT, IdxT) const + HDI DataT MSEGain(BinT const* hist, int i, int n_bins, int, int, int) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -216,7 +213,7 @@ class RegressionObjectiveFunction { return gain; } - HDI DataT PoissonGain(BinT const* hist, IdxT i, IdxT n_bins, IdxT, IdxT, IdxT) const + HDI DataT PoissonGain(BinT const* hist, int i, int n_bins, int, int, int) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -243,7 +240,7 @@ class RegressionObjectiveFunction { return gain; } - HDI DataT GammaGain(BinT const* hist, IdxT i, IdxT n_bins, IdxT, IdxT, IdxT) const + HDI DataT GammaGain(BinT const* hist, int i, int n_bins, int, int, int) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -270,7 +267,7 @@ class RegressionObjectiveFunction { return gain; } - HDI DataT InverseGaussianGain(BinT const* hist, IdxT i, IdxT n_bins, IdxT, IdxT, IdxT) const + HDI DataT InverseGaussianGain(BinT const* hist, int i, int n_bins, int, int, int) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -297,8 +294,7 @@ class RegressionObjectiveFunction { } public: - HDI DataT - GainPerSplit(BinT const* hist, IdxT i, IdxT n_bins, IdxT len, IdxT nLeft, IdxT nRight) const + HDI DataT GainPerSplit(BinT const* hist, int i, int n_bins, int len, int nLeft, int nRight) const { if (nLeft < min_samples_leaf || nRight < min_samples_leaf) return -std::numeric_limits::max(); @@ -313,16 +309,16 @@ class RegressionObjectiveFunction { } } - HDI RegressionObjectiveFunction(IdxT, IdxT min_samples_leaf, CRITERION criterion) + HDI RegressionObjectiveFunction(int, int min_samples_leaf, CRITERION criterion) : min_samples_leaf(min_samples_leaf), criterion(criterion) { } - DI IdxT NumClasses() const { return 1; } + DI int NumClasses() const { return 1; } template DI void IncrementHistogram( - BinT* histogram, IdxT n_bins, IdxT bin, LabelT label, const DatasetT& dataset, IdxT row) const + BinT* histogram, int n_bins, int bin, LabelT label, const DatasetT& dataset, int row) const { double weight = 1.0; if constexpr (weighted) { @@ -331,12 +327,12 @@ class RegressionObjectiveFunction { BinT::IncrementHistogram(histogram, n_bins, bin, label, weight); } - DI Split Gain( - BinT const* shist, DataT const* squantiles, IdxT col, IdxT len, IdxT n_bins) const + DI Split Gain( + BinT const* shist, DataT const* squantiles, int col, int len, int n_bins) const { - Split sp; - for (IdxT i = threadIdx.x; i < n_bins; i += blockDim.x) { - auto nLeft = detail::CountLeft(shist, i, n_bins, IdxT{1}); + Split sp; + for (int i = threadIdx.x; i < n_bins; i += blockDim.x) { + auto nLeft = detail::CountLeft(shist, i, n_bins, int{1}); auto nRight = len - nLeft; auto gain = -std::numeric_limits::max(); if (nLeft >= min_samples_leaf && nRight >= min_samples_leaf) { diff --git a/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh b/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh index f0d3fd000f..2ce6610a61 100644 --- a/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh @@ -112,8 +112,8 @@ struct QuantileResult { rmm::device_uvector quantiles_array; rmm::device_uvector n_bins_array; - Quantiles view() & { return {quantiles_array.data(), n_bins_array.data()}; } - Quantiles view() && = delete; + Quantiles view() & { return {quantiles_array.data(), n_bins_array.data()}; } + Quantiles view() && = delete; }; /** diff --git a/cpp/src/decisiontree/batched-levelalgo/quantiles.h b/cpp/src/decisiontree/batched-levelalgo/quantiles.h index abfcec3ab8..26a89e6b60 100644 --- a/cpp/src/decisiontree/batched-levelalgo/quantiles.h +++ b/cpp/src/decisiontree/batched-levelalgo/quantiles.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2019-2022, NVIDIA CORPORATION. + * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION. * SPDX-License-Identifier: Apache-2.0 */ @@ -8,12 +8,12 @@ namespace ML { namespace DT { -template +template struct Quantiles { /** quantiles computed for each feature of dataset in col-major */ DataT* quantiles_array; /** The number of bins used for quantiles of each feature*/ - IdxT* n_bins_array; + int* n_bins_array; }; } // namespace DT diff --git a/cpp/src/decisiontree/batched-levelalgo/split.cuh b/cpp/src/decisiontree/batched-levelalgo/split.cuh index bea1a2b15e..12f313d87a 100644 --- a/cpp/src/decisiontree/batched-levelalgo/split.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/split.cuh @@ -12,14 +12,14 @@ namespace ML { namespace DT { namespace detail { -template -DI IdxT CountLeft(BinT const* hist, IdxT i, IdxT n_bins, IdxT n_outputs) +template +DI int CountLeft(BinT const* hist, int i, int n_bins, int n_outputs) { auto nLeft = hist[i].Count(); - for (IdxT j = 1; j < n_outputs; ++j) { + for (int j = 1; j < n_outputs; ++j) { nLeft += hist[n_bins * j + i].Count(); } - return static_cast(nLeft); + return static_cast(nLeft); } } // namespace detail @@ -29,9 +29,9 @@ DI IdxT CountLeft(BinT const* hist, IdxT i, IdxT n_bins, IdxT n_outputs) * * @tparam DataT input data type */ -template +template struct Split { - typedef Split SplitT; + typedef Split SplitT; /** start with this as the initial gain */ static constexpr DataT Min = -std::numeric_limits::max(); @@ -39,17 +39,17 @@ struct Split { /** threshold to compare in this node */ DataT quesval; /** feature index */ - IdxT colid; + int colid; /** best info gain on this node */ DataT best_metric_val; /** number of samples in the left child */ int nLeft; /** first quantile index in an inclusive range of training-equivalent splits */ - IdxT split_start; + int split_start; /** last quantile index in an inclusive range of training-equivalent splits */ - IdxT split_end; + int split_end; - DI Split(DataT quesval, IdxT colid, DataT best_metric_val, IdxT nLeft, IdxT bin = -1) + DI Split(DataT quesval, int colid, DataT best_metric_val, int nLeft, int bin = -1) : quesval(quesval), colid(colid), best_metric_val(best_metric_val), nLeft(nLeft) { split_start = bin; @@ -83,10 +83,7 @@ struct Split { return *this; } - DI bool has_valid_split_range() const - { - return split_start >= IdxT{0} && split_end >= split_start; - } + DI bool has_valid_split_range() const { return split_start >= 0 && split_end >= split_start; } DI bool can_merge_equivalent_split_range(const SplitT& other) const { @@ -112,7 +109,7 @@ struct Split { // Several thresholds can be equally good for the training data while still // routing future inference values differently. Select the middle split in // that equivalent range so deterministic tie-breaking does not pick an edge. - DI void select_split_range_midpoint(DataT const* quantiles, IdxT n_bins) + DI void select_split_range_midpoint(DataT const* quantiles, int n_bins) { if (has_valid_split_range() && split_end < n_bins) { auto bin = split_start + (split_end - split_start + 1) / 2; @@ -183,7 +180,7 @@ struct Split { * end thread0 will contain the best split. */ DI void evalBestSplit( - SplitT* split_scratch, volatile SplitT* split, int* mutex, DataT const* quantiles, IdxT n_bins) + SplitT* split_scratch, volatile SplitT* split, int* mutex, DataT const* quantiles, int n_bins) { warpReduce(); auto warp = threadIdx.x / raft::WarpSize; @@ -233,17 +230,17 @@ struct Split { * @param[in] len length of this array * @param[in] s cuda stream where to schedule work */ -template -void initSplit(Split* splits, IdxT len, cudaStream_t s) +template +void initSplit(Split* splits, int len, cudaStream_t s) { - auto op = [] __device__(Split * ptr, IdxT idx) { *ptr = Split(); }; - raft::linalg::writeOnlyUnaryOp, decltype(op), IdxT, TPB>(splits, len, op, s); + auto op = [] __device__(Split * ptr, int idx) { *ptr = Split(); }; + raft::linalg::writeOnlyUnaryOp, decltype(op), int, TPB>(splits, len, op, s); } -template -void printSplits(Split* splits, IdxT len, cudaStream_t s) +template +void printSplits(Split* splits, int len, cudaStream_t s) { - auto op = [] __device__(Split * ptr, IdxT idx) { + auto op = [] __device__(Split * ptr, int idx) { printf("quesval = %e, colid = %d, best_metric_val = %e, nLeft = %d, split_range = [%d, %d]\n", ptr->quesval, ptr->colid, @@ -252,7 +249,7 @@ void printSplits(Split* splits, IdxT len, cudaStream_t s) ptr->split_start, ptr->split_end); }; - raft::linalg::writeOnlyUnaryOp, decltype(op), IdxT, TPB>(splits, len, op, s); + raft::linalg::writeOnlyUnaryOp, decltype(op), int, TPB>(splits, len, op, s); RAFT_CUDA_TRY(cudaDeviceSynchronize()); } diff --git a/cpp/src/decisiontree/decisiontree.cuh b/cpp/src/decisiontree/decisiontree.cuh index 20d3656658..d313d34aba 100644 --- a/cpp/src/decisiontree/decisiontree.cuh +++ b/cpp/src/decisiontree/decisiontree.cuh @@ -242,7 +242,7 @@ class DecisionTree { int unique_labels, DecisionTreeParams params, uint64_t seed, - const Quantiles& quantiles, + const Quantiles& quantiles, int treeid, const double* sample_weight = nullptr) { @@ -252,39 +252,38 @@ class DecisionTree { (std::numeric_limits::is_integer) ? CRITERION::GINI : CRITERION::MSE; params.split_criterion = default_criterion; } - using IdxT = int; // Dispatch objective family. The objective object switches on the criterion at runtime. if (not std::is_same::value and (params.split_criterion == CRITERION::GINI || params.split_criterion == CRITERION::ENTROPY)) { if (sample_weight != nullptr) { - return Builder>(handle, - s, - treeid, - seed, - params, - data, - labels, - sample_weight, - nrows, - ncols, - row_ids, - unique_labels, - quantiles) + return Builder>(handle, + s, + treeid, + seed, + params, + data, + labels, + sample_weight, + nrows, + ncols, + row_ids, + unique_labels, + quantiles) .train(); } - return Builder>(handle, - s, - treeid, - seed, - params, - data, - labels, - sample_weight, - nrows, - ncols, - row_ids, - unique_labels, - quantiles) + return Builder>(handle, + s, + treeid, + seed, + params, + data, + labels, + sample_weight, + nrows, + ncols, + row_ids, + unique_labels, + quantiles) .train(); } else if (std::is_same::value and (params.split_criterion == CRITERION::MSE || @@ -292,34 +291,34 @@ class DecisionTree { params.split_criterion == CRITERION::GAMMA || params.split_criterion == CRITERION::INVERSE_GAUSSIAN)) { if (sample_weight != nullptr) { - return Builder>(handle, - s, - treeid, - seed, - params, - data, - labels, - sample_weight, - nrows, - ncols, - row_ids, - unique_labels, - quantiles) + return Builder>(handle, + s, + treeid, + seed, + params, + data, + labels, + sample_weight, + nrows, + ncols, + row_ids, + unique_labels, + quantiles) .train(); } - return Builder>(handle, - s, - treeid, - seed, - params, - data, - labels, - sample_weight, - nrows, - ncols, - row_ids, - unique_labels, - quantiles) + return Builder>(handle, + s, + treeid, + seed, + params, + data, + labels, + sample_weight, + nrows, + ncols, + row_ids, + unique_labels, + quantiles) .train(); } else { ASSERT(false, "Unknown split criterion."); diff --git a/cpp/tests/sg/rf_test.cu b/cpp/tests/sg/rf_test.cu index 1914df0026..abcdf07e4b 100644 --- a/cpp/tests/sg/rf_test.cu +++ b/cpp/tests/sg/rf_test.cu @@ -1164,21 +1164,21 @@ class RFSampledQuantileDeterminismTest : public ::testing::TestWithParam +template __global__ void objectiveGainKernel(BinT const* hist, DataT const* quantiles, - DT::Split* out, + DT::Split* out, int* mutex, ObjectiveT objective, - IdxT col, - IdxT len, - IdxT n_bins) + int col, + int len, + int n_bins) { - __shared__ __align__(alignof( - DT::Split)) unsigned char split_scratch_storage[sizeof(DT::Split)]; - auto* split_scratch = reinterpret_cast*>(split_scratch_storage); + __shared__ __align__( + alignof(DT::Split)) unsigned char split_scratch_storage[sizeof(DT::Split)]; + auto* split_scratch = reinterpret_cast*>(split_scratch_storage); if (threadIdx.x == 0) { - *out = DT::Split(); + *out = DT::Split(); *mutex = 0; } __syncthreads(); @@ -1190,10 +1190,9 @@ __global__ void objectiveGainKernel(BinT const* hist, TEST(RFEquivalentSplitRangeTest, ClassificationChoosesUpperMiddleBin) { - using DataT = float; - using IdxT = int; - constexpr IdxT len = 10; - constexpr IdxT n_bins = 6; + using DataT = float; + constexpr int len = 10; + constexpr int n_bins = 6; auto stream_pool = std::make_shared(1); raft::handle_t handle(rmm::cuda_stream_per_thread, stream_pool); @@ -1216,29 +1215,29 @@ TEST(RFEquivalentSplitRangeTest, ClassificationChoosesUpperMiddleBin) thrust::device_vector hist(h_hist.begin(), h_hist.end()); thrust::device_vector quantiles(h_quantiles.begin(), h_quantiles.end()); - thrust::device_vector> split(1); + thrust::device_vector> split(1); thrust::device_vector mutex(1); - DT::ClassificationObjectiveFunction objective(2, 1, CRITERION::GINI); + DT::ClassificationObjectiveFunction objective(2, 1, CRITERION::GINI); objectiveGainKernel<<<1, 32, 0, handle.get_stream()>>>(hist.data().get(), quantiles.data().get(), split.data().get(), mutex.data().get(), objective, - IdxT{0}, + 0, len, n_bins); RAFT_CUDA_TRY(cudaGetLastError()); struct HostSplit { DataT quesval; - IdxT colid; + int colid; DataT best_metric_val; int nLeft; - IdxT split_start; - IdxT split_end; + int split_start; + int split_end; }; - static_assert(sizeof(HostSplit) == sizeof(DT::Split)); + static_assert(sizeof(HostSplit) == sizeof(DT::Split)); HostSplit h_split; RAFT_CUDA_TRY(cudaMemcpyAsync( &h_split, split.data().get(), sizeof(h_split), cudaMemcpyDeviceToHost, handle.get_stream())); @@ -1252,10 +1251,9 @@ TEST(RFEquivalentSplitRangeTest, ClassificationChoosesUpperMiddleBin) TEST(RFEquivalentSplitRangeTest, RegressionChoosesUpperMiddleBin) { - using DataT = float; - using IdxT = int; - constexpr IdxT len = 10; - constexpr IdxT n_bins = 6; + using DataT = float; + constexpr int len = 10; + constexpr int n_bins = 6; auto stream_pool = std::make_shared(1); raft::handle_t handle(rmm::cuda_stream_per_thread, stream_pool); @@ -1272,29 +1270,29 @@ TEST(RFEquivalentSplitRangeTest, RegressionChoosesUpperMiddleBin) thrust::device_vector hist(h_hist.begin(), h_hist.end()); thrust::device_vector quantiles(h_quantiles.begin(), h_quantiles.end()); - thrust::device_vector> split(1); + thrust::device_vector> split(1); thrust::device_vector mutex(1); - DT::RegressionObjectiveFunction objective(1, 1, CRITERION::MSE); + DT::RegressionObjectiveFunction objective(1, 1, CRITERION::MSE); objectiveGainKernel<<<1, 32, 0, handle.get_stream()>>>(hist.data().get(), quantiles.data().get(), split.data().get(), mutex.data().get(), objective, - IdxT{0}, + 0, len, n_bins); RAFT_CUDA_TRY(cudaGetLastError()); struct HostSplit { DataT quesval; - IdxT colid; + int colid; DataT best_metric_val; int nLeft; - IdxT split_start; - IdxT split_end; + int split_start; + int split_end; }; - static_assert(sizeof(HostSplit) == sizeof(DT::Split)); + static_assert(sizeof(HostSplit) == sizeof(DT::Split)); HostSplit h_split; RAFT_CUDA_TRY(cudaMemcpyAsync( &h_split, split.data().get(), sizeof(h_split), cudaMemcpyDeviceToHost, handle.get_stream())); @@ -1757,7 +1755,6 @@ class ObjectiveTest : public ::testing::TestWithParam { using ObjectiveT = typename ObjectiveConfig::ObjectiveT; typedef typename ObjectiveT::DataT DataT; typedef typename ObjectiveT::LabelT LabelT; - typedef typename ObjectiveT::IdxT IdxT; typedef typename ObjectiveT::BinT BinT; static constexpr auto eps_ = 10 * std::numeric_limits::epsilon(); @@ -2195,11 +2192,11 @@ class ObjectiveTest : public ::testing::TestWithParam { return DataT(0.0); } - auto NumLeftOfBin(std::vector const& cdf_hist, IdxT idx) + auto NumLeftOfBin(std::vector const& cdf_hist, int idx) { - auto count{IdxT(0)}; + auto count{int(0)}; for (auto c = 0; c < params.n_classes; ++c) { - count += static_cast(cdf_hist[params.max_n_bins * c + idx].Count()); + count += static_cast(cdf_hist[params.max_n_bins * c + idx].Count()); } return count; } @@ -2231,7 +2228,7 @@ class ObjectiveTest : public ::testing::TestWithParam { TEST(WeightedObjectiveEdgeCases, ClassificationRejectsZeroWeightChild) { - using ObjectiveT = ClassificationObjectiveFunction; + using ObjectiveT = ClassificationObjectiveFunction; WeightedClassificationBin hist[]{{1, 0.0}, {1, 0.0}, {0, 0.0}, {1, 1.0}}; CRITERION criteria[] = {CRITERION::GINI, CRITERION::ENTROPY}; @@ -2244,7 +2241,7 @@ TEST(WeightedObjectiveEdgeCases, ClassificationRejectsZeroWeightChild) TEST(WeightedObjectiveEdgeCases, RegressionRejectsZeroWeightChild) { - using ObjectiveT = RegressionObjectiveFunction; + using ObjectiveT = RegressionObjectiveFunction; WeightedRegressionBin hist[]{{0.0, 1, 0.0}, {2.0, 2, 1.0}}; CRITERION criteria[] = { CRITERION::MSE, CRITERION::POISSON, CRITERION::GAMMA, CRITERION::INVERSE_GAUSSIAN}; @@ -2306,28 +2303,28 @@ const std::vector gini_objective_test_parameters = { // mse objective test typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::MSE>> + ObjectiveTestConfig, CRITERION::MSE>> MSEObjectiveTestD; TEST_P(MSEObjectiveTestD, MSEObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, MSEObjectiveTestD, ::testing::ValuesIn(mse_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::MSE>> + ObjectiveTestConfig, CRITERION::MSE>> MSEObjectiveTestF; TEST_P(MSEObjectiveTestF, MSEObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, MSEObjectiveTestF, ::testing::ValuesIn(mse_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::MSE>> + ObjectiveTestConfig, CRITERION::MSE>> WeightedMSEObjectiveTestD; TEST_P(WeightedMSEObjectiveTestD, MSEObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedMSEObjectiveTestD, ::testing::ValuesIn(mse_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::MSE>> + ObjectiveTestConfig, CRITERION::MSE>> WeightedMSEObjectiveTestF; TEST_P(WeightedMSEObjectiveTestF, MSEObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, @@ -2336,28 +2333,28 @@ INSTANTIATE_TEST_CASE_P(RfTests, // poisson objective test typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::POISSON>> + ObjectiveTestConfig, CRITERION::POISSON>> PoissonObjectiveTestD; TEST_P(PoissonObjectiveTestD, poissonObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, PoissonObjectiveTestD, ::testing::ValuesIn(poisson_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::POISSON>> + ObjectiveTestConfig, CRITERION::POISSON>> PoissonObjectiveTestF; TEST_P(PoissonObjectiveTestF, poissonObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, PoissonObjectiveTestF, ::testing::ValuesIn(poisson_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::POISSON>> + ObjectiveTestConfig, CRITERION::POISSON>> WeightedPoissonObjectiveTestD; TEST_P(WeightedPoissonObjectiveTestD, poissonObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedPoissonObjectiveTestD, ::testing::ValuesIn(poisson_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::POISSON>> + ObjectiveTestConfig, CRITERION::POISSON>> WeightedPoissonObjectiveTestF; TEST_P(WeightedPoissonObjectiveTestF, poissonObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, @@ -2366,28 +2363,28 @@ INSTANTIATE_TEST_CASE_P(RfTests, // gamma objective test typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GAMMA>> + ObjectiveTestConfig, CRITERION::GAMMA>> GammaObjectiveTestD; TEST_P(GammaObjectiveTestD, GammaObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, GammaObjectiveTestD, ::testing::ValuesIn(gamma_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GAMMA>> + ObjectiveTestConfig, CRITERION::GAMMA>> GammaObjectiveTestF; TEST_P(GammaObjectiveTestF, GammaObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, GammaObjectiveTestF, ::testing::ValuesIn(gamma_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GAMMA>> + ObjectiveTestConfig, CRITERION::GAMMA>> WeightedGammaObjectiveTestD; TEST_P(WeightedGammaObjectiveTestD, GammaObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedGammaObjectiveTestD, ::testing::ValuesIn(gamma_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GAMMA>> + ObjectiveTestConfig, CRITERION::GAMMA>> WeightedGammaObjectiveTestF; TEST_P(WeightedGammaObjectiveTestF, GammaObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, @@ -2395,29 +2392,29 @@ INSTANTIATE_TEST_CASE_P(RfTests, ::testing::ValuesIn(gamma_objective_test_parameters)); // InvGauss objective test -typedef ObjectiveTest, - CRITERION::INVERSE_GAUSSIAN>> +typedef ObjectiveTest< + ObjectiveTestConfig, CRITERION::INVERSE_GAUSSIAN>> InverseGaussianObjectiveTestD; TEST_P(InverseGaussianObjectiveTestD, InverseGaussianObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, InverseGaussianObjectiveTestD, ::testing::ValuesIn(invgauss_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::INVERSE_GAUSSIAN>> + ObjectiveTestConfig, CRITERION::INVERSE_GAUSSIAN>> InverseGaussianObjectiveTestF; TEST_P(InverseGaussianObjectiveTestF, InverseGaussianObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, InverseGaussianObjectiveTestF, ::testing::ValuesIn(invgauss_objective_test_parameters)); -typedef ObjectiveTest, +typedef ObjectiveTest, CRITERION::INVERSE_GAUSSIAN>> WeightedInverseGaussianObjectiveTestD; TEST_P(WeightedInverseGaussianObjectiveTestD, InverseGaussianObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedInverseGaussianObjectiveTestD, ::testing::ValuesIn(invgauss_objective_test_parameters)); -typedef ObjectiveTest, - CRITERION::INVERSE_GAUSSIAN>> +typedef ObjectiveTest< + ObjectiveTestConfig, CRITERION::INVERSE_GAUSSIAN>> WeightedInverseGaussianObjectiveTestF; TEST_P(WeightedInverseGaussianObjectiveTestF, InverseGaussianObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, @@ -2426,28 +2423,28 @@ INSTANTIATE_TEST_CASE_P(RfTests, // entropy objective test typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::ENTROPY>> + ObjectiveTestConfig, CRITERION::ENTROPY>> EntropyObjectiveTestD; TEST_P(EntropyObjectiveTestD, entropyObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, EntropyObjectiveTestD, ::testing::ValuesIn(entropy_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::ENTROPY>> + ObjectiveTestConfig, CRITERION::ENTROPY>> EntropyObjectiveTestF; TEST_P(EntropyObjectiveTestF, entropyObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, EntropyObjectiveTestF, ::testing::ValuesIn(entropy_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::ENTROPY>> + ObjectiveTestConfig, CRITERION::ENTROPY>> WeightedEntropyObjectiveTestD; TEST_P(WeightedEntropyObjectiveTestD, entropyObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedEntropyObjectiveTestD, ::testing::ValuesIn(entropy_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::ENTROPY>> + ObjectiveTestConfig, CRITERION::ENTROPY>> WeightedEntropyObjectiveTestF; TEST_P(WeightedEntropyObjectiveTestF, entropyObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, @@ -2456,28 +2453,28 @@ INSTANTIATE_TEST_CASE_P(RfTests, // gini objective test typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GINI>> + ObjectiveTestConfig, CRITERION::GINI>> GiniObjectiveTestD; TEST_P(GiniObjectiveTestD, giniObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, GiniObjectiveTestD, ::testing::ValuesIn(gini_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GINI>> + ObjectiveTestConfig, CRITERION::GINI>> GiniObjectiveTestF; TEST_P(GiniObjectiveTestF, giniObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, GiniObjectiveTestF, ::testing::ValuesIn(gini_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GINI>> + ObjectiveTestConfig, CRITERION::GINI>> WeightedGiniObjectiveTestD; TEST_P(WeightedGiniObjectiveTestD, giniObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedGiniObjectiveTestD, ::testing::ValuesIn(gini_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GINI>> + ObjectiveTestConfig, CRITERION::GINI>> WeightedGiniObjectiveTestF; TEST_P(WeightedGiniObjectiveTestF, giniObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, From 582b3cc0e1a41096c4b64ba846a4a91f8389b34a Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Mon, 6 Jul 2026 11:08:11 +0200 Subject: [PATCH 03/14] Use int64_t for RF internal indexes --- cpp/include/cuml/tree/decisiontree.hpp | 3 +- cpp/include/cuml/tree/flatnode.h | 7 +- .../batched-levelalgo/builder.cuh | 83 ++++++++++--------- .../decisiontree/batched-levelalgo/dataset.h | 14 ++-- .../kernels/builder_kernels.cuh | 54 ++++++------ .../kernels/builder_kernels_impl.cuh | 63 +++++++------- .../kernels/classification-double.cu | 12 +-- .../kernels/classification-float.cu | 12 +-- .../batched-levelalgo/kernels/node-split.cu | 16 ++-- .../kernels/regression-double.cu | 12 +-- .../kernels/regression-float.cu | 12 +-- .../kernels/weighted-classification-double.cu | 12 +-- .../kernels/weighted-classification-float.cu | 12 +-- .../kernels/weighted-regression-double.cu | 12 +-- .../kernels/weighted-regression-float.cu | 12 +-- .../batched-levelalgo/objectives.cuh | 77 ++++++++++++----- .../decisiontree/batched-levelalgo/split.cuh | 36 ++++---- cpp/src/decisiontree/decisiontree.cuh | 18 ++-- cpp/src/randomforest/randomforest.cuh | 9 +- cpp/tests/sg/rf_test.cu | 33 ++++---- 20 files changed, 282 insertions(+), 227 deletions(-) diff --git a/cpp/include/cuml/tree/decisiontree.hpp b/cpp/include/cuml/tree/decisiontree.hpp index abbcf7b1e6..1a015b78e7 100644 --- a/cpp/include/cuml/tree/decisiontree.hpp +++ b/cpp/include/cuml/tree/decisiontree.hpp @@ -10,6 +10,7 @@ #include +#include #include #include @@ -96,7 +97,7 @@ struct TreeMetaDataNode { int leaf_counter; double train_time; std::vector vector_leaf; - std::vector> sparsetree; + std::vector> sparsetree; int num_outputs; }; diff --git a/cpp/include/cuml/tree/flatnode.h b/cpp/include/cuml/tree/flatnode.h index 6cfaf840ac..6467b628fc 100644 --- a/cpp/include/cuml/tree/flatnode.h +++ b/cpp/include/cuml/tree/flatnode.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2019-2021, NVIDIA CORPORATION. + * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION. * SPDX-License-Identifier: Apache-2.0 */ @@ -48,12 +48,11 @@ struct SparseTreeNode { FLATNODE_HD static SparseTreeNode CreateSplitNode( IdxT colid, DataT quesval, DataT best_metric_val, int64_t left_child_id, IdxT instance_count) { - return SparseTreeNode{ - colid, quesval, best_metric_val, left_child_id, instance_count}; + return SparseTreeNode{colid, quesval, best_metric_val, left_child_id, instance_count}; } FLATNODE_HD static SparseTreeNode CreateLeafNode(IdxT instance_count) { - return SparseTreeNode{0, 0, 0, -1, instance_count}; + return SparseTreeNode{0, 0, 0, -1, instance_count}; } FLATNODE_HD bool IsLeaf() const { return left_child_id == -1; } bool operator==(const SparseTreeNode& other) const diff --git a/cpp/src/decisiontree/batched-levelalgo/builder.cuh b/cpp/src/decisiontree/batched-levelalgo/builder.cuh index b436aa412f..5f400246af 100644 --- a/cpp/src/decisiontree/batched-levelalgo/builder.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/builder.cuh @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -37,14 +38,17 @@ namespace DT { */ template class NodeQueue { - using NodeT = SparseTreeNode; + using NodeT = SparseTreeNode; const DecisionTreeParams params; std::shared_ptr> tree; std::vector node_instances_; std::deque work_items_; public: - NodeQueue(DecisionTreeParams params, size_t max_nodes, size_t sampled_rows, int num_outputs) + NodeQueue(DecisionTreeParams params, + size_t max_nodes, + size_t sampled_rows, + std::int64_t num_outputs) : params(params), tree(std::make_shared>()) { tree->num_outputs = num_outputs; @@ -79,7 +83,7 @@ class NodeQueue { bool IsExpandable(const NodeT& n, int depth) { if (depth >= params.max_depth) return false; - if (int(n.InstanceCount()) < params.min_samples_split) return false; + if (n.InstanceCount() < params.min_samples_split) return false; if (params.max_leaves != -1 && tree->leaf_counter >= params.max_leaves) return false; return true; } @@ -141,7 +145,7 @@ struct Builder { typedef typename ObjectiveT::DataT DataT; typedef typename ObjectiveT::LabelT LabelT; typedef typename ObjectiveT::BinT BinT; - typedef SparseTreeNode NodeT; + typedef SparseTreeNode NodeT; typedef Split SplitT; typedef Dataset DatasetT; typedef Quantiles QuantilesT; @@ -159,11 +163,11 @@ struct Builder { /** quantiles */ QuantilesT quantiles; /** Tree index */ - int treeid; + std::int64_t treeid; /** Seed used for randomization */ uint64_t seed; /** number of nodes created in the current batch */ - int* n_nodes; + std::int64_t* n_nodes; /** buffer of segmented histograms*/ BinT* histograms; /** threadblock arrival count */ @@ -179,16 +183,16 @@ struct Builder { /** host AOS to map CTA blocks along dimx to nodes of a batch */ WorkloadInfo* h_workload_info; /** maximum CTA blocks along dimx */ - int max_blocks_dimx = 0; + std::int64_t max_blocks_dimx = 0; /** host array of splits */ SplitT* h_splits; /** number of blocks used to parallelize column-wise computations */ int n_blks_for_cols = 10; /** Memory alignment value */ const size_t align_value = 512; - int* column_samples; + std::int64_t* column_samples; /** temporary row IDs for row-wise out-of-place partitioning */ - int* partition_row_ids; + std::int64_t* partition_row_ids; /** rmm device workspace buffer */ rmm::device_uvector d_buff; /** pinned host buffer to store the trained nodes */ @@ -196,16 +200,16 @@ struct Builder { Builder(const raft::handle_t& handle, cudaStream_t s, - int treeid, + std::int64_t treeid, uint64_t seed, const DecisionTreeParams& p, const DataT* data, const LabelT* labels, const double* sample_weight, - int n_rows, - int n_cols, - rmm::device_uvector* row_ids, - int n_classes, + std::int64_t n_rows, + std::int64_t n_cols, + rmm::device_uvector* row_ids, + std::int64_t n_classes, const QuantilesT& q) : handle(handle), builder_stream(s), @@ -217,8 +221,8 @@ struct Builder { sample_weight, n_rows, n_cols, - int(row_ids->size()), - max(1, int(params.max_features * n_cols)), + std::int64_t(row_ids->size()), + max(std::int64_t(1), std::int64_t(params.max_features * n_cols)), row_ids->data(), n_classes}, quantiles(q), @@ -274,7 +278,7 @@ struct Builder { size_t max_len_histograms = max_batch * params.max_n_bins * n_blks_for_cols * dataset.num_outputs; - d_wsize += calculateAlignedBytes(sizeof(int)); // n_nodes + d_wsize += calculateAlignedBytes(sizeof(std::int64_t)); // n_nodes d_wsize += calculateAlignedBytes(sizeof(BinT) * max_len_histograms); // histograms d_wsize += calculateAlignedBytes(sizeof(int) * max_batch * n_blks_for_cols); // done_count d_wsize += calculateAlignedBytes(sizeof(int) * max_batch); // mutex @@ -282,9 +286,10 @@ struct Builder { d_wsize += calculateAlignedBytes(sizeof(NodeWorkItem) * max_batch); // d_work_Items d_wsize += // workload_info calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + d_wsize += calculateAlignedBytes(sizeof(std::int64_t) * max_batch * + dataset.n_sampled_cols); // column_samples d_wsize += - calculateAlignedBytes(sizeof(int) * max_batch * dataset.n_sampled_cols); // column_samples - d_wsize += calculateAlignedBytes(sizeof(int) * dataset.n_sampled_rows); // partition row IDs + calculateAlignedBytes(sizeof(std::int64_t) * dataset.n_sampled_rows); // partition row IDs // all nodes in the tree h_wsize += // h_workload_info @@ -310,8 +315,8 @@ struct Builder { size_t max_len_histograms = max_batch * (params.max_n_bins) * n_blks_for_cols * dataset.num_outputs; // device - n_nodes = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(int)); + n_nodes = reinterpret_cast(d_wspace); + d_wspace += calculateAlignedBytes(sizeof(std::int64_t)); histograms = reinterpret_cast(d_wspace); d_wspace += calculateAlignedBytes(sizeof(BinT) * max_len_histograms); done_count = reinterpret_cast(d_wspace); @@ -324,10 +329,10 @@ struct Builder { d_wspace += calculateAlignedBytes(sizeof(NodeWorkItem) * max_batch); workload_info = reinterpret_cast(d_wspace); d_wspace += calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); - column_samples = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(int) * max_batch * dataset.n_sampled_cols); - partition_row_ids = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(int) * dataset.n_sampled_rows); + column_samples = reinterpret_cast(d_wspace); + d_wspace += calculateAlignedBytes(sizeof(std::int64_t) * max_batch * dataset.n_sampled_cols); + partition_row_ids = reinterpret_cast(d_wspace); + d_wspace += calculateAlignedBytes(sizeof(std::int64_t) * dataset.n_sampled_rows); RAFT_CUDA_TRY( cudaMemsetAsync(done_count, 0, sizeof(int) * max_batch * n_col_blks, builder_stream)); @@ -388,20 +393,20 @@ struct Builder { { raft::common::nvtx::range fun_scope("Builder::doSplit @builder.cuh [batched-levelalgo]"); // start fresh on the number of *new* nodes created in this batch - RAFT_CUDA_TRY(cudaMemsetAsync(n_nodes, 0, sizeof(int), builder_stream)); + RAFT_CUDA_TRY(cudaMemsetAsync(n_nodes, 0, sizeof(std::int64_t), builder_stream)); - const int original_n_sampled_cols = dataset.n_sampled_cols; + const std::int64_t original_n_sampled_cols = dataset.n_sampled_cols; ASSERT(original_n_sampled_cols > 0 && original_n_sampled_cols <= dataset.N, "n_sampled_cols must be in [1, n_cols]"); const std::size_t max_sampling_rounds = std::size_t((dataset.N + original_n_sampled_cols - 1) / original_n_sampled_cols); struct HostSplit { DataT quesval; - int colid; + std::int64_t colid; DataT best_metric_val; - int nLeft; - int split_start; - int split_end; + std::int64_t nLeft; + std::int64_t split_start; + std::int64_t split_end; }; static_assert(sizeof(HostSplit) == sizeof(SplitT)); static_assert(alignof(HostSplit) == alignof(SplitT)); @@ -423,8 +428,8 @@ struct Builder { // Match sklearn's behavior of searching beyond max_features when the // sampled features do not yield a valid split. for (std::size_t round = 0; !active_items.empty() && round < max_sampling_rounds; ++round) { - int sample_offset = int(round) * original_n_sampled_cols; - dataset.n_sampled_cols = std::min(original_n_sampled_cols, dataset.N - sample_offset); + std::int64_t sample_offset = static_cast(round) * original_n_sampled_cols; + dataset.n_sampled_cols = std::min(original_n_sampled_cols, dataset.N - sample_offset); computeBestSplits(active_items, seed, sample_offset); std::vector retry_items; @@ -478,7 +483,7 @@ struct Builder { void computeBestSplits(const std::vector& work_items, uint64_t sampling_seed, - int sample_offset) + std::int64_t sample_offset) { initSplit(splits, work_items.size(), builder_stream); RAFT_CUDA_TRY(cudaMemsetAsync( @@ -489,7 +494,7 @@ struct Builder { sampleFeatures(work_items, sampling_seed, sample_offset); - for (int c = 0; c < dataset.n_sampled_cols; c += n_blks_for_cols) { + for (std::int64_t c = 0; c < dataset.n_sampled_cols; c += n_blks_for_cols) { computeSplit(c, n_blocks_dimx, n_large_nodes); RAFT_CUDA_TRY(cudaPeekAtLastError()); } @@ -499,7 +504,7 @@ struct Builder { void sampleFeatures(const std::vector& work_items, uint64_t sampling_seed, - int sample_offset) + std::int64_t sample_offset) { raft::common::nvtx::range fun_scope("feature-sampling"); sample_features(column_samples, @@ -541,7 +546,7 @@ struct Builder { return dynamic_smem_size; } - void computeSplit(int col, size_t n_blocks_dimx, size_t n_large_nodes) + void computeSplit(std::int64_t col, size_t n_blocks_dimx, size_t n_large_nodes) { // if no instances to split, return if (n_blocks_dimx == 0) return; @@ -549,13 +554,13 @@ struct Builder { auto n_bins = params.max_n_bins; auto n_classes = dataset.num_outputs; // if columns left to be processed lesser than `n_blks_for_cols`, shrink the blocks along dimy - auto n_blocks_dimy = std::min(n_blks_for_cols, dataset.n_sampled_cols - col); + auto n_blocks_dimy = std::min(n_blks_for_cols, dataset.n_sampled_cols - col); // compute required dynamic shared memory auto smem_size = computeSplitSmemSize(); dim3 grid(n_blocks_dimx, n_blocks_dimy, 1); // required total length (in bins) of the global segmented histograms over all // classes, features and (large)nodes. - int len_histograms = n_bins * n_classes * n_blocks_dimy * n_large_nodes; + std::int64_t len_histograms = n_bins * n_classes * n_blocks_dimy * n_large_nodes; RAFT_CUDA_TRY(cudaMemsetAsync(histograms, 0, sizeof(BinT) * len_histograms, builder_stream)); // create the objective function object ObjectiveT objective(dataset.num_outputs, params.min_samples_leaf, params.split_criterion); diff --git a/cpp/src/decisiontree/batched-levelalgo/dataset.h b/cpp/src/decisiontree/batched-levelalgo/dataset.h index d3f55ea1b1..5df5ec9f23 100644 --- a/cpp/src/decisiontree/batched-levelalgo/dataset.h +++ b/cpp/src/decisiontree/batched-levelalgo/dataset.h @@ -5,6 +5,8 @@ #pragma once +#include + namespace ML { namespace DT { @@ -17,17 +19,17 @@ struct Dataset { /** optional input sample weights */ const double* sample_weight; /** total rows in dataset */ - int M; + std::int64_t M; /** total cols in dataset */ - int N; + std::int64_t N; /** total sampled rows in dataset */ - int n_sampled_rows; + std::int64_t n_sampled_rows; /** total sampled cols in dataset */ - int n_sampled_cols; + std::int64_t n_sampled_cols; /** indices of sampled rows */ - int* row_ids; + std::int64_t* row_ids; /** Number of classes or regression outputs*/ - int num_outputs; + std::int64_t num_outputs; }; } // namespace DT diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh index 9fcfc3f821..2aa71b0567 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh @@ -18,6 +18,8 @@ #include #include +#include + namespace ML { namespace DT { @@ -39,16 +41,18 @@ struct NodeWorkItem { * computeSplit kernels of classification and regression */ struct WorkloadInfo { - int nodeid; // Node in the batch on which the threadblock needs to work - int large_nodeid; // counts only large nodes (nodes that require more than one block along x-dim - // for histogram calculation) - int offset_blockid; // Offset threadblock id among all the blocks that are - // working on this node - int num_blocks; // Total number of blocks that are working on the node + std::int64_t nodeid; // Node in the batch on which the threadblock needs to work + std::int64_t large_nodeid; // counts only large nodes (nodes that require more than one block + // along x-dim for histogram calculation) + std::int64_t offset_blockid; // Offset threadblock id among all the blocks that are + // working on this node + std::int64_t num_blocks; // Total number of blocks that are working on the node }; template -HDI bool SplitPartitionNotValid(const SplitT& split, int min_samples_leaf, std::size_t num_rows) +HDI bool SplitPartitionNotValid(const SplitT& split, + std::int64_t min_samples_leaf, + std::size_t num_rows) { auto n_left = static_cast(split.nLeft); return split.colid == -1 || split.nLeft < min_samples_leaf || n_left > num_rows || @@ -58,7 +62,7 @@ HDI bool SplitPartitionNotValid(const SplitT& split, int min_samples_leaf, std:: template HDI bool SplitNotValid(const SplitT& split, DataT min_impurity_decrease, - int min_samples_leaf, + std::int64_t min_samples_leaf, std::size_t num_rows) { return split.best_metric_val <= min_impurity_decrease || @@ -72,14 +76,14 @@ DI OutT* alignPointer(InT dataset) return reinterpret_cast(raft::alignTo(reinterpret_cast(dataset), sizeof(OutT))); } -inline void sample_features(int* column_samples, +inline void sample_features(std::int64_t* column_samples, const NodeWorkItem* work_items, size_t work_items_size, - int treeid, + std::int64_t treeid, uint64_t seed, - int sample_offset, - int n, - int k, + std::int64_t sample_offset, + std::int64_t n, + std::int64_t k, cudaStream_t stream) { auto n_column_samples = work_items_size * size_t(k); @@ -89,27 +93,27 @@ inline void sample_features(int* column_samples, counting, counting + n_column_samples, [=] __device__(size_t sample_idx) { - auto node_idx = sample_idx / size_t(k); - int column_index = static_cast(sample_idx % size_t(k)); + auto node_idx = sample_idx / size_t(k); + auto column_index = static_cast(sample_idx % size_t(k)); - const uint32_t nodeid = work_items[node_idx].idx; - uint32_t rng_seed = fnv1a32_hash(seed, treeid, nodeid); + const auto nodeid = work_items[node_idx].idx; + uint32_t rng_seed = fnv1a32_hash(seed, treeid, nodeid); - cuda::shuffle_iterator shuffled_features( + cuda::shuffle_iterator shuffled_features( n, cuda::std::minstd_rand(rng_seed), sample_offset); column_samples[sample_idx] = shuffled_features[column_index]; }); } template -void launchNodeSplitKernel(const int min_samples_leaf, +void launchNodeSplitKernel(const std::int64_t min_samples_leaf, const DataT min_impurity_decrease, const Dataset& dataset, const NodeWorkItem* work_items, const Split* splits, const WorkloadInfo* workload_info, size_t n_blocks_dimx, - int* partition_row_ids, + std::int64_t* partition_row_ids, cudaStream_t builder_stream); template @@ -124,18 +128,18 @@ void launchLeafKernel(ObjectiveT objective, template void launchComputeSplitKernel(typename ObjectiveT::BinT* histograms, int n_bins, - int min_samples_split, - int max_leaves, + std::int64_t min_samples_split, + std::int64_t max_leaves, const Dataset& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - int colStart, - const int* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* done_count, int* mutex, volatile Split* splits, ObjectiveT& objective, - int treeid, + std::int64_t treeid, const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh index ed04c616aa..2658e34173 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh @@ -23,6 +23,7 @@ #include #include +#include #include namespace ML { @@ -31,7 +32,7 @@ namespace DT { static constexpr int TPB_DEFAULT = 128; struct NodeSplitPartitionState { - int left_count; + std::int64_t left_count; bool valid_row; bool goes_left; }; @@ -54,7 +55,7 @@ struct NodeSplitPartitionWriter { const NodeWorkItem* work_items; const Split* splits; const WorkloadInfo* workload_info; - int* partition_row_ids; + std::int64_t* partition_row_ids; __host__ __device__ void operator()(std::ptrdiff_t index, NodeSplitPartitionState state) const { @@ -69,9 +70,9 @@ struct NodeSplitPartitionWriter { const auto range_start = work_item.instances.begin; const auto range_pos = std::size_t(workload_info_cta.offset_blockid) * TPB + slot % TPB; - const auto row = dataset.row_ids[range_start + range_pos]; - const auto rank = - state.goes_left ? state.left_count - int(1) : int(range_pos) - state.left_count; + const auto row = dataset.row_ids[range_start + range_pos]; + const auto rank = state.goes_left ? state.left_count - std::int64_t(1) + : static_cast(range_pos) - state.left_count; const auto out_idx = range_start + (state.goes_left ? rank : split.nLeft + rank); partition_row_ids[out_idx] = row; } @@ -80,13 +81,13 @@ struct NodeSplitPartitionWriter { // Copy back only ranges for nodes that actually split. Leaf/invalid nodes keep // their existing row-id order because the scan writer skips them too. template -static __global__ void nodeSplitCopyBackKernel(const int min_samples_leaf, +static __global__ void nodeSplitCopyBackKernel(const std::int64_t min_samples_leaf, const DataT min_impurity_decrease, const Dataset dataset, const NodeWorkItem* work_items, const Split* splits, const WorkloadInfo* workload_info, - const int* partition_row_ids) + const std::int64_t* partition_row_ids) { const auto workload_info_cta = workload_info[blockIdx.x]; const auto nid = workload_info_cta.nodeid; @@ -106,14 +107,14 @@ static __global__ void nodeSplitCopyBackKernel(const int min_samples_leaf, } template -void launchNodeSplitKernel(const int min_samples_leaf, +void launchNodeSplitKernel(const std::int64_t min_samples_leaf, const DataT min_impurity_decrease, const Dataset& dataset, const NodeWorkItem* work_items, const Split* splits, const WorkloadInfo* workload_info, size_t n_blocks_dimx, - int* partition_row_ids, + std::int64_t* partition_row_ids, cudaStream_t builder_stream) { if (n_blocks_dimx == 0) return; @@ -133,18 +134,18 @@ void launchNodeSplitKernel(const int min_samples_leaf, const auto work_item = work_items[nid]; const auto split = splits[nid]; if (SplitNotValid(split, min_impurity_decrease, min_samples_leaf, work_item.instances.count)) { - return NodeSplitPartitionState{int(0), false, false}; + return NodeSplitPartitionState{std::int64_t(0), false, false}; } const auto range_pos = std::size_t(workload_info_cta.offset_blockid) * TPB + slot % TPB; if (range_pos >= work_item.instances.count) { - return NodeSplitPartitionState{int(0), false, false}; + return NodeSplitPartitionState{std::int64_t(0), false, false}; } const auto row = dataset.row_ids[work_item.instances.begin + range_pos]; const auto col_idx = std::size_t(split.colid) * dataset.M + row; const auto goes_left = dataset.data[col_idx] <= split.quesval; - return NodeSplitPartitionState{goes_left ? int(1) : int(0), true, goes_left}; + return NodeSplitPartitionState{goes_left ? std::int64_t(1) : std::int64_t(0), true, goes_left}; }; // The scan input is a stream of per-slot partition states keyed by node id. @@ -160,7 +161,7 @@ void launchNodeSplitKernel(const int min_samples_leaf, node_keys + n_slots, partition_states, partition_writer, - thrust::equal_to{}, + thrust::equal_to{}, NodeSplitPartitionScanOp{}); // The original row_ids buffer remains the source during the scan, so copy back after it finishes. @@ -253,18 +254,18 @@ DI BinT pdf_to_cdf(BinT* shared_histogram, int n_bins) template static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, int max_n_bins, - int min_samples_split, - int max_leaves, + std::int64_t min_samples_split, + std::int64_t max_leaves, const Dataset dataset, const Quantiles quantiles, const NodeWorkItem* work_items, - int colStart, - const int* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* done_count, int* mutex, volatile Split* splits, ObjectiveT objective, - int treeid, + std::int64_t treeid, const WorkloadInfo* workload_info, uint64_t seed) { @@ -278,18 +279,18 @@ static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, // Read workload info for this block WorkloadInfo workload_info_cta = workload_info[blockIdx.x]; - int nid = workload_info_cta.nodeid; - int large_nid = workload_info_cta.large_nodeid; + auto nid = workload_info_cta.nodeid; + auto large_nid = workload_info_cta.large_nodeid; const auto work_item = work_items[nid]; auto range_start = work_item.instances.begin; auto range_len = work_item.instances.count; - int offset_blockid = workload_info_cta.offset_blockid; - int num_blocks = workload_info_cta.num_blocks; + auto offset_blockid = workload_info_cta.offset_blockid; + auto num_blocks = workload_info_cta.num_blocks; // obtaining the feature to test split on - int colIndex = colStart + blockIdx.y; - int col = column_samples[nid * dataset.n_sampled_cols + colIndex]; + auto colIndex = colStart + blockIdx.y; + auto col = column_samples[nid * dataset.n_sampled_cols + colIndex]; // getting the n_bins for that feature int n_bins = quantiles.n_bins_array[col]; @@ -299,8 +300,8 @@ static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, auto* shared_histogram = alignPointer(smem); auto* shared_quantiles = alignPointer(shared_histogram + shared_histogram_len); auto* shared_done = alignPointer(shared_quantiles + n_bins); - int stride = blockDim.x * num_blocks; - int tid = threadIdx.x + offset_blockid * blockDim.x; + auto stride = blockDim.x * num_blocks; + auto tid = threadIdx.x + offset_blockid * blockDim.x; // populating shared memory with initial values for (int i = threadIdx.x; i < shared_histogram_len; i += blockDim.x) @@ -386,18 +387,18 @@ static __global__ void computeSplitKernel(typename ObjectiveT::BinT* histograms, template void launchComputeSplitKernel(typename ObjectiveT::BinT* histograms, int max_n_bins, - int min_samples_split, - int max_leaves, + std::int64_t min_samples_split, + std::int64_t max_leaves, const Dataset& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - int colStart, - const int* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* done_count, int* mutex, volatile Split* splits, ObjectiveT& objective, - int treeid, + std::int64_t treeid, const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu index a7ab7de6b9..b7ac6459fa 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu @@ -14,7 +14,7 @@ using LabelT = int; using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -31,18 +31,18 @@ template void launchLeafKernel( template void launchComputeSplitKernel( BinT* histograms, int n_bins, - int min_samples_split, - int max_leaves, + std::int64_t min_samples_split, + std::int64_t max_leaves, const DatasetT& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - int colStart, - const int* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* done_count, int* mutex, volatile Split* splits, ObjectiveT& objective, - int treeid, + std::int64_t treeid, const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu index bd60a5a9c0..1ebefa6c28 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu @@ -14,7 +14,7 @@ using LabelT = int; using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -31,18 +31,18 @@ template void launchLeafKernel( template void launchComputeSplitKernel( BinT* histograms, int n_bins, - int min_samples_split, - int max_leaves, + std::int64_t min_samples_split, + std::int64_t max_leaves, const DatasetT& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - int colStart, - const int* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* done_count, int* mutex, volatile Split* splits, ObjectiveT& objective, - int treeid, + std::int64_t treeid, const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu index bdf6c2c6aa..cf83a5a807 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu @@ -9,48 +9,48 @@ namespace ML { namespace DT { // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel(const int min_samples_leaf, +template void launchNodeSplitKernel(const std::int64_t min_samples_leaf, const float min_impurity_decrease, const Dataset& dataset, const NodeWorkItem* work_items, const Split* splits, const WorkloadInfo* workload_info, size_t n_blocks_dimx, - int* partition_row_ids, + std::int64_t* partition_row_ids, cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel(const int min_samples_leaf, +template void launchNodeSplitKernel(const std::int64_t min_samples_leaf, const double min_impurity_decrease, const Dataset& dataset, const NodeWorkItem* work_items, const Split* splits, const WorkloadInfo* workload_info, size_t n_blocks_dimx, - int* partition_row_ids, + std::int64_t* partition_row_ids, cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel(const int min_samples_leaf, +template void launchNodeSplitKernel(const std::int64_t min_samples_leaf, const float min_impurity_decrease, const Dataset& dataset, const NodeWorkItem* work_items, const Split* splits, const WorkloadInfo* workload_info, size_t n_blocks_dimx, - int* partition_row_ids, + std::int64_t* partition_row_ids, cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchNodeSplitKernel( - const int min_samples_leaf, + const std::int64_t min_samples_leaf, const double min_impurity_decrease, const Dataset& dataset, const NodeWorkItem* work_items, const Split* splits, const WorkloadInfo* workload_info, size_t n_blocks_dimx, - int* partition_row_ids, + std::int64_t* partition_row_ids, cudaStream_t builder_stream); } // namespace DT diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu index 9b08772359..ca3e5906c5 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu @@ -14,7 +14,7 @@ using LabelT = double; using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -31,18 +31,18 @@ template void launchLeafKernel( template void launchComputeSplitKernel( BinT* histograms, int n_bins, - int min_samples_split, - int max_leaves, + std::int64_t min_samples_split, + std::int64_t max_leaves, const DatasetT& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - int colStart, - const int* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* done_count, int* mutex, volatile Split* splits, ObjectiveT& objective, - int treeid, + std::int64_t treeid, const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu index 05b88c76b3..b3ff8a1bb8 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu @@ -14,7 +14,7 @@ using LabelT = float; using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -31,18 +31,18 @@ template void launchLeafKernel( template void launchComputeSplitKernel( BinT* histograms, int n_bins, - int min_samples_split, - int max_leaves, + std::int64_t min_samples_split, + std::int64_t max_leaves, const DatasetT& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - int colStart, - const int* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* done_count, int* mutex, volatile Split* splits, ObjectiveT& objective, - int treeid, + std::int64_t treeid, const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu index ceb7943372..8d2404abdb 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu @@ -14,7 +14,7 @@ using LabelT = int; using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -31,18 +31,18 @@ template void launchLeafKernel( template void launchComputeSplitKernel( BinT* histograms, int n_bins, - int min_samples_split, - int max_leaves, + std::int64_t min_samples_split, + std::int64_t max_leaves, const DatasetT& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - int colStart, - const int* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* done_count, int* mutex, volatile Split* splits, ObjectiveT& objective, - int treeid, + std::int64_t treeid, const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu index fe4bf612ef..feac87d774 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu @@ -14,7 +14,7 @@ using LabelT = int; using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -31,18 +31,18 @@ template void launchLeafKernel( template void launchComputeSplitKernel( BinT* histograms, int n_bins, - int min_samples_split, - int max_leaves, + std::int64_t min_samples_split, + std::int64_t max_leaves, const DatasetT& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - int colStart, - const int* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* done_count, int* mutex, volatile Split* splits, ObjectiveT& objective, - int treeid, + std::int64_t treeid, const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu index bb8f00f2b1..3e54d8f831 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu @@ -14,7 +14,7 @@ using LabelT = double; using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -31,18 +31,18 @@ template void launchLeafKernel( template void launchComputeSplitKernel( BinT* histograms, int n_bins, - int min_samples_split, - int max_leaves, + std::int64_t min_samples_split, + std::int64_t max_leaves, const DatasetT& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - int colStart, - const int* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* done_count, int* mutex, volatile Split* splits, ObjectiveT& objective, - int treeid, + std::int64_t treeid, const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu index 61336064f2..eb7c095d63 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu @@ -14,7 +14,7 @@ using LabelT = float; using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( @@ -31,18 +31,18 @@ template void launchLeafKernel( template void launchComputeSplitKernel( BinT* histograms, int n_bins, - int min_samples_split, - int max_leaves, + std::int64_t min_samples_split, + std::int64_t max_leaves, const DatasetT& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - int colStart, - const int* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* done_count, int* mutex, volatile Split* splits, ObjectiveT& objective, - int treeid, + std::int64_t treeid, const WorkloadInfo* workload_info, uint64_t seed, dim3 grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/objectives.cuh b/cpp/src/decisiontree/batched-levelalgo/objectives.cuh index eaaa467504..a39c0ae967 100644 --- a/cpp/src/decisiontree/batched-levelalgo/objectives.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/objectives.cuh @@ -11,6 +11,7 @@ #include +#include #include #include @@ -25,8 +26,8 @@ class ClassificationObjectiveFunction { static constexpr bool weighted = weighted_; private: - int nclasses; - int min_samples_leaf; + std::int64_t nclasses; + std::int64_t min_samples_leaf; CRITERION criterion; HDI double WeightAt(BinT const* hist, int i, int n_bins) const @@ -38,7 +39,8 @@ class ClassificationObjectiveFunction { return weight; } - HDI DataT GiniGain(BinT const* hist, int i, int n_bins, int, int, int) const + HDI DataT + GiniGain(BinT const* hist, int i, int n_bins, std::int64_t, std::int64_t, std::int64_t) const { constexpr DataT One = DataT(1.0); auto total_weight = WeightAt(hist, n_bins - 1, n_bins); @@ -73,7 +75,8 @@ class ClassificationObjectiveFunction { return gain; } - HDI DataT EntropyGain(BinT const* hist, int i, int n_bins, int, int, int) const + HDI DataT + EntropyGain(BinT const* hist, int i, int n_bins, std::int64_t, std::int64_t, std::int64_t) const { auto total_weight = WeightAt(hist, n_bins - 1, n_bins); auto left_weight = WeightAt(hist, i, n_bins); @@ -113,7 +116,12 @@ class ClassificationObjectiveFunction { } public: - HDI DataT GainPerSplit(BinT const* hist, int i, int n_bins, int len, int nLeft, int nRight) const + HDI DataT GainPerSplit(BinT const* hist, + int i, + int n_bins, + std::int64_t len, + std::int64_t nLeft, + std::int64_t nRight) const { if (nLeft < min_samples_leaf || nRight < min_samples_leaf) return -std::numeric_limits::max(); @@ -125,16 +133,22 @@ class ClassificationObjectiveFunction { } } - HDI ClassificationObjectiveFunction(int nclasses, int min_samples_leaf, CRITERION criterion) + HDI ClassificationObjectiveFunction(std::int64_t nclasses, + std::int64_t min_samples_leaf, + CRITERION criterion) : nclasses(nclasses), min_samples_leaf(min_samples_leaf), criterion(criterion) { } - DI int NumClasses() const { return nclasses; } + DI std::int64_t NumClasses() const { return nclasses; } template - DI void IncrementHistogram( - BinT* histogram, int n_bins, int bin, LabelT label, const DatasetT& dataset, int row) const + DI void IncrementHistogram(BinT* histogram, + int n_bins, + int bin, + LabelT label, + const DatasetT& dataset, + std::int64_t row) const { double weight = 1.0; if constexpr (weighted) { @@ -143,8 +157,11 @@ class ClassificationObjectiveFunction { BinT::IncrementHistogram(histogram, n_bins, bin, label, weight); } - DI Split Gain( - BinT const* shist, DataT const* squantiles, int col, int len, int n_bins) const + DI Split Gain(BinT const* shist, + DataT const* squantiles, + std::int64_t col, + std::int64_t len, + int n_bins) const { Split sp; for (int i = threadIdx.x; i < n_bins; i += blockDim.x) { @@ -187,11 +204,12 @@ class RegressionObjectiveFunction { static constexpr bool weighted = weighted_; private: - int min_samples_leaf; + std::int64_t min_samples_leaf; CRITERION criterion; static constexpr auto eps_ = 10 * std::numeric_limits::epsilon(); - HDI DataT MSEGain(BinT const* hist, int i, int n_bins, int, int, int) const + HDI DataT + MSEGain(BinT const* hist, int i, int n_bins, std::int64_t, std::int64_t, std::int64_t) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -213,7 +231,8 @@ class RegressionObjectiveFunction { return gain; } - HDI DataT PoissonGain(BinT const* hist, int i, int n_bins, int, int, int) const + HDI DataT + PoissonGain(BinT const* hist, int i, int n_bins, std::int64_t, std::int64_t, std::int64_t) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -240,7 +259,8 @@ class RegressionObjectiveFunction { return gain; } - HDI DataT GammaGain(BinT const* hist, int i, int n_bins, int, int, int) const + HDI DataT + GammaGain(BinT const* hist, int i, int n_bins, std::int64_t, std::int64_t, std::int64_t) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -267,7 +287,8 @@ class RegressionObjectiveFunction { return gain; } - HDI DataT InverseGaussianGain(BinT const* hist, int i, int n_bins, int, int, int) const + HDI DataT InverseGaussianGain( + BinT const* hist, int i, int n_bins, std::int64_t, std::int64_t, std::int64_t) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -294,7 +315,12 @@ class RegressionObjectiveFunction { } public: - HDI DataT GainPerSplit(BinT const* hist, int i, int n_bins, int len, int nLeft, int nRight) const + HDI DataT GainPerSplit(BinT const* hist, + int i, + int n_bins, + std::int64_t len, + std::int64_t nLeft, + std::int64_t nRight) const { if (nLeft < min_samples_leaf || nRight < min_samples_leaf) return -std::numeric_limits::max(); @@ -309,7 +335,7 @@ class RegressionObjectiveFunction { } } - HDI RegressionObjectiveFunction(int, int min_samples_leaf, CRITERION criterion) + HDI RegressionObjectiveFunction(std::int64_t, std::int64_t min_samples_leaf, CRITERION criterion) : min_samples_leaf(min_samples_leaf), criterion(criterion) { } @@ -317,8 +343,12 @@ class RegressionObjectiveFunction { DI int NumClasses() const { return 1; } template - DI void IncrementHistogram( - BinT* histogram, int n_bins, int bin, LabelT label, const DatasetT& dataset, int row) const + DI void IncrementHistogram(BinT* histogram, + int n_bins, + int bin, + LabelT label, + const DatasetT& dataset, + std::int64_t row) const { double weight = 1.0; if constexpr (weighted) { @@ -327,8 +357,11 @@ class RegressionObjectiveFunction { BinT::IncrementHistogram(histogram, n_bins, bin, label, weight); } - DI Split Gain( - BinT const* shist, DataT const* squantiles, int col, int len, int n_bins) const + DI Split Gain(BinT const* shist, + DataT const* squantiles, + std::int64_t col, + std::int64_t len, + int n_bins) const { Split sp; for (int i = threadIdx.x; i < n_bins; i += blockDim.x) { diff --git a/cpp/src/decisiontree/batched-levelalgo/split.cuh b/cpp/src/decisiontree/batched-levelalgo/split.cuh index 12f313d87a..e494768e6d 100644 --- a/cpp/src/decisiontree/batched-levelalgo/split.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/split.cuh @@ -8,18 +8,20 @@ #include #include +#include + namespace ML { namespace DT { namespace detail { template -DI int CountLeft(BinT const* hist, int i, int n_bins, int n_outputs) +DI std::int64_t CountLeft(BinT const* hist, int i, int n_bins, std::int64_t n_outputs) { auto nLeft = hist[i].Count(); for (int j = 1; j < n_outputs; ++j) { nLeft += hist[n_bins * j + i].Count(); } - return static_cast(nLeft); + return static_cast(nLeft); } } // namespace detail @@ -39,17 +41,21 @@ struct Split { /** threshold to compare in this node */ DataT quesval; /** feature index */ - int colid; + std::int64_t colid; /** best info gain on this node */ DataT best_metric_val; /** number of samples in the left child */ - int nLeft; + std::int64_t nLeft; /** first quantile index in an inclusive range of training-equivalent splits */ - int split_start; + std::int64_t split_start; /** last quantile index in an inclusive range of training-equivalent splits */ - int split_end; + std::int64_t split_end; - DI Split(DataT quesval, int colid, DataT best_metric_val, int nLeft, int bin = -1) + DI Split(DataT quesval, + std::int64_t colid, + DataT best_metric_val, + std::int64_t nLeft, + std::int64_t bin = -1) : quesval(quesval), colid(colid), best_metric_val(best_metric_val), nLeft(nLeft) { split_start = bin; @@ -241,13 +247,15 @@ template void printSplits(Split* splits, int len, cudaStream_t s) { auto op = [] __device__(Split * ptr, int idx) { - printf("quesval = %e, colid = %d, best_metric_val = %e, nLeft = %d, split_range = [%d, %d]\n", - ptr->quesval, - ptr->colid, - ptr->best_metric_val, - ptr->nLeft, - ptr->split_start, - ptr->split_end); + printf( + "quesval = %e, colid = %lld, best_metric_val = %e, nLeft = %lld, " + "split_range = [%lld, %lld]\n", + ptr->quesval, + static_cast(ptr->colid), + ptr->best_metric_val, + static_cast(ptr->nLeft), + static_cast(ptr->split_start), + static_cast(ptr->split_end)); }; raft::linalg::writeOnlyUnaryOp, decltype(op), int, TPB>(splits, len, op, s); RAFT_CUDA_TRY(cudaDeviceSynchronize()); diff --git a/cpp/src/decisiontree/decisiontree.cuh b/cpp/src/decisiontree/decisiontree.cuh index d313d34aba..e81fce77d5 100644 --- a/cpp/src/decisiontree/decisiontree.cuh +++ b/cpp/src/decisiontree/decisiontree.cuh @@ -87,7 +87,7 @@ std::string get_node_text(const std::string& prefix, int idx, bool isLeft) { - const SparseTreeNode& node = tree->sparsetree[idx]; + const auto& node = tree->sparsetree[idx]; std::ostringstream oss; @@ -124,7 +124,7 @@ std::string get_node_text(const std::string& prefix, template std::string get_node_json(const std::string& prefix, const TreeMetaDataNode* tree, int idx) { - const SparseTreeNode& node = tree->sparsetree[idx]; + const auto& node = tree->sparsetree[idx]; std::ostringstream oss; if (!node.IsLeaf()) { @@ -181,9 +181,9 @@ tl::Tree build_treelite_tree(const DT::TreeMetaDataNode& rf_tree, next_level_queue.resize(std::max(2 * cur_level_size, next_level_queue.size())); for (size_t i = 0; i < cur_level_size; ++i) { - auto cuml_node_id = cur_level_queue[cur_front].first; - const SparseTreeNode& q_node = rf_tree.sparsetree[cuml_node_id]; - auto tl_node_id = cur_level_queue[cur_front].second; + auto cuml_node_id = cur_level_queue[cur_front].first; + const auto& q_node = rf_tree.sparsetree[cuml_node_id]; + auto tl_node_id = cur_level_queue[cur_front].second; ++cur_front; if (!q_node.IsLeaf()) { @@ -235,15 +235,15 @@ class DecisionTree { const raft::handle_t& handle, const cudaStream_t s, const DataT* data, - const int ncols, - const int nrows, + const std::int64_t ncols, + const std::int64_t nrows, const LabelT* labels, - rmm::device_uvector* row_ids, + rmm::device_uvector* row_ids, int unique_labels, DecisionTreeParams params, uint64_t seed, const Quantiles& quantiles, - int treeid, + std::int64_t treeid, const double* sample_weight = nullptr) { if (params.split_criterion == diff --git a/cpp/src/randomforest/randomforest.cuh b/cpp/src/randomforest/randomforest.cuh index b03fbed08e..7a3cc8bf9e 100644 --- a/cpp/src/randomforest/randomforest.cuh +++ b/cpp/src/randomforest/randomforest.cuh @@ -40,6 +40,7 @@ #define omp_get_max_threads() 1 #endif +#include #include #include @@ -100,7 +101,7 @@ class RowSampler { RowSampler(const RowSampler&) = delete; RowSampler& operator=(const RowSampler&) = delete; - rmm::device_uvector& sample(int tree_id, int stream_id, cudaStream_t stream) + rmm::device_uvector& sample(int tree_id, int stream_id, cudaStream_t stream) { raft::common::nvtx::range fun_scope("bootstrapping row IDs @randomforest.cuh"); @@ -130,7 +131,7 @@ class RowSampler { weighted_draw_scratch.end(), selected_rows.begin()); } else { - raft::random::uniformInt( + raft::random::uniformInt( stream_resources, rng_state, selected_rows.data(), selected_rows.size(), 0, n_rows_); } } else { @@ -146,7 +147,7 @@ class RowSampler { private: void store_bootstrap_mask(int tree_id, - rmm::device_uvector& selected_rows, + rmm::device_uvector& selected_rows, cudaStream_t stream) { if (bootstrap_masks_ == nullptr) { return; } @@ -199,7 +200,7 @@ class RowSampler { const double* sample_weight_; double sample_weight_sum_; rmm::device_uvector sample_weight_cdf_; - std::deque> selected_rows_; + std::deque> selected_rows_; std::deque> weighted_draw_scratch_; }; } // namespace detail diff --git a/cpp/tests/sg/rf_test.cu b/cpp/tests/sg/rf_test.cu index abcdf07e4b..52e25b41a7 100644 --- a/cpp/tests/sg/rf_test.cu +++ b/cpp/tests/sg/rf_test.cu @@ -560,10 +560,11 @@ class RfSpecialisedTest { } } - void ExpectNodeCountsMatchTrainingData(const std::vector>& tree, - std::size_t node_id, - const std::vector& rows, - const thrust::host_vector& h_X) + void ExpectNodeCountsMatchTrainingData( + const std::vector>& tree, + std::size_t node_id, + const std::vector& rows, + const thrust::host_vector& h_X) { ASSERT_LT(node_id, tree.size()); const auto& node = tree[node_id]; @@ -1231,11 +1232,11 @@ TEST(RFEquivalentSplitRangeTest, ClassificationChoosesUpperMiddleBin) struct HostSplit { DataT quesval; - int colid; + std::int64_t colid; DataT best_metric_val; - int nLeft; - int split_start; - int split_end; + std::int64_t nLeft; + std::int64_t split_start; + std::int64_t split_end; }; static_assert(sizeof(HostSplit) == sizeof(DT::Split)); HostSplit h_split; @@ -1286,11 +1287,11 @@ TEST(RFEquivalentSplitRangeTest, RegressionChoosesUpperMiddleBin) struct HostSplit { DataT quesval; - int colid; + std::int64_t colid; DataT best_metric_val; - int nLeft; - int split_start; - int split_end; + std::int64_t nLeft; + std::int64_t split_start; + std::int64_t split_end; }; static_assert(sizeof(HostSplit) == sizeof(DT::Split)); HostSplit h_split; @@ -2510,7 +2511,7 @@ class FeatureSamplingBiasTest : public ::testing::TestWithParamget_stream(); // Allocate device memory - rmm::device_uvector d_colids(params.n_nodes * params.k, stream); + rmm::device_uvector d_colids(params.n_nodes * params.k, stream); rmm::device_uvector d_work_items(params.n_nodes, stream); rmm::device_uvector d_counts(params.n_features, stream); @@ -2546,7 +2547,7 @@ class FeatureSamplingBiasTest : public ::testing::TestWithParam Date: Tue, 14 Jul 2026 20:16:57 +0200 Subject: [PATCH 04/14] Hard-code SparseTreeNode indexes to int64 --- cpp/include/cuml/tree/decisiontree.hpp | 4 +- cpp/include/cuml/tree/flatnode.h | 41 +++++++++++-------- .../batched-levelalgo/builder.cuh | 4 +- .../kernels/classification-double.cu | 2 +- .../kernels/classification-float.cu | 2 +- .../kernels/regression-double.cu | 2 +- .../kernels/regression-float.cu | 2 +- .../kernels/weighted-classification-double.cu | 2 +- .../kernels/weighted-classification-float.cu | 2 +- .../kernels/weighted-regression-double.cu | 2 +- .../kernels/weighted-regression-float.cu | 2 +- cpp/tests/sg/rf_test.cu | 9 ++-- 12 files changed, 40 insertions(+), 34 deletions(-) diff --git a/cpp/include/cuml/tree/decisiontree.hpp b/cpp/include/cuml/tree/decisiontree.hpp index 1a015b78e7..747f091ddb 100644 --- a/cpp/include/cuml/tree/decisiontree.hpp +++ b/cpp/include/cuml/tree/decisiontree.hpp @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION. + * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ @@ -97,7 +97,7 @@ struct TreeMetaDataNode { int leaf_counter; double train_time; std::vector vector_leaf; - std::vector> sparsetree; + std::vector> sparsetree; int num_outputs; }; diff --git a/cpp/include/cuml/tree/flatnode.h b/cpp/include/cuml/tree/flatnode.h index 6467b628fc..72efab6c01 100644 --- a/cpp/include/cuml/tree/flatnode.h +++ b/cpp/include/cuml/tree/flatnode.h @@ -1,10 +1,12 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION. + * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ #pragma once +#include + // We want to define some functions as usable on device // But need to guard against this file being compiled by a host compiler #ifdef __CUDACC__ @@ -17,18 +19,20 @@ * A node in Decision Tree. * @tparam T data type * @tparam L label type - * @tparam IdxT type used for indexing operations */ -template +template struct SparseTreeNode { private: - IdxT colid = 0; - DataT quesval = DataT(0); - DataT best_metric_val = DataT(0); - IdxT left_child_id = -1; - IdxT instance_count = 0; - FLATNODE_HD SparseTreeNode( - IdxT colid, DataT quesval, DataT best_metric_val, int64_t left_child_id, IdxT instance_count) + std::int64_t colid = 0; + DataT quesval = DataT(0); + DataT best_metric_val = DataT(0); + std::int64_t left_child_id = -1; + std::int64_t instance_count = 0; + FLATNODE_HD SparseTreeNode(std::int64_t colid, + DataT quesval, + DataT best_metric_val, + std::int64_t left_child_id, + std::int64_t instance_count) : colid(colid), quesval(quesval), best_metric_val(best_metric_val), @@ -38,19 +42,22 @@ struct SparseTreeNode { } public: - FLATNODE_HD IdxT ColumnId() const { return colid; } + FLATNODE_HD std::int64_t ColumnId() const { return colid; } FLATNODE_HD DataT QueryValue() const { return quesval; } FLATNODE_HD DataT BestMetric() const { return best_metric_val; } - FLATNODE_HD int64_t LeftChildId() const { return left_child_id; } - FLATNODE_HD int64_t RightChildId() const { return left_child_id + 1; } - FLATNODE_HD IdxT InstanceCount() const { return instance_count; } + FLATNODE_HD std::int64_t LeftChildId() const { return left_child_id; } + FLATNODE_HD std::int64_t RightChildId() const { return left_child_id + 1; } + FLATNODE_HD std::int64_t InstanceCount() const { return instance_count; } - FLATNODE_HD static SparseTreeNode CreateSplitNode( - IdxT colid, DataT quesval, DataT best_metric_val, int64_t left_child_id, IdxT instance_count) + FLATNODE_HD static SparseTreeNode CreateSplitNode(std::int64_t colid, + DataT quesval, + DataT best_metric_val, + std::int64_t left_child_id, + std::int64_t instance_count) { return SparseTreeNode{colid, quesval, best_metric_val, left_child_id, instance_count}; } - FLATNODE_HD static SparseTreeNode CreateLeafNode(IdxT instance_count) + FLATNODE_HD static SparseTreeNode CreateLeafNode(std::int64_t instance_count) { return SparseTreeNode{0, 0, 0, -1, instance_count}; } diff --git a/cpp/src/decisiontree/batched-levelalgo/builder.cuh b/cpp/src/decisiontree/batched-levelalgo/builder.cuh index 2e3cb798c8..af7faf4a56 100644 --- a/cpp/src/decisiontree/batched-levelalgo/builder.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/builder.cuh @@ -38,7 +38,7 @@ namespace DT { */ template class NodeQueue { - using NodeT = SparseTreeNode; + using NodeT = SparseTreeNode; const DecisionTreeParams params; std::shared_ptr> tree; std::vector node_instances_; @@ -151,7 +151,7 @@ struct Builder { typedef typename ObjectiveT::LabelT LabelT; typedef typename ObjectiveT::IdxT IdxT; typedef typename ObjectiveT::BinT BinT; - typedef SparseTreeNode NodeT; + typedef SparseTreeNode NodeT; typedef Split SplitT; typedef Dataset DatasetT; typedef Quantiles QuantilesT; diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu index 7975b62ed2..65d07ec48c 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu @@ -15,7 +15,7 @@ using IdxT = std::int64_t; using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu index e013b8d192..6df8300afe 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu @@ -15,7 +15,7 @@ using IdxT = std::int64_t; using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu index 6c1eddf0b3..b79366e766 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu @@ -15,7 +15,7 @@ using IdxT = std::int64_t; using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu index 83714deb33..54c8591928 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu @@ -15,7 +15,7 @@ using IdxT = std::int64_t; using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu index e46391b5c9..fe6bb966f5 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu @@ -15,7 +15,7 @@ using IdxT = std::int64_t; using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu index f5d8afcaaa..d01d51bc2b 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu @@ -15,7 +15,7 @@ using IdxT = std::int64_t; using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu index 342eae1be7..96414f460d 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu @@ -15,7 +15,7 @@ using IdxT = std::int64_t; using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu index cd48cec55c..db4abd55c1 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu @@ -15,7 +15,7 @@ using IdxT = std::int64_t; using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; using DatasetT = Dataset; -using NodeT = SparseTreeNode; +using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchLeafKernel( diff --git a/cpp/tests/sg/rf_test.cu b/cpp/tests/sg/rf_test.cu index 1ccd65ae67..85e889f287 100644 --- a/cpp/tests/sg/rf_test.cu +++ b/cpp/tests/sg/rf_test.cu @@ -574,11 +574,10 @@ class RfSpecialisedTest { } } - void ExpectNodeCountsMatchTrainingData( - const std::vector>& tree, - std::size_t node_id, - const std::vector& rows, - const thrust::host_vector& h_X) + void ExpectNodeCountsMatchTrainingData(const std::vector>& tree, + std::size_t node_id, + const std::vector& rows, + const thrust::host_vector& h_X) { ASSERT_LT(node_id, tree.size()); const auto& node = tree[node_id]; From d1574cddeee83dd2af404f41fb7486acef542155 Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Tue, 14 Jul 2026 20:24:59 +0200 Subject: [PATCH 05/14] Trim RF index template cleanup --- .../batched-levelalgo/builder.cuh | 13 ++++++++----- .../kernels/builder_kernels.cuh | 2 +- .../kernels/builder_kernels_impl.cuh | 6 +++--- .../kernels/classification-double.cu | 19 +++++++++---------- .../kernels/classification-float.cu | 19 +++++++++---------- .../kernels/regression-double.cu | 19 +++++++++---------- .../kernels/regression-float.cu | 19 +++++++++---------- .../kernels/weighted-classification-double.cu | 19 +++++++++---------- .../kernels/weighted-classification-float.cu | 19 +++++++++---------- .../kernels/weighted-regression-double.cu | 19 +++++++++---------- .../kernels/weighted-regression-float.cu | 19 +++++++++---------- .../batched-levelalgo/quantiles.cuh | 4 ++-- .../batched-levelalgo/quantiles.h | 2 +- cpp/src/decisiontree/decisiontree.cuh | 2 +- 14 files changed, 88 insertions(+), 93 deletions(-) diff --git a/cpp/src/decisiontree/batched-levelalgo/builder.cuh b/cpp/src/decisiontree/batched-levelalgo/builder.cuh index af7faf4a56..a5c552b023 100644 --- a/cpp/src/decisiontree/batched-levelalgo/builder.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/builder.cuh @@ -36,7 +36,7 @@ namespace DT { * Structure that manages the iterative batched-level training and building of nodes * in the host. */ -template +template class NodeQueue { using NodeT = SparseTreeNode; const DecisionTreeParams params; @@ -45,10 +45,13 @@ class NodeQueue { std::deque work_items_; public: - NodeQueue(DecisionTreeParams params, size_t max_nodes, size_t sampled_rows, IdxT num_outputs) + NodeQueue(DecisionTreeParams params, + size_t max_nodes, + size_t sampled_rows, + std::int64_t num_outputs) : params(params), tree(std::make_shared>()) { - tree->num_outputs = num_outputs; + tree->num_outputs = ML::narrow_cast(num_outputs); tree->sparsetree.reserve(max_nodes); tree->sparsetree.emplace_back(NodeT::CreateLeafNode(sampled_rows)); tree->leaf_counter = 1; @@ -154,7 +157,7 @@ struct Builder { typedef SparseTreeNode NodeT; typedef Split SplitT; typedef Dataset DatasetT; - typedef Quantiles QuantilesT; + typedef Quantiles QuantilesT; /** default threads per block for most kernels in here */ static constexpr int TPB_DEFAULT = 128; @@ -359,7 +362,7 @@ struct Builder { { raft::common::nvtx::range fun_scope("Builder::train @builder.cuh [batched-levelalgo]"); MLCommon::TimerCPU timer; - NodeQueue queue( + NodeQueue queue( params, this->maxNodes(), dataset.n_sampled_rows, dataset.num_outputs); while (queue.HasWork()) { auto work_items = queue.Pop(); diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh index 05d1257c07..a1294c796f 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh @@ -133,7 +133,7 @@ template & dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, IdxT colStart, const IdxT* column_samples, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh index f84eb70292..506a2f3b34 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh @@ -251,7 +251,7 @@ template dataset, - const Quantiles quantiles, + const Quantiles quantiles, const NodeWorkItem* work_items, IdxT colStart, const IdxT* column_samples, @@ -326,7 +326,7 @@ template dataset, - const Quantiles quantiles, + const Quantiles quantiles, const NodeWorkItem* work_items, IdxT colStart, const IdxT* column_samples, @@ -370,7 +370,7 @@ template & dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, IdxT colStart, const IdxT* column_samples, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu index 65d07ec48c..50f580d34c 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu @@ -11,10 +11,9 @@ namespace ML { namespace DT { using DataT = double; using LabelT = int; -using IdxT = std::int64_t; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -29,18 +28,18 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, - IdxT n_bins, + std::int64_t n_bins, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu index 6df8300afe..fa7e93ef1f 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu @@ -11,10 +11,9 @@ namespace ML { namespace DT { using DataT = float; using LabelT = int; -using IdxT = std::int64_t; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -29,18 +28,18 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, - IdxT n_bins, + std::int64_t n_bins, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu index b79366e766..05b8cba62c 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu @@ -11,10 +11,9 @@ namespace ML { namespace DT { using DataT = double; using LabelT = double; -using IdxT = std::int64_t; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -29,18 +28,18 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, - IdxT n_bins, + std::int64_t n_bins, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu index 54c8591928..d7f07fc868 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu @@ -11,10 +11,9 @@ namespace ML { namespace DT { using DataT = float; using LabelT = float; -using IdxT = std::int64_t; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -29,18 +28,18 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, - IdxT n_bins, + std::int64_t n_bins, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu index fe6bb966f5..8ecc5aacdc 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu @@ -11,10 +11,9 @@ namespace ML { namespace DT { using DataT = double; using LabelT = int; -using IdxT = std::int64_t; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -29,18 +28,18 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, - IdxT n_bins, + std::int64_t n_bins, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu index d01d51bc2b..27b4a8818c 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu @@ -11,10 +11,9 @@ namespace ML { namespace DT { using DataT = float; using LabelT = int; -using IdxT = std::int64_t; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -29,18 +28,18 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, - IdxT n_bins, + std::int64_t n_bins, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu index 96414f460d..6645e97f2d 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu @@ -11,10 +11,9 @@ namespace ML { namespace DT { using DataT = double; using LabelT = double; -using IdxT = std::int64_t; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -29,18 +28,18 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, - IdxT n_bins, + std::int64_t n_bins, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu index db4abd55c1..7f67352aad 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu @@ -11,10 +11,9 @@ namespace ML { namespace DT { using DataT = float; using LabelT = float; -using IdxT = std::int64_t; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -29,18 +28,18 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, - IdxT n_bins, + std::int64_t n_bins, const DatasetT& dataset, - const Quantiles& quantiles, + const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh b/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh index ce55b5d418..8f2aa3a9be 100644 --- a/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh @@ -115,8 +115,8 @@ struct QuantileResult { rmm::device_uvector quantiles_array; rmm::device_uvector n_bins_array; - Quantiles view() & { return {quantiles_array.data(), n_bins_array.data()}; } - Quantiles view() && = delete; + Quantiles view() & { return {quantiles_array.data(), n_bins_array.data()}; } + Quantiles view() && = delete; }; /** diff --git a/cpp/src/decisiontree/batched-levelalgo/quantiles.h b/cpp/src/decisiontree/batched-levelalgo/quantiles.h index c09b28c39a..3b65de1a3b 100644 --- a/cpp/src/decisiontree/batched-levelalgo/quantiles.h +++ b/cpp/src/decisiontree/batched-levelalgo/quantiles.h @@ -8,7 +8,7 @@ namespace ML { namespace DT { -template +template struct Quantiles { /** quantiles computed for each feature of dataset in col-major */ DataT* quantiles_array; diff --git a/cpp/src/decisiontree/decisiontree.cuh b/cpp/src/decisiontree/decisiontree.cuh index 9d2eec3f29..c5721d799c 100644 --- a/cpp/src/decisiontree/decisiontree.cuh +++ b/cpp/src/decisiontree/decisiontree.cuh @@ -243,7 +243,7 @@ class DecisionTree { int unique_labels, DecisionTreeParams params, uint64_t seed, - const Quantiles& quantiles, + const Quantiles& quantiles, std::int64_t treeid, const double* sample_weight = nullptr, bool row_major = false) From 96d0d3d3f0e7b7105c91669cafc85079b84d3594 Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Tue, 14 Jul 2026 20:29:37 +0200 Subject: [PATCH 06/14] Drop RF dataset header churn --- cpp/src/decisiontree/batched-levelalgo/dataset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/decisiontree/batched-levelalgo/dataset.h b/cpp/src/decisiontree/batched-levelalgo/dataset.h index c726f6bcf0..c2cc369301 100644 --- a/cpp/src/decisiontree/batched-levelalgo/dataset.h +++ b/cpp/src/decisiontree/batched-levelalgo/dataset.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION. * SPDX-License-Identifier: Apache-2.0 */ From d969d6d1fbfd7656589bca37096c86845a2256ca Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Tue, 14 Jul 2026 20:44:33 +0200 Subject: [PATCH 07/14] Hard-code RF dataset and objective indexes --- .../batched-levelalgo/builder.cuh | 156 +++++++++--------- .../decisiontree/batched-levelalgo/dataset.h | 14 +- .../kernels/builder_kernels.cuh | 70 ++++---- .../kernels/builder_kernels_impl.cuh | 147 +++++++++-------- .../kernels/classification-double.cu | 8 +- .../kernels/classification-float.cu | 8 +- .../batched-levelalgo/kernels/node-split.cu | 24 +-- .../kernels/regression-double.cu | 8 +- .../kernels/regression-float.cu | 8 +- .../kernels/weighted-classification-double.cu | 8 +- .../kernels/weighted-classification-float.cu | 8 +- .../kernels/weighted-regression-double.cu | 8 +- .../kernels/weighted-regression-float.cu | 8 +- .../batched-levelalgo/objectives.cuh | 126 +++++++++----- cpp/src/decisiontree/decisiontree.cuh | 113 +++++++------ cpp/tests/sg/rf_test.cu | 67 ++++---- 16 files changed, 410 insertions(+), 371 deletions(-) diff --git a/cpp/src/decisiontree/batched-levelalgo/builder.cuh b/cpp/src/decisiontree/batched-levelalgo/builder.cuh index a5c552b023..4e5d383710 100644 --- a/cpp/src/decisiontree/batched-levelalgo/builder.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/builder.cuh @@ -152,11 +152,10 @@ template struct Builder { typedef typename ObjectiveT::DataT DataT; typedef typename ObjectiveT::LabelT LabelT; - typedef typename ObjectiveT::IdxT IdxT; typedef typename ObjectiveT::BinT BinT; typedef SparseTreeNode NodeT; - typedef Split SplitT; - typedef Dataset DatasetT; + typedef Split SplitT; + typedef Dataset DatasetT; typedef Quantiles QuantilesT; /** default threads per block for most kernels in here */ @@ -177,11 +176,11 @@ struct Builder { /** quantiles */ QuantilesT quantiles; /** Tree index */ - IdxT treeid; + std::int64_t treeid; /** Seed used for randomization */ uint64_t seed; /** number of nodes created in the current batch */ - IdxT* n_nodes; + std::int64_t* n_nodes; /** buffer of segmented histograms*/ BinT* histograms; /** mutex array used for atomically updating best split */ @@ -191,9 +190,9 @@ struct Builder { /** current batch of nodes */ NodeWorkItem* d_work_items; /** device AOS to map CTA blocks along dimx to nodes of a batch */ - WorkloadInfo* workload_info; + WorkloadInfo* workload_info; /** host AOS to map CTA blocks along dimx to nodes of a batch */ - WorkloadInfo* h_workload_info; + WorkloadInfo* h_workload_info; /** maximum CTA blocks along dimx */ int max_blocks_dimx = 0; /** host array of splits */ @@ -202,9 +201,9 @@ struct Builder { int n_blks_for_cols = 10; /** Memory alignment value */ const size_t align_value = 512; - IdxT* column_samples; + std::int64_t* column_samples; /** temporary row IDs for row-wise out-of-place partitioning */ - IdxT* partition_row_ids; + std::int64_t* partition_row_ids; /** rmm device workspace buffer */ rmm::device_uvector d_buff; /** pinned host buffer to store the trained nodes */ @@ -212,16 +211,16 @@ struct Builder { Builder(const raft::handle_t& handle, cudaStream_t s, - IdxT treeid, + std::int64_t treeid, uint64_t seed, const DecisionTreeParams& p, const DataT* data, const LabelT* labels, const double* sample_weight, - IdxT n_rows, - IdxT n_cols, - rmm::device_uvector* row_ids, - IdxT n_classes, + std::int64_t n_rows, + std::int64_t n_cols, + rmm::device_uvector* row_ids, + std::int64_t n_classes, const QuantilesT& q, bool row_major = false) : handle(handle), @@ -234,10 +233,10 @@ struct Builder { sample_weight, n_rows, n_cols, - row_major ? n_cols : IdxT{1}, - row_major ? IdxT{1} : n_rows, - static_cast(row_ids->size()), - std::max(IdxT{1}, IdxT(params.max_features * n_cols)), + row_major ? n_cols : std::int64_t{1}, + row_major ? std::int64_t{1} : n_rows, + static_cast(row_ids->size()), + std::max(std::int64_t{1}, std::int64_t(params.max_features * n_cols)), row_ids->data(), n_classes}, quantiles(q), @@ -293,20 +292,21 @@ struct Builder { size_t max_len_histograms = max_batch * params.max_n_bins * n_blks_for_cols * dataset.num_outputs; - d_wsize += calculateAlignedBytes(sizeof(IdxT)); // n_nodes + d_wsize += calculateAlignedBytes(sizeof(std::int64_t)); // n_nodes d_wsize += calculateAlignedBytes(sizeof(BinT) * max_len_histograms); // histograms d_wsize += calculateAlignedBytes(sizeof(int) * max_batch); // mutex d_wsize += calculateAlignedBytes(sizeof(SplitT) * max_batch); // splits d_wsize += calculateAlignedBytes(sizeof(NodeWorkItem) * max_batch); // d_work_Items d_wsize += // workload_info - calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + d_wsize += calculateAlignedBytes(sizeof(std::int64_t) * max_batch * + dataset.n_sampled_cols); // column_samples d_wsize += - calculateAlignedBytes(sizeof(IdxT) * max_batch * dataset.n_sampled_cols); // column_samples - d_wsize += calculateAlignedBytes(sizeof(IdxT) * dataset.n_sampled_rows); // partition row IDs + calculateAlignedBytes(sizeof(std::int64_t) * dataset.n_sampled_rows); // partition row IDs // all nodes in the tree h_wsize += // h_workload_info - calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); h_wsize += calculateAlignedBytes(sizeof(SplitT) * max_batch); // splits return std::make_pair(d_wsize, h_wsize); @@ -327,8 +327,8 @@ struct Builder { size_t max_len_histograms = max_batch * (params.max_n_bins) * n_blks_for_cols * dataset.num_outputs; // device - n_nodes = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(IdxT)); + n_nodes = reinterpret_cast(d_wspace); + d_wspace += calculateAlignedBytes(sizeof(std::int64_t)); histograms = reinterpret_cast(d_wspace); d_wspace += calculateAlignedBytes(sizeof(BinT) * max_len_histograms); mutex = reinterpret_cast(d_wspace); @@ -337,18 +337,18 @@ struct Builder { d_wspace += calculateAlignedBytes(sizeof(SplitT) * max_batch); d_work_items = reinterpret_cast(d_wspace); d_wspace += calculateAlignedBytes(sizeof(NodeWorkItem) * max_batch); - workload_info = reinterpret_cast*>(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); - column_samples = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(IdxT) * max_batch * dataset.n_sampled_cols); - partition_row_ids = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(IdxT) * dataset.n_sampled_rows); + workload_info = reinterpret_cast(d_wspace); + d_wspace += calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + column_samples = reinterpret_cast(d_wspace); + d_wspace += calculateAlignedBytes(sizeof(std::int64_t) * max_batch * dataset.n_sampled_cols); + partition_row_ids = reinterpret_cast(d_wspace); + d_wspace += calculateAlignedBytes(sizeof(std::int64_t) * dataset.n_sampled_rows); RAFT_CUDA_TRY(cudaMemsetAsync(mutex, 0, sizeof(int) * max_batch, builder_stream)); // host - h_workload_info = reinterpret_cast*>(h_wspace); - h_wspace += calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + h_workload_info = reinterpret_cast(h_wspace); + h_wspace += calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); h_splits = reinterpret_cast(h_wspace); h_wspace += calculateAlignedBytes(sizeof(SplitT) * max_batch); } @@ -397,9 +397,9 @@ struct Builder { { raft::common::nvtx::range fun_scope("Builder::doSplit @builder.cuh [batched-levelalgo]"); // start fresh on the number of *new* nodes created in this batch - RAFT_CUDA_TRY(cudaMemsetAsync(n_nodes, 0, sizeof(IdxT), builder_stream)); + RAFT_CUDA_TRY(cudaMemsetAsync(n_nodes, 0, sizeof(std::int64_t), builder_stream)); - const IdxT original_n_sampled_cols = dataset.n_sampled_cols; + const std::int64_t original_n_sampled_cols = dataset.n_sampled_cols; ASSERT(original_n_sampled_cols > 0 && original_n_sampled_cols <= dataset.n_cols, "n_sampled_cols must be in [1, n_cols]"); const std::size_t max_sampling_rounds = @@ -421,9 +421,9 @@ struct Builder { // Match sklearn's behavior of searching beyond max_features when the // sampled features do not yield a valid split. for (std::size_t round = 0; !active_items.empty() && round < max_sampling_rounds; ++round) { - IdxT sample_offset = IdxT(round) * original_n_sampled_cols; - dataset.n_sampled_cols = - std::min(original_n_sampled_cols, static_cast(dataset.n_cols) - sample_offset); + std::int64_t sample_offset = std::int64_t(round) * original_n_sampled_cols; + dataset.n_sampled_cols = std::min(original_n_sampled_cols, + static_cast(dataset.n_cols) - sample_offset); computeBestSplits(active_items, seed, sample_offset); std::vector retry_items; @@ -454,15 +454,15 @@ struct Builder { raft::update_device(d_work_items, work_items.data(), work_items.size(), builder_stream); const auto n_partition_blocks = this->updateWorkloadInfo(work_items); raft::common::nvtx::push_range("nodeSplitKernel @builder.cuh [batched-levelalgo]"); - launchNodeSplitKernel(params.min_samples_leaf, - params.min_impurity_decrease, - dataset, - d_work_items, - splits, - workload_info, - n_partition_blocks, - partition_row_ids, - builder_stream); + launchNodeSplitKernel(params.min_samples_leaf, + params.min_impurity_decrease, + dataset, + d_work_items, + splits, + workload_info, + n_partition_blocks, + partition_row_ids, + builder_stream); RAFT_CUDA_TRY(cudaPeekAtLastError()); raft::common::nvtx::pop_range(); raft::update_host(h_splits, splits, work_items.size(), builder_stream); @@ -472,9 +472,9 @@ struct Builder { void computeBestSplits(const std::vector& work_items, uint64_t sampling_seed, - IdxT sample_offset) + std::int64_t sample_offset) { - initSplit(splits, work_items.size(), builder_stream); + initSplit(splits, work_items.size(), builder_stream); RAFT_CUDA_TRY(cudaMemsetAsync(mutex, 0, sizeof(int) * params.max_batch_size, builder_stream)); raft::update_device(d_work_items, work_items.data(), work_items.size(), builder_stream); auto n_blocks_dimx = this->updateWorkloadInfo(work_items); @@ -482,7 +482,7 @@ struct Builder { sampleFeatures(work_items, sampling_seed, sample_offset); - for (IdxT c = 0; c < dataset.n_sampled_cols; c += n_blks_for_cols) { + for (std::int64_t c = 0; c < dataset.n_sampled_cols; c += n_blks_for_cols) { computeSplit(c, n_blocks_dimx, work_items.size(), split_smem_config); RAFT_CUDA_TRY(cudaPeekAtLastError()); } @@ -492,18 +492,18 @@ struct Builder { void sampleFeatures(const std::vector& work_items, uint64_t sampling_seed, - IdxT sample_offset) + std::int64_t sample_offset) { raft::common::nvtx::range fun_scope("feature-sampling"); - sample_features(column_samples, - d_work_items, - work_items.size(), - treeid, - sampling_seed, - sample_offset, - static_cast(dataset.n_cols), - dataset.n_sampled_cols, - builder_stream); + sample_features(column_samples, + d_work_items, + work_items.size(), + treeid, + sampling_seed, + sample_offset, + static_cast(dataset.n_cols), + dataset.n_sampled_cols, + builder_stream); RAFT_CUDA_TRY(cudaPeekAtLastError()); } @@ -538,7 +538,7 @@ struct Builder { use_global_memory_histogram ? 0 : histogram_dynamic_smem_size}; } - void computeSplit(IdxT col, + void computeSplit(std::int64_t col, size_t n_blocks_dimx, size_t n_work_items, const SharedMemoryConfig& split_smem_config) @@ -549,8 +549,8 @@ struct Builder { auto n_bins = params.max_n_bins; auto n_classes = dataset.num_outputs; // if columns left to be processed lesser than `n_blks_for_cols`, shrink the blocks along dimy - auto n_blocks_dimy = - std::min(static_cast(n_blks_for_cols), dataset.n_sampled_cols - col); + auto n_blocks_dimy = std::min(static_cast(n_blks_for_cols), + dataset.n_sampled_cols - col); dim3 histogram_grid(ML::narrow_cast(n_blocks_dimx), ML::narrow_cast(n_blocks_dimy), 1); @@ -565,21 +565,21 @@ struct Builder { ObjectiveT objective(dataset.num_outputs, params.min_samples_leaf, params.split_criterion); // call the compute split kernels raft::common::nvtx::range kernel_scope("computeSplitKernels @builder.cuh [batched-levelalgo]"); - launchComputeSplitKernels(histograms, - params.max_n_bins, - dataset, - quantiles, - d_work_items, - col, - column_samples, - mutex, - splits, - objective, - workload_info, - histogram_grid, - split_grid, - split_smem_config, - builder_stream); + launchComputeSplitKernels(histograms, + params.max_n_bins, + dataset, + quantiles, + d_work_items, + col, + column_samples, + mutex, + splits, + objective, + workload_info, + histogram_grid, + split_grid, + split_smem_config, + builder_stream); } // Set the leaf value predictions in batch diff --git a/cpp/src/decisiontree/batched-levelalgo/dataset.h b/cpp/src/decisiontree/batched-levelalgo/dataset.h index c2cc369301..eb5f98f64a 100644 --- a/cpp/src/decisiontree/batched-levelalgo/dataset.h +++ b/cpp/src/decisiontree/batched-levelalgo/dataset.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION. + * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ @@ -12,7 +12,7 @@ namespace ML { namespace DT { -template +template struct Dataset { /** input dataset */ const DataT* data; @@ -29,15 +29,15 @@ struct Dataset { /** column stride in input data elements */ std::int64_t col_stride; /** total sampled rows in dataset */ - IdxT n_sampled_rows; + std::int64_t n_sampled_rows; /** total sampled cols in dataset */ - IdxT n_sampled_cols; + std::int64_t n_sampled_cols; /** indices of sampled rows */ - IdxT* row_ids; + std::int64_t* row_ids; /** Number of classes or regression outputs*/ - IdxT num_outputs; + std::int64_t num_outputs; - HDI DataT value(IdxT row, IdxT col) const + HDI DataT value(std::int64_t row, std::int64_t col) const { return data[static_cast(row) * row_stride + static_cast(col) * col_stride]; diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh index a1294c796f..b7f40803f4 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh @@ -40,12 +40,11 @@ struct NodeWorkItem { * This struct has information about workload of a single threadblock of * computeSplit kernels of classification and regression */ -template struct WorkloadInfo { - IdxT nodeid; // Node in the batch on which the threadblock needs to work - IdxT offset_blockid; // Offset threadblock id among all the blocks that are - // working on this node - IdxT num_blocks; // Total number of blocks that are working on the node + std::int64_t nodeid; // Node in the batch on which the threadblock needs to work + std::int64_t offset_blockid; // Offset threadblock id among all the blocks that are + // working on this node + std::int64_t num_blocks; // Total number of blocks that are working on the node }; struct SharedMemoryConfig { @@ -53,19 +52,21 @@ struct SharedMemoryConfig { size_t histogram_dynamic_smem_size; }; -template -HDI bool SplitPartitionNotValid(const SplitT& split, IdxT min_samples_leaf, std::size_t num_rows) +template +HDI bool SplitPartitionNotValid(const SplitT& split, + std::int64_t min_samples_leaf, + std::size_t num_rows) { const auto local_count = static_cast(num_rows); const auto min_leaf = static_cast(min_samples_leaf); - return split.colid == IdxT(-1) || split.local_nLeft > local_count || + return split.colid == std::int64_t{-1} || split.local_nLeft > local_count || split.local_nLeft < min_leaf || (local_count - split.local_nLeft) < min_leaf; } -template +template HDI bool SplitNotValid(const SplitT& split, DataT min_impurity_decrease, - IdxT min_samples_leaf, + std::int64_t min_samples_leaf, std::size_t num_rows) { return split.best_metric_val <= min_impurity_decrease || @@ -79,16 +80,15 @@ DI OutT* alignPointer(InT dataset) return reinterpret_cast(raft::alignTo(reinterpret_cast(dataset), sizeof(OutT))); } -template -void sample_features(IdxT* column_samples, - const NodeWorkItem* work_items, - size_t work_items_size, - IdxT treeid, - uint64_t seed, - IdxT sample_offset, - IdxT n, - IdxT k, - cudaStream_t stream) +inline void sample_features(std::int64_t* column_samples, + const NodeWorkItem* work_items, + size_t work_items_size, + std::int64_t treeid, + uint64_t seed, + std::int64_t sample_offset, + std::int64_t n, + std::int64_t k, + cudaStream_t stream) { auto n_column_samples = work_items_size * size_t(k); auto counting = thrust::make_counting_iterator(0); @@ -98,26 +98,26 @@ void sample_features(IdxT* column_samples, counting + n_column_samples, [=] __device__(size_t sample_idx) { auto node_idx = sample_idx / size_t(k); - IdxT column_index = static_cast(sample_idx % size_t(k)); + auto column_index = static_cast(sample_idx % size_t(k)); const uint32_t nodeid = work_items[node_idx].idx; uint32_t rng_seed = fnv1a32_hash(seed, treeid, nodeid); - cuda::shuffle_iterator shuffled_features( + cuda::shuffle_iterator shuffled_features( n, cuda::std::minstd_rand(rng_seed), sample_offset); column_samples[sample_idx] = shuffled_features[column_index]; }); } -template -void launchNodeSplitKernel(const IdxT min_samples_leaf, +template +void launchNodeSplitKernel(const std::int64_t min_samples_leaf, const DataT min_impurity_decrease, - const Dataset& dataset, + const Dataset& dataset, const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, + const Split* splits, + const WorkloadInfo* workload_info, size_t n_blocks_dimx, - IdxT* partition_row_ids, + std::int64_t* partition_row_ids, cudaStream_t builder_stream); template @@ -129,18 +129,18 @@ void launchLeafKernel(ObjectiveT objective, int batch_size, size_t smem_size, cudaStream_t builder_stream); -template +template void launchComputeSplitKernels(typename ObjectiveT::BinT* histograms, - IdxT n_bins, - const Dataset& dataset, + std::int64_t n_bins, + const Dataset& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh index 506a2f3b34..eb29a7d288 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh @@ -50,13 +50,13 @@ struct NodeSplitPartitionScanOp { // inclusive left count and current row side for each logical row slot in its // node segment; this writer uses that state to place the row into the temporary // partition buffer. -template +template struct NodeSplitPartitionWriter { - Dataset dataset; + Dataset dataset; const NodeWorkItem* work_items; - const Split* splits; - const WorkloadInfo* workload_info; - IdxT* partition_row_ids; + const Split* splits; + const WorkloadInfo* workload_info; + std::int64_t* partition_row_ids; __host__ __device__ void operator()(std::ptrdiff_t index, NodeSplitPartitionState state) const { @@ -82,14 +82,14 @@ struct NodeSplitPartitionWriter { // Copy back only ranges for nodes that actually split. Leaf/invalid nodes keep // their existing row-id order because the scan writer skips them too. -template -static __global__ void nodeSplitCopyBackKernel(const IdxT min_samples_leaf, +template +static __global__ void nodeSplitCopyBackKernel(const std::int64_t min_samples_leaf, const DataT min_impurity_decrease, - const Dataset dataset, + const Dataset dataset, const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, - const IdxT* partition_row_ids) + const Split* splits, + const WorkloadInfo* workload_info, + const std::int64_t* partition_row_ids) { const auto workload_info_cta = workload_info[blockIdx.x]; const auto nid = workload_info_cta.nodeid; @@ -108,15 +108,15 @@ static __global__ void nodeSplitCopyBackKernel(const IdxT min_samples_leaf, } } -template -void launchNodeSplitKernel(const IdxT min_samples_leaf, +template +void launchNodeSplitKernel(const std::int64_t min_samples_leaf, const DataT min_impurity_decrease, - const Dataset& dataset, + const Dataset& dataset, const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, + const Split* splits, + const WorkloadInfo* workload_info, size_t n_blocks_dimx, - IdxT* partition_row_ids, + std::int64_t* partition_row_ids, cudaStream_t builder_stream) { if (n_blocks_dimx == 0) return; @@ -155,18 +155,18 @@ void launchNodeSplitKernel(const IdxT min_samples_leaf, auto node_keys = thrust::make_transform_iterator(slots_begin, node_key); auto partition_states = thrust::make_transform_iterator(slots_begin, partition_state); auto partition_writer = - thrust::make_tabulate_output_iterator(NodeSplitPartitionWriter{ + thrust::make_tabulate_output_iterator(NodeSplitPartitionWriter{ dataset, work_items, splits, workload_info, partition_row_ids}); thrust::inclusive_scan_by_key(exec_policy, node_keys, node_keys + n_slots, partition_states, partition_writer, - thrust::equal_to{}, + thrust::equal_to{}, NodeSplitPartitionScanOp{}); // The original row_ids buffer remains the source during the scan, so copy back after it finishes. - nodeSplitCopyBackKernel + nodeSplitCopyBackKernel <<>>(min_samples_leaf, min_impurity_decrease, dataset, @@ -226,8 +226,8 @@ void launchLeafKernel(ObjectiveT objective, * @brief For every threadblock, converts a pdf-histogram to a * cdf-histogram inplace using inclusive block-sum-scan. */ -template -DI void pdf_to_cdf(BinT* histogram, IdxT n_bins) +template +DI void pdf_to_cdf(BinT* histogram, std::int64_t n_bins) { // Blockscan instance preparation typedef cub::BlockScan BlockScan; @@ -236,7 +236,8 @@ DI void pdf_to_cdf(BinT* histogram, IdxT n_bins) // variable to accumulate aggregate of sumscans of previous iterations BinT total_aggregate = BinT(); - for (IdxT tix = threadIdx.x; tix < raft::ceildiv(n_bins, IdxT{TPB}) * TPB; tix += blockDim.x) { + for (std::int64_t tix = threadIdx.x; tix < raft::ceildiv(n_bins, std::int64_t{TPB}) * TPB; + tix += blockDim.x) { BinT result; BinT block_aggregate; BinT element = tix < n_bins ? histogram[tix] : BinT(); @@ -247,33 +248,33 @@ DI void pdf_to_cdf(BinT* histogram, IdxT n_bins) } } -template +template static __global__ void buildHistogramsKernel(typename ObjectiveT::BinT* histograms, - IdxT max_n_bins, - const Dataset dataset, + std::int64_t max_n_bins, + const Dataset dataset, const Quantiles quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, ObjectiveT objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, bool use_global_memory_histogram) { using BinT = typename ObjectiveT::BinT; extern __shared__ char smem[]; - WorkloadInfo workload_info_cta = workload_info[blockIdx.x]; - IdxT nid = workload_info_cta.nodeid; - const auto work_item = work_items[nid]; - auto range_start = work_item.instances.begin; - auto range_len = work_item.instances.count; + WorkloadInfo workload_info_cta = workload_info[blockIdx.x]; + std::int64_t nid = workload_info_cta.nodeid; + const auto work_item = work_items[nid]; + auto range_start = work_item.instances.begin; + auto range_len = work_item.instances.count; - IdxT offset_blockid = workload_info_cta.offset_blockid; - IdxT num_blocks = workload_info_cta.num_blocks; + std::int64_t offset_blockid = workload_info_cta.offset_blockid; + std::int64_t num_blocks = workload_info_cta.num_blocks; - IdxT colIndex = colStart + blockIdx.y; - IdxT col = column_samples[nid * dataset.n_sampled_cols + colIndex]; - int n_bins = quantiles.n_bins_array[col]; + std::int64_t colIndex = colStart + blockIdx.y; + std::int64_t col = column_samples[nid * dataset.n_sampled_cols + colIndex]; + int n_bins = quantiles.n_bins_array[col]; auto n_classes = objective.NumClasses(); auto end = range_start + range_len; @@ -282,17 +283,17 @@ static __global__ void buildHistogramsKernel(typename ObjectiveT::BinT* histogra auto* global_histogram = histograms + histograms_offset; auto* histogram = global_histogram; auto* quantiles_for_split = quantiles.quantiles_array + std::size_t(max_n_bins) * col; - IdxT stride = blockDim.x * num_blocks; - IdxT tid = threadIdx.x + offset_blockid * blockDim.x; + std::int64_t stride = blockDim.x * num_blocks; + std::int64_t tid = threadIdx.x + offset_blockid * blockDim.x; if (!use_global_memory_histogram) { histogram = alignPointer(smem); auto* shared_quantiles = alignPointer(histogram + histogram_len); quantiles_for_split = shared_quantiles; - for (IdxT i = threadIdx.x; i < histogram_len; i += blockDim.x) { + for (std::int64_t i = threadIdx.x; i < histogram_len; i += blockDim.x) { histogram[i] = BinT(); } - for (IdxT b = threadIdx.x; b < n_bins; b += blockDim.x) { + for (std::int64_t b = threadIdx.x; b < n_bins; b += blockDim.x) { shared_quantiles[b] = quantiles.quantiles_array[max_n_bins * col + b]; } __syncthreads(); @@ -311,79 +312,81 @@ static __global__ void buildHistogramsKernel(typename ObjectiveT::BinT* histogra return quantiles_for_split[bin] < value; }); auto bin = bin_it == bin_end ? n_bins - 1 : *bin_it; - objective.IncrementHistogram(histogram, n_bins, static_cast(bin), label, dataset, row); + objective.IncrementHistogram( + histogram, n_bins, static_cast(bin), label, dataset, row); } if (!use_global_memory_histogram) { __syncthreads(); - for (IdxT i = threadIdx.x; i < histogram_len; i += blockDim.x) { + for (std::int64_t i = threadIdx.x; i < histogram_len; i += blockDim.x) { BinT::AtomicAdd(global_histogram + i, histogram[i]); } } } -template +template static __global__ void findBestSplitsKernel(typename ObjectiveT::BinT* histograms, - IdxT max_n_bins, - const Dataset dataset, + std::int64_t max_n_bins, + const Dataset dataset, const Quantiles quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT objective) { using BinT = typename ObjectiveT::BinT; constexpr int n_split_warps = (TPB + raft::WarpSize - 1) / raft::WarpSize; - __shared__ __align__(alignof(Split)) unsigned char - split_scratch_storage[sizeof(Split) * n_split_warps]; - auto* split_scratch = reinterpret_cast*>(split_scratch_storage); + __shared__ __align__(alignof(Split)) unsigned char + split_scratch_storage[sizeof(Split) * n_split_warps]; + auto* split_scratch = reinterpret_cast*>(split_scratch_storage); - IdxT nid = blockIdx.x; - auto work_item = work_items[nid]; - auto range_len = work_item.instances.count; + std::int64_t nid = blockIdx.x; + auto work_item = work_items[nid]; + auto range_len = work_item.instances.count; - IdxT colIndex = colStart + blockIdx.y; - IdxT col = column_samples[nid * dataset.n_sampled_cols + colIndex]; - int n_bins = quantiles.n_bins_array[col]; + std::int64_t colIndex = colStart + blockIdx.y; + std::int64_t col = column_samples[nid * dataset.n_sampled_cols + colIndex]; + int n_bins = quantiles.n_bins_array[col]; auto n_classes = objective.NumClasses(); auto histograms_offset = (std::size_t(nid) * gridDim.y + blockIdx.y) * max_n_bins * n_classes; auto* histogram = histograms + histograms_offset; auto* quantiles_for_split = quantiles.quantiles_array + std::size_t(max_n_bins) * col; - for (IdxT c = 0; c < n_classes; ++c) { - pdf_to_cdf(histogram + n_bins * c, n_bins); + for (std::int64_t c = 0; c < n_classes; ++c) { + pdf_to_cdf(histogram + n_bins * c, n_bins); } __syncthreads(); - Split sp = objective.Gain(histogram, quantiles_for_split, col, range_len, n_bins); + Split sp = + objective.Gain(histogram, quantiles_for_split, col, range_len, n_bins); __syncthreads(); sp.evalBestSplit(split_scratch, splits + nid, mutex + nid, quantiles_for_split, n_bins); } -template +template void launchComputeSplitKernels(typename ObjectiveT::BinT* histograms, - IdxT max_n_bins, - const Dataset& dataset, + std::int64_t max_n_bins, + const Dataset& dataset, const Quantiles& quantiles, const NodeWorkItem* work_items, - IdxT colStart, - const IdxT* column_samples, + std::int64_t colStart, + const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, cudaStream_t builder_stream) { - buildHistogramsKernel + buildHistogramsKernel <<>>( histograms, max_n_bins, @@ -396,7 +399,7 @@ void launchComputeSplitKernels(typename ObjectiveT::BinT* histograms, workload_info, split_smem_config.use_global_memory_histogram); - findBestSplitsKernel + findBestSplitsKernel <<>>(histograms, max_n_bins, dataset, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu index 50f580d34c..547f937c18 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu @@ -11,9 +11,9 @@ namespace ML { namespace DT { using DataT = double; using LabelT = int; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -28,7 +28,7 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, std::int64_t n_bins, const DatasetT& dataset, @@ -39,7 +39,7 @@ template void launchComputeSplitKernels* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu index fa7e93ef1f..ebeaabff19 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu @@ -11,9 +11,9 @@ namespace ML { namespace DT { using DataT = float; using LabelT = int; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -28,7 +28,7 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, std::int64_t n_bins, const DatasetT& dataset, @@ -39,7 +39,7 @@ template void launchComputeSplitKernels* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu index c8222cabd4..37f415d2db 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu @@ -9,49 +9,49 @@ namespace ML { namespace DT { // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel( +template void launchNodeSplitKernel( const std::int64_t min_samples_leaf, const float min_impurity_decrease, - const Dataset& dataset, + const Dataset& dataset, const NodeWorkItem* work_items, const Split* splits, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, size_t n_blocks_dimx, std::int64_t* partition_row_ids, cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel( +template void launchNodeSplitKernel( const std::int64_t min_samples_leaf, const double min_impurity_decrease, - const Dataset& dataset, + const Dataset& dataset, const NodeWorkItem* work_items, const Split* splits, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, size_t n_blocks_dimx, std::int64_t* partition_row_ids, cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel( +template void launchNodeSplitKernel( const std::int64_t min_samples_leaf, const float min_impurity_decrease, - const Dataset& dataset, + const Dataset& dataset, const NodeWorkItem* work_items, const Split* splits, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, size_t n_blocks_dimx, std::int64_t* partition_row_ids, cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel( +template void launchNodeSplitKernel( const std::int64_t min_samples_leaf, const double min_impurity_decrease, - const Dataset& dataset, + const Dataset& dataset, const NodeWorkItem* work_items, const Split* splits, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, size_t n_blocks_dimx, std::int64_t* partition_row_ids, cudaStream_t builder_stream); diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu index 05b8cba62c..17a67a401d 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu @@ -11,9 +11,9 @@ namespace ML { namespace DT { using DataT = double; using LabelT = double; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -28,7 +28,7 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, std::int64_t n_bins, const DatasetT& dataset, @@ -39,7 +39,7 @@ template void launchComputeSplitKernels* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu index d7f07fc868..1b23792b62 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu @@ -11,9 +11,9 @@ namespace ML { namespace DT { using DataT = float; using LabelT = float; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -28,7 +28,7 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, std::int64_t n_bins, const DatasetT& dataset, @@ -39,7 +39,7 @@ template void launchComputeSplitKernels* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu index 8ecc5aacdc..c06d561e28 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu @@ -11,9 +11,9 @@ namespace ML { namespace DT { using DataT = double; using LabelT = int; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -28,7 +28,7 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, std::int64_t n_bins, const DatasetT& dataset, @@ -39,7 +39,7 @@ template void launchComputeSplitKernels* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu index 27b4a8818c..896fd02a0f 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu @@ -11,9 +11,9 @@ namespace ML { namespace DT { using DataT = float; using LabelT = int; -using ObjectiveT = ClassificationObjectiveFunction; +using ObjectiveT = ClassificationObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -28,7 +28,7 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, std::int64_t n_bins, const DatasetT& dataset, @@ -39,7 +39,7 @@ template void launchComputeSplitKernels* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu index 6645e97f2d..54fde73866 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu @@ -11,9 +11,9 @@ namespace ML { namespace DT { using DataT = double; using LabelT = double; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -28,7 +28,7 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, std::int64_t n_bins, const DatasetT& dataset, @@ -39,7 +39,7 @@ template void launchComputeSplitKernels* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu index 7f67352aad..60dba7415d 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu @@ -11,9 +11,9 @@ namespace ML { namespace DT { using DataT = float; using LabelT = float; -using ObjectiveT = RegressionObjectiveFunction; +using ObjectiveT = RegressionObjectiveFunction; using BinT = typename ObjectiveT::BinT; -using DatasetT = Dataset; +using DatasetT = Dataset; using NodeT = SparseTreeNode; // Explicit instantiations are split across separate .cu files to increase compilation parallelism. @@ -28,7 +28,7 @@ template void launchLeafKernel( cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchComputeSplitKernels( +template void launchComputeSplitKernels( BinT* histograms, std::int64_t n_bins, const DatasetT& dataset, @@ -39,7 +39,7 @@ template void launchComputeSplitKernels* splits, ObjectiveT& objective, - const WorkloadInfo* workload_info, + const WorkloadInfo* workload_info, dim3 histogram_grid, dim3 split_grid, const SharedMemoryConfig& split_smem_config, diff --git a/cpp/src/decisiontree/batched-levelalgo/objectives.cuh b/cpp/src/decisiontree/batched-levelalgo/objectives.cuh index ef37b9ef8b..cf01027c1f 100644 --- a/cpp/src/decisiontree/batched-levelalgo/objectives.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/objectives.cuh @@ -17,31 +17,34 @@ namespace ML { namespace DT { -template +template class ClassificationObjectiveFunction { public: using DataT = DataT_; using LabelT = LabelT_; - using IdxT = IdxT_; using BinT = std::conditional_t; static constexpr bool weighted = weighted_; private: - IdxT nclasses; - IdxT min_samples_leaf; + std::int64_t nclasses; + std::int64_t min_samples_leaf; CRITERION criterion; - HDI double WeightAt(BinT const* hist, IdxT i, IdxT n_bins) const + HDI double WeightAt(BinT const* hist, std::int64_t i, std::int64_t n_bins) const { double weight = 0.0; - for (IdxT j = 0; j < nclasses; ++j) { + for (std::int64_t j = 0; j < nclasses; ++j) { weight += hist[n_bins * j + i].Weight(); } return weight; } - HDI DataT - GiniGain(BinT const* hist, IdxT i, IdxT n_bins, std::int64_t, std::int64_t, std::int64_t) const + HDI DataT GiniGain(BinT const* hist, + std::int64_t i, + std::int64_t n_bins, + std::int64_t, + std::int64_t, + std::int64_t) const { constexpr DataT One = DataT(1.0); auto total_weight = WeightAt(hist, n_bins - 1, n_bins); @@ -56,7 +59,7 @@ class ClassificationObjectiveFunction { auto invRight = One / DataT(right_weight); auto gain = DataT(0.0); - for (IdxT j = 0; j < nclasses; ++j) { + for (std::int64_t j = 0; j < nclasses; ++j) { double val_i = 0.0; auto lval_i = hist[n_bins * j + i].Weight(); auto lval = DataT(lval_i); @@ -76,8 +79,12 @@ class ClassificationObjectiveFunction { return gain; } - HDI DataT - EntropyGain(BinT const* hist, IdxT i, IdxT n_bins, std::int64_t, std::int64_t, std::int64_t) const + HDI DataT EntropyGain(BinT const* hist, + std::int64_t i, + std::int64_t n_bins, + std::int64_t, + std::int64_t, + std::int64_t) const { auto total_weight = WeightAt(hist, n_bins - 1, n_bins); auto left_weight = WeightAt(hist, i, n_bins); @@ -90,7 +97,7 @@ class ClassificationObjectiveFunction { auto invLeft{DataT(1.0) / DataT(left_weight)}; auto invRight{DataT(1.0) / DataT(right_weight)}; auto invLen{DataT(1.0) / DataT(total_weight)}; - for (IdxT c = 0; c < nclasses; ++c) { + for (std::int64_t c = 0; c < nclasses; ++c) { double val_i = 0.0; auto lval_i = hist[n_bins * c + i].Weight(); if (lval_i != 0) { @@ -118,8 +125,8 @@ class ClassificationObjectiveFunction { public: HDI DataT GainPerSplit(BinT const* hist, - IdxT i, - IdxT n_bins, + std::int64_t i, + std::int64_t n_bins, std::int64_t len, std::int64_t nLeft, std::int64_t nRight) const @@ -135,16 +142,22 @@ class ClassificationObjectiveFunction { } } - HDI ClassificationObjectiveFunction(IdxT nclasses, IdxT min_samples_leaf, CRITERION criterion) + HDI ClassificationObjectiveFunction(std::int64_t nclasses, + std::int64_t min_samples_leaf, + CRITERION criterion) : nclasses(nclasses), min_samples_leaf(min_samples_leaf), criterion(criterion) { } - DI IdxT NumClasses() const { return nclasses; } + DI std::int64_t NumClasses() const { return nclasses; } template - DI void IncrementHistogram( - BinT* histogram, IdxT n_bins, IdxT bin, LabelT label, const DatasetT& dataset, IdxT row) const + DI void IncrementHistogram(BinT* histogram, + std::int64_t n_bins, + std::int64_t bin, + LabelT label, + const DatasetT& dataset, + std::int64_t row) const { double weight = 1.0; if constexpr (weighted) { @@ -153,11 +166,14 @@ class ClassificationObjectiveFunction { BinT::IncrementHistogram(histogram, n_bins, bin, label, weight); } - DI Split Gain( - BinT const* shist, DataT const* squantiles, IdxT col, std::int64_t len, IdxT n_bins) const + DI Split Gain(BinT const* shist, + DataT const* squantiles, + std::int64_t col, + std::int64_t len, + std::int64_t n_bins) const { - Split sp; - for (IdxT i = threadIdx.x; i < n_bins; i += blockDim.x) { + Split sp; + for (std::int64_t i = threadIdx.x; i < n_bins; i += blockDim.x) { auto nLeft = detail::CountLeft(shist, i, n_bins, nclasses); auto nRight = len - nLeft; auto gain = -std::numeric_limits::max(); @@ -189,22 +205,25 @@ class ClassificationObjectiveFunction { } }; -template +template class RegressionObjectiveFunction { public: using DataT = DataT_; using LabelT = LabelT_; - using IdxT = IdxT_; using BinT = std::conditional_t; static constexpr bool weighted = weighted_; private: - IdxT min_samples_leaf; + std::int64_t min_samples_leaf; CRITERION criterion; static constexpr auto eps_ = 10 * std::numeric_limits::epsilon(); - HDI DataT - MSEGain(BinT const* hist, IdxT i, IdxT n_bins, std::int64_t, std::int64_t, std::int64_t) const + HDI DataT MSEGain(BinT const* hist, + std::int64_t i, + std::int64_t n_bins, + std::int64_t, + std::int64_t, + std::int64_t) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -226,8 +245,12 @@ class RegressionObjectiveFunction { return gain; } - HDI DataT - PoissonGain(BinT const* hist, IdxT i, IdxT n_bins, std::int64_t, std::int64_t, std::int64_t) const + HDI DataT PoissonGain(BinT const* hist, + std::int64_t i, + std::int64_t n_bins, + std::int64_t, + std::int64_t, + std::int64_t) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -254,8 +277,12 @@ class RegressionObjectiveFunction { return gain; } - HDI DataT - GammaGain(BinT const* hist, IdxT i, IdxT n_bins, std::int64_t, std::int64_t, std::int64_t) const + HDI DataT GammaGain(BinT const* hist, + std::int64_t i, + std::int64_t n_bins, + std::int64_t, + std::int64_t, + std::int64_t) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -282,8 +309,12 @@ class RegressionObjectiveFunction { return gain; } - HDI DataT InverseGaussianGain( - BinT const* hist, IdxT i, IdxT n_bins, std::int64_t, std::int64_t, std::int64_t) const + HDI DataT InverseGaussianGain(BinT const* hist, + std::int64_t i, + std::int64_t n_bins, + std::int64_t, + std::int64_t, + std::int64_t) const { auto parent_weight = hist[n_bins - 1].Weight(); auto left_weight = hist[i].Weight(); @@ -311,8 +342,8 @@ class RegressionObjectiveFunction { public: HDI DataT GainPerSplit(BinT const* hist, - IdxT i, - IdxT n_bins, + std::int64_t i, + std::int64_t n_bins, std::int64_t len, std::int64_t nLeft, std::int64_t nRight) const @@ -331,16 +362,20 @@ class RegressionObjectiveFunction { } } - HDI RegressionObjectiveFunction(IdxT, IdxT min_samples_leaf, CRITERION criterion) + HDI RegressionObjectiveFunction(std::int64_t, std::int64_t min_samples_leaf, CRITERION criterion) : min_samples_leaf(min_samples_leaf), criterion(criterion) { } - DI IdxT NumClasses() const { return 1; } + DI std::int64_t NumClasses() const { return 1; } template - DI void IncrementHistogram( - BinT* histogram, IdxT n_bins, IdxT bin, LabelT label, const DatasetT& dataset, IdxT row) const + DI void IncrementHistogram(BinT* histogram, + std::int64_t n_bins, + std::int64_t bin, + LabelT label, + const DatasetT& dataset, + std::int64_t row) const { double weight = 1.0; if constexpr (weighted) { @@ -349,12 +384,15 @@ class RegressionObjectiveFunction { BinT::IncrementHistogram(histogram, n_bins, bin, label, weight); } - DI Split Gain( - BinT const* shist, DataT const* squantiles, IdxT col, std::int64_t len, IdxT n_bins) const + DI Split Gain(BinT const* shist, + DataT const* squantiles, + std::int64_t col, + std::int64_t len, + std::int64_t n_bins) const { - Split sp; - for (IdxT i = threadIdx.x; i < n_bins; i += blockDim.x) { - auto nLeft = detail::CountLeft(shist, i, n_bins, IdxT{1}); + Split sp; + for (std::int64_t i = threadIdx.x; i < n_bins; i += blockDim.x) { + auto nLeft = detail::CountLeft(shist, i, n_bins, std::int64_t{1}); auto nRight = len - nLeft; auto gain = -std::numeric_limits::max(); if (nLeft >= static_cast(min_samples_leaf) && diff --git a/cpp/src/decisiontree/decisiontree.cuh b/cpp/src/decisiontree/decisiontree.cuh index c5721d799c..aee148c09c 100644 --- a/cpp/src/decisiontree/decisiontree.cuh +++ b/cpp/src/decisiontree/decisiontree.cuh @@ -254,41 +254,40 @@ class DecisionTree { (std::numeric_limits::is_integer) ? CRITERION::GINI : CRITERION::MSE; params.split_criterion = default_criterion; } - using IdxT = std::int64_t; // Dispatch objective family. The objective object switches on the criterion at runtime. if (not std::is_same::value and (params.split_criterion == CRITERION::GINI || params.split_criterion == CRITERION::ENTROPY)) { if (sample_weight != nullptr) { - return Builder>(handle, - s, - treeid, - seed, - params, - data, - labels, - sample_weight, - nrows, - ncols, - row_ids, - unique_labels, - quantiles, - row_major) + return Builder>(handle, + s, + treeid, + seed, + params, + data, + labels, + sample_weight, + nrows, + ncols, + row_ids, + unique_labels, + quantiles, + row_major) .train(); } - return Builder>(handle, - s, - treeid, - seed, - params, - data, - labels, - sample_weight, - nrows, - ncols, - row_ids, - unique_labels, - quantiles, - row_major) + return Builder>(handle, + s, + treeid, + seed, + params, + data, + labels, + sample_weight, + nrows, + ncols, + row_ids, + unique_labels, + quantiles, + row_major) .train(); } else if (std::is_same::value and (params.split_criterion == CRITERION::MSE || @@ -296,36 +295,36 @@ class DecisionTree { params.split_criterion == CRITERION::GAMMA || params.split_criterion == CRITERION::INVERSE_GAUSSIAN)) { if (sample_weight != nullptr) { - return Builder>(handle, - s, - treeid, - seed, - params, - data, - labels, - sample_weight, - nrows, - ncols, - row_ids, - unique_labels, - quantiles, - row_major) + return Builder>(handle, + s, + treeid, + seed, + params, + data, + labels, + sample_weight, + nrows, + ncols, + row_ids, + unique_labels, + quantiles, + row_major) .train(); } - return Builder>(handle, - s, - treeid, - seed, - params, - data, - labels, - sample_weight, - nrows, - ncols, - row_ids, - unique_labels, - quantiles, - row_major) + return Builder>(handle, + s, + treeid, + seed, + params, + data, + labels, + sample_weight, + nrows, + ncols, + row_ids, + unique_labels, + quantiles, + row_major) .train(); } else { ASSERT(false, "Unknown split criterion."); diff --git a/cpp/tests/sg/rf_test.cu b/cpp/tests/sg/rf_test.cu index 85e889f287..2db36d1741 100644 --- a/cpp/tests/sg/rf_test.cu +++ b/cpp/tests/sg/rf_test.cu @@ -1308,7 +1308,7 @@ TEST(RFEquivalentSplitRangeTest, ClassificationChoosesUpperMiddleBin) thrust::device_vector> split(1); thrust::device_vector mutex(1); - DT::ClassificationObjectiveFunction objective(2, 1, CRITERION::GINI); + DT::ClassificationObjectiveFunction objective(2, 1, CRITERION::GINI); objectiveGainKernel<<<1, 32, 0, handle.get_stream()>>>(hist.data().get(), quantiles.data().get(), split.data().get(), @@ -1356,7 +1356,7 @@ TEST(RFEquivalentSplitRangeTest, RegressionChoosesUpperMiddleBin) thrust::device_vector> split(1); thrust::device_vector mutex(1); - DT::RegressionObjectiveFunction objective(1, 1, CRITERION::MSE); + DT::RegressionObjectiveFunction objective(1, 1, CRITERION::MSE); objectiveGainKernel<<<1, 32, 0, handle.get_stream()>>>(hist.data().get(), quantiles.data().get(), split.data().get(), @@ -1832,7 +1832,6 @@ class ObjectiveTest : public ::testing::TestWithParam { using ObjectiveT = typename ObjectiveConfig::ObjectiveT; typedef typename ObjectiveT::DataT DataT; typedef typename ObjectiveT::LabelT LabelT; - typedef typename ObjectiveT::IdxT IdxT; typedef typename ObjectiveT::BinT BinT; static constexpr auto eps_ = 10 * std::numeric_limits::epsilon(); @@ -2270,11 +2269,11 @@ class ObjectiveTest : public ::testing::TestWithParam { return DataT(0.0); } - auto NumLeftOfBin(std::vector const& cdf_hist, IdxT idx) + auto NumLeftOfBin(std::vector const& cdf_hist, std::int64_t idx) { - auto count{IdxT(0)}; + auto count{std::int64_t(0)}; for (auto c = 0; c < params.n_classes; ++c) { - count += static_cast(cdf_hist[params.max_n_bins * c + idx].Count()); + count += static_cast(cdf_hist[params.max_n_bins * c + idx].Count()); } return count; } @@ -2306,7 +2305,7 @@ class ObjectiveTest : public ::testing::TestWithParam { TEST(WeightedObjectiveEdgeCases, ClassificationRejectsZeroWeightChild) { - using ObjectiveT = ClassificationObjectiveFunction; + using ObjectiveT = ClassificationObjectiveFunction; WeightedClassificationBin hist[]{{1, 0.0}, {1, 0.0}, {0, 0.0}, {1, 1.0}}; CRITERION criteria[] = {CRITERION::GINI, CRITERION::ENTROPY}; @@ -2319,7 +2318,7 @@ TEST(WeightedObjectiveEdgeCases, ClassificationRejectsZeroWeightChild) TEST(WeightedObjectiveEdgeCases, RegressionRejectsZeroWeightChild) { - using ObjectiveT = RegressionObjectiveFunction; + using ObjectiveT = RegressionObjectiveFunction; WeightedRegressionBin hist[]{{0.0, 1, 0.0}, {2.0, 2, 1.0}}; CRITERION criteria[] = { CRITERION::MSE, CRITERION::POISSON, CRITERION::GAMMA, CRITERION::INVERSE_GAUSSIAN}; @@ -2381,28 +2380,28 @@ const std::vector gini_objective_test_parameters = { // mse objective test typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::MSE>> + ObjectiveTestConfig, CRITERION::MSE>> MSEObjectiveTestD; TEST_P(MSEObjectiveTestD, MSEObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, MSEObjectiveTestD, ::testing::ValuesIn(mse_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::MSE>> + ObjectiveTestConfig, CRITERION::MSE>> MSEObjectiveTestF; TEST_P(MSEObjectiveTestF, MSEObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, MSEObjectiveTestF, ::testing::ValuesIn(mse_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::MSE>> + ObjectiveTestConfig, CRITERION::MSE>> WeightedMSEObjectiveTestD; TEST_P(WeightedMSEObjectiveTestD, MSEObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedMSEObjectiveTestD, ::testing::ValuesIn(mse_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::MSE>> + ObjectiveTestConfig, CRITERION::MSE>> WeightedMSEObjectiveTestF; TEST_P(WeightedMSEObjectiveTestF, MSEObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, @@ -2411,28 +2410,28 @@ INSTANTIATE_TEST_CASE_P(RfTests, // poisson objective test typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::POISSON>> + ObjectiveTestConfig, CRITERION::POISSON>> PoissonObjectiveTestD; TEST_P(PoissonObjectiveTestD, poissonObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, PoissonObjectiveTestD, ::testing::ValuesIn(poisson_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::POISSON>> + ObjectiveTestConfig, CRITERION::POISSON>> PoissonObjectiveTestF; TEST_P(PoissonObjectiveTestF, poissonObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, PoissonObjectiveTestF, ::testing::ValuesIn(poisson_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::POISSON>> + ObjectiveTestConfig, CRITERION::POISSON>> WeightedPoissonObjectiveTestD; TEST_P(WeightedPoissonObjectiveTestD, poissonObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedPoissonObjectiveTestD, ::testing::ValuesIn(poisson_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::POISSON>> + ObjectiveTestConfig, CRITERION::POISSON>> WeightedPoissonObjectiveTestF; TEST_P(WeightedPoissonObjectiveTestF, poissonObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, @@ -2441,28 +2440,28 @@ INSTANTIATE_TEST_CASE_P(RfTests, // gamma objective test typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GAMMA>> + ObjectiveTestConfig, CRITERION::GAMMA>> GammaObjectiveTestD; TEST_P(GammaObjectiveTestD, GammaObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, GammaObjectiveTestD, ::testing::ValuesIn(gamma_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GAMMA>> + ObjectiveTestConfig, CRITERION::GAMMA>> GammaObjectiveTestF; TEST_P(GammaObjectiveTestF, GammaObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, GammaObjectiveTestF, ::testing::ValuesIn(gamma_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GAMMA>> + ObjectiveTestConfig, CRITERION::GAMMA>> WeightedGammaObjectiveTestD; TEST_P(WeightedGammaObjectiveTestD, GammaObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedGammaObjectiveTestD, ::testing::ValuesIn(gamma_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GAMMA>> + ObjectiveTestConfig, CRITERION::GAMMA>> WeightedGammaObjectiveTestF; TEST_P(WeightedGammaObjectiveTestF, GammaObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, @@ -2470,29 +2469,29 @@ INSTANTIATE_TEST_CASE_P(RfTests, ::testing::ValuesIn(gamma_objective_test_parameters)); // InvGauss objective test -typedef ObjectiveTest, - CRITERION::INVERSE_GAUSSIAN>> +typedef ObjectiveTest< + ObjectiveTestConfig, CRITERION::INVERSE_GAUSSIAN>> InverseGaussianObjectiveTestD; TEST_P(InverseGaussianObjectiveTestD, InverseGaussianObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, InverseGaussianObjectiveTestD, ::testing::ValuesIn(invgauss_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::INVERSE_GAUSSIAN>> + ObjectiveTestConfig, CRITERION::INVERSE_GAUSSIAN>> InverseGaussianObjectiveTestF; TEST_P(InverseGaussianObjectiveTestF, InverseGaussianObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, InverseGaussianObjectiveTestF, ::testing::ValuesIn(invgauss_objective_test_parameters)); -typedef ObjectiveTest, +typedef ObjectiveTest, CRITERION::INVERSE_GAUSSIAN>> WeightedInverseGaussianObjectiveTestD; TEST_P(WeightedInverseGaussianObjectiveTestD, InverseGaussianObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedInverseGaussianObjectiveTestD, ::testing::ValuesIn(invgauss_objective_test_parameters)); -typedef ObjectiveTest, - CRITERION::INVERSE_GAUSSIAN>> +typedef ObjectiveTest< + ObjectiveTestConfig, CRITERION::INVERSE_GAUSSIAN>> WeightedInverseGaussianObjectiveTestF; TEST_P(WeightedInverseGaussianObjectiveTestF, InverseGaussianObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, @@ -2501,28 +2500,28 @@ INSTANTIATE_TEST_CASE_P(RfTests, // entropy objective test typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::ENTROPY>> + ObjectiveTestConfig, CRITERION::ENTROPY>> EntropyObjectiveTestD; TEST_P(EntropyObjectiveTestD, entropyObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, EntropyObjectiveTestD, ::testing::ValuesIn(entropy_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::ENTROPY>> + ObjectiveTestConfig, CRITERION::ENTROPY>> EntropyObjectiveTestF; TEST_P(EntropyObjectiveTestF, entropyObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, EntropyObjectiveTestF, ::testing::ValuesIn(entropy_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::ENTROPY>> + ObjectiveTestConfig, CRITERION::ENTROPY>> WeightedEntropyObjectiveTestD; TEST_P(WeightedEntropyObjectiveTestD, entropyObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedEntropyObjectiveTestD, ::testing::ValuesIn(entropy_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::ENTROPY>> + ObjectiveTestConfig, CRITERION::ENTROPY>> WeightedEntropyObjectiveTestF; TEST_P(WeightedEntropyObjectiveTestF, entropyObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, @@ -2531,28 +2530,28 @@ INSTANTIATE_TEST_CASE_P(RfTests, // gini objective test typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GINI>> + ObjectiveTestConfig, CRITERION::GINI>> GiniObjectiveTestD; TEST_P(GiniObjectiveTestD, giniObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, GiniObjectiveTestD, ::testing::ValuesIn(gini_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GINI>> + ObjectiveTestConfig, CRITERION::GINI>> GiniObjectiveTestF; TEST_P(GiniObjectiveTestF, giniObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, GiniObjectiveTestF, ::testing::ValuesIn(gini_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GINI>> + ObjectiveTestConfig, CRITERION::GINI>> WeightedGiniObjectiveTestD; TEST_P(WeightedGiniObjectiveTestD, giniObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, WeightedGiniObjectiveTestD, ::testing::ValuesIn(gini_objective_test_parameters)); typedef ObjectiveTest< - ObjectiveTestConfig, CRITERION::GINI>> + ObjectiveTestConfig, CRITERION::GINI>> WeightedGiniObjectiveTestF; TEST_P(WeightedGiniObjectiveTestF, giniObjectiveTest) {} INSTANTIATE_TEST_CASE_P(RfTests, From 733925446f3bc15b78e20a3168822e07b90e3325 Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Tue, 14 Jul 2026 20:52:43 +0200 Subject: [PATCH 08/14] Simplify RF split signatures --- .../batched-levelalgo/builder.cuh | 4 +- .../kernels/builder_kernels.cuh | 4 +- .../kernels/builder_kernels_impl.cuh | 19 +++--- .../kernels/classification-double.cu | 2 +- .../kernels/classification-float.cu | 2 +- .../batched-levelalgo/kernels/node-split.cu | 59 +++++++++---------- .../kernels/regression-double.cu | 2 +- .../kernels/regression-float.cu | 2 +- .../kernels/weighted-classification-double.cu | 2 +- .../kernels/weighted-classification-float.cu | 2 +- .../kernels/weighted-regression-double.cu | 2 +- .../kernels/weighted-regression-float.cu | 2 +- .../batched-levelalgo/objectives.cuh | 24 ++++---- .../decisiontree/batched-levelalgo/split.cuh | 50 +++++++++------- cpp/tests/sg/rf_test.cu | 44 +++++++------- 15 files changed, 110 insertions(+), 110 deletions(-) diff --git a/cpp/src/decisiontree/batched-levelalgo/builder.cuh b/cpp/src/decisiontree/batched-levelalgo/builder.cuh index 4e5d383710..373dc66f72 100644 --- a/cpp/src/decisiontree/batched-levelalgo/builder.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/builder.cuh @@ -154,7 +154,7 @@ struct Builder { typedef typename ObjectiveT::LabelT LabelT; typedef typename ObjectiveT::BinT BinT; typedef SparseTreeNode NodeT; - typedef Split SplitT; + typedef Split SplitT; typedef Dataset DatasetT; typedef Quantiles QuantilesT; @@ -474,7 +474,7 @@ struct Builder { uint64_t sampling_seed, std::int64_t sample_offset) { - initSplit(splits, work_items.size(), builder_stream); + initSplit(splits, work_items.size(), builder_stream); RAFT_CUDA_TRY(cudaMemsetAsync(mutex, 0, sizeof(int) * params.max_batch_size, builder_stream)); raft::update_device(d_work_items, work_items.data(), work_items.size(), builder_stream); auto n_blocks_dimx = this->updateWorkloadInfo(work_items); diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh index b7f40803f4..d1fcef758c 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh @@ -114,7 +114,7 @@ void launchNodeSplitKernel(const std::int64_t min_samples_leaf, const DataT min_impurity_decrease, const Dataset& dataset, const NodeWorkItem* work_items, - const Split* splits, + const Split* splits, const WorkloadInfo* workload_info, size_t n_blocks_dimx, std::int64_t* partition_row_ids, @@ -138,7 +138,7 @@ void launchComputeSplitKernels(typename ObjectiveT::BinT* histograms, std::int64_t colStart, const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, const WorkloadInfo* workload_info, dim3 histogram_grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh index eb29a7d288..c4fded35fd 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh @@ -54,7 +54,7 @@ template struct NodeSplitPartitionWriter { Dataset dataset; const NodeWorkItem* work_items; - const Split* splits; + const Split* splits; const WorkloadInfo* workload_info; std::int64_t* partition_row_ids; @@ -87,7 +87,7 @@ static __global__ void nodeSplitCopyBackKernel(const std::int64_t min_samples_le const DataT min_impurity_decrease, const Dataset dataset, const NodeWorkItem* work_items, - const Split* splits, + const Split* splits, const WorkloadInfo* workload_info, const std::int64_t* partition_row_ids) { @@ -113,7 +113,7 @@ void launchNodeSplitKernel(const std::int64_t min_samples_leaf, const DataT min_impurity_decrease, const Dataset& dataset, const NodeWorkItem* work_items, - const Split* splits, + const Split* splits, const WorkloadInfo* workload_info, size_t n_blocks_dimx, std::int64_t* partition_row_ids, @@ -333,14 +333,14 @@ static __global__ void findBestSplitsKernel(typename ObjectiveT::BinT* histogram std::int64_t colStart, const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT objective) { using BinT = typename ObjectiveT::BinT; constexpr int n_split_warps = (TPB + raft::WarpSize - 1) / raft::WarpSize; - __shared__ __align__(alignof(Split)) unsigned char - split_scratch_storage[sizeof(Split) * n_split_warps]; - auto* split_scratch = reinterpret_cast*>(split_scratch_storage); + __shared__ __align__(alignof( + Split)) unsigned char split_scratch_storage[sizeof(Split) * n_split_warps]; + auto* split_scratch = reinterpret_cast*>(split_scratch_storage); std::int64_t nid = blockIdx.x; auto work_item = work_items[nid]; @@ -361,8 +361,7 @@ static __global__ void findBestSplitsKernel(typename ObjectiveT::BinT* histogram __syncthreads(); - Split sp = - objective.Gain(histogram, quantiles_for_split, col, range_len, n_bins); + Split sp = objective.Gain(histogram, quantiles_for_split, col, range_len, n_bins); __syncthreads(); @@ -378,7 +377,7 @@ void launchComputeSplitKernels(typename ObjectiveT::BinT* histograms, std::int64_t colStart, const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, const WorkloadInfo* workload_info, dim3 histogram_grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu index 547f937c18..30ae32ccc6 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-double.cu @@ -37,7 +37,7 @@ template void launchComputeSplitKernels( std::int64_t colStart, const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, const WorkloadInfo* workload_info, dim3 histogram_grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu index ebeaabff19..79831a6ca0 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/classification-float.cu @@ -37,7 +37,7 @@ template void launchComputeSplitKernels( std::int64_t colStart, const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, const WorkloadInfo* workload_info, dim3 histogram_grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu index 37f415d2db..8b8553ea58 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/node-split.cu @@ -9,40 +9,37 @@ namespace ML { namespace DT { // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel( - const std::int64_t min_samples_leaf, - const float min_impurity_decrease, - const Dataset& dataset, - const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, - size_t n_blocks_dimx, - std::int64_t* partition_row_ids, - cudaStream_t builder_stream); +template void launchNodeSplitKernel(const std::int64_t min_samples_leaf, + const float min_impurity_decrease, + const Dataset& dataset, + const NodeWorkItem* work_items, + const Split* splits, + const WorkloadInfo* workload_info, + size_t n_blocks_dimx, + std::int64_t* partition_row_ids, + cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel( - const std::int64_t min_samples_leaf, - const double min_impurity_decrease, - const Dataset& dataset, - const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, - size_t n_blocks_dimx, - std::int64_t* partition_row_ids, - cudaStream_t builder_stream); +template void launchNodeSplitKernel(const std::int64_t min_samples_leaf, + const double min_impurity_decrease, + const Dataset& dataset, + const NodeWorkItem* work_items, + const Split* splits, + const WorkloadInfo* workload_info, + size_t n_blocks_dimx, + std::int64_t* partition_row_ids, + cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. -template void launchNodeSplitKernel( - const std::int64_t min_samples_leaf, - const float min_impurity_decrease, - const Dataset& dataset, - const NodeWorkItem* work_items, - const Split* splits, - const WorkloadInfo* workload_info, - size_t n_blocks_dimx, - std::int64_t* partition_row_ids, - cudaStream_t builder_stream); +template void launchNodeSplitKernel(const std::int64_t min_samples_leaf, + const float min_impurity_decrease, + const Dataset& dataset, + const NodeWorkItem* work_items, + const Split* splits, + const WorkloadInfo* workload_info, + size_t n_blocks_dimx, + std::int64_t* partition_row_ids, + cudaStream_t builder_stream); // Explicit instantiations are split across separate .cu files to increase compilation parallelism. template void launchNodeSplitKernel( @@ -50,7 +47,7 @@ template void launchNodeSplitKernel( const double min_impurity_decrease, const Dataset& dataset, const NodeWorkItem* work_items, - const Split* splits, + const Split* splits, const WorkloadInfo* workload_info, size_t n_blocks_dimx, std::int64_t* partition_row_ids, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu index 17a67a401d..2748e9bc31 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-double.cu @@ -37,7 +37,7 @@ template void launchComputeSplitKernels( std::int64_t colStart, const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, const WorkloadInfo* workload_info, dim3 histogram_grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu index 1b23792b62..ab57f06cd7 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/regression-float.cu @@ -37,7 +37,7 @@ template void launchComputeSplitKernels( std::int64_t colStart, const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, const WorkloadInfo* workload_info, dim3 histogram_grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu index c06d561e28..a56ac9f761 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-double.cu @@ -37,7 +37,7 @@ template void launchComputeSplitKernels( std::int64_t colStart, const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, const WorkloadInfo* workload_info, dim3 histogram_grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu index 896fd02a0f..a2ac262a9d 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-classification-float.cu @@ -37,7 +37,7 @@ template void launchComputeSplitKernels( std::int64_t colStart, const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, const WorkloadInfo* workload_info, dim3 histogram_grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu index 54fde73866..6e50a2e61c 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-double.cu @@ -37,7 +37,7 @@ template void launchComputeSplitKernels( std::int64_t colStart, const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, const WorkloadInfo* workload_info, dim3 histogram_grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu index 60dba7415d..e2f1ae5955 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/weighted-regression-float.cu @@ -37,7 +37,7 @@ template void launchComputeSplitKernels( std::int64_t colStart, const std::int64_t* column_samples, int* mutex, - volatile Split* splits, + volatile Split* splits, ObjectiveT& objective, const WorkloadInfo* workload_info, dim3 histogram_grid, diff --git a/cpp/src/decisiontree/batched-levelalgo/objectives.cuh b/cpp/src/decisiontree/batched-levelalgo/objectives.cuh index cf01027c1f..03cde3c0ec 100644 --- a/cpp/src/decisiontree/batched-levelalgo/objectives.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/objectives.cuh @@ -166,13 +166,13 @@ class ClassificationObjectiveFunction { BinT::IncrementHistogram(histogram, n_bins, bin, label, weight); } - DI Split Gain(BinT const* shist, - DataT const* squantiles, - std::int64_t col, - std::int64_t len, - std::int64_t n_bins) const + DI Split Gain(BinT const* shist, + DataT const* squantiles, + std::int64_t col, + std::int64_t len, + std::int64_t n_bins) const { - Split sp; + Split sp; for (std::int64_t i = threadIdx.x; i < n_bins; i += blockDim.x) { auto nLeft = detail::CountLeft(shist, i, n_bins, nclasses); auto nRight = len - nLeft; @@ -384,13 +384,13 @@ class RegressionObjectiveFunction { BinT::IncrementHistogram(histogram, n_bins, bin, label, weight); } - DI Split Gain(BinT const* shist, - DataT const* squantiles, - std::int64_t col, - std::int64_t len, - std::int64_t n_bins) const + DI Split Gain(BinT const* shist, + DataT const* squantiles, + std::int64_t col, + std::int64_t len, + std::int64_t n_bins) const { - Split sp; + Split sp; for (std::int64_t i = threadIdx.x; i < n_bins; i += blockDim.x) { auto nLeft = detail::CountLeft(shist, i, n_bins, std::int64_t{1}); auto nRight = len - nLeft; diff --git a/cpp/src/decisiontree/batched-levelalgo/split.cuh b/cpp/src/decisiontree/batched-levelalgo/split.cuh index 5d2b42cdf6..b1b0830794 100644 --- a/cpp/src/decisiontree/batched-levelalgo/split.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/split.cuh @@ -16,11 +16,14 @@ namespace ML { namespace DT { namespace detail { -template -DI std::int64_t CountLeft(BinT const* hist, IdxT i, IdxT n_bins, IdxT n_outputs) +template +DI std::int64_t CountLeft(BinT const* hist, + std::int64_t i, + std::int64_t n_bins, + std::int64_t n_outputs) { auto nLeft = hist[i].Count(); - for (IdxT j = 1; j < n_outputs; ++j) { + for (std::int64_t j = 1; j < n_outputs; ++j) { nLeft += hist[n_bins * j + i].Count(); } return static_cast(nLeft); @@ -33,16 +36,16 @@ DI std::int64_t CountLeft(BinT const* hist, IdxT i, IdxT n_bins, IdxT n_outputs) * * @tparam DataT input data type */ -template +template struct Split { - typedef Split SplitT; + typedef Split SplitT; /** start with this as the initial gain */ static constexpr DataT Min = -std::numeric_limits::max(); /** threshold to compare in this node */ DataT quesval; /** feature index */ - IdxT colid; + std::int64_t colid; /** best info gain on this node */ DataT best_metric_val; /** global number of samples in the left child */ @@ -50,16 +53,16 @@ struct Split { /** rank-local number of samples in the left child */ std::int64_t local_nLeft; /** first quantile index in an inclusive range of training-equivalent splits */ - IdxT split_start; + std::int64_t split_start; /** last quantile index in an inclusive range of training-equivalent splits */ - IdxT split_end; + std::int64_t split_end; HDI Split(DataT quesval, - IdxT colid, + std::int64_t colid, DataT best_metric_val, std::int64_t global_nLeft, std::int64_t local_nLeft, - IdxT bin) + std::int64_t bin) : quesval(quesval), colid(colid), best_metric_val(best_metric_val), @@ -94,7 +97,7 @@ struct Split { DI bool has_valid_split_range() const { - return split_start >= IdxT{0} && split_end >= split_start; + return split_start >= std::int64_t{0} && split_end >= split_start; } DI bool can_merge_equivalent_split_range(const SplitT& other) const @@ -122,7 +125,7 @@ struct Split { // Several thresholds can be equally good for the training data while still // routing future inference values differently. Select the middle split in // that equivalent range so deterministic tie-breaking does not pick an edge. - DI void select_split_range_midpoint(DataT const* quantiles, IdxT n_bins) + DI void select_split_range_midpoint(DataT const* quantiles, std::int64_t n_bins) { if (has_valid_split_range() && split_end < n_bins) { auto bin = split_start + (split_end - split_start + 1) / 2; @@ -193,8 +196,11 @@ struct Split { * @note all threads in the block must enter this function together. At the * end thread0 will contain the best split. */ - DI void evalBestSplit( - SplitT* split_scratch, volatile SplitT* split, int* mutex, DataT const* quantiles, IdxT n_bins) + DI void evalBestSplit(SplitT* split_scratch, + volatile SplitT* split, + int* mutex, + DataT const* quantiles, + std::int64_t n_bins) { warpReduce(); auto warp = threadIdx.x / raft::WarpSize; @@ -246,17 +252,17 @@ struct Split { * @param[in] len length of this array * @param[in] s cuda stream where to schedule work */ -template -void initSplit(Split* splits, IdxT len, cudaStream_t s) +template +void initSplit(Split* splits, std::int64_t len, cudaStream_t s) { - auto op = [] __device__(Split * ptr, IdxT idx) { *ptr = Split(); }; - raft::linalg::writeOnlyUnaryOp, decltype(op), IdxT, TPB>(splits, len, op, s); + auto op = [] __device__(Split * ptr, std::int64_t idx) { *ptr = Split(); }; + raft::linalg::writeOnlyUnaryOp, decltype(op), std::int64_t, TPB>(splits, len, op, s); } -template -void printSplits(Split* splits, IdxT len, cudaStream_t s) +template +void printSplits(Split* splits, std::int64_t len, cudaStream_t s) { - auto op = [] __device__(Split * ptr, IdxT idx) { + auto op = [] __device__(Split * ptr, std::int64_t idx) { printf( "quesval = %e, colid = %lld, best_metric_val = %e, global_nLeft = %lld, " "local_nLeft = %lld, split_range = [%lld, %lld]\n", @@ -268,7 +274,7 @@ void printSplits(Split* splits, IdxT len, cudaStream_t s) static_cast(ptr->split_start), static_cast(ptr->split_end)); }; - raft::linalg::writeOnlyUnaryOp, decltype(op), IdxT, TPB>(splits, len, op, s); + raft::linalg::writeOnlyUnaryOp, decltype(op), std::int64_t, TPB>(splits, len, op, s); RAFT_CUDA_TRY(cudaDeviceSynchronize()); } diff --git a/cpp/tests/sg/rf_test.cu b/cpp/tests/sg/rf_test.cu index 2db36d1741..8bdfd7ff69 100644 --- a/cpp/tests/sg/rf_test.cu +++ b/cpp/tests/sg/rf_test.cu @@ -1253,21 +1253,21 @@ class RFSampledQuantileDeterminismTest : public ::testing::TestWithParam +template __global__ void objectiveGainKernel(BinT const* hist, DataT const* quantiles, - DT::Split* out, + DT::Split* out, int* mutex, ObjectiveT objective, - IdxT col, - IdxT len, - IdxT n_bins) + std::int64_t col, + std::int64_t len, + std::int64_t n_bins) { - __shared__ __align__(alignof( - DT::Split)) unsigned char split_scratch_storage[sizeof(DT::Split)]; - auto* split_scratch = reinterpret_cast*>(split_scratch_storage); + __shared__ __align__( + alignof(DT::Split)) unsigned char split_scratch_storage[sizeof(DT::Split)]; + auto* split_scratch = reinterpret_cast*>(split_scratch_storage); if (threadIdx.x == 0) { - *out = DT::Split(); + *out = DT::Split(); *mutex = 0; } __syncthreads(); @@ -1279,10 +1279,9 @@ __global__ void objectiveGainKernel(BinT const* hist, TEST(RFEquivalentSplitRangeTest, ClassificationChoosesUpperMiddleBin) { - using DataT = float; - using IdxT = std::int64_t; - constexpr IdxT len = 10; - constexpr IdxT n_bins = 6; + using DataT = float; + constexpr std::int64_t len = 10; + constexpr std::int64_t n_bins = 6; auto stream_pool = std::make_shared(1); raft::handle_t handle(rmm::cuda_stream_per_thread, stream_pool); @@ -1305,7 +1304,7 @@ TEST(RFEquivalentSplitRangeTest, ClassificationChoosesUpperMiddleBin) thrust::device_vector hist(h_hist.begin(), h_hist.end()); thrust::device_vector quantiles(h_quantiles.begin(), h_quantiles.end()); - thrust::device_vector> split(1); + thrust::device_vector> split(1); thrust::device_vector mutex(1); DT::ClassificationObjectiveFunction objective(2, 1, CRITERION::GINI); @@ -1314,12 +1313,12 @@ TEST(RFEquivalentSplitRangeTest, ClassificationChoosesUpperMiddleBin) split.data().get(), mutex.data().get(), objective, - IdxT{0}, + std::int64_t{0}, len, n_bins); RAFT_CUDA_TRY(cudaGetLastError()); - DT::Split h_split; + DT::Split h_split; RAFT_CUDA_TRY(cudaMemcpyAsync( &h_split, split.data().get(), sizeof(h_split), cudaMemcpyDeviceToHost, handle.get_stream())); handle.sync_stream(); @@ -1333,10 +1332,9 @@ TEST(RFEquivalentSplitRangeTest, ClassificationChoosesUpperMiddleBin) TEST(RFEquivalentSplitRangeTest, RegressionChoosesUpperMiddleBin) { - using DataT = float; - using IdxT = std::int64_t; - constexpr IdxT len = 10; - constexpr IdxT n_bins = 6; + using DataT = float; + constexpr std::int64_t len = 10; + constexpr std::int64_t n_bins = 6; auto stream_pool = std::make_shared(1); raft::handle_t handle(rmm::cuda_stream_per_thread, stream_pool); @@ -1353,7 +1351,7 @@ TEST(RFEquivalentSplitRangeTest, RegressionChoosesUpperMiddleBin) thrust::device_vector hist(h_hist.begin(), h_hist.end()); thrust::device_vector quantiles(h_quantiles.begin(), h_quantiles.end()); - thrust::device_vector> split(1); + thrust::device_vector> split(1); thrust::device_vector mutex(1); DT::RegressionObjectiveFunction objective(1, 1, CRITERION::MSE); @@ -1362,12 +1360,12 @@ TEST(RFEquivalentSplitRangeTest, RegressionChoosesUpperMiddleBin) split.data().get(), mutex.data().get(), objective, - IdxT{0}, + std::int64_t{0}, len, n_bins); RAFT_CUDA_TRY(cudaGetLastError()); - DT::Split h_split; + DT::Split h_split; RAFT_CUDA_TRY(cudaMemcpyAsync( &h_split, split.data().get(), sizeof(h_split), cudaMemcpyDeviceToHost, handle.get_stream())); handle.sync_stream(); From 809bd9e12f44a38d47cffaf932744823695cfc98 Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Wed, 15 Jul 2026 11:53:48 +0200 Subject: [PATCH 09/14] Use int for RF num outputs --- cpp/src/decisiontree/batched-levelalgo/builder.cuh | 13 +++++-------- cpp/src/decisiontree/batched-levelalgo/dataset.h | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/cpp/src/decisiontree/batched-levelalgo/builder.cuh b/cpp/src/decisiontree/batched-levelalgo/builder.cuh index 373dc66f72..216688ad68 100644 --- a/cpp/src/decisiontree/batched-levelalgo/builder.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/builder.cuh @@ -45,13 +45,10 @@ class NodeQueue { std::deque work_items_; public: - NodeQueue(DecisionTreeParams params, - size_t max_nodes, - size_t sampled_rows, - std::int64_t num_outputs) + NodeQueue(DecisionTreeParams params, size_t max_nodes, size_t sampled_rows, int num_outputs) : params(params), tree(std::make_shared>()) { - tree->num_outputs = ML::narrow_cast(num_outputs); + tree->num_outputs = num_outputs; tree->sparsetree.reserve(max_nodes); tree->sparsetree.emplace_back(NodeT::CreateLeafNode(sampled_rows)); tree->leaf_counter = 1; @@ -220,7 +217,7 @@ struct Builder { std::int64_t n_rows, std::int64_t n_cols, rmm::device_uvector* row_ids, - std::int64_t n_classes, + int n_classes, const QuantilesT& q, bool row_major = false) : handle(handle), @@ -549,8 +546,8 @@ struct Builder { auto n_bins = params.max_n_bins; auto n_classes = dataset.num_outputs; // if columns left to be processed lesser than `n_blks_for_cols`, shrink the blocks along dimy - auto n_blocks_dimy = std::min(static_cast(n_blks_for_cols), - dataset.n_sampled_cols - col); + auto remaining_sampled_cols = ML::narrow_cast(dataset.n_sampled_cols - col); + auto n_blocks_dimy = std::min(n_blks_for_cols, remaining_sampled_cols); dim3 histogram_grid(ML::narrow_cast(n_blocks_dimx), ML::narrow_cast(n_blocks_dimy), 1); diff --git a/cpp/src/decisiontree/batched-levelalgo/dataset.h b/cpp/src/decisiontree/batched-levelalgo/dataset.h index eb5f98f64a..da231dab91 100644 --- a/cpp/src/decisiontree/batched-levelalgo/dataset.h +++ b/cpp/src/decisiontree/batched-levelalgo/dataset.h @@ -35,7 +35,7 @@ struct Dataset { /** indices of sampled rows */ std::int64_t* row_ids; /** Number of classes or regression outputs*/ - std::int64_t num_outputs; + int num_outputs; HDI DataT value(std::int64_t row, std::int64_t col) const { From e8a94c2eea3a2048f5aa8ce45fbea8aef9e0310a Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Wed, 15 Jul 2026 12:03:03 +0200 Subject: [PATCH 10/14] Remove redundant RF int64 casts --- .../batched-levelalgo/builder.cuh | 5 ++--- .../decisiontree/batched-levelalgo/dataset.h | 3 +-- .../kernels/builder_kernels.cuh | 4 ++-- .../kernels/builder_kernels_impl.cuh | 3 +-- .../batched-levelalgo/objectives.cuh | 20 ++++++++----------- .../batched-levelalgo/quantiles.cuh | 10 ++++------ 6 files changed, 18 insertions(+), 27 deletions(-) diff --git a/cpp/src/decisiontree/batched-levelalgo/builder.cuh b/cpp/src/decisiontree/batched-levelalgo/builder.cuh index 216688ad68..30ddf29da0 100644 --- a/cpp/src/decisiontree/batched-levelalgo/builder.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/builder.cuh @@ -419,8 +419,7 @@ struct Builder { // sampled features do not yield a valid split. for (std::size_t round = 0; !active_items.empty() && round < max_sampling_rounds; ++round) { std::int64_t sample_offset = std::int64_t(round) * original_n_sampled_cols; - dataset.n_sampled_cols = std::min(original_n_sampled_cols, - static_cast(dataset.n_cols) - sample_offset); + dataset.n_sampled_cols = std::min(original_n_sampled_cols, dataset.n_cols - sample_offset); computeBestSplits(active_items, seed, sample_offset); std::vector retry_items; @@ -498,7 +497,7 @@ struct Builder { treeid, sampling_seed, sample_offset, - static_cast(dataset.n_cols), + dataset.n_cols, dataset.n_sampled_cols, builder_stream); RAFT_CUDA_TRY(cudaPeekAtLastError()); diff --git a/cpp/src/decisiontree/batched-levelalgo/dataset.h b/cpp/src/decisiontree/batched-levelalgo/dataset.h index da231dab91..18630a4128 100644 --- a/cpp/src/decisiontree/batched-levelalgo/dataset.h +++ b/cpp/src/decisiontree/batched-levelalgo/dataset.h @@ -39,8 +39,7 @@ struct Dataset { HDI DataT value(std::int64_t row, std::int64_t col) const { - return data[static_cast(row) * row_stride + - static_cast(col) * col_stride]; + return data[row * row_stride + col * col_stride]; } }; diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh index d1fcef758c..382d91f81a 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh @@ -58,9 +58,9 @@ HDI bool SplitPartitionNotValid(const SplitT& split, std::size_t num_rows) { const auto local_count = static_cast(num_rows); - const auto min_leaf = static_cast(min_samples_leaf); return split.colid == std::int64_t{-1} || split.local_nLeft > local_count || - split.local_nLeft < min_leaf || (local_count - split.local_nLeft) < min_leaf; + split.local_nLeft < min_samples_leaf || + (local_count - split.local_nLeft) < min_samples_leaf; } template diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh index c4fded35fd..ddf21344ee 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels_impl.cuh @@ -312,8 +312,7 @@ static __global__ void buildHistogramsKernel(typename ObjectiveT::BinT* histogra return quantiles_for_split[bin] < value; }); auto bin = bin_it == bin_end ? n_bins - 1 : *bin_it; - objective.IncrementHistogram( - histogram, n_bins, static_cast(bin), label, dataset, row); + objective.IncrementHistogram(histogram, n_bins, bin, label, dataset, row); } if (!use_global_memory_histogram) { diff --git a/cpp/src/decisiontree/batched-levelalgo/objectives.cuh b/cpp/src/decisiontree/batched-levelalgo/objectives.cuh index 03cde3c0ec..a77308e3df 100644 --- a/cpp/src/decisiontree/batched-levelalgo/objectives.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/objectives.cuh @@ -131,8 +131,7 @@ class ClassificationObjectiveFunction { std::int64_t nLeft, std::int64_t nRight) const { - if (nLeft < static_cast(min_samples_leaf) || - nRight < static_cast(min_samples_leaf)) + if (nLeft < min_samples_leaf || nRight < min_samples_leaf) return -std::numeric_limits::max(); switch (criterion) { @@ -153,8 +152,8 @@ class ClassificationObjectiveFunction { template DI void IncrementHistogram(BinT* histogram, - std::int64_t n_bins, - std::int64_t bin, + int n_bins, + int bin, LabelT label, const DatasetT& dataset, std::int64_t row) const @@ -177,8 +176,7 @@ class ClassificationObjectiveFunction { auto nLeft = detail::CountLeft(shist, i, n_bins, nclasses); auto nRight = len - nLeft; auto gain = -std::numeric_limits::max(); - if (nLeft >= static_cast(min_samples_leaf) && - nRight >= static_cast(min_samples_leaf)) { + if (nLeft >= min_samples_leaf && nRight >= min_samples_leaf) { gain = GainPerSplit(shist, i, n_bins, len, nLeft, nRight); } sp.update({squantiles[i], col, gain, nLeft, nLeft, i}); @@ -348,8 +346,7 @@ class RegressionObjectiveFunction { std::int64_t nLeft, std::int64_t nRight) const { - if (nLeft < static_cast(min_samples_leaf) || - nRight < static_cast(min_samples_leaf)) + if (nLeft < min_samples_leaf || nRight < min_samples_leaf) return -std::numeric_limits::max(); switch (criterion) { @@ -371,8 +368,8 @@ class RegressionObjectiveFunction { template DI void IncrementHistogram(BinT* histogram, - std::int64_t n_bins, - std::int64_t bin, + int n_bins, + int bin, LabelT label, const DatasetT& dataset, std::int64_t row) const @@ -395,8 +392,7 @@ class RegressionObjectiveFunction { auto nLeft = detail::CountLeft(shist, i, n_bins, std::int64_t{1}); auto nRight = len - nLeft; auto gain = -std::numeric_limits::max(); - if (nLeft >= static_cast(min_samples_leaf) && - nRight >= static_cast(min_samples_leaf)) { + if (nLeft >= min_samples_leaf && nRight >= min_samples_leaf) { gain = GainPerSplit(shist, i, n_bins, len, nLeft, nRight); } sp.update({squantiles[i], col, gain, nLeft, nLeft, i}); diff --git a/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh b/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh index 8f2aa3a9be..f28aefbf18 100644 --- a/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/quantiles.cuh @@ -197,12 +197,10 @@ CUML_EXPORT QuantileResult computeQuantiles(const raft::handle_t& handle, rmm::device_uvector sampled_columns(total_sample_values, stream); rmm::device_uvector sorted_samples(total_sample_values, stream); - int n_threads = 256; - auto segment_offsets = - thrust::make_transform_iterator(thrust::make_counting_iterator(0), - [sample_count] __host__ __device__(std::int64_t col) { - return col * static_cast(sample_count); - }); + int n_threads = 256; + auto segment_offsets = thrust::make_transform_iterator( + thrust::make_counting_iterator(0), + [sample_count] __host__ __device__(std::int64_t col) { return col * sample_count; }); rmm::device_uvector quantiles_array(ML::checked_mul(n_cols, max_n_bins), stream); rmm::device_uvector n_bins_array(n_cols, stream); From f4f48eb92c833adb46ed8b579a97cf158f18173e Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Wed, 15 Jul 2026 12:29:56 +0200 Subject: [PATCH 11/14] Address RF cleanup review comments --- cpp/src/decisiontree/batched-levelalgo/builder.cuh | 7 +++++-- cpp/tests/sg/rf_test.cu | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cpp/src/decisiontree/batched-levelalgo/builder.cuh b/cpp/src/decisiontree/batched-levelalgo/builder.cuh index 30ddf29da0..8a0704ad4f 100644 --- a/cpp/src/decisiontree/batched-levelalgo/builder.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/builder.cuh @@ -545,8 +545,11 @@ struct Builder { auto n_bins = params.max_n_bins; auto n_classes = dataset.num_outputs; // if columns left to be processed lesser than `n_blks_for_cols`, shrink the blocks along dimy - auto remaining_sampled_cols = ML::narrow_cast(dataset.n_sampled_cols - col); - auto n_blocks_dimy = std::min(n_blks_for_cols, remaining_sampled_cols); + auto remaining_sampled_cols = dataset.n_sampled_cols - col; + auto n_blocks_dimy = n_blks_for_cols; + if (remaining_sampled_cols < n_blocks_dimy) { + n_blocks_dimy = ML::narrow_cast(remaining_sampled_cols); + } dim3 histogram_grid(ML::narrow_cast(n_blocks_dimx), ML::narrow_cast(n_blocks_dimy), 1); diff --git a/cpp/tests/sg/rf_test.cu b/cpp/tests/sg/rf_test.cu index 8bdfd7ff69..892f2cc1a6 100644 --- a/cpp/tests/sg/rf_test.cu +++ b/cpp/tests/sg/rf_test.cu @@ -1470,8 +1470,6 @@ typedef RFQuantileTest RFQuantileTestD; TEST_P(RFQuantileTestD, test) {} INSTANTIATE_TEST_CASE_P(RfTests, RFQuantileTestD, ::testing::ValuesIn(inputs)); -// float type quantile bins lower bounds test -// double type quantile bins lower bounds test // float type quantile variable binning test typedef RFQuantileVariableBinsTest RFQuantileVariableBinsTestF; TEST_P(RFQuantileVariableBinsTestF, test) {} From ad2a356ed3f434d447b2886a33acff233535e1c8 Mon Sep 17 00:00:00 2001 From: Rory Mitchell Date: Wed, 15 Jul 2026 15:45:21 +0200 Subject: [PATCH 12/14] Address RF checked arithmetic review comments --- .../batched-levelalgo/builder.cuh | 151 ++++++++++-------- .../kernels/builder_kernels.cuh | 22 ++- cpp/tests/sg/rf_test.cu | 91 +++++------ 3 files changed, 139 insertions(+), 125 deletions(-) diff --git a/cpp/src/decisiontree/batched-levelalgo/builder.cuh b/cpp/src/decisiontree/batched-levelalgo/builder.cuh index 8a0704ad4f..b2643088d9 100644 --- a/cpp/src/decisiontree/batched-levelalgo/builder.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/builder.cuh @@ -232,14 +232,15 @@ struct Builder { n_cols, row_major ? n_cols : std::int64_t{1}, row_major ? std::int64_t{1} : n_rows, - static_cast(row_ids->size()), + ML::narrow_cast(row_ids->size()), std::max(std::int64_t{1}, std::int64_t(params.max_features * n_cols)), row_ids->data(), n_classes}, quantiles(q), d_buff(0, builder_stream) { - max_blocks_dimx = 1 + params.max_batch_size + dataset.n_sampled_rows / TPB_DEFAULT; + max_blocks_dimx = ML::narrow_cast(ML::checked_add( + 1, params.max_batch_size, dataset.n_sampled_rows / TPB_DEFAULT)); ASSERT(q.quantiles_array != nullptr && q.n_bins_array != nullptr, "Currently quantiles need to be computed before this call!"); ASSERT(n_classes >= 1, "n_classes should be at least 1"); @@ -285,26 +286,31 @@ struct Builder { { size_t d_wsize = 0, h_wsize = 0; raft::common::nvtx::range fun_scope("Builder::workspaceSize @builder.cuh [batched-levelalgo]"); - auto max_batch = params.max_batch_size; - size_t max_len_histograms = - max_batch * params.max_n_bins * n_blks_for_cols * dataset.num_outputs; - - d_wsize += calculateAlignedBytes(sizeof(std::int64_t)); // n_nodes - d_wsize += calculateAlignedBytes(sizeof(BinT) * max_len_histograms); // histograms - d_wsize += calculateAlignedBytes(sizeof(int) * max_batch); // mutex - d_wsize += calculateAlignedBytes(sizeof(SplitT) * max_batch); // splits - d_wsize += calculateAlignedBytes(sizeof(NodeWorkItem) * max_batch); // d_work_Items - d_wsize += // workload_info - calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); - d_wsize += calculateAlignedBytes(sizeof(std::int64_t) * max_batch * - dataset.n_sampled_cols); // column_samples - d_wsize += - calculateAlignedBytes(sizeof(std::int64_t) * dataset.n_sampled_rows); // partition row IDs + auto max_batch = params.max_batch_size; + size_t max_len_histograms = ML::checked_mul( + max_batch, params.max_n_bins, n_blks_for_cols, dataset.num_outputs); + auto histograms_bytes = ML::checked_mul(sizeof(BinT), max_len_histograms); + auto mutex_bytes = ML::checked_mul(sizeof(int), max_batch); + auto splits_bytes = ML::checked_mul(sizeof(SplitT), max_batch); + auto work_items_bytes = ML::checked_mul(sizeof(NodeWorkItem), max_batch); + auto workload_info_bytes = ML::checked_mul(sizeof(WorkloadInfo), max_blocks_dimx); + auto column_samples_bytes = + ML::checked_mul(sizeof(std::int64_t), max_batch, dataset.n_sampled_cols); + auto partition_row_ids_bytes = + ML::checked_mul(sizeof(std::int64_t), dataset.n_sampled_rows); + + d_wsize += calculateAlignedBytes(sizeof(std::int64_t)); // n_nodes + d_wsize += calculateAlignedBytes(histograms_bytes); // histograms + d_wsize += calculateAlignedBytes(mutex_bytes); // mutex + d_wsize += calculateAlignedBytes(splits_bytes); // splits + d_wsize += calculateAlignedBytes(work_items_bytes); // d_work_Items + d_wsize += calculateAlignedBytes(workload_info_bytes); // workload_info + d_wsize += calculateAlignedBytes(column_samples_bytes); // column_samples + d_wsize += calculateAlignedBytes(partition_row_ids_bytes); // partition row IDs // all nodes in the tree - h_wsize += // h_workload_info - calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); - h_wsize += calculateAlignedBytes(sizeof(SplitT) * max_batch); // splits + h_wsize += calculateAlignedBytes(workload_info_bytes); // h_workload_info + h_wsize += calculateAlignedBytes(splits_bytes); // splits return std::make_pair(d_wsize, h_wsize); } @@ -320,34 +326,43 @@ struct Builder { { raft::common::nvtx::range fun_scope( "Builder::assignWorkspace @builder.cuh [batched-levelalgo]"); - auto max_batch = params.max_batch_size; - size_t max_len_histograms = - max_batch * (params.max_n_bins) * n_blks_for_cols * dataset.num_outputs; + auto max_batch = params.max_batch_size; + size_t max_len_histograms = ML::checked_mul( + max_batch, params.max_n_bins, n_blks_for_cols, dataset.num_outputs); + auto histograms_bytes = ML::checked_mul(sizeof(BinT), max_len_histograms); + auto mutex_bytes = ML::checked_mul(sizeof(int), max_batch); + auto splits_bytes = ML::checked_mul(sizeof(SplitT), max_batch); + auto work_items_bytes = ML::checked_mul(sizeof(NodeWorkItem), max_batch); + auto workload_info_bytes = ML::checked_mul(sizeof(WorkloadInfo), max_blocks_dimx); + auto column_samples_bytes = + ML::checked_mul(sizeof(std::int64_t), max_batch, dataset.n_sampled_cols); + auto partition_row_ids_bytes = + ML::checked_mul(sizeof(std::int64_t), dataset.n_sampled_rows); // device n_nodes = reinterpret_cast(d_wspace); d_wspace += calculateAlignedBytes(sizeof(std::int64_t)); histograms = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(BinT) * max_len_histograms); + d_wspace += calculateAlignedBytes(histograms_bytes); mutex = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(int) * max_batch); + d_wspace += calculateAlignedBytes(mutex_bytes); splits = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(SplitT) * max_batch); + d_wspace += calculateAlignedBytes(splits_bytes); d_work_items = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(NodeWorkItem) * max_batch); + d_wspace += calculateAlignedBytes(work_items_bytes); workload_info = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + d_wspace += calculateAlignedBytes(workload_info_bytes); column_samples = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(std::int64_t) * max_batch * dataset.n_sampled_cols); + d_wspace += calculateAlignedBytes(column_samples_bytes); partition_row_ids = reinterpret_cast(d_wspace); - d_wspace += calculateAlignedBytes(sizeof(std::int64_t) * dataset.n_sampled_rows); + d_wspace += calculateAlignedBytes(partition_row_ids_bytes); - RAFT_CUDA_TRY(cudaMemsetAsync(mutex, 0, sizeof(int) * max_batch, builder_stream)); + RAFT_CUDA_TRY(cudaMemsetAsync(mutex, 0, mutex_bytes, builder_stream)); // host h_workload_info = reinterpret_cast(h_wspace); - h_wspace += calculateAlignedBytes(sizeof(WorkloadInfo) * max_blocks_dimx); + h_wspace += calculateAlignedBytes(workload_info_bytes); h_splits = reinterpret_cast(h_wspace); - h_wspace += calculateAlignedBytes(sizeof(SplitT) * max_batch); + h_wspace += calculateAlignedBytes(splits_bytes); } /** @@ -373,18 +388,21 @@ struct Builder { } private: - auto updateWorkloadInfo(const std::vector& work_items) + std::size_t updateWorkloadInfo(const std::vector& work_items) { - int n_blocks_dimx = 0; // gridDim.x required for histogram construction + std::size_t n_blocks_dimx = 0; // gridDim.x required for histogram construction for (std::size_t i = 0; i < work_items.size(); i++) { - auto item = work_items[i]; - int n_blocks_per_node = - std::max(raft::ceildiv(item.instances.count, size_t(TPB_DEFAULT)), size_t(1)); - - for (int b = 0; b < n_blocks_per_node; b++) { - h_workload_info[n_blocks_dimx + b] = {int(i), b, n_blocks_per_node}; + auto item = work_items[i]; + auto n_blocks_per_node = std::max( + raft::ceildiv(item.instances.count, std::size_t{TPB_DEFAULT}), std::size_t{1}); + + for (std::size_t b = 0; b < n_blocks_per_node; b++) { + auto workload_idx = ML::checked_add(n_blocks_dimx, b); + h_workload_info[workload_idx] = {ML::narrow_cast(i), + ML::narrow_cast(b), + ML::narrow_cast(n_blocks_per_node)}; } - n_blocks_dimx += n_blocks_per_node; + n_blocks_dimx = ML::checked_add(n_blocks_dimx, n_blocks_per_node); } raft::update_device(workload_info, h_workload_info, n_blocks_dimx, builder_stream); return n_blocks_dimx; @@ -399,8 +417,10 @@ struct Builder { const std::int64_t original_n_sampled_cols = dataset.n_sampled_cols; ASSERT(original_n_sampled_cols > 0 && original_n_sampled_cols <= dataset.n_cols, "n_sampled_cols must be in [1, n_cols]"); - const std::size_t max_sampling_rounds = - std::size_t((dataset.n_cols + original_n_sampled_cols - 1) / original_n_sampled_cols); + const auto sampling_round_numerator = ML::checked_sub( + ML::checked_add(dataset.n_cols, original_n_sampled_cols), 1); + const auto max_sampling_rounds = ML::narrow_cast( + ML::checked_div(sampling_round_numerator, original_n_sampled_cols)); // The final split chosen for each original work item. Nodes that need // additional feature samples are compacted in active_items, so successful // splits must be copied back to their original batch position. @@ -418,8 +438,10 @@ struct Builder { // Match sklearn's behavior of searching beyond max_features when the // sampled features do not yield a valid split. for (std::size_t round = 0; !active_items.empty() && round < max_sampling_rounds; ++round) { - std::int64_t sample_offset = std::int64_t(round) * original_n_sampled_cols; - dataset.n_sampled_cols = std::min(original_n_sampled_cols, dataset.n_cols - sample_offset); + auto sample_offset = ML::checked_mul(ML::narrow_cast(round), + original_n_sampled_cols); + dataset.n_sampled_cols = std::min( + original_n_sampled_cols, ML::checked_sub(dataset.n_cols, sample_offset)); computeBestSplits(active_items, seed, sample_offset); std::vector retry_items; @@ -442,11 +464,9 @@ struct Builder { // Partition samples once, using the valid split found for each node. Nodes // still without a valid split after all features have been visited remain leaves. - RAFT_CUDA_TRY(cudaMemcpyAsync(splits, - final_splits.data(), - sizeof(SplitT) * work_items.size(), - cudaMemcpyHostToDevice, - builder_stream)); + auto split_copy_bytes = ML::checked_mul(sizeof(SplitT), work_items.size()); + RAFT_CUDA_TRY(cudaMemcpyAsync( + splits, final_splits.data(), split_copy_bytes, cudaMemcpyHostToDevice, builder_stream)); raft::update_device(d_work_items, work_items.data(), work_items.size(), builder_stream); const auto n_partition_blocks = this->updateWorkloadInfo(work_items); raft::common::nvtx::push_range("nodeSplitKernel @builder.cuh [batched-levelalgo]"); @@ -471,7 +491,8 @@ struct Builder { std::int64_t sample_offset) { initSplit(splits, work_items.size(), builder_stream); - RAFT_CUDA_TRY(cudaMemsetAsync(mutex, 0, sizeof(int) * params.max_batch_size, builder_stream)); + auto mutex_bytes = ML::checked_mul(sizeof(int), params.max_batch_size); + RAFT_CUDA_TRY(cudaMemsetAsync(mutex, 0, mutex_bytes, builder_stream)); raft::update_device(d_work_items, work_items.data(), work_items.size(), builder_stream); auto n_blocks_dimx = this->updateWorkloadInfo(work_items); auto split_smem_config = computeSharedMemoryConfig(); @@ -585,28 +606,30 @@ struct Builder { void SetLeafPredictions(std::shared_ptr> tree, const std::vector& instance_ranges) { - tree->vector_leaf.resize(tree->sparsetree.size() * dataset.num_outputs); + auto vector_leaf_size = + ML::checked_mul(tree->sparsetree.size(), dataset.num_outputs); + tree->vector_leaf.resize(vector_leaf_size); ASSERT(tree->sparsetree.size() == instance_ranges.size(), "Expected instance range for each node"); // do this in batch to reduce peak memory usage in extreme cases - std::size_t max_batch_size = min(std::size_t(100000), tree->sparsetree.size()); + std::size_t max_batch_size = min(std::size_t{100000}, tree->sparsetree.size()); + auto max_leaf_values = ML::checked_mul(max_batch_size, dataset.num_outputs); rmm::device_uvector d_tree(max_batch_size, builder_stream); rmm::device_uvector d_instance_ranges(max_batch_size, builder_stream); - rmm::device_uvector d_leaves(max_batch_size * dataset.num_outputs, builder_stream); + rmm::device_uvector d_leaves(max_leaf_values, builder_stream); ObjectiveT objective(dataset.num_outputs, params.min_samples_leaf, params.split_criterion); for (std::size_t batch_begin = 0; batch_begin < tree->sparsetree.size(); batch_begin += max_batch_size) { - std::size_t batch_end = min(batch_begin + max_batch_size, tree->sparsetree.size()); - std::size_t batch_size = batch_end - batch_begin; + std::size_t batch_size = min(max_batch_size, tree->sparsetree.size() - batch_begin); raft::update_device( d_tree.data(), tree->sparsetree.data() + batch_begin, batch_size, builder_stream); raft::update_device( d_instance_ranges.data(), instance_ranges.data() + batch_begin, batch_size, builder_stream); - RAFT_CUDA_TRY( - cudaMemsetAsync(d_leaves.data(), 0, sizeof(DataT) * d_leaves.size(), builder_stream)); - size_t smem_size = sizeof(BinT) * dataset.num_outputs; + auto leaves_bytes = ML::checked_mul(sizeof(DataT), d_leaves.size()); + RAFT_CUDA_TRY(cudaMemsetAsync(d_leaves.data(), 0, leaves_bytes, builder_stream)); + size_t smem_size = ML::checked_mul(sizeof(BinT), dataset.num_outputs); launchLeafKernel(objective, dataset, d_tree.data(), @@ -615,10 +638,10 @@ struct Builder { batch_size, smem_size, builder_stream); - raft::update_host(tree->vector_leaf.data() + batch_begin * dataset.num_outputs, - d_leaves.data(), - batch_size * dataset.num_outputs, - builder_stream); + auto leaf_offset = ML::checked_mul(batch_begin, dataset.num_outputs); + auto leaf_count = ML::checked_mul(batch_size, dataset.num_outputs); + raft::update_host( + tree->vector_leaf.data() + leaf_offset, d_leaves.data(), leaf_count, builder_stream); } } }; // end Builder diff --git a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh index 382d91f81a..2e4a8560cc 100644 --- a/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh +++ b/cpp/src/decisiontree/batched-levelalgo/kernels/builder_kernels.cuh @@ -10,14 +10,18 @@ #include "../quantiles.h" #include "../random_utils.cuh" +#include #include +#include + #include #include #include #include #include +#include #include namespace ML { @@ -90,18 +94,22 @@ inline void sample_features(std::int64_t* column_samples, std::int64_t k, cudaStream_t stream) { - auto n_column_samples = work_items_size * size_t(k); - auto counting = thrust::make_counting_iterator(0); + RAFT_EXPECTS(k >= 0, "k must be non-negative"); + RAFT_EXPECTS(n >= k, "k must not exceed n"); + + auto sampled_cols = ML::narrow_cast(k); + auto n_column_samples = ML::checked_mul(work_items_size, sampled_cols); + auto counting = thrust::make_counting_iterator(0); thrust::for_each(thrust::cuda::par.on(stream), counting, counting + n_column_samples, - [=] __device__(size_t sample_idx) { - auto node_idx = sample_idx / size_t(k); - auto column_index = static_cast(sample_idx % size_t(k)); + [=] __device__(std::size_t sample_idx) { + auto node_idx = sample_idx / sampled_cols; + auto column_index = static_cast(sample_idx % sampled_cols); - const uint32_t nodeid = work_items[node_idx].idx; - uint32_t rng_seed = fnv1a32_hash(seed, treeid, nodeid); + auto nodeid = work_items[node_idx].idx; + uint32_t rng_seed = fnv1a32_hash(seed, treeid, nodeid); cuda::shuffle_iterator shuffled_features( n, cuda::std::minstd_rand(rng_seed), sample_offset); diff --git a/cpp/tests/sg/rf_test.cu b/cpp/tests/sg/rf_test.cu index 892f2cc1a6..b3852cf400 100644 --- a/cpp/tests/sg/rf_test.cu +++ b/cpp/tests/sg/rf_test.cu @@ -2,6 +2,7 @@ * SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include @@ -2582,14 +2583,17 @@ class FeatureSamplingBiasTest : public ::testing::TestWithParamget_stream(); + const auto node_count = ML::narrow_cast(params.n_nodes); + const auto feature_count = ML::narrow_cast(params.n_features); + const auto sampled_col_count = ML::checked_mul(params.n_nodes, params.k); + // Allocate device memory - rmm::device_uvector d_colids(params.n_nodes * params.k, stream); - rmm::device_uvector d_work_items(params.n_nodes, stream); - rmm::device_uvector d_counts(params.n_features, stream); + rmm::device_uvector d_colids(sampled_col_count, stream); + rmm::device_uvector d_work_items(node_count, stream); // Initialize work items on host - std::vector h_work_items(params.n_nodes); - for (int i = 0; i < params.n_nodes; ++i) { + std::vector h_work_items(node_count); + for (std::size_t i = 0; i < node_count; ++i) { h_work_items[i].idx = i; h_work_items[i].depth = 0; h_work_items[i].instances.begin = 0; @@ -2597,58 +2601,35 @@ class FeatureSamplingBiasTest : public ::testing::TestWithParam= 0 && feature_idx < params.n_features) { - EXPECT_FALSE(feature_seen[feature_idx]) << "Node " << node << " has duplicate feature " + const auto feature_pos = ML::narrow_cast(feature_idx); + h_counts[feature_pos]++; + EXPECT_FALSE(feature_seen[feature_pos]) << "Node " << node << " has duplicate feature " << feature_idx << " at positions in sampled set"; - if (!feature_seen[feature_idx]) { - feature_seen[feature_idx] = true; + if (!feature_seen[feature_pos]) { + feature_seen[feature_pos] = true; unique_count++; } } @@ -2673,8 +2656,8 @@ class FeatureSamplingBiasTest : public ::testing::TestWithParam(params.n_nodes, params.k); + double expected_per_feature = double(total_samples) / params.n_features; // Check for feature 0 under-sampling double feature_0_ratio = h_counts[0] / expected_per_feature; @@ -2682,12 +2665,12 @@ class FeatureSamplingBiasTest : public ::testing::TestWithParam Date: Mon, 20 Jul 2026 12:48:14 +0200 Subject: [PATCH 13/14] Use int64 row counts in RF row sampler --- cpp/src/randomforest/randomforest.cuh | 40 ++++++++++++++++----------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/cpp/src/randomforest/randomforest.cuh b/cpp/src/randomforest/randomforest.cuh index a8fe4056f8..8ce5992eef 100644 --- a/cpp/src/randomforest/randomforest.cuh +++ b/cpp/src/randomforest/randomforest.cuh @@ -65,8 +65,8 @@ class RowSampler { public: RowSampler(const raft::handle_t& handle, const RF_params& rf_params, - int n_rows, - int n_sampled_rows, + std::int64_t n_rows, + std::int64_t n_sampled_rows, int n_streams, bool* bootstrap_masks, const double* sample_weight) @@ -83,7 +83,7 @@ class RowSampler { "bootstrap_masks must be a GPU pointer"); validate_sample_weight(handle, sample_weight_, n_rows_); if (use_weighted_bootstrap()) { - sample_weight_cdf_.resize(n_rows_, handle.get_stream()); + sample_weight_cdf_.resize(ML::narrow_cast(n_rows_), handle.get_stream()); thrust::inclusive_scan(rmm::exec_policy(handle.get_stream()), sample_weight_, sample_weight_ + n_rows_, @@ -96,11 +96,12 @@ class RowSampler { "sample_weight values must contain at least one positive value"); } // Use a deque instead of vector because device_uvector has a deleted copy constructor. + auto const n_sampled_rows_size = ML::narrow_cast(n_sampled_rows_); for (int i = 0; i < n_streams; i++) { auto stream = handle.get_stream_from_stream_pool(i); - selected_rows_.emplace_back(n_sampled_rows_, stream); + selected_rows_.emplace_back(n_sampled_rows_size, stream); if (use_weighted_bootstrap()) { - weighted_draw_scratch_.emplace_back(n_sampled_rows_, stream); + weighted_draw_scratch_.emplace_back(n_sampled_rows_size, stream); } } } @@ -144,7 +145,7 @@ class RowSampler { stream_resources, rng_state, selected_rows.data(), selected_rows.size(), 0, n_rows_); } else if (sample_weight_ != nullptr) { // Remove zero-weight rows from the non-bootstrap row set. - selected_rows.resize(n_sampled_rows_, stream); + selected_rows.resize(ML::narrow_cast(n_sampled_rows_), stream); auto rows_begin = thrust::make_counting_iterator(0); auto selected_rows_end = thrust::copy_if(rmm::exec_policy(stream), rows_begin, @@ -156,7 +157,7 @@ class RowSampler { ASSERT(n_selected > 0, "sample_weight values must contain at least one positive value"); selected_rows.resize(n_selected, stream); } else { - selected_rows.resize(n_sampled_rows_, stream); + selected_rows.resize(ML::narrow_cast(n_sampled_rows_), stream); thrust::sequence(rmm::exec_policy(stream), selected_rows.begin(), selected_rows.end()); } @@ -199,7 +200,7 @@ class RowSampler { static void validate_sample_weight(const raft::handle_t& handle, const double* sample_weight, - int n_rows) + std::int64_t n_rows) { ASSERT(sample_weight == nullptr || DT::is_dev_ptr(sample_weight), "sample_weight must be a GPU pointer"); @@ -216,8 +217,8 @@ class RowSampler { bool bootstrap_; uint64_t seed_; - int n_rows_; - int n_sampled_rows_; + std::int64_t n_rows_; + std::int64_t n_sampled_rows_; bool* bootstrap_masks_; const double* sample_weight_; double sample_weight_sum_; @@ -297,10 +298,12 @@ class RandomForest { { raft::common::nvtx::range fun_scope("RandomForest::fit @randomforest.cuh"); this->error_checking(input, labels, n_rows, n_cols, false); - const raft::handle_t& handle = user_handle; - int n_sampled_rows = 0; + const raft::handle_t& handle = user_handle; + std::int64_t const n_rows_i64 = n_rows; + std::int64_t n_sampled_rows = 0; if (this->rf_params.bootstrap) { - n_sampled_rows = std::round(this->rf_params.max_samples * n_rows); + n_sampled_rows = + static_cast(std::round(this->rf_params.max_samples * n_rows_i64)); } else { if (this->rf_params.max_samples != 1.0) { CUML_LOG_WARN( @@ -308,7 +311,7 @@ class RandomForest { "whole dataset is used for building each tree"); this->rf_params.max_samples = 1.0; } - n_sampled_rows = n_rows; + n_sampled_rows = n_rows_i64; } int n_streams = this->rf_params.n_streams; ASSERT(static_cast(n_streams) <= handle.get_stream_pool_size(), @@ -329,8 +332,13 @@ class RandomForest { // n_streams should not be less than n_trees if (this->rf_params.n_trees < n_streams) n_streams = this->rf_params.n_trees; - detail::RowSampler row_sampler( - handle, this->rf_params, n_rows, n_sampled_rows, n_streams, bootstrap_masks, sample_weight); + detail::RowSampler row_sampler(handle, + this->rf_params, + n_rows_i64, + n_sampled_rows, + n_streams, + bootstrap_masks, + sample_weight); forest->n_features = n_cols; From 7e89e34549b7bc1fa8e330b9e7fce21dfd5320a6 Mon Sep 17 00:00:00 2001 From: Hyunsu Cho Date: Fri, 24 Jul 2026 16:26:11 -0700 Subject: [PATCH 14/14] Set strict=false to test_voting::test_sample_weight[42] in cuml.accel tests --- .../cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml b/python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml index 0d49c7e4f0..8b3777ad82 100644 --- a/python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml +++ b/python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml @@ -475,6 +475,7 @@ - reason: Test should fail with cuml.accel on scikit-learn <1.9 marker: cuml_accel_bugs condition: scikit-learn<1.9 + strict: false tests: - "sklearn.ensemble.tests.test_voting::test_sample_weight[42]" - reason: These tests sometimes fail in CI due to a misconfigured machine leading to ASCII codec reads