Skip to content

Implement weighted bootstrap sampling for RF - #8296

Merged
rapids-bot[bot] merged 10 commits into
NVIDIA:mainfrom
RAMitchell:codex/enh-rf-weighted-bootstrap
Jul 1, 2026
Merged

Implement weighted bootstrap sampling for RF#8296
rapids-bot[bot] merged 10 commits into
NVIDIA:mainfrom
RAMitchell:codex/enh-rf-weighted-bootstrap

Conversation

@RAMitchell

Copy link
Copy Markdown
Contributor

Summary

  • Add sklearn-style weighted bootstrap sampling for C++ RandomForest.
  • Treat RF sample weights as double internally, including float forests.
  • Refactor row sampling into an internal RowSampler that owns validation, CDF construction, and per-stream sampling buffers.
  • Remove the unused bootstrap_masks RF API/plumbing and update tests to validate behavior through trained trees instead.
  • Preserve non-bootstrap behavior where sample weights are passed into tree objective/impurity math.

Details

Weighted bootstrap now uses sample_weight as draw probabilities. When bootstrap is enabled, trees train from the sampled row IDs/counts rather than receiving the original sample weights, matching sklearn behavior.

RowSampler handles sample-weight validation and sum computation, weighted CDF construction, per-stream selected row buffers, weighted draw scratch storage, and bootstrap/non-bootstrap row-id generation.

