Skip to content

Apply new validation to metrics.hinge_loss - #8060

Merged
rapids-bot[bot] merged 7 commits into
NVIDIA:mainfrom
csadorf:issue-7998-apply-new-validation-to-metrics-hinge-loss
May 8, 2026
Merged

Apply new validation to metrics.hinge_loss#8060
rapids-bot[bot] merged 7 commits into
NVIDIA:mainfrom
csadorf:issue-7998-apply-new-validation-to-metrics-hinge-loss

Conversation

@csadorf

@csadorf csadorf commented May 6, 2026

Copy link
Copy Markdown
Contributor

Applies the new input validation system to cuml.metrics.hinge_loss.

  • Replaces the cudf-backed LabelEncoder/LabelBinarizer round-trip in
    the multiclass and binary paths with cp.searchsorted and cp.where
    (~3× speedup on typical inputs).
  • Deprecates sample_weights in favor of sample_weight to match
    sklearn's convention (removal in 26.08).

Part of #7998

@csadorf
csadorf requested a review from a team as a code owner May 6, 2026 19:07
@csadorf
csadorf requested a review from dantegd May 6, 2026 19:07
@github-actions github-actions Bot added the Cython / Python Cython or Python issue label May 6, 2026
@csadorf csadorf added improvement Improvement / enhancement to an existing function non-breaking Non-breaking change breaking Breaking change and removed Cython / Python Cython or Python issue non-breaking Non-breaking change labels May 6, 2026
@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Improved hinge loss metric with more robust input validation, consistent float return, and reliable binary & multiclass behavior across NumPy, CuPy, pandas and other containers.
  • Bug Fixes

    • Renamed parameter to sample_weight (old sample_weights kept as deprecated alias emitting a warning).
  • Tests

    • Added extensive hinge-loss tests covering containers, labels, sample weights, and error cases.

Walkthrough

The hinge_loss function is refactored from a cuDF-centric implementation to a CuPy/NumPy-based approach using new validation utilities. The API changes the sample_weights parameter to sample_weight with a deprecated keyword-only alias. Binary and multiclass computation paths are unified under consistent validation. Comprehensive test coverage is added.

Changes

Hinge Loss Implementation Refactor

Layer / File(s) Summary
API Surface & Deprecation
python/cuml/cuml/metrics/hinge_loss.py
Function signature updated to use singular sample_weight parameter with deprecated sample_weights keyword-only alias; warnings import added.
Deprecated Alias Handling
python/cuml/cuml/metrics/hinge_loss.py
sample_weights is supported as a deprecated alias: emits FutureWarning and maps to sample_weight.
Input Validation & Class Extraction
python/cuml/cuml/metrics/hinge_loss.py
Replaced cuDF/coercion logic with check_array, check_y, check_sample_weight, and check_consistent_length; determine/validate classes consistent with labels.
Multiclass Computation
python/cuml/cuml/metrics/hinge_loss.py
Validate pred_decision 2D and class-dimension; compute margin as target-class score minus best non-target score.
Binary Computation
python/cuml/cuml/metrics/hinge_loss.py
Flatten pred_decision if needed; encode true labels to {-1,+1} and compute margin via signed-label × pred_decision.
Loss Aggregation
python/cuml/cuml/metrics/hinge_loss.py
Compute per-sample hinge = max(0, 1 − margin), average with validated sample_weight, return Python float.
Test Coverage
python/cuml/tests/test_metrics.py
Add pandas import and tests: binary (multi-container), single-observed-class labels, multiclass (with/without labels and sample_weight), inconsistent-length and missing-label errors, and deprecated sample_weights behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • rapidsai/cuml#8049: Both PRs migrate metric functions to the new cuml.internals.validation helpers (e.g., check_array, check_sample_weight, check_consistent_length), so they are related.
  • rapidsai/cuml#8012: Both PRs migrate metrics code to the new input validation utilities — the main PR refactors hinge_loss to use check_array, check_y, check_sample_weight, and check_consistent_length, matching the validation-driven changes in PR #8012.

Suggested labels

Cython / Python, non-breaking, sklearn-api-compat

Suggested reviewers

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

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% 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 title clearly and concisely summarizes the main change: applying validation system to hinge_loss metrics function.
Description check ✅ Passed The description is directly related to the changeset, detailing validation system implementation, performance improvements, and parameter deprecation.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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: 1

🧹 Nitpick comments (1)
python/cuml/tests/test_metrics.py (1)

1773-1785: ⚡ Quick win

Add a regression for invalid binary score shapes.

