Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
355eaf8
Deprecate max_deth=16 in RandomForest and add None support
Nzouh Apr 8, 2026
a083d6c
Merge remote-tracking branch 'upstream/main' into feature/max-depth-d…
Nzouh Apr 8, 2026
e7bde34
Address PR review: fix FutureWarning false positives for max_depth=16
Nzouh Apr 8, 2026
adcfa83
Merge branch 'main' into feature/max-depth-deprecate
Nzouh Apr 8, 2026
6921658
Address CodeRabbit review: fix double warning in Dask and tighten max…
Nzouh Apr 8, 2026
79f5e4b
Merge branch 'feature/max-depth-deprecate' of https://github.com/Nzou…
Nzouh Apr 8, 2026
59f1b73
Update CHANGELOG to 26.06.00 for next development cycle
Nzouh Apr 8, 2026
0ba7257
Address Style Checker (Linter) failures
Nzouh Apr 9, 2026
defd4d4
fix: Explicitly set max_depth=16 in tests to resolve FutureWarning fa…
Nzouh Apr 9, 2026
b340e9b
fix: add explicit max_depth to all remaining RF test initializations
Nzouh Apr 9, 2026
91f2f1d
revert: remove changelog changes as requested by maintainer
Nzouh Apr 9, 2026
67c6a23
Merge branch 'main' into feature/max-depth-deprecate
chyunsu3 Apr 9, 2026
5d51a13
style: apply ruff formatting and fix remaining max_depth test failures
Nzouh Apr 9, 2026
3bea1f0
Revert "style: apply ruff formatting and fix remaining max_depth test…
chyunsu3 Apr 9, 2026
63b5778
Use pre-commit to make style fixes
chyunsu3 Apr 9, 2026
8177f4f
Undo changes to CHANGELOG.md
chyunsu3 Apr 9, 2026
adfb2ca
Update general testing infrastructure for RF deprecation
Nzouh Apr 10, 2026
9484a91
Update SPDX copyright headers for modified files
Nzouh Apr 10, 2026
d8c66b7
Fix max_depth deprecation warning in test_fil.py (wide data test)
Nzouh Apr 10, 2026
c7e0a12
Harden devcontainer build with apt-get update retries
Nzouh Apr 10, 2026
2938b1f
Revert changes to .devcontainer/Dockerfile
Nzouh Apr 10, 2026
0013b70
Address PR review: simplify RF constructor, move warning to fit, and …
Nzouh Apr 10, 2026
12442c9
Align Scikit-learn baseline hyperparameters in Dask RF tests
Nzouh Apr 11, 2026
66de880
Merge branch 'main' into feature/max-depth-deprecate
Nzouh Apr 12, 2026
9fe06fa
Address PR review comments: cleanup dead logic, fix whitespace, and a…
Nzouh Apr 17, 2026
1ea64dc
Address all review comments: global warning filters with TODOs and cl…
Nzouh Apr 18, 2026
7ff63b1
Final cleanup: Ensure all RandomForest tests have global filters with…
Nzouh Apr 18, 2026
eb9910b
Audit cleanup: Add missing TODO(26.08) comments to all warning filters.
Nzouh Apr 18, 2026
55fca14
Merge branch 'main' into feature/max-depth-deprecate
chyunsu3 Apr 20, 2026
39342b5
Formatting fix
chyunsu3 Apr 20, 2026
3dfc806
fix(rf): re-enable FutureWarning in test_default_parameters
Nzouh Apr 20, 2026
4daa59e
fix(rf): expect FutureWarning on fit() instead of get_params()
Nzouh Apr 21, 2026
8e8be69
Merge branch 'main' into feature/max-depth-deprecate
chyunsu3 Apr 23, 2026
9a65eed
Merge remote-tracking branch 'upstream/main' into pr-7958-upstream
csadorf Apr 27, 2026
064e496
Warn at fit not during __init__ for Dask estimators.
csadorf Apr 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion python/cuml/cuml/dask/ensemble/base.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright (c) 2021-2025, NVIDIA CORPORATION.
# SPDX-FileCopyrightText: Copyright (c) 2021-2026, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#

Expand Down Expand Up @@ -46,6 +46,17 @@ def _create_model(
)
self.workers = workers
self._set_internal_model(None)
# TODO(26.08): Drop along with the single-GPU deprecation in
# cuml.ensemble.randomforest_common.
# Record whether the user explicitly set `max_depth`; the warning is
# emitted from `_fit` so it fires at fit time (matching the single-GPU
# path) rather than at construction. We still forward an explicit
# `max_depth=16` to the per-worker single-GPU estimators so they don't
# each emit their own FutureWarning.
self._max_depth_user_set = "max_depth" in kwargs
if not self._max_depth_user_set:
kwargs["max_depth"] = 16

