Fix RF multi-stream fits on non-default device - #8131
Conversation
f197b1a to
3c2352f
Compare
|
/ok to test 3c2352f |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (3)
📝 WalkthroughSummary by CodeRabbit
WalkthroughRandomForest::fit now sets the CUDA device from the provided raft::handle_t using raft::device_setter for initial pointer validation and installs per-thread device_setter guards inside the OpenMP tree-building loop. Python tests were updated: a prior n_streams=1 workaround was removed and a multi-device CuPy test was added. ChangesDevice Context Management in RandomForest Training
🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
jcrist
left a comment
There was a problem hiding this comment.
One concern on correctness.
Beyond that, there are a few other places in the C++ code where we use stream pools across threads. I assume those also need this change applied?
Also, in the original issue (and last time we discussed this) we decided we didn't necessarily want to support users changing the device at runtime this way (and instead wanted users to use CUDA_VISIBLE_DEVICES). If this change doesn't result in any downsides (perf, maintainability, ...) it's probably fine, but otherwise we may want to fix this with docs (and maybe a different way of preventing runtime errors) rather than supporting this.
| this->error_checking(input, labels, n_rows, n_cols, false); | ||
| const raft::handle_t& handle = user_handle; | ||
| int n_sampled_rows = 0; | ||
| int handle_device = handle.get_device(); |
There was a problem hiding this comment.
Is this value cached by the handle? If it is, then it won't get the correct device id on repeated calls if cp.cuda.Device is used to change the device.
There was a problem hiding this comment.
Good catch! The device id is usually cached because the handle itself is cached thread-local. However, since by default RandomForestClassifier set the n_streams value to nonzero, it happens to not be cached.
With n_streams > 0, the handle we will be created with a new CUDA stream pool and use the per thread default stream for each thread. The device id will be set on the first call to get_device() based on whatever is the currently active device. That is all to say that this will indeed not work well if we create arrays with one device active, and then run fit with a different device active, but it will generally work for switching devices, but only incidentally because n_streams > 0.
The changes on this PR still have merit since we should generally use the device set by the handle, but we probably have to apply this in a few other cases as well.
Given that – as you correctly assert - we currently don't generally support a workflow for setting devices via cp.cuda.Device() I think we should not merge this PR as-is and instead perform a broader evaluation of this failure class.
There was a problem hiding this comment.
We will document the expected behavior in #8134 , so I'll just retarget this PR to 26.08 and pick it back up then.
3c2352f to
7969078
Compare
|
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. |
Ensures random forest fitting sets the RAFT handle's CUDA device in both the main thread and OpenMP workers, avoiding invalid multi-stream CUDA calls when training data is created under
cp.cuda.Device(1). Adds regression coverage for the reported crash and removes then_streams=1workaround from the FIL device-selection test.Closes #5983