Skip to content

ENH - check datafit + penalty compatibility with solver - #137

Merged
Badr-MOUFAD merged 77 commits into
scikit-learn-contrib:mainfrom
PABannier:solver_dispatcher
Jul 15, 2024
Merged

Badr-MOUFAD merged 77 commits into
scikit-learn-contrib:mainfrom
PABannier:solver_dispatcher

Conversation

@PABannier

@PABannier PABannier commented Dec 10, 2022 •

Copy link
Copy Markdown
Collaborator

A quick proof-of-concept of a function that checks if the combination (solver, datafit, penalty) is supported. Currently we have some edge cases where one can pass ProxNewton solver with L0_5 penalty without any error being raised.

Pros of this design: the validation rules are centralized and validating a 3-uple is a one-liner in glm_fit.
Cons: we have to update the rules as we enhance the capabilities of the solver.

All in all, I think it is very valuable to have more verbose errors when fitting estimators (e.g. Ali Rahimi initially passed a combination Quadratic, L2_3, ProxNewton which cannot be optimized at the moment of writing).

Closes #101
Closes #90
Closes #109

@PABannier

PABannier commented Dec 10, 2022 •

Copy link
Copy Markdown
Collaborator Author

With this PR, the errors are more verbose:

In [1]: from skglm.estimators import GeneralizedLinearEstimator
           from skglm.penalties import L0_5
           from skglm.datafits import Quadratic, Logistic
           from skglm.solvers import ProxNewton, AndersonCD
           import numpy as np

In [2]: X = np.random.normal(0, 1, (30, 50))
           y = np.random.normal(0, 1, (30,))

In [3]: clf = GeneralizedLinearEstimator(Quadratic(), L0_5(1.), ProxNewton())

In [4]: clf.fit(X, y)
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
Input In [4], in <cell line: 1>()
----> 1 clf.fit(X, y)

File ~/Documents/skglm/skglm/estimators.py:241, in GeneralizedLinearEstimator.fit(self, X, y)
    238 self.datafit = self.datafit if self.datafit else Quadratic()
    239 self.solver = self.solver if self.solver else AndersonCD()
--> 241 return _glm_fit(X, y, self, self.datafit, self.penalty, self.solver)

File ~/Documents/skglm/skglm/estimators.py:29, in _glm_fit(X, y, model, datafit, penalty, solver)
     27 is_classif = isinstance(datafit, (Logistic, QuadraticSVC))
     28 fit_intercept = solver.fit_intercept
---> 29 validate_solver(solver, datafit, penalty)
     31 if is_classif:
     32     check_classification_targets(y)

File ~/Documents/skglm/skglm/utils/dispatcher.py:21, in validate_solver(solver, datafit, penalty)
      6 """Ensure the solver is suited for the `datafit` + `penalty` problem.
      7
      8 Parameters
   (...)
     17     Penalty.
     18 """
     19 if (isinstance(solver, ProxNewton)
     20     and not set(("raw_grad", "raw_hessian")) <= set(dir(datafit))):
---> 21     raise Exception(
     22         f"ProwNewton cannot optimize {datafit.__class__.__name__}, since `raw_grad`"
     23         " and `raw_hessian` are not implemented.")
     24 if ("ws_strategy" in dir(solver) and solver.ws_strategy == "subdiff"
     25     and isinstance(penalty, (L0_5, L2_3))):
     26     raise Exception(
     27         "ws_strategy=`subdiff` is not available for Lp penalties (p < 1). "
     28         "Set ws_strategy to `fixpoint`.")

Exception: ProwNewton cannot optimize Quadratic, since `raw_grad` and `raw_hessian` are not implemented.

@PABannier PABannier changed the title POC Add validation logic passing datafit, penalty and solver POC Add validation logic when passing datafit, penalty and solver to _glm_fit Dec 10, 2022
@PABannier
PABannier marked this pull request as draft December 11, 2022 19:02
@mathurinm

Copy link
Copy Markdown
Collaborator

Looks nice @PABannier, this will definitely improve UX!

From an API point of view, shouldn't this check be delegated to each solver? This way we don't have one big function, but Solver.validate(datafit, penalty), in the spirit of what @Badr-MOUFAD implemented here : https://github.com/scikit-learn-contrib/skglm/blob/main/skglm/experimental/pdcd_ws.py#L201

Such functions could also take care of the initialization (e.g. stepsize computation) which is done on a solver basis. WDYT?

@PABannier

Copy link
Copy Markdown
Collaborator Author

@mathurinm Yes I think it's cleaner, currently refining the POC.

@mathurinm

Copy link
Copy Markdown
Collaborator

This would be a nice addition if we can ship it in the 0.3 release @Badr-MOUFAD , given that we added a few datafits, penalties and solvers !

@mathurinm

Copy link
Copy Markdown
Collaborator

@Badr-MOUFAD the issue popped up in #188, do you have time to take this over ? A simple check, at the beginning of each solver, that the datafit and penalty are supported (eg AndersonCD does not support Gamma datafit)

@Badr-MOUFAD

Copy link
Copy Markdown
Collaborator

@Badr-MOUFAD the issue popped up in #188, do you have time to take this over ? A simple check, at the beginning of each solver, that the datafit and penalty are supported (eg AndersonCD does not support Gamma datafit)

Sure, I will resume this PR.

@Badr-MOUFAD Badr-MOUFAD changed the title POC Add validation logic when passing datafit, penalty and solver to _glm_fit ENH - check datafit + penalty compatibility with solver Oct 18, 2023
@Badr-MOUFAD
Badr-MOUFAD requested a review from mathurinm October 18, 2023 13:47
@mathurinm

Copy link
Copy Markdown
Collaborator

Requires #191 to be implemented fit to allow for better checks

Comment thread skglm/solvers/gram_cd.py Outdated
Comment thread skglm/solvers/gram_cd.py Outdated
Comment thread skglm/solvers/prox_newton.py Outdated
@mathurinm

mathurinm commented May 30, 2024 •

Copy link
Copy Markdown
Collaborator
  • I’m +1 with having _solve method and adding run_checks argument to solve method.
    I feel it give us more freedom to standardize the behavior and make less verbose the solve method.
    I don’t think the check have a big overhead, though I didn’t check that in practice

Let's perform checks all the time for now, this will simplify our lives. WDYT?

  • The support of sparse data is covered in check_obj_solver_attr function, so I don’t think it hurts us to cover it in this PR

OK

  • I have no strong opion about the names, I’m +1 with your proposed name @mathurinm

@QB3 any opinion?

@PABannier
PABannier marked this pull request as ready for review July 15, 2024 08:18

@Badr-MOUFAD Badr-MOUFAD left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, thanks for everyone 💪

We should be careful in internalizing the jit-compilation of dataffits and penalties as jit-compilation undoes the datafit initialization.

I believe this PR brings several contributions to the API and touches many parts of the codebase. we better merge it and tackle the aforementioned issue in that in a separate PR.

@Badr-MOUFAD
Badr-MOUFAD merged commit ed7bf2d into scikit-learn-contrib:main Jul 15, 2024
floriankozikowski pushed a commit to PascalCarrivain/skglm that referenced this pull request Apr 22, 2025
…earn-contrib#137)

Co-authored-by: Badr-MOUFAD <badr.moufad@emines.um6p.ma>
Co-authored-by: Badr MOUFAD <65614794+Badr-MOUFAD@users.noreply.github.com>
Co-authored-by: Quentin Bertrand <quentin.bertrand@mila.quebec>
Co-authored-by: mathurinm <mathurin.massias@gmail.com>
Co-authored-by: mathurinm <mathurinm@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

4 participants