Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 0 additions & 3 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,6 @@ Mini Batch SGD Regressor
Multiclass Classification
-------------------------

.. autoclass:: cuml.multiclass.MulticlassClassifier
:members:

.. autoclass:: cuml.multiclass.OneVsOneClassifier
:members:

Expand Down
38 changes: 3 additions & 35 deletions python/cuml/cuml/cluster/agglomerative.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
# SPDX-FileCopyrightText: Copyright (c) 2019-2025, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#
import warnings

import numpy as np

from cuml.common import input_to_cuml_array
Expand Down Expand Up @@ -125,7 +123,6 @@ class AgglomerativeClustering(Base, ClusterMixin, CMajorInputTagMixin):
"linkage",
"connectivity",
"c",
"n_neighbors",
]

def __init__(
Expand All @@ -139,7 +136,6 @@ class AgglomerativeClustering(Base, ClusterMixin, CMajorInputTagMixin):
handle=None,
verbose=False,
output_type=None,
n_neighbors="deprecated",
):
super().__init__(handle=handle, verbose=verbose, output_type=output_type)

Expand All @@ -148,7 +144,6 @@ class AgglomerativeClustering(Base, ClusterMixin, CMajorInputTagMixin):
self.connectivity = connectivity
self.linkage = linkage
self.c = c
self.n_neighbors = n_neighbors

@generate_docstring()
@reflect(reset=True)
Expand Down Expand Up @@ -185,37 +180,9 @@ class AgglomerativeClustering(Base, ClusterMixin, CMajorInputTagMixin):
raise ValueError("'connectivity' can only be one of {'knn', 'pairwise'}")
cdef bool use_knn = self.connectivity == "knn"

cdef int c
if self.n_neighbors != "deprecated":
warnings.warn(
(
"`n_neighbors` was deprecated in 25.12 and will be removed "
"in 26.02. Please use `c` instead, where "
"`n_neighbors = log(n_samples) + c`"
),
FutureWarning
)
# Before we were passing `c = n_neighbors`, so we continue to do so,
# understanding that this was a bug then and didn't directly indicate
# the number of neighbors.
c = self.n_neighbors
else:
c = self.c

cdef DistanceType metric
if self.metric is None:
warnings.warn(
(
"metric=None was deprecated in 25.12 and will be removed "
"in 26.02, please use metric='euclidean' instead",
),
FutureWarning
)
metric = DistanceType.L2SqrtExpanded
elif self.metric not in _metrics_mapping:
if self.metric not in _metrics_mapping:
raise ValueError("metric={self.metric!r} not supported")
else:
metric = _metrics_mapping[self.metric]
cdef DistanceType metric = _metrics_mapping[self.metric]

cdef size_t n_clusters = self.n_clusters
if n_clusters < 1 or n_clusters > n_rows:
Expand All @@ -228,6 +195,7 @@ class AgglomerativeClustering(Base, ClusterMixin, CMajorInputTagMixin):
children = CumlArray.empty((n_rows - 1, 2), dtype="int32", order="C")

cdef handle_t* handle_ = <handle_t*><size_t>self.handle.getHandle()
cdef int c = self.c
cdef float* X_ptr = <float*><uintptr_t>X.ptr
cdef int* children_ptr = <int*><uintptr_t>children.ptr
cdef int* labels_ptr = <int*><uintptr_t>labels.ptr
Expand Down
23 changes: 1 addition & 22 deletions python/cuml/cuml/manifold/t_sne.pyx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# SPDX-FileCopyrightText: Copyright (c) 2019-2025, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0

import warnings

import cupy
Expand Down Expand Up @@ -187,17 +186,7 @@ cdef _init_params(self, int n_samples, TSNEParams &params):
if n_samples < 2:
raise ValueError("TSNE requires >= 2 samples")

if self.n_iter != "deprecated":
warnings.warn(
(
"`n_iter` was deprecated in 25.12 and will be removed in 26.02. "
"Please use `max_iter` instead."
),
FutureWarning,
)
max_iter = _check_numeric(self, "n_iter", gt=0)
else:
max_iter = _check_numeric(self, "max_iter", gt=0)
max_iter = _check_numeric(self, "max_iter", gt=0)