self.active_workers = list()
self.ignore_empty_partitions = ignore_empty_partitions
self.n_estimators = n_estimators
Expand Down Expand Up @@ -89,6 +100,17 @@ def _estimators_per_worker(self, n_estimators):
return n_estimators_per_worker

def _fit(self, model, dataset, convert_dtype, broadcast_data):
# TODO(26.08): Drop along with the single-GPU deprecation in
# cuml.ensemble.randomforest_common.
if not getattr(self, "_max_depth_user_set", True):
warnings.warn(
"The default value of 'max_depth' will change from 16 to "
"None (unlimited depth) in release 26.08. To suppress this "
"warning, set 'max_depth' explicitly.",
FutureWarning,
stacklevel=3,
)

data = DistributedDataHandler.create(dataset, client=self.client)
self.active_workers = data.workers
self.datatype = data.datatype
Expand Down Expand Up @@ -230,6 +252,10 @@ def _get_params(self, deep):
return params_of_each_model

def _set_params(self, **params):
# TODO(26.08): Drop along with the single-GPU deprecation in
# cuml.ensemble.randomforest_common.
if "max_depth" in params:
self._max_depth_user_set = True
model_params = list()
for idx, worker in enumerate(self.workers):
model_params.append(
Expand Down
3 changes: 3 additions & 0 deletions python/cuml/cuml/dask/ensemble/randomforestclassifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ class RandomForestClassifier(

.. note:: This default differs from scikit-learn's
random forest, which defaults to unlimited depth.

.. versionchanged:: 26.08
The default of `max_depth` will change from `16` to `None`.
max_leaves : int (default = -1)
Maximum leaf nodes per tree. Soft constraint. Unlimited, If ``-1``.
max_features : float (default = 'auto')
Expand Down
3 changes: 3 additions & 0 deletions python/cuml/cuml/dask/ensemble/randomforestregressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ class RandomForestRegressor(

.. note:: This default differs from scikit-learn's
random forest, which defaults to unlimited depth.

.. versionchanged:: 26.08
The default of `max_depth` will change from `16` to `None`.
max_leaves : int (default = -1)
Maximum leaf nodes per tree. Soft constraint. Unlimited, If ``-1``.
max_features : float (default = 'auto')
Expand Down
27 changes: 21 additions & 6 deletions python/cuml/cuml/ensemble/randomforest_common.pyx

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.

We need to explicitly convert max_depth=<sentinel> to max_depth=16 within the _params_to_cpu function.

Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ def compute_max_features(
)


_DEPRECATED_MAX_DEPTH_DEFAULT = "deprecated"


class BaseRandomForestModel(Base, InteropMixin):

@classmethod
Expand Down Expand Up @@ -244,7 +247,9 @@ class BaseRandomForestModel(Base, InteropMixin):
return {
"n_estimators": self.n_estimators,
"criterion": criterion,
"max_depth": self.max_depth,
"max_depth": (
16 if self.max_depth == _DEPRECATED_MAX_DEPTH_DEFAULT else self.max_depth
),
"min_samples_split": self.min_samples_split,
"min_samples_leaf": self.min_samples_leaf,
"max_features": self.max_features,
Expand Down Expand Up @@ -307,7 +312,7 @@ class BaseRandomForestModel(Base, InteropMixin):
n_estimators=100,
bootstrap=True,
max_samples=1.0,
max_depth=16,
max_depth=_DEPRECATED_MAX_DEPTH_DEFAULT,
Comment thread
csadorf marked this conversation as resolved.
max_leaves=-1,
max_features='sqrt',
n_bins=128,
Expand Down Expand Up @@ -417,15 +422,25 @@ class BaseRandomForestModel(Base, InteropMixin):
cdef int n_classes = self.n_classes_ if is_classifier else 0

cdef int max_depth_c
if self.max_depth is None:
max_depth = self.max_depth

if max_depth == _DEPRECATED_MAX_DEPTH_DEFAULT:
warnings.warn(
"The default value of 'max_depth' will change from 16 to "
"None (unlimited depth) in release 26.08. To suppress this "
"warning, set 'max_depth' explicitly.",
FutureWarning, stacklevel=3)
max_depth = 16

if max_depth is None:
max_depth_c = np.iinfo(np.int32).max
elif not isinstance(self.max_depth, int) or self.max_depth <= 0:
elif not isinstance(max_depth, int) or max_depth <= 0:
raise ValueError(
f"max_depth must be a positive integer or None (unlimited); "
f"got {self.max_depth!r}"
f"got {max_depth!r}"
)
else:
max_depth_c = self.max_depth
max_depth_c = max_depth

# Validate OOB score parameter
if callable(self.oob_score):
Expand Down
3 changes: 3 additions & 0 deletions python/cuml/cuml/ensemble/randomforestclassifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ class RandomForestClassifier(BaseRandomForestModel, ClassifierMixin):

.. note:: This default differs from scikit-learn's random forest,
which defaults to unlimited depth.

.. versionchanged:: 26.08
The default of `max_depth` will change from `16` to `None`.
max_leaves : int (default = -1)
Maximum leaf nodes per tree. Soft constraint. Unlimited,
If ``-1``.
Expand Down
3 changes: 3 additions & 0 deletions python/cuml/cuml/ensemble/randomforestregressor.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class RandomForestRegressor(BaseRandomForestModel, RegressorMixin):

.. note:: This default differs from scikit-learn's random forest,
which defaults to unlimited depth.

.. versionchanged:: 26.08
The default of `max_depth` will change from `16` to `None`.
max_leaves : int (default = -1)
Maximum leaf nodes per tree. Soft constraint. Unlimited,
If ``-1``.
Expand Down
16 changes: 13 additions & 3 deletions python/cuml/tests/dask/test_dask_random_forest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
from cuml.ensemble import RandomForestClassifier as cuRFC_sg
from cuml.ensemble import RandomForestRegressor as cuRFR_sg

# TODO(26.08): Remove this filter
pytestmark = pytest.mark.filterwarnings(
"ignore:The default value of 'max_depth':FutureWarning"
)


def _prep_training_data(c, X_train, y_train, partitions_per_worker):
workers = c.has_what().keys()
Expand Down Expand Up @@ -234,7 +239,11 @@ def test_rf_classification_dask_fil_predict_proba(
y_proba[:, 1] = y_test
y_proba[:, 0] = 1.0 - y_test
fil_mse = mean_squared_error(y_proba, fil_preds_proba)
sk_model = skrfc(n_estimators=40, max_depth=16, random_state=10)
sk_model = skrfc(
n_estimators=cu_rf_params["n_estimators"],
max_depth=cu_rf_params["max_depth"],
random_state=10,
)
sk_model.fit(X_train, y_train)
sk_preds_proba = sk_model.predict_proba(X_test)
sk_mse = mean_squared_error(y_proba, sk_preds_proba)
Expand All @@ -258,7 +267,7 @@ def test_rf_concatenation_dask(client, model_type):
else:
y = y.astype(np.float32)
n_estimators = 40
cu_rf_params = {"n_estimators": n_estimators}
cu_rf_params = {"n_estimators": n_estimators, "max_depth": 16}

X_df, y_df = _prep_training_data(client, X, y, partitions_per_worker=2)

Expand All @@ -284,7 +293,8 @@ def test_single_input_regression(client, ignore_empty_partitions):

X, y = _prep_training_data(client, X, y, partitions_per_worker=2)
cu_rf_mg = cuRFR_mg(
n_bins=1, ignore_empty_partitions=ignore_empty_partitions
n_bins=1,
ignore_empty_partitions=ignore_empty_partitions,
)

if (
Expand Down
6 changes: 5 additions & 1 deletion python/cuml/tests/explainer/test_explainer_common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION.
# SPDX-FileCopyrightText: Copyright (c) 2020-2026, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#

Expand All @@ -21,6 +21,10 @@
)
from cuml.testing.utils import ClassEnumerator

# TODO(26.08) Remove this filter
pytestmark = pytest.mark.filterwarnings(
"ignore:The default value of 'max_depth':FutureWarning"
)
models_config = ClassEnumerator(module=cuml)
models = models_config.get_models()

Expand Down
4 changes: 4 additions & 0 deletions python/cuml/tests/explainer/test_explainer_kernel_shap.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
from cuml.testing.datasets import with_dtype
from cuml.testing.utils import ClassEnumerator, get_shap_values

# TODO(26.08): Remove this filter
pytestmark = pytest.mark.filterwarnings(
"ignore:The default value of 'max_depth':FutureWarning"
)
models_config = ClassEnumerator(module=cuml)
models = models_config.get_models()

Expand Down
6 changes: 6 additions & 0 deletions python/cuml/tests/explainer/test_gpu_treeshap.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
shap = pytest.importorskip("shap")


# TODO(26.08): Remove this filter
pytestmark = pytest.mark.filterwarnings(
"ignore:The default value of 'max_depth':FutureWarning"
)


def make_classification_with_categorical(
*,
n_samples,
Expand Down
4 changes: 3 additions & 1 deletion python/cuml/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,10 @@ def test_mro(model):


@pytest.mark.parametrize("model_name", list(models.keys()))
# ignore random forest float64 warnings
# ignore random forest float64 warnings and max_depth deprecation
@pytest.mark.filterwarnings("ignore:To use pickling or GPU-based")
# TODO(26.08): Remove this filter
@pytest.mark.filterwarnings("ignore:The default value of 'max_depth'")

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.

Please add a comment to every filter like this that we need to remove the filter within the 26.08 release.

def test_fit_function(dataset, model_name):
# This test ensures that our estimators return self after a call to fit
if model_name in [
Expand Down
8 changes: 7 additions & 1 deletion python/cuml/tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,10 @@ def get_param_doc(param_doc_obj, name: str):


@pytest.mark.parametrize("child_class", list(all_base_children.keys()))
# ignore ColumnTransformer init warning
# ignore ColumnTransformer init warning and max_depth deprecation
@pytest.mark.filterwarnings("ignore:Transformers are required")
# TODO(26.08) Remove this filter
@pytest.mark.filterwarnings("ignore:The default value of 'max_depth'")
@pytest.mark.filterwarnings("ignore::FutureWarning")
def test_base_children__get_param_names(child_class: str):
"""
Expand Down Expand Up @@ -293,6 +295,8 @@ def test_get_handle_device_ids():
and hasattr(cls, "predict")
],
)
# TODO(26.08) Remove this filter
@pytest.mark.filterwarnings("ignore:The default value of 'max_depth'")
def test_regressor_predict_dtype(cls):
X, y = make_regression(n_samples=200, random_state=42)
X32 = X.astype("float32")
Expand Down Expand Up @@ -327,6 +331,8 @@ def test_regressor_predict_dtype(cls):
(cuml.MBSGDClassifier, None),
],
)
# TODO(26.08) Remove this filter
@pytest.mark.filterwarnings("ignore:The default value of 'max_depth'")
@pytest.mark.parametrize(
"target_kind", ["binary", "multiclass", "multitarget"]
)
Expand Down
4 changes: 3 additions & 1 deletion python/cuml/tests/test_common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION.
# SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#
import numpy as np
Expand All @@ -20,6 +20,8 @@
],
)
@pytest.mark.filterwarnings("ignore:The number of bins.*:UserWarning")
# TODO(26.08) Remove this filter
@pytest.mark.filterwarnings("ignore:The default value of 'max_depth'")
def test_random_state_argument(Estimator):
X, y = make_blobs(random_state=0)
# Check that both integer and np.random.RandomState are accepted
Expand Down
7 changes: 6 additions & 1 deletion python/cuml/tests/test_fil.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright (c) 2019-2025, NVIDIA CORPORATION.
# SPDX-FileCopyrightText: Copyright (c) 2019-2026, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#

Expand Down Expand Up @@ -42,6 +42,11 @@
unit_param,
)

# TODO(26.08): Remove this filter
pytestmark = pytest.mark.filterwarnings(
"ignore:The default value of 'max_depth':FutureWarning"
)


def simulate_data(
m,
Expand Down
7 changes: 6 additions & 1 deletion python/cuml/tests/test_meta_estimators.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# SPDX-FileCopyrightText: Copyright (c) 2021-2025, NVIDIA CORPORATION.
# SPDX-FileCopyrightText: Copyright (c) 2021-2026, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#

Expand All @@ -15,6 +15,11 @@
from cuml.svm import SVC
from cuml.testing.utils import ClassEnumerator

# TODO(26.08): Remove this filter
pytestmark = pytest.mark.filterwarnings(
"ignore:The default value of 'max_depth':FutureWarning"
)


def test_pipeline():
X, y = make_classification(random_state=0)
Expand Down
5 changes: 5 additions & 0 deletions python/cuml/tests/test_pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
)
from cuml.tsa.arima import ARIMA

# TODO(26.08) Remove this filter
pytestmark = pytest.mark.filterwarnings(
"ignore:The default value of 'max_depth':FutureWarning"
)
regression_config = ClassEnumerator(module=cuml.linear_model)
regression_models = regression_config.get_models()

Expand Down Expand Up @@ -369,6 +373,7 @@ def assert_model(pickled_model, X_train):
@pytest.mark.filterwarnings(
"ignore:Transformers((.|\n)*):UserWarning:cuml[.*]"
)
@pytest.mark.filterwarnings("ignore:The default value of 'max_depth'")
def test_unfit_pickle(model_name):
# Any model xfailed in this test cannot be used for hyperparameter sweeps
# with dask or sklearn
Expand Down
Loading
Loading