Skip to content

Use new input validation in cuml.linear_models/cuml.solvers - #7978

Merged
rapids-bot[bot] merged 16 commits into
NVIDIA:mainfrom
jcrist:input-validation-linear-models
Apr 23, 2026
Merged

Use new input validation in cuml.linear_models/cuml.solvers#7978
rapids-bot[bot] merged 16 commits into
NVIDIA:mainfrom
jcrist:input-validation-linear-models

Conversation

@jcrist

@jcrist jcrist commented Apr 21, 2026

Copy link
Copy Markdown
Member

This applies the new input validation utilities added in #7973 to cuml.linear_models and cuml.solvers.

Doing this fixed ~70 failing sklearn compatibility tests for cuml proper, and at least 60 upstream tests for cuml.accel.

Fixes #7986
Fixes #7987
Part of #7428

@copy-pr-bot

copy-pr-bot Bot commented Apr 21, 2026

Copy link
Copy Markdown

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.

@github-actions github-actions Bot added the Cython / Python Cython or Python issue label Apr 21, 2026
@jcrist
jcrist force-pushed the input-validation-linear-models branch from 8a209b6 to 870f66c Compare April 22, 2026 16:19
@jcrist jcrist added improvement Improvement / enhancement to an existing function non-breaking Non-breaking change cuml-accel Issues related to cuml.accel sklearn-api-compat Issues around cuml matching sklearn API conventions/standards labels Apr 22, 2026
@jcrist
jcrist marked this pull request as ready for review April 22, 2026 16:19
@jcrist
jcrist requested a review from a team as a code owner April 22, 2026 16:19
@jcrist
jcrist requested a review from betatim April 22, 2026 16:19
@jcrist jcrist changed the title [WIP] Use new input validation in cuml.linear_models/cuml.solvers Use new input validation in cuml.linear_models/cuml.solvers Apr 22, 2026
@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 07691209-48d2-4b93-8f4d-1c3c4e80fd03

📥 Commits

Reviewing files that changed from the base of the PR and between 7cdafb4 and fc22aa1.

📒 Files selected for processing (1)
  • python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml
💤 Files with no reviewable changes (1)
  • python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • More consistent sample-weight and class-weight handling across regressors, classifiers, and SVMs.
    • Clearer error messages for unsupported multiclass/binary cases and input-validation failures.
  • Code Quality

    • Unified input validation and solver flows produce more consistent fit/predict behavior and standardized stored attributes (coefficients/intercepts).
  • Tests

    • Updated test expectations and removed outdated xfails to reflect improved compatibility.

Walkthrough

Consolidates input/target validation using new check_* helpers across solvers and estimators, centralizes ElasticNet/Lasso GPU-fit logic into a new _ElasticNetMixin, updates solver APIs to accept estimator context and optionally return classes, and changes many @reflect decorators from reset=True to reset="type".

Changes

