Skip to content

Commit 8658e06

Browse files
wdevazelhesbellet
authored andcommitted
[MRG] FIX put back nca's tests (#143)
* FIX put back nca's tests * Remove deprecation test for learning rate because there is no more learning rate * FIX: update tests with new terminology ('transformer_')
1 parent 23d0746 commit 8658e06

File tree

1 file changed

+94
-1
lines changed

1 file changed

+94
-1
lines changed

test/metric_learn_test.py

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from six.moves import xrange
77
from sklearn.metrics import pairwise_distances
88
from sklearn.datasets import load_iris, make_classification, make_regression
9-
from numpy.testing import assert_array_almost_equal
9+
from numpy.testing import assert_array_almost_equal, assert_array_equal
1010
from sklearn.utils.testing import assert_warns_message
1111
from sklearn.exceptions import ConvergenceWarning
1212
from sklearn.utils.validation import check_X_y
@@ -138,6 +138,99 @@ def test_iris(self):
138138
csep = class_separation(nca.transform(self.iris_points), self.iris_labels)
139139
self.assertLess(csep, 0.20)
140140

141+
def test_finite_differences(self):
142+
"""Test gradient of loss function
143+
144+
Assert that the gradient is almost equal to its finite differences
145+
approximation.
146+
"""
147+
# Initialize the transformation `M`, as well as `X` and `y` and `NCA`
148+
X, y = make_classification()
149+
M = np.random.randn(np.random.randint(1, X.shape[1] + 1), X.shape[1])
150+
mask = y[:, np.newaxis] == y[np.newaxis, :]
151+
nca = NCA()
152+
nca.n_iter_ = 0
153+
154+
def fun(M):
155+
return nca._loss_grad_lbfgs(M, X, mask)[0]
156+
157+
def grad(M):
158+
return nca._loss_grad_lbfgs(M, X, mask)[1].ravel()
159+
160+
# compute relative error
161+
rel_diff = check_grad(fun, grad, M.ravel()) / np.linalg.norm(grad(M))
162+
np.testing.assert_almost_equal(rel_diff, 0., decimal=6)
163+
164+
def test_simple_example(self):
165+
"""Test on a simple example.
166+
167+
Puts four points in the input space where the opposite labels points are
168+
next to each other. After transform the same labels points should be next
169+
to each other.
170+
171+
"""
172+
X = np.array([[0, 0], [0, 1], [2, 0], [2, 1]])
173+
y = np.array([1, 0, 1, 0])
174+
nca = NCA(num_dims=2,)
175+
nca.fit(X, y)
176+
Xansformed = nca.transform(X)
177+
np.testing.assert_equal(pairwise_distances(Xansformed).argsort()[:, 1],
178+
np.array([2, 3, 0, 1]))
179+
180+
def test_singleton_class(self):
181+
X = self.iris_points
182+
y = self.iris_labels
183+
184+
# one singleton class: test fitting works
185+
singleton_class = 1
186+
ind_singleton, = np.where(y == singleton_class)
187+
y[ind_singleton] = 2
188+
y[ind_singleton[0]] = singleton_class
189+
190+
nca = NCA(max_iter=30)
191+
nca.fit(X, y)
192+
193+
# One non-singleton class: test fitting works
194+
ind_1, = np.where(y == 1)
195+
ind_2, = np.where(y == 2)
196+
y[ind_1] = 0
197+
y[ind_1[0]] = 1
198+
y[ind_2] = 0
199+
y[ind_2[0]] = 2
200+
201+
nca = NCA(max_iter=30)
202+
nca.fit(X, y)
203+
204+
# Only singleton classes: test fitting does nothing (the gradient
205+
# must be null in this case, so the final matrix must stay like
206+
# the initialization)
207+
ind_0, = np.where(y == 0)
208+
ind_1, = np.where(y == 1)
209+
ind_2, = np.where(y == 2)
210+
X = X[[ind_0[0], ind_1[0], ind_2[0]]]
211+
y = y[[ind_0[0], ind_1[0], ind_2[0]]]
212+
213+
EPS = np.finfo(float).eps
214+
A = np.zeros((X.shape[1], X.shape[1]))
215+
np.fill_diagonal(A,
216+
1. / (np.maximum(X.max(axis=0) - X.min(axis=0), EPS)))
217+
nca = NCA(max_iter=30, num_dims=X.shape[1])
218+
nca.fit(X, y)
219+
assert_array_equal(nca.transformer_, A)
220+
221+
def test_one_class(self):
222+
# if there is only one class the gradient is null, so the final matrix
223+
# must stay like the initialization
224+
X = self.iris_points[self.iris_labels == 0]
225+
y = self.iris_labels[self.iris_labels == 0]
226+
EPS = np.finfo(float).eps
227+
A = np.zeros((X.shape[1], X.shape[1]))
228+
np.fill_diagonal(A,
229+
1. / (np.maximum(X.max(axis=0) - X.min(axis=0), EPS)))
230+
nca = NCA(max_iter=30, num_dims=X.shape[1])
231+
nca.fit(X, y)
232+
assert_array_equal(nca.transformer_, A)
233+
141234

142235
class TestLFDA(MetricTestCase):
143236
def test_iris(self):

0 commit comments

Comments
 (0)