Skip to content
Closed
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
7 changes: 3 additions & 4 deletions python/cuml/cuml/cluster/agglomerative.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
#
import numpy as np

from cuml.common import input_to_cuml_array
from cuml.common.array_descriptor import CumlArrayDescriptor
from cuml.common.doc_utils import generate_docstring
from cuml.internals.array import CumlArray
from cuml.internals.base import Base, get_handle
from cuml.internals.input_utils import validate_data
from cuml.internals.mixins import ClusterMixin, CMajorInputTagMixin
from cuml.internals.outputs import reflect

Expand Down Expand Up @@ -144,9 +144,8 @@ class AgglomerativeClustering(Base, ClusterMixin, CMajorInputTagMixin):
Fit the hierarchical clustering from features.
"""
# Validate and process inputs
X = input_to_cuml_array(
X,
order="C",
X = validate_data(
self, X, order="C",
check_dtype=np.float32,
convert_to_dtype=(np.float32 if convert_dtype else None),
).array
Expand Down
9 changes: 4 additions & 5 deletions python/cuml/cuml/cluster/dbscan.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ from cuml.common.doc_utils import generate_docstring
from cuml.internals import logger, reflect
from cuml.internals.array import CumlArray
from cuml.internals.base import Base, get_handle
from cuml.internals.input_utils import input_to_cuml_array
from cuml.internals.input_utils import input_to_cuml_array, validate_data
from cuml.internals.interop import (
InteropMixin,
UnsupportedOnGPU,
Expand Down Expand Up @@ -330,11 +330,10 @@ class DBSCAN(Base,
)

cdef int64_t n_rows, n_cols
X, n_rows, n_cols, _ = input_to_cuml_array(
X,
order='C',
X, n_rows, n_cols, _ = validate_data(
self, X, order='C',
convert_to_dtype=(np.float32 if convert_dtype else None),
check_dtype=[np.float32, np.float64]
check_dtype=[np.float32, np.float64],
)

if n_rows * n_cols > (2**31 - 1):
Expand Down
8 changes: 4 additions & 4 deletions python/cuml/cuml/cluster/hdbscan/hdbscan.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ from cuml.common.doc_utils import generate_docstring
from cuml.internals import logger, reflect
from cuml.internals.array import CumlArray
from cuml.internals.base import Base, get_handle
from cuml.internals.input_utils import validate_data
from cuml.internals.interop import (
InteropMixin,
UnsupportedOnGPU,
Expand Down Expand Up @@ -933,12 +934,11 @@ class HDBSCAN(Base, InteropMixin, ClusterMixin, CMajorInputTagMixin):
else:
convert_to_mem_type = MemoryType.device

self._raw_data = input_to_cuml_array(
X,
order='C',
self._raw_data = validate_data(
self, X, order='C',
check_dtype=[np.float32],
convert_to_dtype=np.float32 if convert_dtype else None,
convert_to_mem_type=convert_to_mem_type
convert_to_mem_type=convert_to_mem_type,
)[0]
self._raw_data_cpu = None

Expand Down
21 changes: 10 additions & 11 deletions python/cuml/cuml/cluster/kmeans.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import typing

import numpy as np

from cuml._thirdparty.sklearn.utils.validation import check_is_fitted
from cuml.common import input_to_cuml_array
from cuml.common.array_descriptor import CumlArrayDescriptor
from cuml.common.doc_utils import generate_docstring
from cuml.internals.array import CumlArray
from cuml.internals.base import Base, get_handle
from cuml.internals.input_utils import validate_data
from cuml.internals.interop import (
InteropMixin,
UnsupportedOnGPU,
Expand Down Expand Up @@ -517,9 +519,8 @@ class KMeans(Base,

"""
# Process input arrays
X_m, n_rows, n_cols, dtype = input_to_cuml_array(
X,
order="C",
X_m, n_rows, n_cols, dtype = validate_data(
self, X, order="C",
convert_to_dtype=(np.float32 if convert_dtype else None),
check_dtype=[np.float32, np.float64],
)
Expand Down Expand Up @@ -635,12 +636,10 @@ class KMeans(Base,
"""
dtype = self.cluster_centers_.dtype

X_m, n_rows, _, _ = input_to_cuml_array(
X,
order="C",
X_m, n_rows, _, _ = validate_data(
self, X, reset=False, order="C",
check_dtype=dtype,
convert_to_dtype=(dtype if convert_dtype else None),
check_cols=self.n_features_in_,
)

if sample_weight is None:
Expand Down Expand Up @@ -681,6 +680,7 @@ class KMeans(Base,
Predict the closest cluster each sample in X belongs to.

"""
check_is_fitted(self)
labels, _ = self._predict_labels_inertia(X, convert_dtype=convert_dtype)
return labels

Expand All @@ -694,14 +694,13 @@ class KMeans(Base,
Transform X to a cluster-distance space.

"""
check_is_fitted(self)
dtype = self.cluster_centers_.dtype

X_m = input_to_cuml_array(
X,
order="C",
X_m = validate_data(
self, X, reset=False, order="C",
check_dtype=dtype,
convert_to_dtype=(dtype if convert_dtype else None),
check_cols=self.cluster_centers_.shape[1],
).array

cdef int64_t n_rows = X_m.shape[0]
Expand Down
10 changes: 6 additions & 4 deletions python/cuml/cuml/common/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#
# SPDX-FileCopyrightText: Copyright (c) 2020, NVIDIA CORPORATION.
# SPDX-FileCopyrightText: Copyright (c) 2020-2026, NVIDIA CORPORATION.
# SPDX-License-Identifier: Apache-2.0
#

from sklearn.exceptions import NotFittedError as _SklearnNotFittedError

class NotFittedError(ValueError, AttributeError):

class NotFittedError(_SklearnNotFittedError):
"""Exception class to raise if estimator is used before fitting.

This class inherits from both ValueError and AttributeError to help with
exception handling and backward compatibility.
Inherits from sklearn's NotFittedError so that sklearn's estimator
checks and except clauses catch it correctly.
"""
18 changes: 12 additions & 6 deletions python/cuml/cuml/covariance/ledoit_wolf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from cuml.internals import reflect, run_in_internal_context
from cuml.internals.array import CumlArray
from cuml.internals.base import Base
from cuml.internals.input_utils import input_to_cupy_array
from cuml.internals.input_utils import input_to_cupy_array, validate_data
from cuml.internals.interop import InteropMixin, to_cpu, to_gpu


Expand Down Expand Up @@ -246,8 +246,10 @@ def fit(self, X, y=None, *, convert_dtype=True) -> "LedoitWolf":
self : LedoitWolf
Returns the instance itself.
"""
X_arr, n_samples, n_features, dtype = input_to_cupy_array(
X_arr, n_samples, n_features, dtype = validate_data(
self,
X,
array_output_type="cupy",
check_dtype=[np.float32, np.float64],
order="C",
convert_to_dtype=(np.float32 if convert_dtype else None),
Expand Down Expand Up @@ -324,10 +326,12 @@ def score(self, X_test, y=None) -> float:
log_likelihood : float
Log-likelihood of the data under the fitted Gaussian model.
"""
X_arr, _, n_features, _ = input_to_cupy_array(
X_arr, _, n_features, _ = validate_data(
self,
X_test,
reset=False,
array_output_type="cupy",
check_dtype=[np.float32, np.float64],
check_cols=self.n_features_in_,
order="C",
)

Expand Down Expand Up @@ -408,10 +412,12 @@ def mahalanobis(self, X):
mahalanobis_distances : ndarray of shape (n_samples,)
Squared Mahalanobis distances of the observations.
"""
X_arr, _, _, _ = input_to_cupy_array(
X_arr, _, _, _ = validate_data(
self,
X,
reset=False,
array_output_type="cupy",
check_dtype=[np.float32, np.float64],
check_cols=self.n_features_in_,
order="C",
)
precision = cp.asarray(self.get_precision())
Expand Down
6 changes: 4 additions & 2 deletions python/cuml/cuml/decomposition/incremental_pca.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from cuml.decomposition.pca import PCA
from cuml.internals.array import CumlArray
from cuml.internals.base import Base
from cuml.internals.input_utils import input_to_cupy_array
from cuml.internals.input_utils import input_to_cupy_array, validate_data


class IncrementalPCA(PCA):
Expand Down Expand Up @@ -224,8 +224,10 @@ def fit(self, X, y=None, *, convert_dtype=True) -> "IncrementalPCA":
# is done by PCA, which IncrementalPCA inherits from. PCA's
# transform and inverse transform convert the output to the
# required type.
X, n_samples, n_features, _ = input_to_cupy_array(
X, n_samples, n_features, _ = validate_data(
self,
X,
array_output_type="cupy",
order="K",
convert_to_dtype=(cp.float32 if convert_dtype else None),
check_dtype=[cp.float32, cp.float64],
Expand Down
18 changes: 10 additions & 8 deletions python/cuml/cuml/decomposition/pca.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ from cuml.common.exceptions import NotFittedError
from cuml.common.sparse_utils import is_sparse
from cuml.internals.array import CumlArray
from cuml.internals.base import Base, get_handle
from cuml.internals.input_utils import input_to_cuml_array
from cuml.internals.input_utils import input_to_cuml_array, validate_data
from cuml.internals.interop import (
InteropMixin,
UnsupportedOnGPU,
Expand Down Expand Up @@ -486,11 +486,13 @@ class PCA(Base,
X = cupyx.scipy.sparse.coo_matrix(X)
n_rows, n_cols = X.shape
else:
X, n_rows, n_cols, _ = input_to_cuml_array(
X,
convert_to_dtype=(np.float32 if convert_dtype else None),
X_out = validate_data(
self, X,
convert_to_dtype=(np.float32 if convert_dtype else False),
check_dtype=[np.float32, np.float64],
)
X = X_out.array
n_rows, n_cols = X_out.n_rows, X_out.n_cols

self.n_samples_ = n_rows

Expand Down Expand Up @@ -637,12 +639,12 @@ class PCA(Base,
def _transform_dense(self, X, convert_dtype=True):
dtype = self.components_.dtype

X_m, n_rows, n_cols, _ = input_to_cuml_array(
X,
X_out = validate_data(
self, X, reset=False,
check_dtype=dtype,
convert_to_dtype=(dtype if convert_dtype else None),
check_cols=self.n_features_in_,
convert_to_dtype=(dtype if convert_dtype else False),
)
X_m, n_rows, n_cols = X_out.array, X_out.n_rows, X_out.n_cols

out = CumlArray.zeros(
(n_rows, self.n_components_), dtype=dtype, index=X_m.index
Expand Down
20 changes: 12 additions & 8 deletions python/cuml/cuml/decomposition/tsvd.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
#

import numpy as np
from sklearn.utils.validation import check_is_fitted

import cuml.internals
from cuml.common import input_to_cuml_array
from cuml.common.array_descriptor import CumlArrayDescriptor
from cuml.common.doc_utils import generate_docstring
from cuml.internals.array import CumlArray
from cuml.internals.base import Base, get_handle
from cuml.internals.input_utils import validate_data
from cuml.internals.interop import InteropMixin, to_cpu, to_gpu
from cuml.internals.mixins import FMajorInputTagMixin

Expand Down Expand Up @@ -306,11 +308,12 @@ class TruncatedSVD(Base,

"""
# Validate input
X_m, n_rows, n_cols, dtype = input_to_cuml_array(
X,
convert_to_dtype=(np.float32 if convert_dtype else None),
check_dtype=[np.float32, np.float64]
X_out = validate_data(
self, X,
convert_to_dtype=(np.float32 if convert_dtype else False),
check_dtype=[np.float32, np.float64],
)
X_m, n_rows, n_cols, dtype = X_out

# Validate and initialize parameters
if self.n_components > n_cols:
Expand Down Expand Up @@ -455,13 +458,14 @@ class TruncatedSVD(Base,
Perform dimensionality reduction on X.

"""
check_is_fitted(self)
dtype = self.components_.dtype
X_m, n_rows, _, _ = input_to_cuml_array(
X,
X_out = validate_data(
self, X, reset=False,
check_dtype=dtype,
convert_to_dtype=(dtype if convert_dtype else None),
check_cols=self.n_features_in_,
convert_to_dtype=(dtype if convert_dtype else False),
)
X_m, n_rows = X_out.array, X_out.n_rows

cdef paramsTSVD params
params.n_components = self.n_components
Expand Down
25 changes: 21 additions & 4 deletions python/cuml/cuml/ensemble/randomforestclassifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import cupy as cp
import numpy as np
from sklearn.utils.validation import check_is_fitted

import cuml.internals
import cuml.internals.nvtx as nvtx
Expand All @@ -11,7 +12,7 @@
from cuml.common.doc_utils import generate_docstring, insert_into_docstring
from cuml.ensemble.randomforest_common import BaseRandomForestModel
from cuml.internals.array import CumlArray
from cuml.internals.input_utils import input_to_cuml_array
from cuml.internals.input_utils import validate_data
from cuml.internals.interop import UnsupportedOnGPU
from cuml.internals.mixins import ClassifierMixin
from cuml.metrics import accuracy_score
Expand Down Expand Up @@ -221,11 +222,17 @@ def fit(self, X, y, *, convert_dtype=True) -> "RandomForestClassifier":
y to be of dtype int32. This will increase memory used for
the method.
"""
X_m = input_to_cuml_array(
# y is only forwarded when None so that validate_data's tag-driven
# check raises ValueError for missing targets. Non-None y is skipped
# here because classifiers accept string labels that
# input_to_cuml_array cannot convert; preprocess_labels handles y
# conversion below.
X_m = validate_data(
self,
X,
convert_to_dtype=(np.float32 if convert_dtype else None),
y=y if y is None else "no_validation",
convert_to_dtype=(np.float32 if convert_dtype else False),
check_dtype=[np.float32, np.float64],
order="F",
).array
y, classes = preprocess_labels(
y, n_samples=X_m.shape[0], dtype=cp.int32
Expand Down Expand Up @@ -280,6 +287,16 @@ def predict(
-------
y : {}
"""
check_is_fitted(self)

if X.ndim == 1:
raise ValueError(
"Expected 2D array, got 1D array instead.\n"
"Reshape your data either using array.reshape(-1, 1) if "
"your data has a single feature or array.reshape(1, -1) "
"if it contains a single sample."
)

fil = self._get_inference_fil_model(
layout=layout,
default_chunk_size=default_chunk_size,
Expand Down
Loading