The new binary coverage only exercises valid 1D scores, so the flattening bug in the binary path would still pass CI. A small pytest.raises(ValueError) case for pred_decision.shape == (n_samples, 2) would lock in the intended validation. As per coding guidelines, **/*.py: "Update unit tests when making code changes".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cuml/tests/test_metrics.py` around lines 1773 - 1785, Add a negative
test to ensure the binary hinge path rejects 2D score arrays: in
test_hinge_loss_binary add a pytest.raises(ValueError) case that calls
cuml_hinge with y_true (1D labels) and pred_decision shaped (n_samples, 2) and
asserts a ValueError is raised; reference the existing test_hinge_loss_binary
and cuml_hinge to locate where to add this regression test so the flattening bug
is prevented.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/cuml/cuml/metrics/hinge_loss.py`:
- Around line 135-137: The code currently flattens any 2D pred_decision in
hinge_loss, which can corrupt binary inputs; update the logic in the hinge_loss
function to only ravel pred_decision when pred_decision.ndim == 2 and
pred_decision.shape[1] == 1 (i.e., a single-column 2D array), and otherwise
raise a clear ValueError rejecting multi-column binary score arrays; keep the
rest of the flow (use of pos_label and classes) unchanged so multi-column inputs
fail early with an explicit error instead of silent corruption or opaque
broadcasts.

---

Nitpick comments:
In `@python/cuml/tests/test_metrics.py`:
- Around line 1773-1785: Add a negative test to ensure the binary hinge path
rejects 2D score arrays: in test_hinge_loss_binary add a
pytest.raises(ValueError) case that calls cuml_hinge with y_true (1D labels) and
pred_decision shaped (n_samples, 2) and asserts a ValueError is raised;
reference the existing test_hinge_loss_binary and cuml_hinge to locate where to
add this regression test so the flattening bug is prevented.
🪄 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: Enterprise

Run ID: ebd74ba0-8364-41ca-9da4-bb2065ab4235

📥 Commits

Reviewing files that changed from the base of the PR and between 7ba22e6 and f29f08e.

📒 Files selected for processing (2)
  • python/cuml/cuml/metrics/hinge_loss.py
  • python/cuml/tests/test_metrics.py

Comment thread python/cuml/cuml/metrics/hinge_loss.py Outdated
Comment on lines +135 to +137
if pred_decision.ndim > 1:
pred_decision = cp.ravel(pred_decision)
pos_label = classes[-1]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject multi-column binary score arrays.

Line 135 currently ravels any 2D pred_decision. In the binary path that can silently corrupt the sample axis: a (1, 2) input becomes two losses for one sample, while larger (n, 2) inputs fail later with an opaque broadcast error. Only a single-column 2D input should be flattened here.

Possible fix
-        if pred_decision.ndim > 1:
-            pred_decision = cp.ravel(pred_decision)
+        if pred_decision.ndim == 2 and pred_decision.shape[1] == 1:
+            pred_decision = cp.ravel(pred_decision)
+        elif pred_decision.ndim != 1:
+            raise ValueError(
+                "pred_decision must be 1D for binary hinge loss, "
+                f"got shape {pred_decision.shape}."
+            )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cuml/cuml/metrics/hinge_loss.py` around lines 135 - 137, The code
currently flattens any 2D pred_decision in hinge_loss, which can corrupt binary
inputs; update the logic in the hinge_loss function to only ravel pred_decision
when pred_decision.ndim == 2 and pred_decision.shape[1] == 1 (i.e., a
single-column 2D array), and otherwise raise a clear ValueError rejecting
multi-column binary score arrays; keep the rest of the flow (use of pos_label
and classes) unchanged so multi-column inputs fail early with an explicit error
instead of silent corruption or opaque broadcasts.

@csadorf
csadorf force-pushed the issue-7998-apply-new-validation-to-metrics-hinge-loss branch from f29f08e to 1f7a697 Compare May 7, 2026 18:34
@github-actions github-actions Bot added the Cython / Python Cython or Python issue label May 7, 2026

@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.

🧹 Nitpick comments (1)
python/cuml/tests/test_metrics.py (1)

1880-1963: 💤 Low value

Consider adding test coverage for binary path shape handling.

Once the multi-column binary validation fix is applied, add tests for:

  1. A 2D single-column input (n, 1) that should work correctly
  2. A 2D multi-column input (n, 2) that should raise ValueError
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/cuml/tests/test_metrics.py` around lines 1880 - 1963, Add two tests
around the binary hinge-loss path to validate 2D shapes: create one test that
passes a 2D single-column prediction array shape (n,1) to cuml_hinge (e.g., use
y_true = np.array([-1,1,...]) and pred_decision =
np.array([[-2.18],[2.36],...])) and assert it matches scikit-learn's sk_hinge
result; add another test that passes a 2D two-column prediction array shape
(n,2) and assert cuml_hinge raises ValueError (use pytest.raises(...,
match="...") consistent with other tests). Place these tests near
test_hinge_loss_binary / test_hinge_loss_binary_labels_* so they exercise the
binary code paths for cuml_hinge.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@python/cuml/tests/test_metrics.py`:
- Around line 1880-1963: Add two tests around the binary hinge-loss path to
validate 2D shapes: create one test that passes a 2D single-column prediction
array shape (n,1) to cuml_hinge (e.g., use y_true = np.array([-1,1,...]) and
pred_decision = np.array([[-2.18],[2.36],...])) and assert it matches
scikit-learn's sk_hinge result; add another test that passes a 2D two-column
prediction array shape (n,2) and assert cuml_hinge raises ValueError (use
pytest.raises(..., match="...") consistent with other tests). Place these tests
near test_hinge_loss_binary / test_hinge_loss_binary_labels_* so they exercise
the binary code paths for cuml_hinge.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7f420bf6-cf7f-4868-af01-23b88fde6ea4

📥 Commits

Reviewing files that changed from the base of the PR and between f29f08e and 1f7a697.

📒 Files selected for processing (2)
  • python/cuml/cuml/metrics/hinge_loss.py
  • python/cuml/tests/test_metrics.py

@jcrist jcrist left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice work!

@jcrist

jcrist commented May 8, 2026

Copy link
Copy Markdown
Member

/merge

@rapids-bot
rapids-bot Bot merged commit aed66d5 into NVIDIA:main May 8, 2026
93 checks passed
@csadorf
csadorf deleted the issue-7998-apply-new-validation-to-metrics-hinge-loss branch May 8, 2026 13:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking Breaking change Cython / Python Cython or Python issue improvement Improvement / enhancement to an existing function

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants