From fd3776fe71f3efd123c1ebb732b20467386c851f Mon Sep 17 00:00:00 2001 From: meshulam Date: Fri, 9 Oct 2020 20:40:41 -0400 Subject: [PATCH 1/7] added save/load functionality to funcalign\srm --- brainiak/funcalign/srm.py | 63 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/brainiak/funcalign/srm.py b/brainiak/funcalign/srm.py index 023e71872..8b09525c2 100644 --- a/brainiak/funcalign/srm.py +++ b/brainiak/funcalign/srm.py @@ -41,6 +41,7 @@ from sklearn.exceptions import NotFittedError from mpi4py import MPI import sys +import os __all__ = [ "DetSRM", @@ -105,6 +106,47 @@ def _init_w_transforms(data, features, random_states, comm=MPI.COMM_SELF): voxels = comm.allreduce(voxels, op=MPI.SUM) return w, voxels +def load(file): + """Load fitted Shared Response Model from .npz file + + Parameters + ---------- + + file : The file to read (string) of type .npz + + Returns + -------- + + srm_obj: fitted SRM model + """ + # check file exists + if not (os.path.isfile(file)): + raise FileError("Input file not found") + + # Check file format + if not file[-4:]=='.npz': + raise FileError("Input file is not in .npz format") + + # load data + loaded = np.load(file) + w_ = [s for s in loaded['w_']] + s_ = loaded['s_'] + sigma_s_ = loaded['sigma_s_'] + mu_ = [s for s in loaded['mu_']] + rho2_ = loaded['rho2_'] + n_feature,n_iter,seed = loaded['features'] + + # init new SRM object + srm_obj = SRM(n_iter=n_iter, features=n_feature ,rand_seed=seed) + srm_obj.w_ = w_ + srm_obj.s_ = s_ + srm_obj.sigma_s_ = sigma_s_ + srm_obj.mu_ = mu_ + srm_obj.rho2_ = rho2_ + + return srm_obj + + class SRM(BaseEstimator, TransformerMixin): """Probabilistic Shared Response Model (SRM) @@ -411,7 +453,27 @@ def transform_subject(self, X): w = self._update_transform_subject(X, self.s_) return w + + def save(self, file): + """Save fitted Shared Response Model to .npz file + + + Parameters + ---------- + file : The filename (string) where the data will be saved. If file is a string or a Path, the .npz extension will be appended to the filename if it is not already there. + + Returns + -------- + None + """ + + # Check if the model exists + if hasattr(self, 'w_') is False: + raise NotFittedError("The model fit has not been run yet.") + + np.savez_compressed(file, w_=self.w_, s_=self.s_, sigma_s_=self.sigma_s_, mu_=self.mu_, rho2_=self.rho2_, features=np.array([self.features,self.n_iter,self.rand_seed])) + def _srm(self, data): """Expectation-Maximization algorithm for fitting the probabilistic SRM. @@ -844,3 +906,4 @@ def _srm(self, data): logger.info('Objective function %f' % objective) return w, shared_response + From adb6a23ca81b22d71ad653a3d7f4bb2fef15dc19 Mon Sep 17 00:00:00 2001 From: meshulam Date: Fri, 9 Oct 2020 21:36:22 -0400 Subject: [PATCH 2/7] typos in srm.py --- brainiak/funcalign/srm.py | 98 +++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/brainiak/funcalign/srm.py b/brainiak/funcalign/srm.py index 8b09525c2..96fe10df8 100644 --- a/brainiak/funcalign/srm.py +++ b/brainiak/funcalign/srm.py @@ -41,7 +41,6 @@ from sklearn.exceptions import NotFittedError from mpi4py import MPI import sys -import os __all__ = [ "DetSRM", @@ -106,46 +105,38 @@ def _init_w_transforms(data, features, random_states, comm=MPI.COMM_SELF): voxels = comm.allreduce(voxels, op=MPI.SUM) return w, voxels + def load(file): - """Load fitted Shared Response Model from .npz file - - Parameters - ---------- + """Load fitted Shared Response Model from .npz file - file : The file to read (string) of type .npz - - Returns - -------- - - srm_obj: fitted SRM model - """ - # check file exists - if not (os.path.isfile(file)): - raise FileError("Input file not found") - - # Check file format - if not file[-4:]=='.npz': - raise FileError("Input file is not in .npz format") - - # load data - loaded = np.load(file) - w_ = [s for s in loaded['w_']] - s_ = loaded['s_'] - sigma_s_ = loaded['sigma_s_'] - mu_ = [s for s in loaded['mu_']] - rho2_ = loaded['rho2_'] - n_feature,n_iter,seed = loaded['features'] - - # init new SRM object - srm_obj = SRM(n_iter=n_iter, features=n_feature ,rand_seed=seed) - srm_obj.w_ = w_ - srm_obj.s_ = s_ - srm_obj.sigma_s_ = sigma_s_ - srm_obj.mu_ = mu_ - srm_obj.rho2_ = rho2_ - - return srm_obj - + Parameters + ---------- + + file : The file to read (string) of type .npz + + Returns + -------- + + srm_obj: fitted SRM model + """ + # load data + loaded = np.load(file) + w_ = [s for s in loaded['w_']] + s_ = loaded['s_'] + sigma_s_ = loaded['sigma_s_'] + mu_ = [s for s in loaded['mu_']] + rho2_ = loaded['rho2_'] + n_feature, n_iter, seed = loaded['features'] + + # init new SRM object + srm_obj = SRM(n_iter=n_iter, features=n_feature, rand_seed=seed) + srm_obj.w_ = w_ + srm_obj.s_ = s_ + srm_obj.sigma_s_ = sigma_s_ + srm_obj.mu_ = mu_ + srm_obj.rho2_ = rho2_ + + return srm_obj class SRM(BaseEstimator, TransformerMixin): @@ -453,27 +444,37 @@ def transform_subject(self, X): w = self._update_transform_subject(X, self.s_) return w - + def save(self, file): """Save fitted Shared Response Model to .npz file - - + + Parameters ---------- - file : The filename (string) where the data will be saved. If file is a string or a Path, the .npz extension will be appended to the filename if it is not already there. - + file : The filename (string) where the data will be saved. If file + is a string or a Path, the .npz extension will be appended to the + filename if it is not already there. + Returns -------- None """ - + # Check if the model exists if hasattr(self, 'w_') is False: raise NotFittedError("The model fit has not been run yet.") - - np.savez_compressed(file, w_=self.w_, s_=self.s_, sigma_s_=self.sigma_s_, mu_=self.mu_, rho2_=self.rho2_, features=np.array([self.features,self.n_iter,self.rand_seed])) - + + np.savez_compressed( + file, + w_=self.w_, + s_=self.s_, + sigma_s_=self.sigma_s_, + mu_=self.mu_, + rho2_=self.rho2_, + features=np.array([self.features, self.n_iter, self.rand_seed]) + ) + def _srm(self, data): """Expectation-Maximization algorithm for fitting the probabilistic SRM. @@ -906,4 +907,3 @@ def _srm(self, data): logger.info('Objective function %f' % objective) return w, shared_response - From d24bf007a79c1ec10bc7b6ac9a132025e26042b1 Mon Sep 17 00:00:00 2001 From: Sam Nastase Date: Tue, 13 Oct 2020 15:00:21 -0400 Subject: [PATCH 3/7] Minor adjustments to wording --- brainiak/funcalign/srm.py | 43 +++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/brainiak/funcalign/srm.py b/brainiak/funcalign/srm.py index 96fe10df8..046c80903 100644 --- a/brainiak/funcalign/srm.py +++ b/brainiak/funcalign/srm.py @@ -107,36 +107,38 @@ def _init_w_transforms(data, features, random_states, comm=MPI.COMM_SELF): def load(file): - """Load fitted Shared Response Model from .npz file + """Load fitted SRM from .npz file. Parameters ---------- - file : The file to read (string) of type .npz + file : str, file-like object, or pathlib.Path + The .npz file to read containing fitted SRM saved using srm.save Returns -------- - srm_obj: fitted SRM model + srm : fitted SRM model """ - # load data + + # Load file and extract SRM attributes loaded = np.load(file) w_ = [s for s in loaded['w_']] s_ = loaded['s_'] sigma_s_ = loaded['sigma_s_'] mu_ = [s for s in loaded['mu_']] rho2_ = loaded['rho2_'] - n_feature, n_iter, seed = loaded['features'] + features, n_iter, rand_seed = loaded['kwargs'] - # init new SRM object - srm_obj = SRM(n_iter=n_iter, features=n_feature, rand_seed=seed) - srm_obj.w_ = w_ - srm_obj.s_ = s_ - srm_obj.sigma_s_ = sigma_s_ - srm_obj.mu_ = mu_ - srm_obj.rho2_ = rho2_ + # Initialize new SRM object and attach loaded attributes + srm = SRM(n_iter=n_iter, features=features, rand_seed=rand_seed) + srm.w_ = w_ + srm.s_ = s_ + srm.sigma_s_ = sigma_s_ + srm.mu_ = mu_ + srm.rho2_ = rho2_ - return srm_obj + return srm class SRM(BaseEstimator, TransformerMixin): @@ -446,22 +448,23 @@ def transform_subject(self, X): return w def save(self, file): - """Save fitted Shared Response Model to .npz file - + """Save fitted SRM to .npz file. Parameters ---------- - file : The filename (string) where the data will be saved. If file - is a string or a Path, the .npz extension will be appended to the - filename if it is not already there. + file : str, file-like object, or pathlib.Path + Filename (string), open file (file-like object) or pathlib.Path + where the fitted SRM will be saved. If file is a string or a Path, + the .npz extension will be appended to the filename if it is not + already there. Returns -------- None """ - # Check if the model exists + # Check if the model has been estimated if hasattr(self, 'w_') is False: raise NotFittedError("The model fit has not been run yet.") @@ -472,7 +475,7 @@ def save(self, file): sigma_s_=self.sigma_s_, mu_=self.mu_, rho2_=self.rho2_, - features=np.array([self.features, self.n_iter, self.rand_seed]) + kwargs=np.array([self.features, self.n_iter, self.rand_seed]) ) def _srm(self, data): From 3cc324046898804e320d27b258f2e44b51fec468 Mon Sep 17 00:00:00 2001 From: Sam Nastase Date: Tue, 13 Oct 2020 15:01:10 -0400 Subject: [PATCH 4/7] Simple test for save/load SRM --- tests/funcalign/test_srm.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/funcalign/test_srm.py b/tests/funcalign/test_srm.py index 08a022dc4..4f8153d89 100644 --- a/tests/funcalign/test_srm.py +++ b/tests/funcalign/test_srm.py @@ -117,6 +117,21 @@ def test_can_instantiate(): s.fit(X) print("Test: different number of samples per subject") + # Check save/load functionality for fitted SRM + srm_fn = '/Users/snastase/Work/srm-example.npz' + s.save(srm_fn) + s_load = brainiak.funcalign.srm.load(srm_fn) + assert np.array_equal(s.s_, s_load.s_) + for w, wl in zip(s.w_, s_load.w_): + assert np.array_equal(w, wl) + assert np.array_equal(s.sigma_s_, s_load.sigma_s_) + assert np.array_equal(s.mu_, s_load.mu_) + assert np.array_equal(s.rho2_, s_load.rho2_) + assert s.features == s_load.features + assert s.n_iter == s_load.n_iter + assert s.rand_seed == s_load.rand_seed + print("Test: save/load functionality") + def test_new_subject(): import brainiak.funcalign.srm From b03b1d29906278263b299ebe3a0e18492947a2d3 Mon Sep 17 00:00:00 2001 From: Sam Nastase Date: Tue, 13 Oct 2020 15:12:46 -0400 Subject: [PATCH 5/7] Use tmp_path for SRM load/save --- tests/funcalign/test_srm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/funcalign/test_srm.py b/tests/funcalign/test_srm.py index 4f8153d89..cc9958aaa 100644 --- a/tests/funcalign/test_srm.py +++ b/tests/funcalign/test_srm.py @@ -118,7 +118,7 @@ def test_can_instantiate(): print("Test: different number of samples per subject") # Check save/load functionality for fitted SRM - srm_fn = '/Users/snastase/Work/srm-example.npz' + srm_fn = tmp_path s.save(srm_fn) s_load = brainiak.funcalign.srm.load(srm_fn) assert np.array_equal(s.s_, s_load.s_) From d36ae51d48c6f50c742bf79660c62e6ab799a705 Mon Sep 17 00:00:00 2001 From: Sam Nastase Date: Tue, 13 Oct 2020 16:19:23 -0400 Subject: [PATCH 6/7] Fix tmp_path usage in SRM save/load test --- tests/funcalign/test_srm.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/funcalign/test_srm.py b/tests/funcalign/test_srm.py index cc9958aaa..b109a77bd 100644 --- a/tests/funcalign/test_srm.py +++ b/tests/funcalign/test_srm.py @@ -15,7 +15,7 @@ import pytest -def test_can_instantiate(): +def test_can_instantiate(tmp_path): import brainiak.funcalign.srm s = brainiak.funcalign.srm.SRM() assert s, "Invalid SRM instance!" @@ -118,9 +118,9 @@ def test_can_instantiate(): print("Test: different number of samples per subject") # Check save/load functionality for fitted SRM - srm_fn = tmp_path - s.save(srm_fn) - s_load = brainiak.funcalign.srm.load(srm_fn) + srm_path = tmp_path / 'srm.npz' + s.save(srm_path) + s_load = brainiak.funcalign.srm.load(srm_path) assert np.array_equal(s.s_, s_load.s_) for w, wl in zip(s.w_, s_load.w_): assert np.array_equal(w, wl) From 54be7a722b3f0cddc6e8e300c03e0211f1f0f11e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mihai=20Capot=C4=83?= Date: Tue, 13 Oct 2020 18:47:31 -0700 Subject: [PATCH 7/7] Fix docstring formatting --- brainiak/funcalign/srm.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/brainiak/funcalign/srm.py b/brainiak/funcalign/srm.py index 046c80903..3ed56a1df 100644 --- a/brainiak/funcalign/srm.py +++ b/brainiak/funcalign/srm.py @@ -113,7 +113,7 @@ def load(file): ---------- file : str, file-like object, or pathlib.Path - The .npz file to read containing fitted SRM saved using srm.save + The .npz file to read containing fitted SRM saved using srm.save Returns -------- @@ -454,13 +454,14 @@ def save(self, file): ---------- file : str, file-like object, or pathlib.Path - Filename (string), open file (file-like object) or pathlib.Path - where the fitted SRM will be saved. If file is a string or a Path, - the .npz extension will be appended to the filename if it is not - already there. + Filename (string), open file (file-like object) or pathlib.Path + where the fitted SRM will be saved. If file is a string or a Path, + the .npz extension will be appended to the filename if it is not + already there. Returns - -------- + ------- + None """