Tests

  • cmake --build /home/rorym/cuml-builds/codex-enh-rf-weighted-bootstrap/cpp-release --target SG_RF_TEST -j 8
  • /home/rorym/cuml-builds/codex-enh-rf-weighted-bootstrap/cpp-release/tests/SG_RF_TEST --gtest_filter=RfWeightedTest.*:WeightedObjectiveEdgeCases.*:RfTests.InvalidSampleWeightThrows:RfTests.WeightedBootstrapSamplesOnlyPositiveWeightRows
  • /home/rorym/cuml-builds/codex-enh-rf-weighted-bootstrap/cpp-release/tests/SG_RF_TEST --gtest_filter=RfTests/RfTest.PropertyBasedTest/*

No Python changes.

@copy-pr-bot

copy-pr-bot Bot commented Jun 26, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@RAMitchell
RAMitchell requested a review from Copilot June 26, 2026 16:54
@RAMitchell RAMitchell added improvement Improvement / enhancement to an existing function non-breaking Non-breaking change labels Jun 26, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements sklearn-style weighted bootstrap sampling for the C++ RandomForest training path by sampling row IDs according to sample_weight when bootstrap=true, while standardizing RF sample weights to double across float/double forests and removing the bootstrap_masks plumbing.

Changes:

  • Introduces an internal detail::RowSampler that validates weights, builds a weighted CDF, and generates per-tree sampled row IDs (weighted or unweighted).
  • Changes RF/DT APIs to take const double* sample_weight and removes the bootstrap_masks output parameter.
  • Updates C++ SG RF tests to use double weights and validate weighted-bootstrap behavior via trained trees rather than bootstrap masks.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
cpp/tests/sg/rf_test.cu Updates tests to use double sample weights and adds coverage for weighted bootstrap sampling semantics.
cpp/src/randomforest/randomforest.cuh Adds RowSampler and rewires RF training to use sampled row IDs and conditional weight propagation.
cpp/src/randomforest/randomforest.cu Updates exported fit / fit_treelite entry points to the new double* sample weight signature and removes bootstrap_masks.
cpp/src/decisiontree/decisiontree.cuh Updates DT fit signature to accept const double* sample_weight.
cpp/src/decisiontree/batched-levelalgo/dataset.h Changes dataset sample weight storage to const double*.
cpp/src/decisiontree/batched-levelalgo/builder.cuh Threads const double* sample_weight through the batched builder constructor.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cpp/src/randomforest/randomforest.cuh
Comment thread cpp/include/cuml/ensemble/randomforest.hpp
@RAMitchell
RAMitchell marked this pull request as ready for review June 26, 2026 18:04
@RAMitchell
RAMitchell requested a review from a team as a code owner June 26, 2026 18:04
@RAMitchell
RAMitchell requested review from aamijar and jcrist June 26, 2026 18:04
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

RandomForest and DecisionTree training interfaces now take const double* sample_weight. The RandomForest fit path uses a row-sampling helper, and the tests update weighted training and objective-gain coverage to double-typed weights.

Changes

RandomForest sample-weight plumbing

Layer / File(s) Summary
Public fit contracts
cpp/include/cuml/ensemble/randomforest.hpp, cpp/src/decisiontree/batched-levelalgo/builder.cuh, cpp/src/decisiontree/batched-levelalgo/dataset.h, cpp/src/decisiontree/decisiontree.cuh, cpp/src/randomforest/randomforest.cuh
RandomForest fit declarations and the shared DecisionTree/Builder/Dataset sample-weight declarations use const double*.
RandomForest sampling and fit wiring
cpp/src/randomforest/randomforest.cuh, cpp/src/randomforest/randomforest.cu
RowSampler handles bootstrap row selection and mask writes, and RandomForest::fit and its exported overloads pass double sample weights through the tree-fitting path.
Shared weighted test helpers
cpp/tests/sg/rf_test.cu
Score, TrainScore, and RfSpecialisedTest use double sample weights, and invalid-weight checks operate on double values.
Weighted RF behavior tests
cpp/tests/sg/rf_test.cu
RfWeightedTest cases switch to double-typed device weights and update the weighted bootstrap, zero-weight, and duplicate-occurrence assertions.
Objective gain helpers
cpp/tests/sg/rf_test.cu
DT::ObjectiveTest generates, stores, slices, and consumes std::vector<double> sample weights across the criterion-specific gain helpers.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • rapidsai/cuml#8132: Weighted decision-tree groundwork with double-typed weight handling in the same training path.
  • rapidsai/cuml#8247: Updates the same weighted RandomForest and decision-tree test paths exercised here.
  • rapidsai/cuml#8258: Threads sample_weight through the same RandomForest and batched-levelalgo training path.

Suggested reviewers

  • dantegd
  • hcho3
  • csadorf

Suggested labels

CMake

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding weighted bootstrap sampling for RandomForest.
Description check ✅ Passed The description is directly aligned with the code changes and testing updates in this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cpp/include/cuml/ensemble/randomforest.hpp (1)

145-177: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

HIGH: Add migration coverage for this public fit signature break.

Removing bootstrap_masks and changing float-forest sample_weight to const double* breaks existing callers of these cpp/include/cuml declarations. Please add a migration/docs note or compatibility/deprecation path for the old signature.

As per path instructions, “Breaking changes require deprecation warnings and migration guide updates.”

Also applies to: 227-256

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cpp/include/cuml/ensemble/randomforest.hpp` around lines 145 - 177, The
public fit API in randomforest.hpp has a breaking signature change, so update
the migration/docs path and provide compatibility or deprecation coverage for
existing callers of fit and fit_treelite. Add deprecation warnings or an
overload/adaptor for the old bootstrap_masks-based signature and the previous
float-forest sample_weight form, and document the migration in the relevant
public API notes so users can transition safely.

Sources: Coding guidelines, Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cpp/src/randomforest/randomforest.cuh`:
- Around line 64-73: The weighted bootstrap path in randomforest.cuh can produce
an out-of-range row index because sample_weight_sum_ is derived separately from
sample_weight_cdf_ and upper_bound may return n_rows_ if the sum exceeds the
scan tail due to roundoff. Update the weighted draw logic in the constructor and
the selection code paths (the bootstrap sampling and downstream uses of
selected_rows) to clamp or derive the search bound from
sample_weight_cdf_.back() instead of the independent sum, so generated indices
always stay within [0, n_rows_ - 1].

---

Outside diff comments:
In `@cpp/include/cuml/ensemble/randomforest.hpp`:
- Around line 145-177: The public fit API in randomforest.hpp has a breaking
signature change, so update the migration/docs path and provide compatibility or
deprecation coverage for existing callers of fit and fit_treelite. Add
deprecation warnings or an overload/adaptor for the old bootstrap_masks-based
signature and the previous float-forest sample_weight form, and document the
migration in the relevant public API notes so users can transition safely.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: d8ae3902-55c0-46be-8b68-c25c001f405d

📥 Commits

Reviewing files that changed from the base of the PR and between ecb6469 and 1c31701.

📒 Files selected for processing (7)
  • cpp/include/cuml/ensemble/randomforest.hpp
  • cpp/src/decisiontree/batched-levelalgo/builder.cuh
  • cpp/src/decisiontree/batched-levelalgo/dataset.h
  • cpp/src/decisiontree/decisiontree.cuh
  • cpp/src/randomforest/randomforest.cu
  • cpp/src/randomforest/randomforest.cuh
  • cpp/tests/sg/rf_test.cu

Comment thread cpp/src/randomforest/randomforest.cuh Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cpp/include/cuml/ensemble/randomforest.hpp (1)

145-180: 🗄️ Data Integrity & Integration | 🟠 Major

Preserve the existing sample_weight signature
Changing the public RF fit/fit_treelite overloads to const double* sample_weight breaks callers that pass float*. Add a deprecated compatibility overload or migration note for the new type.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cpp/include/cuml/ensemble/randomforest.hpp` around lines 145 - 180, The
public random forest fit overloads and fit_treelite now take sample_weight as
const double*, which breaks existing callers that pass float*; update the API in
randomforest.hpp to preserve backward compatibility by adding a deprecated
shim/overload for the old float* signature or an equivalent compatibility path.
Keep the new const double* form in fit and fit_treelite, and make sure the
compatibility overload forwards to the new implementation so existing call sites
continue to compile.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cpp/src/randomforest/randomforest.cuh`:
- Around line 134-147: `store_bootstrap_mask()` in `randomforest.cuh` writes to
`bootstrap_masks_` without validating that the device buffer is usable, so add a
guard before the Thrust fill/scatter path to ensure `bootstrap_masks_` is
non-null and points to valid device memory for the current tree; if the pointer
is invalid, fail fast or skip the write. Keep the check close to the
`store_bootstrap_mask`/`bootstrap_masks_` logic so the device writes are only
launched when `RowSampler` has a safe mask buffer.
- Line 140: The tree mask pointer offset in the bootstrap mask handling is
computed with unchecked host-side multiplication, which can wrap and corrupt the
destination mask. Update the offset calculation in the random forest mask logic
that uses bootstrap_masks_ and tree_id to use the checked arithmetic helpers for
host-side count arithmetic before forming the tree_mask pointer. Keep the fix
localized to the tree mask row-offset computation so overflow is detected
instead of silently wrapping.

---

Outside diff comments:
In `@cpp/include/cuml/ensemble/randomforest.hpp`:
- Around line 145-180: The public random forest fit overloads and fit_treelite
now take sample_weight as const double*, which breaks existing callers that pass
float*; update the API in randomforest.hpp to preserve backward compatibility by
adding a deprecated shim/overload for the old float* signature or an equivalent
compatibility path. Keep the new const double* form in fit and fit_treelite, and
make sure the compatibility overload forwards to the new implementation so
existing call sites continue to compile.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1aa170ce-5bde-44ba-86f0-67eeef9cdccd

📥 Commits

Reviewing files that changed from the base of the PR and between 1c31701 and 836fbbc.

📒 Files selected for processing (4)
  • cpp/include/cuml/ensemble/randomforest.hpp
  • cpp/src/randomforest/randomforest.cu
  • cpp/src/randomforest/randomforest.cuh
  • cpp/tests/sg/rf_test.cu
🚧 Files skipped from review as they are similar to previous changes (1)
  • cpp/tests/sg/rf_test.cu

Comment thread cpp/src/randomforest/randomforest.cuh
Comment thread cpp/src/randomforest/randomforest.cuh Outdated
@csadorf
csadorf requested a review from chyunsu3 June 26, 2026 19:43
Comment thread cpp/src/randomforest/randomforest.cuh Outdated
Comment thread cpp/src/randomforest/randomforest.cuh Outdated
Comment thread cpp/src/randomforest/randomforest.cuh

@csadorf csadorf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@RAMitchell

Copy link
Copy Markdown
Contributor Author

/merge

@rapids-bot
rapids-bot Bot merged commit 0b19540 into NVIDIA:main Jul 1, 2026
102 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CUDA/C++ improvement Improvement / enhancement to an existing function non-breaking Non-breaking change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants