Skip to content

[MRG] FIX put back nca's tests #143

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 94 additions & 1 deletion test/metric_learn_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from six.moves import xrange
from sklearn.metrics import pairwise_distances
from sklearn.datasets import load_iris, make_classification, make_regression
from numpy.testing import assert_array_almost_equal
from numpy.testing import assert_array_almost_equal, assert_array_equal
from sklearn.utils.testing import assert_warns_message
from sklearn.exceptions import ConvergenceWarning
from sklearn.utils.validation import check_X_y
Expand Down Expand Up @@ -138,6 +138,99 @@ def test_iris(self):
csep = class_separation(nca.transform(self.iris_points), self.iris_labels)
self.assertLess(csep, 0.20)

def test_finite_differences(self):
"""Test gradient of loss function

Assert that the gradient is almost equal to its finite differences
approximation.
"""
# Initialize the transformation `M`, as well as `X` and `y` and `NCA`
X, y = make_classification()
M = np.random.randn(np.random.randint(1, X.shape[1] + 1), X.shape[1])
mask = y[:, np.newaxis] == y[np.newaxis, :]
nca = NCA()
nca.n_iter_ = 0

def fun(M):
return nca._loss_grad_lbfgs(M, X, mask)[0]

def grad(M):
return nca._loss_grad_lbfgs(M, X, mask)[1].ravel()

# compute relative error
rel_diff = check_grad(fun, grad, M.ravel()) / np.linalg.norm(grad(M))
np.testing.assert_almost_equal(rel_diff, 0., decimal=6)

def test_simple_example(self):
"""Test on a simple example.

Puts four points in the input space where the opposite labels points are
next to each other. After transform the same labels points should be next
to each other.

"""
X = np.array([[0, 0], [0, 1], [2, 0], [2, 1]])
y = np.array([1, 0, 1, 0])
nca = NCA(num_dims=2,)
nca.fit(X, y)
Xansformed = nca.transform(X)
np.testing.assert_equal(pairwise_distances(Xansformed).argsort()[:, 1],
np.array([2, 3, 0, 1]))

def test_singleton_class(self):
X = self.iris_points
y = self.iris_labels

# one singleton class: test fitting works
singleton_class = 1
ind_singleton, = np.where(y == singleton_class)
y[ind_singleton] = 2
y[ind_singleton[0]] = singleton_class

nca = NCA(max_iter=30)
nca.fit(X, y)

# One non-singleton class: test fitting works
ind_1, = np.where(y == 1)
ind_2, = np.where(y == 2)
y[ind_1] = 0
y[ind_1[0]] = 1
y[ind_2] = 0
y[ind_2[0]] = 2

nca = NCA(max_iter=30)
nca.fit(X, y)

# Only singleton classes: test fitting does nothing (the gradient
# must be null in this case, so the final matrix must stay like
# the initialization)
ind_0, = np.where(y == 0)
ind_1, = np.where(y == 1)
ind_2, = np.where(y == 2)
X = X[[ind_0[0], ind_1[0], ind_2[0]]]
y = y[[ind_0[0], ind_1[0], ind_2[0]]]

EPS = np.finfo(float).eps
A = np.zeros((X.shape[1], X.shape[1]))
np.fill_diagonal(A,
1. / (np.maximum(X.max(axis=0) - X.min(axis=0), EPS)))
nca = NCA(max_iter=30, num_dims=X.shape[1])
nca.fit(X, y)
assert_array_equal(nca.transformer_, A)

def test_one_class(self):
# if there is only one class the gradient is null, so the final matrix
# must stay like the initialization
X = self.iris_points[self.iris_labels == 0]
y = self.iris_labels[self.iris_labels == 0]
EPS = np.finfo(float).eps
A = np.zeros((X.shape[1], X.shape[1]))
np.fill_diagonal(A,
1. / (np.maximum(X.max(axis=0) - X.min(axis=0), EPS)))
nca = NCA(max_iter=30, num_dims=X.shape[1])
nca.fit(X, y)
assert_array_equal(nca.transformer_, A)


class TestLFDA(MetricTestCase):
def test_iris(self):
Expand Down