Cohort / File(s) Summary
Linear models (core)
python/cuml/cuml/linear_model/linear_regression.pyx, python/cuml/cuml/linear_model/ridge.pyx, python/cuml/cuml/linear_model/elastic_net.py
Replaced ad-hoc input/target handling with check_inputs/check_y; updated internal _fit signatures to use may-mutate flags; unified coef/intercept wrapping as CumlArray(data=...); changed @reflect reset arg to "type"; Ridge now declares multioutput support.
Solvers
python/cuml/cuml/solvers/cd.pyx, python/cuml/cuml/solvers/qn.pyx, python/cuml/cuml/solvers/sgd.pyx
Added estimator param and return_classes control; centralized validation via check_inputs; switched allocations to cupy arrays and pointer access to .data.ptr; renamed/exported fit_cd; solvers may return classes when requested.
Accel overrides & classification utils
python/cuml/cuml/accel/_overrides/sklearn/linear_model.py, python/cuml/cuml/common/classification.py
Introduced _ElasticNetMixin implementing _gpu_fit using check_y; refactored process_class_weight to operate on cupy arrays with a dtype param; removed prior input-to-CumlArray conversions and CUDA pointer alias checks.
Estimator entrypoints / wrappers
python/cuml/cuml/linear_model/logistic_regression.py, python/cuml/cuml/linear_model/mbsgd_classifier.py, python/cuml/cuml/linear_model/mbsgd_regressor.py
Delegated class/weight handling to solvers (fit_qn/fit_sgd), pass self into solver calls, wrap returned coefficients with CumlArray(data=...), and use @reflect(reset="type").
SVM
python/cuml/cuml/svm/linear_svc.py, python/cuml/cuml/svm/svc.py
Added check_sample_weight and check_consistent_length; harmonized dtype selection; forward sample_weight as CumlArray when calling lower-level fits; adjusted probability-fitting path.
Predict/IO adjustments
python/cuml/cuml/solvers/..., python/cuml/cuml/linear_model/...
Predict methods now call check_is_fitted, use check_inputs(..., return_index=True), allocate outputs with cupy, use .data.ptr, and return CumlArray(data=..., index=...).
Tests / xfails / test adjustments
python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml, python/cuml/tests/test_sklearn_compatibility.py, python/cuml/tests/test_mbsgd_classifier.py, python/cuml/tests/*
Removed many xfail entries tied to sample-weight/input-validation; updated tests to expect new error messages and solver defaults (e.g., QN loss); adjusted test configurations and solver instantiations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • betatim
  • csadorf
  • dantegd
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the main change: applying new input validation utilities to linear_models and solvers modules.
Description check ✅ Passed The PR description explains the purpose, scope, and impact of applying input validation utilities from #7973 to linear_models and solvers, with concrete outcomes (70+ fixed tests) and related issue references.
Linked Issues check ✅ Passed The PR implements the objectives from linked issues #7986 and #7987 by refactoring linear_model and solvers modules to use centralized check_inputs validation instead of manual input handling.
Out of Scope Changes check ✅ Passed All changes are directly related to applying the new input validation framework across linear_models and solvers; xfail removals reflect test improvements from the validation refactoring and are in-scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
python/cuml/cuml/solvers/sgd.pyx (1)

447-460: ⚠️ Potential issue | 🟠 Major

Call check_is_fitted() before touching self.coef_ in predict().

This path reads self.coef_.dtype immediately, so an unfitted estimator raises an attribute error instead of the standard not-fitted error.

As per coding guidelines, "predict/transform methods must call check_is_fitted(), validate input dimensions against fitted dimensions, handle input type correctly (cuDF, pandas, NumPy), and ensure output type is consistent with input type."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/cuml/cuml/solvers/sgd.pyx` around lines 447 - 460, predict() reads
self.coef_.dtype before verifying the estimator is fitted, causing
AttributeError for unfitted models; add a call to check_is_fitted(self) at the
start of predict() (before accessing self.coef_) and then proceed to call
check_inputs(self, X, dtype=self.coef_.dtype, ...). Also ensure after
check_inputs you validate input feature dimension against the fitted coef_ shape
(e.g., compare X.shape[1] to self.coef_.shape[0] or similar) so predict follows
the expected fitted/validation flow.
python/cuml/cuml/solvers/qn.pyx (1)

558-587: ⚠️ Potential issue | 🟠 Major

Don't drop the decoded class labels returned by fit_qn().

In classifier mode, fit_qn(..., return_classes=True) gives you the original label set, but QN.fit() only stores n_classes_. QN.predict() still emits 0/1 or argmax indices, so labels like {-1, 1} or strings will no longer round-trip correctly after fit.

As per coding guidelines, "Silent data corruption from type coercion, incorrect handling of cuDF vs pandas vs NumPy inputs, or missing validation causing crashes on invalid input must be addressed."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@python/cuml/cuml/solvers/qn.pyx` around lines 558 - 587, The classifier
branch of QN.fit currently discards the decoded labels returned by fit_qn(...,
return_classes=True); update QN.fit so that when is_classifier is True you
capture and persist the returned classes (e.g., assign the returned classes to
self.classes_ or similar) instead of only storing n_classes_, and wrap them in
the appropriate container (CumlArray or native array consistent with other
estimator attributes) to preserve original label types for QN.predict and
downstream round-trip; update any existing code that expects n_classes_ only to
continue to set n_classes_ from len(self.classes_) when present.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@python/cuml/cuml/linear_model/linear_regression.pyx`:
- Around line 344-345: Replace the cupyx-only sparse check in
linear_regression.pyx: import is_sparse from cuml.common.sparse_utils and change
the predicate that currently uses sp.issparse(X) (the branch setting solver =
"lsmr") to use is_sparse(X) instead so host scipy.sparse.spmatrix and device
cupyx sparse types are both detected before calling _fit_libcuml() or
cp.asarray(X); keep the existing solver assignment and surrounding logic
unchanged.

In `@python/cuml/cuml/solvers/cd.pyx`:
- Around line 19-20: Restore the deprecated alias fit_coordinate_descent to
point to the new fit_cd and include it in the module exports: add either
fit_coordinate_descent = fit_cd (or a thin wrapper that calls fit_cd and issues
a DeprecationWarning) and update __all__ to contain "fit_coordinate_descent"
alongside "fit_cd" and "CD"; also ensure the same alias/wrapper is provided for
the helper/function defined around lines 78-92 so downstream imports keep
working for one release cycle.

In `@python/cuml/cuml/solvers/qn.pyx`:
- Around line 243-245: The call to check_array in qn.pyx incorrectly uses the
keyword convert_to_dtype; change it to convert_dtype in the coef =
check_array(...) call (so it becomes convert_dtype=convert_dtype) to match
check_array's signature, and update the docstring around the parameter
description (currently labeled convert_to_dtype at line ~158) to use
convert_dtype for consistency; locate the call in the QN warm-start path and the
docstring in the same module to apply these two renames.
- Around line 184-195: The call to check_inputs inside fit_qn is missing the
convert_dtype argument, causing implicit dtype coercion; update the check_inputs
invocation in fit_qn to pass convert_dtype=convert_dtype (preserving the
existing y_dtype/return_classes logic) so callers that request strict dtype
checking are honored; ensure the symbol names match the surrounding scope
(fit_qn and convert_dtype) and run tests for QN.fit and linear-model paths after
the change.

In `@python/cuml/cuml/solvers/sgd.pyx`:
- Around line 174-182: The call to check_inputs in fit_sgd ignores the
convert_dtype parameter so callers like SGD.fit(..., convert_dtype=False) are
silently coerced; update the check_inputs invocation in fit_sgd to forward
convert_dtype (e.g., check_inputs(..., convert_dtype=convert_dtype, ...)) and
ensure the fit_sgd function signature exposes convert_dtype (and any callers
such as MBSGDClassifier.fit that call fit_sgd propagate it) so dtype conversion
behavior honors the original argument.

---

Outside diff comments:
In `@python/cuml/cuml/solvers/qn.pyx`:
- Around line 558-587: The classifier branch of QN.fit currently discards the
decoded labels returned by fit_qn(..., return_classes=True); update QN.fit so
that when is_classifier is True you capture and persist the returned classes
(e.g., assign the returned classes to self.classes_ or similar) instead of only
storing n_classes_, and wrap them in the appropriate container (CumlArray or
native array consistent with other estimator attributes) to preserve original
label types for QN.predict and downstream round-trip; update any existing code
that expects n_classes_ only to continue to set n_classes_ from
len(self.classes_) when present.

In `@python/cuml/cuml/solvers/sgd.pyx`:
- Around line 447-460: predict() reads self.coef_.dtype before verifying the
estimator is fitted, causing AttributeError for unfitted models; add a call to
check_is_fitted(self) at the start of predict() (before accessing self.coef_)
and then proceed to call check_inputs(self, X, dtype=self.coef_.dtype, ...).
Also ensure after check_inputs you validate input feature dimension against the
fitted coef_ shape (e.g., compare X.shape[1] to self.coef_.shape[0] or similar)
so predict follows the expected fitted/validation flow.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 010d7871-5f1b-4687-b480-6b139e249576

📥 Commits

Reviewing files that changed from the base of the PR and between 146f616 and 870f66c.

📒 Files selected for processing (16)
  • python/cuml/cuml/accel/_overrides/sklearn/linear_model.py
  • python/cuml/cuml/common/classification.py
  • python/cuml/cuml/linear_model/elastic_net.py
  • python/cuml/cuml/linear_model/linear_regression.pyx
  • python/cuml/cuml/linear_model/logistic_regression.py
  • python/cuml/cuml/linear_model/mbsgd_classifier.py
  • python/cuml/cuml/linear_model/mbsgd_regressor.py
  • python/cuml/cuml/linear_model/ridge.pyx
  • python/cuml/cuml/solvers/cd.pyx
  • python/cuml/cuml/solvers/qn.pyx
  • python/cuml/cuml/solvers/sgd.pyx
  • python/cuml/cuml/svm/linear_svc.py
  • python/cuml/cuml/svm/svc.py
  • python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml
  • python/cuml/tests/test_mbsgd_classifier.py
  • python/cuml/tests/test_sklearn_compatibility.py
💤 Files with no reviewable changes (1)
  • python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml

Comment thread python/cuml/cuml/linear_model/linear_regression.pyx
Comment thread python/cuml/cuml/solvers/cd.pyx
Comment thread python/cuml/cuml/solvers/qn.pyx
Comment thread python/cuml/cuml/solvers/qn.pyx
Comment thread python/cuml/cuml/solvers/sgd.pyx
@csadorf
csadorf self-requested a review April 22, 2026 18:38
@jcrist

jcrist commented Apr 22, 2026

Copy link
Copy Markdown
Member Author

Gah, a commit got lost somehow in a rebase.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@python/cuml/tests/test_input_estimators.py`:
- Around line 114-122: The call to make_dataset is passing a 1-tuple instead of
a boolean due to the trailing comma in (is_classifier(model) or
isinstance(model, cuml.QN),); remove the trailing comma so the third argument is
the boolean expression is_classifier(model) or isinstance(model, cuml.QN) (leave
the rest of the call intact) to ensure make_dataset receives a proper True/False
classifier flag for model.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b21d294-8a44-4d93-80d1-50cf37221252

📥 Commits

Reviewing files that changed from the base of the PR and between 51f6882 and 9049907.

📒 Files selected for processing (4)
  • python/cuml/cuml/linear_model/base.py
  • python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml
  • python/cuml/tests/test_input_estimators.py
  • python/cuml/tests/test_pickle.py
💤 Files with no reviewable changes (1)
  • python/cuml/cuml_accel_tests/upstream/scikit-learn/xfail-list.yaml

Comment thread python/cuml/tests/test_input_estimators.py

@csadorf csadorf left a comment

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.

LGTM!

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.

Beautiful!

@jcrist

jcrist commented Apr 23, 2026

Copy link
Copy Markdown
Member Author

/merge

@rapids-bot
rapids-bot Bot merged commit 42f57b5 into NVIDIA:main Apr 23, 2026
93 checks passed
@jcrist
jcrist deleted the input-validation-linear-models branch April 23, 2026 04:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cuml-accel Issues related to cuml.accel Cython / Python Cython or Python issue improvement Improvement / enhancement to an existing function non-breaking Non-breaking change sklearn-api-compat Issues around cuml matching sklearn API conventions/standards

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update cuml.solvers to new input validation Update cuml.linear_model to new input validation

4 participants