From 94ab26769c617f0ef73f771cab500ff052f7e6c6 Mon Sep 17 00:00:00 2001 From: Dominique Benielli <dominique.benielli@lis-lab.fr> Date: Mon, 24 Feb 2020 19:34:43 +0100 Subject: [PATCH] one versu one --- multimodal/kernels/lpMKL.py | 62 +++++++++++++++++++++++++----------- multimodal/kernels/mvml.py | 39 +++++++++++++++++++---- multimodal/tests/test_mkl.py | 18 +++++------ 3 files changed, 85 insertions(+), 34 deletions(-) diff --git a/multimodal/kernels/lpMKL.py b/multimodal/kernels/lpMKL.py index 5bca05f..3a26104 100644 --- a/multimodal/kernels/lpMKL.py +++ b/multimodal/kernels/lpMKL.py @@ -19,7 +19,7 @@ class MKL(BaseEstimator, ClassifierMixin, MKernel): lmbda : float coeficient for combined kernels - m_param : float (default : 1.0) + nystrom_param : float (default : 1.0) value between 0 and 1 indicating level of nyström approximation; 1 = no approximation @@ -74,13 +74,13 @@ class MKL(BaseEstimator, ClassifierMixin, MKernel): weights : learned weight for combining the solutions of views, learned in """ - def __init__(self, lmbda, m_param=1.0, kernel="precomputed", + def __init__(self, lmbda, nystrom_param=1.0, kernel="linear", kernel_params=None, use_approx=True, precision=1E-4, n_loops=50): # calculate nyström approximation (if used) self.lmbda = lmbda self.n_loops = n_loops self.use_approx = use_approx - self.m_param = m_param + self.nystrom_param = nystrom_param self.kernel= kernel self.kernel_params = kernel_params self.precision = precision @@ -134,11 +134,12 @@ class MKL(BaseEstimator, ClassifierMixin, MKernel): y = y.astype(float) self.regression_ = True else: - raise ValueError("MKL algorithms is a binary classifier" - " or performs regression with float target") + raise ValueError("MKL algorithms is a binary classifier") + # " or performs regression with float target") self.y_ = y n = self.K_.shape[0] self._calc_nystrom(self.K_, n) + C, weights = self.learn_lpMKL() self.C = C self.weights = weights @@ -175,7 +176,7 @@ class MKL(BaseEstimator, ClassifierMixin, MKernel): # gammas are fixed upon arrival to the loop # -> solve for alpha! - if self.m_param < 1 and self.use_approx: + if self.nystrom_param < 1 and self.use_approx: combined_kernel = np.zeros((n, n)) for v in range(0, views): combined_kernel = combined_kernel + weights[v] * kernels[v] @@ -194,7 +195,7 @@ class MKL(BaseEstimator, ClassifierMixin, MKernel): # first the ||f_t||^2 todo wtf is the formula used here???? ft2 = np.zeros(views) for v in range(0, views): - if self.m_param < 1 and self.use_approx: + if self.nystrom_param < 1 and self.use_approx: # ft2[v,vv] = weights_old[v,vv] * np.dot(np.transpose(C), np.dot(np.dot(np.dot(data.U_dict[v], # np.transpose(data.U_dict[v])), # np.dot(data.U_dict[vv], @@ -247,6 +248,39 @@ class MKL(BaseEstimator, ClassifierMixin, MKernel): else: return C, weights + def decision_function(self, X): + """Compute the decision function of X. + + Parameters + ---------- + X : dict dictionary with all views {array like} with shape = (n_samples, n_features) for multi-view + for each view. + or + `MultiModalData` , `MultiModalArray` + or + {array-like,}, shape = (n_samples, n_features) + Training multi-view input samples. can be also Kernel where attibute 'kernel' + is set to precompute "precomputed" + + Returns + ------- + dec_fun : numpy.ndarray, shape = (n_samples, ) + Decision function of the input samples. + For binary classification, + values <=0 mean classification in the first class in ``classes_`` + and values >0 mean classification in the second class in + ``classes_``. + + """ + check_is_fitted(self, ['X_', 'C', 'K_', 'y_', 'weights']) + X, K = self._global_kernel_transform(X, + views_ind=self.X_.views_ind, + Y=self.X_) + check_array(X) + C = self.C + weights = self.weights + pred = self.lpMKL_predict(K, C, weights) + return pred def predict(self, X): """ @@ -280,15 +314,7 @@ class MKL(BaseEstimator, ClassifierMixin, MKernel): y : numpy.ndarray, shape = (n_samples,) Predicted classes. """ - check_is_fitted(self, ['X_', 'C', 'K_', 'y_', 'weights']) - X, K = self._global_kernel_transform(X, - views_ind=self.X_.views_ind, - Y=self.X_) - check_array(X) - C = self.C - weights = self.weights - pred = self.lpMKL_predict(K, C, weights) - + pred = self.decision_function(X) pred = np.sign(pred) pred = pred.astype(int) pred = np.where(pred == -1, 0, pred) @@ -315,7 +341,7 @@ class MKL(BaseEstimator, ClassifierMixin, MKernel): """ views = X.n_views tt = X.shape[0] - m = self.K_.shape[0] # self.m_param * n + m = self.K_.shape[0] # self.nystrom_param * n # NO TEST KERNEL APPROXIMATION # kernel = weights[0] * self.data.test_kernel_dict[0] @@ -325,7 +351,7 @@ class MKL(BaseEstimator, ClassifierMixin, MKernel): # TEST KERNEL APPROXIMATION kernel = np.zeros((tt, self.K_.shape[0])) for v in range(0, views): - if self.m_param < 1: + if self.nystrom_param < 1: kernel = kernel + weights[v] * np.dot(np.dot(X.get_view(v)[:, 0:m], self.W_sqrootinv_dict[v]), np.transpose(self.U_dict[v])) else: diff --git a/multimodal/kernels/mvml.py b/multimodal/kernels/mvml.py index 2ce26b6..d2ce3e9 100644 --- a/multimodal/kernels/mvml.py +++ b/multimodal/kernels/mvml.py @@ -194,6 +194,7 @@ class MVML(MKernel, BaseEstimator, ClassifierMixin, RegressorMixin): if type_of_target(y) in "binary": self.classes_, y = np.unique(y, return_inverse=True) y[y==0] = -1.0 + self.n_classes = len(self.classes_) elif type_of_target(y) in "continuous": y = y.astype(float) self.regression_ = True @@ -434,13 +435,7 @@ class MVML(MKernel, BaseEstimator, ClassifierMixin, RegressorMixin): y : numpy.ndarray, shape = (n_samples,) Predicted classes. """ - check_is_fitted(self, ['X_', 'U_dict', 'K_', 'y_']) # , 'U_dict', 'K_' 'y_' - X, test_kernels = self._global_kernel_transform(X, - views_ind=self.X_.views_ind, - Y=self.X_) - - check_array(X) - pred = self._predict_mvml(test_kernels, self.g, self.w).squeeze() + pred = self.decision_function(X) if self.regression_: return pred else: @@ -449,6 +444,36 @@ class MVML(MKernel, BaseEstimator, ClassifierMixin, RegressorMixin): pred = np.where(pred == -1, 0, pred) return np.take(self.classes_, pred) + + def decision_function(self, X): + """Compute the decision function of X. + + Parameters + ---------- + X : { array-like, sparse matrix}, + shape = (n_samples, n_views * n_features) + Multi-view input samples. + maybe also MultimodalData + + Returns + ------- + dec_fun : numpy.ndarray, shape = (n_samples, ) + Decision function of the input samples. + For binary classification, + values <=0 mean classification in the first class in ``classes_`` + and values >0 mean classification in the second class in + ``classes_``. + + """ + check_is_fitted(self, ['X_', 'U_dict', 'K_', 'y_']) # , 'U_dict', 'K_' 'y_' + X, test_kernels = self._global_kernel_transform(X, + views_ind=self.X_.views_ind, + Y=self.X_) + + check_array(X) + pred = self._predict_mvml(test_kernels, self.g, self.w).squeeze() + return pred + def _predict_mvml(self, test_kernels, g, w): """ diff --git a/multimodal/tests/test_mkl.py b/multimodal/tests/test_mkl.py index c6c755f..baf0e6e 100644 --- a/multimodal/tests/test_mkl.py +++ b/multimodal/tests/test_mkl.py @@ -32,10 +32,10 @@ class MKLTest(unittest.TestCase): clf.test_y = test_y def testInitMKL(self): - mkl = MKL(lmbda=3, m_param = 1.0, kernel = "precomputed", + mkl = MKL(lmbda=3, nystrom_param=1.0, kernel = "precomputed", kernel_params = None, use_approx = True, precision = 1E-4, n_loops = 50) - self.assertEqual(mkl.m_param, 1.0) + self.assertEqual(mkl.nystrom_param, 1.0) self.assertEqual(mkl.lmbda, 3) self.assertEqual(mkl.n_loops, 50) self.assertEqual(mkl.precision, 1E-4) @@ -44,7 +44,7 @@ class MKLTest(unittest.TestCase): ####################################################### # task with dict and not precomputed ####################################################### - mkl = MKL(lmbda=3, m_param = 1.0, kernel=['rbf'], kernel_params=[{'gamma':50}], + mkl = MKL(lmbda=3, nystrom_param=1.0, kernel=['rbf'], kernel_params=[{'gamma':50}], use_approx = True, precision = 1E-4, n_loops = 50) mkl.fit(self.kernel_dict, y=self.y, views_ind=None) @@ -56,8 +56,8 @@ class MKLTest(unittest.TestCase): ####################################################### # task with dict and not precomputed ####################################################### - mkl = MKL(lmbda=3, m_param = 0.3, kernel=['rbf'], kernel_params=[{'gamma':50}], - use_approx = True, + mkl = MKL(lmbda=3, nystrom_param=0.3, kernel=['rbf'], kernel_params=[{'gamma':50}], + use_approx=True, precision = 1E-4, n_loops = 50) views_ind = [120, 240] mkl.fit(self.kernel_dict, y=self.y, views_ind=None) @@ -71,7 +71,7 @@ class MKLTest(unittest.TestCase): # mvml = MVML.fit(self.kernel_dict, self.y) w_expected = np.array([[0.5], [0.5]]) x_metricl = MultiModalArray(self.kernel_dict) - mkl2 = MKL(lmbda=3, m_param = 0.3, kernel=['rbf'], kernel_params=[{'gamma':50}], + mkl2 = MKL(lmbda=3, nystrom_param = 0.3, kernel=['rbf'], kernel_params=[{'gamma':50}], use_approx = True, precision = 1E0, n_loops = 50) with self.assertRaises(ValueError): @@ -84,13 +84,13 @@ class MKLTest(unittest.TestCase): # mvml = MVML.fit(self.kernel_dict, self.y) w_expected = np.array([[0.5], [0.5]]) x_metricl = MultiModalArray(self.kernel_dict) - mkl2 = MKL(lmbda=3, m_param = 0.3, kernel="precomputed", + mkl2 = MKL(lmbda=3, nystrom_param=0.3, kernel="precomputed", use_approx = True, precision = 1E-9, n_loops = 600) mkl2.fit(x_metricl, y=self.y, views_ind=None) def testPredictMVML_witoutFit(self): - mkl = MKL(lmbda=3, m_param = 0.3, kernel=['rbf'], kernel_params=[{'gamma':50}], + mkl = MKL(lmbda=3, nystrom_param=0.3, kernel=['rbf'], kernel_params=[{'gamma':50}], use_approx = True, precision = 1E-9, n_loops = 50) with self.assertRaises(NotFittedError): @@ -98,7 +98,7 @@ class MKLTest(unittest.TestCase): def testPredictMVML_witoutFit(self): x_metric = MultiModalArray(self.kernel_dict) - mkl = MKL(lmbda=3, m_param = 0.3, kernel=['rbf'], kernel_params=[{'gamma':50}], + mkl = MKL(lmbda=3, nystrom_param = 0.3, kernel=['rbf'], kernel_params=[{'gamma':50}], use_approx = True, precision = 1E-9, n_loops = 50) mkl.fit(x_metric, y=self.y, views_ind=None) -- GitLab