exaggeration_iter = min(exaggeration_iter, max_iter)
if n_neighbors > 1023:
Expand Down Expand Up @@ -299,13 +288,6 @@ class TSNE(Base,
n_iter_without_progress : int (default 300)
Currently unused. When the KL Divergence becomes too small after some
iterations, terminate t-SNE early.
n_iter : int (default 1000)

.. deprecated:: 25.12
``n_iter`` has been renamed to ``max_iter`` to better match the
API of ``sklearn.manifold.TSNE``. ``n_iter`` is deprecated in favor
of ``max_iter`` and will be removed in 26.02.

min_grad_norm : float (default 1e-07)
The minimum gradient norm for when t-SNE will terminate early.
Used in the 'exact' and 'fft' algorithms. Consider reducing if
Expand Down Expand Up @@ -437,7 +419,6 @@ class TSNE(Base,
"learning_rate",
"max_iter",
"n_iter_without_progress",
"n_iter",
"min_grad_norm",
"metric",
"metric_params",
Expand Down Expand Up @@ -540,7 +521,6 @@ class TSNE(Base,
learning_rate=200.0,
max_iter=1000,
n_iter_without_progress=300,
n_iter="deprecated",
min_grad_norm=1e-07,
metric='euclidean',
metric_params=None,
Expand Down Expand Up @@ -568,7 +548,6 @@ class TSNE(Base,
self.learning_rate = learning_rate
self.max_iter = max_iter
self.n_iter_without_progress = n_iter_without_progress
self.n_iter = n_iter
self.min_grad_norm = min_grad_norm
self.metric = metric
self.metric_params = metric_params
Expand Down
13 changes: 1 addition & 12 deletions python/cuml/cuml/multiclass/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
# SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#

from cuml.multiclass.multiclass import (
MulticlassClassifier,
OneVsOneClassifier,
OneVsRestClassifier,
)

__all__ = [
"OneVsOneClassifier",
"OneVsRestClassifier",
"MulticlassClassifier",
]
from cuml.multiclass.multiclass import OneVsOneClassifier, OneVsRestClassifier
94 changes: 0 additions & 94 deletions python/cuml/cuml/multiclass/multiclass.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#
import warnings

import cuml
from cuml.common import (
input_to_host_array,
Expand Down Expand Up @@ -100,98 +98,6 @@ def decision_function(self, X) -> CumlArray:
return self.multiclass_estimator.decision_function(X)


class MulticlassClassifier(_BaseMulticlassClassifier):
"""
Wrapper around scikit-learn multiclass classifiers that allows to
choose different multiclass strategies.

.. deprecated:: 25.12

This estimator was deprecated in 25.12 and will be removed in 26.02.
Please use OneVsOneClassifier or OneVsRestClassifier directly instead.

The input can be any kind of cuML compatible array, and the output type
follows cuML's output type configuration rules.

Before passing the data to scikit-learn, it is converted to host (numpy)
array. Under the hood the data is partitioned for binary classification,
and it is transformed back to the device by the cuML estimator. These
copies back and forth the device and the host have some overhead. For more
details see issue https://github.com/rapidsai/cuml/issues/2876.

Parameters
----------
estimator : cuML estimator
handle : cuml.Handle
Specifies the cuml.handle that holds internal CUDA state for
computations in this model. Most importantly, this specifies the CUDA
stream that will be used for the model's computations, so users can
run different models concurrently in different streams by creating
handles in several streams.
If it is None, a new one is created.
verbose : int or boolean, default=False
Sets logging level. It must be one of `cuml.common.logger.level_*`.
See :ref:`verbosity-levels` for more info.
output_type : {'input', 'array', 'dataframe', 'series', 'df_obj', \
'numba', 'cupy', 'numpy', 'cudf', 'pandas'}, default=None
Return results and set estimator attributes to the indicated output
type. If None, the output type set at the module level
(`cuml.global_settings.output_type`) will be used. See
:ref:`output-data-type-configuration` for more info.
strategy: string {'ovr', 'ovo'}, default='ovr'
Multiclass classification strategy: 'ovr': one vs. rest or 'ovo': one
vs. one

Attributes
----------
classes_ : float, shape (`n_classes_`)
Array of class labels.
n_classes_ : int
Number of classes.

Examples
--------
>>> from cuml.linear_model import LogisticRegression
>>> from cuml.multiclass import MulticlassClassifier
>>> from cuml.datasets.classification import make_classification

>>> X, y = make_classification(n_samples=10, n_features=6,
... n_informative=4, n_classes=3,
... random_state=137)

>>> cls = MulticlassClassifier(LogisticRegression(), strategy='ovo')
>>> cls.fit(X, y)
MulticlassClassifier(estimator=LogisticRegression())
>>> cls.predict(X)
array([1, 1, 0, 1, 1, 1, 2, 2, 1, 2])
"""

def __init__(
self,
estimator,
*,
handle=None,
verbose=False,
output_type=None,
strategy="ovr",
):
warnings.warn(
"MulticlassClassifier was deprecated in version 25.12 and will be "
"removed in version 26.02. Please use OneVsOneClassifier or "
"OneVsRestClassifier directly instead.",
FutureWarning,
)

super().__init__(
estimator, handle=handle, verbose=verbose, output_type=output_type
)
self.strategy = strategy

@classmethod
def _get_param_names(cls):
return [*super()._get_param_names(), "strategy"]


class OneVsRestClassifier(_BaseMulticlassClassifier):
"""
Wrapper around Sckit-learn's class with the same name. The input can be
Expand Down
21 changes: 0 additions & 21 deletions python/cuml/tests/test_agglomerative.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: Copyright (c) 2019-2025, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#

import cupy as cp
import pytest
from sklearn import cluster
Expand Down Expand Up @@ -69,26 +68,6 @@ def test_single_linkage_sklearn_compare(
assert cuml_agg.children_.shape == sk_agg.children_.shape


def test_metric_none_deprecated():
X, _ = make_blobs()

model = AgglomerativeClustering(metric=None)
with pytest.warns(FutureWarning, match="metric=None"):
model.fit(X)

assert hasattr(model, "labels_")


def test_n_neighobrs_deprecated():
X, _ = make_blobs()

model = AgglomerativeClustering(n_neighbors=15)
with pytest.warns(FutureWarning, match="n_neighbors"):
model.fit(X)

assert hasattr(model, "labels_")


def test_invalid_inputs():
X, _ = make_blobs()

Expand Down
16 changes: 4 additions & 12 deletions python/cuml/tests/test_multiclass.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@


@pytest.mark.parametrize("strategy", ["ovr", "ovo"])
@pytest.mark.parametrize("use_wrapper", [True, False])
@pytest.mark.parametrize("nrows", [1000])
@pytest.mark.parametrize("num_classes", [3])
@pytest.mark.parametrize("column_info", [[10, 4]])
def test_logistic_regression(
strategy, use_wrapper, nrows, num_classes, column_info, dtype=np.float32
strategy, nrows, num_classes, column_info, dtype=np.float32
):
ncols, n_info = column_info

Expand All @@ -30,17 +29,10 @@ def test_logistic_regression(
y_test = y_test.astype(dtype)
culog = cuLog()

if use_wrapper:
with pytest.warns(
FutureWarning,
match="MulticlassClassifier was deprecated",
):
cls = cu_multiclass.MulticlassClassifier(culog, strategy=strategy)
if strategy == "ovo":
cls = cu_multiclass.OneVsOneClassifier(culog)
else:
if strategy == "ovo":
cls = cu_multiclass.OneVsOneClassifier(culog)
else:
cls = cu_multiclass.OneVsRestClassifier(culog)
cls = cu_multiclass.OneVsRestClassifier(culog)

cls.fit(X_train, y_train)
test_score = cls.score(X_test, y_test)
Expand Down
2 changes: 0 additions & 2 deletions python/cuml/tests/test_pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,13 @@
"KalmanFilter",
"BaseRandomForestModel",
"ForestInference",
"MulticlassClassifier",
"OneVsOneClassifier",
"OneVsRestClassifier",
]
unfit_clone_xfail = [
"AutoARIMA",
"ARIMA",
"BaseRandomForestModel",
"MulticlassClassifier",
"OneVsOneClassifier",
"OneVsRestClassifier",
"UMAP",
Expand Down
12 changes: 0 additions & 12 deletions python/cuml/tests/test_tsne.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,15 +432,3 @@ def test_tsne_n_iter(algorithm):
model = TSNE(n_components=2, random_state=42).fit(X)
assert model.n_iter_ > 0
assert model.n_iter_ <= model.max_iter


def test_tsne_n_iter_deprecated():
X, _ = make_blobs(
n_samples=1000, n_features=64, centers=5, random_state=42
)
model = TSNE(n_components=2, random_state=42, n_iter=2)
with pytest.warns(FutureWarning, match="n_iter"):
model.fit(X)

assert model.n_iter_ > 0
assert model.n_iter_ <= model.n_iter