Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revise the type reflection system #6241

Draft
wants to merge 22 commits into
base: branch-25.02
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7b0e13c
Implement prototype for revised type reflection system.
csadorf Jan 15, 2025
ac3e5f3
fixup! Implement prototype for revised type reflection system.
csadorf Jan 16, 2025
5f8d9f6
fixup! Implement prototype for revised type reflection system.
csadorf Jan 16, 2025
6b9895b
fixup! Implement prototype for revised type reflection system.
csadorf Jan 16, 2025
fb389c9
fixup! Implement prototype for revised type reflection system.
csadorf Jan 16, 2025
7b28815
fixup! Implement prototype for revised type reflection system.
csadorf Jan 16, 2025
6966f3b
fixup! Implement prototype for revised type reflection system.
csadorf Jan 16, 2025
964705d
Implement prototype within cuml namespace.
csadorf Jan 16, 2025
0e5c55a
fixup! Implement prototype within cuml namespace.
csadorf Jan 16, 2025
9b4736e
Rename 'cuml_api' -> 'cuml_public_api'.
csadorf Jan 17, 2025
815c6e3
Use cuml's CumlArray.
csadorf Jan 17, 2025
a5b1bc5
Tiny revision to the new CumlArrayDescriptor class implementation.
csadorf Jan 17, 2025
2456eb9
Revise internal_api related names.
csadorf Jan 17, 2025
04230f1
further refine
csadorf Jan 17, 2025
a36cea7
Implement CumlArrayDescriptor caching.
csadorf Jan 17, 2025
bc8d5e2
Implement revision for LinearRegression estimator.
csadorf Jan 17, 2025
3a3aacd
Update docs and add example workflow module.
csadorf Jan 17, 2025
3d7decd
fixup! Update docs and add example workflow module.
csadorf Jan 17, 2025
93cd87d
Use pre-existing CM for overriding global output type.
csadorf Jan 17, 2025
d27dc22
Implement logistic regression.
csadorf Jan 21, 2025
d6ba7cf
fixup! Implement logistic regression.
csadorf Jan 21, 2025
47eeff7
fixup! Implement logistic regression.
csadorf Jan 21, 2025
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
11 changes: 10 additions & 1 deletion python/cuml/cuml/common/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2019-2023, NVIDIA CORPORATION.
# Copyright (c) 2019-2025, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -40,6 +40,12 @@
from cuml.internals.memory_utils import with_cupy_rmm
from cuml.common.device_selection import using_device_type

from cuml.internals.type_reflection import (
CumlArrayDescriptor,
set_output_type,
convert_cuml_arrays,
)


if is_cuda_available():
from cuml.common.pointer_utils import device_of_gpu_matrix
Expand All @@ -51,6 +57,7 @@

__all__ = [
"CumlArray",
"CumlArrayDescriptor",
"SparseCumlArray",
"device_of_gpu_matrix",
"has_cupy",
Expand All @@ -67,6 +74,8 @@
"using_memory_type",
"using_output_type",
"with_cupy_rmm",
"convert_cuml_arrays",
"set_output_type",
"sparse_scipy_to_cp",
"timed",
]
143 changes: 3 additions & 140 deletions python/cuml/cuml/internals/base.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,7 @@ class VerbosityDescriptor:
obj._verbose = value


class Base(TagsMixin,
metaclass=cuml.internals.BaseMetaClass):
class Base(TagsMixin):
"""
Base class for all the ML algos. It handles some of the common operations
across all algos. Every ML algo class exposed at cython level must inherit
Expand Down Expand Up @@ -283,15 +282,6 @@ class Base(TagsMixin,
# rendered unnecessary with https://github.com/rapidsai/cuml/pull/6189.
GlobalSettings().root_cm = GlobalSettings().prev_root_cm

self.output_type = _check_output_type_str(
cuml.global_settings.output_type
if output_type is None else output_type)
if output_mem_type is None:
self.output_mem_type = cuml.global_settings.memory_type
else:
self.output_mem_type = MemoryType.from_str(output_mem_type)
self._input_type = None
self._input_mem_type = None
self.target_dtype = None
self.n_features_in_ = None

Expand Down Expand Up @@ -390,122 +380,15 @@ class Base(TagsMixin,
"""
Redirects to `solver_model` if the attribute exists.
"""
# TODO: I think we should handle this explicitly on a
# estimator-by-estimator basis.
if attr == "solver_model":
return self.__dict__['solver_model']
if "solver_model" in self.__dict__.keys():
return getattr(self.solver_model, attr)
else:
raise AttributeError(attr)

def _set_base_attributes(self,
output_type=None,
target_dtype=None,
n_features=None):
"""
Method to set the base class attributes - output type,
target dtype and n_features. It combines the three different
function calls. It's called in fit function from estimators.

Parameters
--------
output_type : DataFrame (default = None)
Is output_type is passed, aets the output_type on the
dataframe passed
target_dtype : Target column (default = None)
If target_dtype is passed, we call _set_target_dtype
on it
n_features: int or DataFrame (default=None)
If an int is passed, we set it to the number passed
If dataframe, we set it based on the passed df.

