def fit(self, X, y, X_domain, y_domain, sample_weight=None): """Fit (estimates) the centroids. Parameters ---------- X : ndarray, shape (n_trials, n_channels, n_channels) ndarray of SPD matrices. y : ndarray shape (n_trials, 1) labels corresponding to each trial. sample_weight : None | ndarray shape (n_trials, 1) the weights of each sample from the domain. if None, each sample is treated with equal weights. Returns ------- self : MDM instance The MDM instance. """ self.classes_ = np.unique(y) # TODO: ajouter un test pour verifier que y et y_domain # ont les meme classes if sample_weight is None: sample_weight = np.ones(X_domain.shape[0]) if self.n_jobs == 1: self.target_means_ = [ mean_covariance(X[y == label], metric=self.metric_mean) # sample_weight=sample_weight_target[y == l]) for label in self.classes_ ] self.domain_means_ = [ mean_covariance( X_domain[y_domain == label], metric=self.metric_mean, sample_weight=sample_weight[y_domain == label], ) for label in self.classes_ ] else: self.target_means_ = Parallel(n_jobs=self.n_jobs)( delayed(mean_covariance)(X[y == label], metric=self.metric_mean) for label in self.classes_) # sample_weight=sample_weight_target[y == l]) self.domain_means_ = Parallel(n_jobs=self.n_jobs)( delayed(mean_covariance)( X_domain[y_domain == label], metric=self.metric_mean, sample_weight=sample_weight[y_domain == label], ) for label in self.classes_) self.class_center_ = [ geodesic(self.target_means_[i], self.domain_means_[i], self.L, self.metric) for i, _ in enumerate(self.classes_) ] return self
def test_distance_wrapper_random(met, gfunc, get_covmats): n_trials, n_channels = 2, 5 covmats = get_covmats(n_trials, n_channels) A, B = covmats[0], covmats[1] if gfunc is geodesic_euclid: Ctrue = mean_euclid(covmats) elif gfunc is geodesic_logeuclid: Ctrue = mean_logeuclid(covmats) elif gfunc is geodesic_riemann: Ctrue = mean_riemann(covmats) assert geodesic(A, B, 0.5, metric=met) == approx(Ctrue)
def test_distance_wrapper_simple(metric): n_channels = 3 if metric == "euclid": A = 1.0 * np.eye(n_channels) B = 2.0 * np.eye(n_channels) Ctrue = 1.5 * np.eye(n_channels) else: A = 0.5 * np.eye(n_channels) B = 2 * np.eye(n_channels) Ctrue = np.eye(n_channels) assert geodesic(A, B, 0.5, metric=metric) == approx(Ctrue)
def test_geodesic_logeuclid(): """Test riemannian geodesic when alpha = 0.5 for global function""" A = 0.5*np.eye(3) B = 2*np.eye(3) Ctrue = 1*np.eye(3) assert_array_almost_equal(geodesic(A,B,0.5,metric='logeuclid'),Ctrue)
def get_gram_matrices_for_images(pyramid_gram_model, image_sources, source_width=None, source_scale=None, join_mode=JoinMode.AVERAGE): target_grams = [] print("Loading image files") image_files = image_files_from_sources(image_sources) for i, prepped in enumerate( get_images(image_files, source_width=source_width, source_scale=source_scale)): print("{} / {}...".format(i + 1, len(image_files))) this_grams = pyramid_gram_model.predict(prepped) print("got the grams!") # There is a bug somewhere where if the # of octaves is set to 0 the shapes of these arrays is different this_grams = [np.squeeze(g) for g in this_grams] if join_mode in { JoinMode.AFFINE_INVARIANT, JoinMode.LOG_EUCLIDEAN, JoinMode.RIEMANN }: # Add a small epsilon to the diagonals to ensure a positive definite matrix eps = 0.05 this_grams = [ g + np.identity(g.shape[0]) * eps for g in this_grams ] print(this_grams) if join_mode in {JoinMode.AFFINE_INVARIANT, JoinMode.RIEMANN}: target_grams.append(this_grams) else: if len(target_grams) == 0: if join_mode == JoinMode.LOG_EUCLIDEAN: target_grams = [linalg.logm(gram) for gram in this_grams] else: target_grams = this_grams else: for target_gram, this_gram in zip(target_grams, this_grams): # There are likely more interesting ways to join gram matrices, including # having "don't care" regions where it's not necessary to match at all. This would # probably allow fusion between disparate image types to work better. if join_mode == JoinMode.AVERAGE: target_gram += this_gram elif join_mode == JoinMode.MAX: np.maximum(target_gram, this_gram, out=target_gram) elif join_mode == JoinMode.LOG_EUCLIDEAN: print(this_gram.shape) target_gram += linalg.logm(this_gram) else: assert False # Normalize the targets if join_mode in {JoinMode.AVERAGE, JoinMode.LOG_EUCLIDEAN}: for i, target_gram in enumerate(target_grams): target_gram /= len(image_files) if join_mode == JoinMode.LOG_EUCLIDEAN: target_gram = linalg.expm(target_gram) target_gram = np.expand_dims(target_gram, -1) target_grams[i] = target_gram elif join_mode == JoinMode.AFFINE_INVARIANT: if len(target_grams) != 2: print( "WARNING! affine_invariant join mode requires 2 source images") source_grams = target_grams # This was mis-named target_grams = [] for A, B in zip(source_grams[0], source_grams[1]): print("A SHAPE", A.shape) print("B SHAPE", B.shape) #if len(A.shape) > 2: A = A[0] #if len(B.shape) > 2: B = B[0] # TODO: Fix, yo rootA = linalg.fractional_matrix_power(A, 0.5) rootAinv = linalg.fractional_matrix_power( A, -0.5) # hmm... non-invertible because 0 determinant? internal = 0.5 * rootAinv.dot(B).dot(rootAinv) interpolated = rootA.dot(linalg.expm(internal)).dot(rootA) target_grams.append(interpolated) elif join_mode == JoinMode.RIEMANN: from pyriemann.utils import geodesic source_grams = target_grams # This was mis-named print("Number of source grams: ", len(source_grams)) target_grams = [] for A, B in zip(source_grams[0], source_grams[1]): print("Geodesic...") interp = geodesic.geodesic(A, B, 0.5, 'riemann') print("A", A) print("B", B) print("interp", interp) target_grams.append(interp) print("Target grams shapes: ", [t.shape for t in target_grams]) return target_grams
def test_distance_func_rand(dist, get_covmats): n_trials, n_channels = 2, 6 covmats = get_covmats(n_trials, n_channels) A, C = covmats[0], covmats[1] B = geodesic(A, C, alpha=0.5) assert dist(A, B) < dist(A, C)