From c4291fa3af2f3cd33e5f7eb04911231d3cc4e2f3 Mon Sep 17 00:00:00 2001 From: mathurinm Date: Thu, 1 Aug 2024 13:11:45 +0200 Subject: [PATCH 1/4] add missing attributes to Pinball loss and PDCD_WS solver --- debug_pinball.py | 17 +++++++++++++++++ skglm/experimental/pdcd_ws.py | 7 +++++-- skglm/experimental/quantile_regression.py | 17 +++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 debug_pinball.py diff --git a/debug_pinball.py b/debug_pinball.py new file mode 100644 index 000000000..bf83acfed --- /dev/null +++ b/debug_pinball.py @@ -0,0 +1,17 @@ +from skglm.experimental import Pinball, PDCD_WS +from skglm import GeneralizedLinearEstimator +from skglm.penalties import L1 +from skglm.solvers import ProxNewton, AndersonCD +from skglm.utils.data import make_correlated_data + + +solver = PDCD_WS(verbose=2) +# solver = AndersonCD(verbose=2, fit_intercept=False) + +X, y, _ = make_correlated_data(random_state=0) +estimator = GeneralizedLinearEstimator( + datafit=Pinball(.2), + penalty=L1(alpha=1.), + solver=solver, +) +estimator.fit(X, y) diff --git a/skglm/experimental/pdcd_ws.py b/skglm/experimental/pdcd_ws.py index 81e72da8c..f21668c76 100644 --- a/skglm/experimental/pdcd_ws.py +++ b/skglm/experimental/pdcd_ws.py @@ -82,13 +82,16 @@ class PDCD_WS(BaseSolver): _datafit_required_attr = ('prox_conjugate',) _penalty_required_attr = ("prox_1d",) - def __init__(self, max_iter=1000, max_epochs=1000, dual_init=None, - p0=100, tol=1e-6, verbose=False): + def __init__( + self, max_iter=1000, max_epochs=1000, dual_init=None, p0=100, tol=1e-6, + fit_intercept=False, warm_start=True, verbose=False): self.max_iter = max_iter self.max_epochs = max_epochs self.dual_init = dual_init self.p0 = p0 self.tol = tol + self.fit_intercept = fit_intercept # TODO not handled + self.warm_start = warm_start # TODO not handled self.verbose = verbose def _solve(self, X, y, datafit, penalty, w_init=None, Xw_init=None): diff --git a/skglm/experimental/quantile_regression.py b/skglm/experimental/quantile_regression.py index 85e9e54e1..6d64c281e 100644 --- a/skglm/experimental/quantile_regression.py +++ b/skglm/experimental/quantile_regression.py @@ -65,6 +65,23 @@ def subdiff_distance(self, Xw, z, y): return max_distance + def raw_grad(self, y, Xw): + """Gradient ignoring the nondifferentiability at 0.""" + neg_res = (y - Xw) < 0 + grad = self.quantile_level * np.ones_like(Xw) + grad[neg_res] = 1 - self.quantile_level + return grad + + def gradient(self, X, y, Xw): + return X.T @ self.raw_grad(y, Xw) + + def gradient_scalar(self, X, y, w, Xw, j): + return X[:, j] @ self.raw_grad(y, Xw) + + def get_lipschitz(self, X, y): + return np.sum(np.abs(X), axis=0) + + def get_spec(self): spec = ( ('quantile_level', float64), From 8fd2c3c72dfb0d39eccd44bd03a4cd1851914da9 Mon Sep 17 00:00:00 2001 From: mathurinm Date: Thu, 1 Aug 2024 16:18:01 +0200 Subject: [PATCH 2/4] revert + add test --- skglm/experimental/quantile_regression.py | 17 ----------------- .../tests/test_quantile_regression.py | 8 ++++++++ 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/skglm/experimental/quantile_regression.py b/skglm/experimental/quantile_regression.py index 6d64c281e..85e9e54e1 100644 --- a/skglm/experimental/quantile_regression.py +++ b/skglm/experimental/quantile_regression.py @@ -65,23 +65,6 @@ def subdiff_distance(self, Xw, z, y): return max_distance - def raw_grad(self, y, Xw): - """Gradient ignoring the nondifferentiability at 0.""" - neg_res = (y - Xw) < 0 - grad = self.quantile_level * np.ones_like(Xw) - grad[neg_res] = 1 - self.quantile_level - return grad - - def gradient(self, X, y, Xw): - return X.T @ self.raw_grad(y, Xw) - - def gradient_scalar(self, X, y, w, Xw, j): - return X[:, j] @ self.raw_grad(y, Xw) - - def get_lipschitz(self, X, y): - return np.sum(np.abs(X), axis=0) - - def get_spec(self): spec = ( ('quantile_level', float64), diff --git a/skglm/experimental/tests/test_quantile_regression.py b/skglm/experimental/tests/test_quantile_regression.py index 65e0c1e65..f4d1aa914 100644 --- a/skglm/experimental/tests/test_quantile_regression.py +++ b/skglm/experimental/tests/test_quantile_regression.py @@ -3,6 +3,7 @@ from numpy.linalg import norm from skglm.penalties import L1 +from skglm import GeneralizedLinearEstimator from skglm.experimental.pdcd_ws import PDCD_WS from skglm.experimental.quantile_regression import Pinball from skglm.utils.jit_compilation import compiled_clone @@ -37,6 +38,13 @@ def test_PDCD_WS(quantile_level): ).fit(X, y) np.testing.assert_allclose(w, clf.coef_, atol=1e-5) + # test compatibility when inside GLM: + estimator = GeneralizedLinearEstimator( + datafit=Pinball(.2), + penalty=L1(alpha=1.), + solver=PDCD_WS(), + ) + estimator.fit(X, y) if __name__ == '__main__': From 665fca28e8c2702fc08c4f37e10fb5c46af50920 Mon Sep 17 00:00:00 2001 From: Badr-MOUFAD Date: Thu, 1 Aug 2024 16:30:26 +0200 Subject: [PATCH 3/4] rm ``debug_script`` --- debug_pinball.py | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 debug_pinball.py diff --git a/debug_pinball.py b/debug_pinball.py deleted file mode 100644 index bf83acfed..000000000 --- a/debug_pinball.py +++ /dev/null @@ -1,17 +0,0 @@ -from skglm.experimental import Pinball, PDCD_WS -from skglm import GeneralizedLinearEstimator -from skglm.penalties import L1 -from skglm.solvers import ProxNewton, AndersonCD -from skglm.utils.data import make_correlated_data - - -solver = PDCD_WS(verbose=2) -# solver = AndersonCD(verbose=2, fit_intercept=False) - -X, y, _ = make_correlated_data(random_state=0) -estimator = GeneralizedLinearEstimator( - datafit=Pinball(.2), - penalty=L1(alpha=1.), - solver=solver, -) -estimator.fit(X, y) From 23dd6bb89fd61191a4f479067b3acccd8d04bf5c Mon Sep 17 00:00:00 2001 From: Badr-MOUFAD Date: Thu, 1 Aug 2024 16:32:04 +0200 Subject: [PATCH 4/4] format ``PDCD_WS`` args --- skglm/experimental/pdcd_ws.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/skglm/experimental/pdcd_ws.py b/skglm/experimental/pdcd_ws.py index f21668c76..5ef49e5d4 100644 --- a/skglm/experimental/pdcd_ws.py +++ b/skglm/experimental/pdcd_ws.py @@ -83,8 +83,9 @@ class PDCD_WS(BaseSolver): _penalty_required_attr = ("prox_1d",) def __init__( - self, max_iter=1000, max_epochs=1000, dual_init=None, p0=100, tol=1e-6, - fit_intercept=False, warm_start=True, verbose=False): + self, max_iter=1000, max_epochs=1000, dual_init=None, p0=100, tol=1e-6, + fit_intercept=False, warm_start=True, verbose=False + ): self.max_iter = max_iter self.max_epochs = max_epochs self.dual_init = dual_init