From 04c19e071ddfabb43ab3110da5b0bb3d920ea1cc Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Wed, 12 Jun 2019 10:36:11 +0200 Subject: [PATCH 1/2] Add ChangedBehaviorWarning message for LMNN too --- metric_learn/lmnn.py | 27 ++++++++++++++++++++++----- metric_learn/lsml.py | 2 +- metric_learn/mlkr.py | 2 +- metric_learn/nca.py | 12 ++++++------ metric_learn/sdml.py | 2 +- test/metric_learn_test.py | 27 ++++++++++++++++++++++----- test/test_base_metric.py | 2 +- 7 files changed, 54 insertions(+), 20 deletions(-) diff --git a/metric_learn/lmnn.py b/metric_learn/lmnn.py index c2437b86..b99a104f 100644 --- a/metric_learn/lmnn.py +++ b/metric_learn/lmnn.py @@ -17,6 +17,7 @@ import warnings from collections import Counter from six.moves import xrange +from sklearn.exceptions import ChangedBehaviorWarning from sklearn.metrics import euclidean_distances from sklearn.base import TransformerMixin @@ -26,7 +27,7 @@ # commonality between LMNN implementations class _base_LMNN(MahalanobisMixin, TransformerMixin): - def __init__(self, init='auto', k=3, min_iter=50, max_iter=1000, + def __init__(self, init=None, k=3, min_iter=50, max_iter=1000, learn_rate=1e-7, regularization=0.5, convergence_tol=0.001, use_pca=True, verbose=False, preprocessor=None, n_components=None, num_dims='deprecated', random_state=None): @@ -34,10 +35,12 @@ def __init__(self, init='auto', k=3, min_iter=50, max_iter=1000, Parameters ---------- - init : string or numpy array, optional (default='auto') + init : None, string or numpy array, optional (default=None) Initialization of the linear transformation. Possible options are - 'auto', 'pca', 'lda', 'identity', 'random', and a numpy array of shape - (n_features_a, n_features_b). + 'auto', 'pca', 'identity', 'random', and a numpy array of shape + (n_features_a, n_features_b). If None, will be set automatically to + 'auto' (this option is to raise a warning if 'init' is not set, + and stays to its default value None, in v0.5.0). 'auto' Depending on ``n_components``, the most reasonable initialization @@ -135,7 +138,21 @@ def fit(self, X, y): if len(label_inds) != num_pts: raise ValueError('Must have one label per point.') self.labels_ = np.arange(len(unique_labels)) - self.transformer_ = _initialize_transformer(output_dim, X, y, self.init, + + # if the init is the default (None), we raise a warning + if self.init is None: + # TODO: replace init=None by init='auto' in v0.6.0 and remove the warning + msg = ("Warning, no init was set (`init=None`). As of version 0.5.0, " + "the default init will now be set to 'auto', instead of the " + "previous identity matrix. If you still want to use the identity " + "matrix as before as an init, set init='identity'. This warning " + "will disappear in v0.6.0, and `init` parameter's default value " + "will be set to 'auto'.") + warnings.warn(msg, ChangedBehaviorWarning) + init = 'auto' + else: + init = self.init + self.transformer_ = _initialize_transformer(output_dim, X, y, init, self.verbose, self.random_state) required_k = np.bincount(label_inds).min() diff --git a/metric_learn/lsml.py b/metric_learn/lsml.py index 4350b003..f59392c1 100644 --- a/metric_learn/lsml.py +++ b/metric_learn/lsml.py @@ -94,7 +94,7 @@ def _fit(self, quadruplets, weights=None): else: self.w_ = weights self.w_ /= self.w_.sum() # weights must sum to 1 - # if the prior is the default (identity), we raise a warning just in case + # if the prior is the default (None), we raise a warning if self.prior is None: msg = ("Warning, no prior was set (`prior=None`). As of version 0.5.0, " "the default prior will now be set to " diff --git a/metric_learn/mlkr.py b/metric_learn/mlkr.py index 9e9cf433..c625b67c 100644 --- a/metric_learn/mlkr.py +++ b/metric_learn/mlkr.py @@ -156,7 +156,7 @@ def fit(self, X, y): m = self.n_components if m is None: m = d - # if the init is the default (identity), we raise a warning just in case + # if the init is the default (None), we raise a warning if self.init is None: # TODO: # replace init=None by init='auto' in v0.6.0 and remove the warning diff --git a/metric_learn/nca.py b/metric_learn/nca.py index 1626e02f..e23912b5 100644 --- a/metric_learn/nca.py +++ b/metric_learn/nca.py @@ -141,16 +141,16 @@ def fit(self, X, y): train_time = time.time() # Initialize A - # if the init is the default (auto), we raise a warning just in case + # if the init is the default (None), we raise a warning if self.init is None: # TODO: replace init=None by init='auto' in v0.6.0 and remove the warning msg = ("Warning, no init was set (`init=None`). As of version 0.5.0, " "the default init will now be set to 'auto', instead of the " - "previous scaling matrix. same scaling matrix as before as an " - "init, set init=np.eye(X.shape[1])/" - "(np.maximum(X.max(axis=0)-X.min(axis=0), EPS))). This warning " - "will disappear in v0.6.0, and `init` parameter's default value " - "will be set to 'auto'.") + "previous scaling matrix. If you still want to use the same " + "scaling matrix as before as an init, set " + "init=np.eye(X.shape[1])/(np.maximum(X.max(axis=0)-X.min(axis=0)" + ", EPS))). This warning will disappear in v0.6.0, and `init` " + "parameter's default value will be set to 'auto'.") warnings.warn(msg, ChangedBehaviorWarning) init = 'auto' else: diff --git a/metric_learn/sdml.py b/metric_learn/sdml.py index b83c553d..c5e63fa8 100644 --- a/metric_learn/sdml.py +++ b/metric_learn/sdml.py @@ -111,7 +111,7 @@ def _fit(self, pairs, y): type_of_inputs='tuples') # set up (the inverse of) the prior M - # if the prior is the default (identity), we raise a warning just in case + # if the prior is the default (None), we raise a warning if self.prior is None: # TODO: # replace prior=None by prior='identity' in v0.6.0 and remove the diff --git a/test/metric_learn_test.py b/test/metric_learn_test.py index 18643363..4ff1dc2b 100644 --- a/test/metric_learn_test.py +++ b/test/metric_learn_test.py @@ -275,6 +275,23 @@ def grad(x): np.linalg.norm(approx_fprime(L.ravel(), fun, epsilon))) np.testing.assert_almost_equal(rel_diff, 0., decimal=5) + def test_changed_behaviour_warning(self): + # test that a ChangedBehavior warning is thrown about the init, if the + # default parameters are used. + # TODO: remove in v.0.6 + X = np.array([[0, 0], [0, 1], [2, 0], [2, 1]]) + y = np.array([1, 0, 1, 0]) + lmnn = LMNN(k=2) + msg = ("Warning, no init was set (`init=None`). As of version 0.5.0, " + "the default init will now be set to 'auto', instead of the " + "previous identity matrix. If you still want to use the identity " + "matrix as before as an init, set init='identity'. This warning " + "will disappear in v0.6.0, and `init` parameter's default value " + "will be set to 'auto'.") + with pytest.warns(ChangedBehaviorWarning) as raised_warning: + lmnn.fit(X, y) + assert any(msg == str(wrn.message) for wrn in raised_warning) + @pytest.mark.parametrize('X, y, loss', [(np.array([[0], [1], [2], [3]]), [1, 1, 0, 0], 3.0), @@ -744,11 +761,11 @@ def test_changed_behaviour_warning(self): nca = NCA() msg = ("Warning, no init was set (`init=None`). As of version 0.5.0, " "the default init will now be set to 'auto', instead of the " - "previous scaling matrix. same scaling matrix as before as an " - "init, set init=np.eye(X.shape[1])/" - "(np.maximum(X.max(axis=0)-X.min(axis=0), EPS))). This warning will" - " disappear in v0.6.0, and `init` parameter's default value will " - "be set to 'auto'.") + "previous scaling matrix. If you still want to use the same " + "scaling matrix as before as an init, set " + "init=np.eye(X.shape[1])/(np.maximum(X.max(axis=0)-X.min(axis=0)" + ", EPS))). This warning will disappear in v0.6.0, and `init` " + "parameter's default value will be set to 'auto'.") with pytest.warns(ChangedBehaviorWarning) as raised_warning: nca.fit(X, y) assert any(msg == str(wrn.message) for wrn in raised_warning) diff --git a/test/test_base_metric.py b/test/test_base_metric.py index 1b312b35..5c258f2e 100644 --- a/test/test_base_metric.py +++ b/test/test_base_metric.py @@ -21,7 +21,7 @@ def test_covariance(self): def test_lmnn(self): self.assertRegexpMatches( str(metric_learn.LMNN()), - r"(python_)?LMNN\(convergence_tol=0.001, init='auto', k=3, " + r"(python_)?LMNN\(convergence_tol=0.001, init=None, k=3, " r"learn_rate=1e-07,\s+" r"max_iter=1000, min_iter=50, n_components=None, " r"num_dims='deprecated',\s+preprocessor=None, random_state=None, " From a3b2dc45131fa21a726d27d8666151bceb5a23f4 Mon Sep 17 00:00:00 2001 From: William de Vazelhes Date: Wed, 12 Jun 2019 10:42:16 +0200 Subject: [PATCH 2/2] Remove useless 'as an init' --- metric_learn/lmnn.py | 2 +- metric_learn/nca.py | 2 +- test/metric_learn_test.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/metric_learn/lmnn.py b/metric_learn/lmnn.py index b99a104f..bbef122d 100644 --- a/metric_learn/lmnn.py +++ b/metric_learn/lmnn.py @@ -145,7 +145,7 @@ def fit(self, X, y): msg = ("Warning, no init was set (`init=None`). As of version 0.5.0, " "the default init will now be set to 'auto', instead of the " "previous identity matrix. If you still want to use the identity " - "matrix as before as an init, set init='identity'. This warning " + "matrix as before, set init='identity'. This warning " "will disappear in v0.6.0, and `init` parameter's default value " "will be set to 'auto'.") warnings.warn(msg, ChangedBehaviorWarning) diff --git a/metric_learn/nca.py b/metric_learn/nca.py index e23912b5..2b541a64 100644 --- a/metric_learn/nca.py +++ b/metric_learn/nca.py @@ -147,7 +147,7 @@ def fit(self, X, y): msg = ("Warning, no init was set (`init=None`). As of version 0.5.0, " "the default init will now be set to 'auto', instead of the " "previous scaling matrix. If you still want to use the same " - "scaling matrix as before as an init, set " + "scaling matrix as before, set " "init=np.eye(X.shape[1])/(np.maximum(X.max(axis=0)-X.min(axis=0)" ", EPS))). This warning will disappear in v0.6.0, and `init` " "parameter's default value will be set to 'auto'.") diff --git a/test/metric_learn_test.py b/test/metric_learn_test.py index 4ff1dc2b..1ec7fe4c 100644 --- a/test/metric_learn_test.py +++ b/test/metric_learn_test.py @@ -285,7 +285,7 @@ def test_changed_behaviour_warning(self): msg = ("Warning, no init was set (`init=None`). As of version 0.5.0, " "the default init will now be set to 'auto', instead of the " "previous identity matrix. If you still want to use the identity " - "matrix as before as an init, set init='identity'. This warning " + "matrix as before, set init='identity'. This warning " "will disappear in v0.6.0, and `init` parameter's default value " "will be set to 'auto'.") with pytest.warns(ChangedBehaviorWarning) as raised_warning: @@ -762,7 +762,7 @@ def test_changed_behaviour_warning(self): msg = ("Warning, no init was set (`init=None`). As of version 0.5.0, " "the default init will now be set to 'auto', instead of the " "previous scaling matrix. If you still want to use the same " - "scaling matrix as before as an init, set " + "scaling matrix as before, set " "init=np.eye(X.shape[1])/(np.maximum(X.max(axis=0)-X.min(axis=0)" ", EPS))). This warning will disappear in v0.6.0, and `init` " "parameter's default value will be set to 'auto'.")