Examples
--------

.. code-block:: python

# To set output_type and n_features based on X
self._set_base_attributes(output_type=X, n_features=X)

# To set output_type on X and n_features to 10
self._set_base_attributes(output_type=X, n_features=10)

# To only set target_dtype
self._set_base_attributes(output_type=X, target_dtype=y)
"""
if output_type is not None:
self._set_output_type(output_type)
self._set_output_mem_type(output_type)
if target_dtype is not None:
self._set_target_dtype(target_dtype)
if n_features is not None:
self._set_n_features_in(n_features)

def _set_output_type(self, inp):
self._input_type = determine_array_type(inp)

def _set_output_mem_type(self, inp):
self._input_mem_type = determine_array_memtype(
inp
)

def _get_output_type(self, inp):
"""
Method to be called by predict/transform methods of inheriting classes.
Returns the appropriate output type depending on the type of the input,
class output type and global output type.
"""

# Default to the global type
output_type = cuml.global_settings.output_type

# If its None, default to our type
if (output_type is None or output_type == "mirror"):
output_type = self.output_type

# If we are input, get the type from the input
if output_type == 'input':
output_type = determine_array_type(inp)

return output_type

def _get_output_mem_type(self, inp):
"""
Method to be called by predict/transform methods of inheriting classes.
Returns the appropriate memory type depending on the type of the input,
class output type and global output type.
"""

# Default to the global type
mem_type = cuml.global_settings.memory_type

# If we are input, get the type from the input
if cuml.global_settings.output_type == 'input':
mem_type = determine_array_memtype(inp)

return mem_type

def _set_target_dtype(self, target):
self.target_dtype = cuml.internals.input_utils.determine_array_dtype(
target)

def _get_target_dtype(self):
"""
Method to be called by predict/transform methods of
inheriting classifier classes. Returns the appropriate output
dtype depending on the dtype of the target.
"""
try:
out_dtype = self.target_dtype
except AttributeError:
out_dtype = None
return out_dtype

def _set_n_features_in(self, X):
if isinstance(X, int):
self.n_features_in_ = X
else:
self.n_features_in_ = X.shape[1]

def _more_tags(self):
# 'preserves_dtype' tag's Scikit definition currently only applies to
# transformers and whether the transform method conserves the dtype
Expand Down Expand Up @@ -593,26 +476,6 @@ def _check_output_type_str(output_str):
)


def _determine_stateless_output_type(output_type, input_obj):
"""
This function determines the output type using the same steps that are
performed in `cuml.common.base.Base`. This can be used to mimic the
functionality in `Base` for stateless functions or objects that do not
derive from `Base`.
"""

# Default to the global type if not specified, otherwise, check the
# output_type string
temp_output = cuml.global_settings.output_type if output_type is None \
else _check_output_type_str(output_type)

# If we are using 'input', determine the the type from the input object
if temp_output == 'input':
temp_output = determine_array_type(input_obj)

return temp_output


class UniversalBase(Base):
# variable to enable dispatching non-implemented methods to CPU
# estimators, experimental.
Expand Down
13 changes: 12 additions & 1 deletion python/cuml/cuml/internals/global_settings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2021-2024, NVIDIA CORPORATION.
# Copyright (c) 2021-2025, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -53,6 +53,7 @@ def __init__(self):
"accelerator_active": False,
"accelerator_loaded": False,
"accelerated_modules": {},
"_api_depth": 0,
}
)

Expand Down Expand Up @@ -134,3 +135,13 @@ def output_type(self, value):
@property
def xpy(self):
return self.memory_type.xpy

@property
def api_depth(self):
return self._api_depth

def increment_api_depth(self):
self._api_depth += 1

def decrement_api_depth(self):
self._api_depth -= 1
8 changes: 4 additions & 4 deletions python/cuml/cuml/internals/mixins.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2021-2023, NVIDIA CORPORATION.
# Copyright (c) 2021-2025, NVIDIA CORPORATION.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -18,9 +18,9 @@

from copy import deepcopy
from cuml.common.doc_utils import generate_docstring
from cuml.internals.api_decorators import api_base_return_any_skipall
from cuml.internals.base_helpers import _tags_class_and_instance
from cuml.internals.api_decorators import enable_device_interop
from cuml.common import convert_cuml_arrays


###############################################################################
Expand Down Expand Up @@ -198,8 +198,8 @@ class RegressorMixin:
"description": "R^2 of self.predict(X) " "wrt. y.",
}
)
@api_base_return_any_skipall
@enable_device_interop
@convert_cuml_arrays()
def score(self, X, y, **kwargs):
"""
Scoring function for regression estimators
Expand Down Expand Up @@ -239,8 +239,8 @@ class ClassifierMixin:
),
}
)
@api_base_return_any_skipall
@enable_device_interop
@convert_cuml_arrays()
def score(self, X, y, **kwargs):
"""
Scoring function for classifier estimators based on mean accuracy.
Expand Down
Loading
Loading