From 4a96d81ff59f174580b52f90e7a59ea4dfd8ac12 Mon Sep 17 00:00:00 2001 From: SeanNobel Date: Tue, 13 Jun 2023 05:32:42 +0000 Subject: [PATCH 1/7] tmp --- assets/reports.md | 10 +- configs/config.yaml | 2 +- speech_decoding/dataclass/brennan2018.py | 36 ++++-- speech_decoding/dataclass/gwilliams2022.py | 131 +++++++++++++-------- speech_decoding/utils/preproc_utils.py | 2 +- 5 files changed, 115 insertions(+), 66 deletions(-) diff --git a/assets/reports.md b/assets/reports.md index 43d7b01..8f2759f 100644 --- a/assets/reports.md +++ b/assets/reports.md @@ -31,6 +31,12 @@ ## Questions -- After wav2vec2.0 embedding, audios become somewhere like 50Hz (because wav2vec2.0 requires them to be originally 16kHz and it downsamples them a lot), so we need to upsample them to match brains' 120Hz. Do you actually do that? If so, which method do you use? We've tried linear interpolation by torchaudio and zero-padding but neither worked well. +- After wav2vec2.0 embedding, audios become something like 50Hz (because wav2vec2.0 requires them to be originally 16kHz and it downsamples them a lot), so we need to upsample them to match brains' 120Hz. Do you actually do that? If so, which method do you use? We've tried linear interpolation by torchaudio and zero-padding but neither worked well. + +- Learnable temperature of CLIP loss was not mentioned and absent in equation (2). It was mentioned in the original CLIP paper but do you actually use it? + + +# Gwilliams2022 + +## Experiments -- Learnable temperature of CLIP loss was not mentioned and absent in equation (2). It was mentioned in the original CLIP paper but do you actually use it? \ No newline at end of file diff --git a/configs/config.yaml b/configs/config.yaml index bf4962d..66b41c5 100644 --- a/configs/config.yaml +++ b/configs/config.yaml @@ -43,7 +43,7 @@ preprocs: shift_brain: True # whether to shift M/EEG into the future relative to audio shift_len: 150 # if True, by how many ms last4layers: True # if True, the brain_encoder's emsize will be 1024, not 512 - channel_wise: True # whether to scale each channel's EEG dataset individually (only for Brennan2018) + channel_wise: True # Whether to scale each channel of MEG/EEG datasets individually clamp: True clamp_lim: 20 y_upsample: interpolate # interpolate / pad diff --git a/speech_decoding/dataclass/brennan2018.py b/speech_decoding/dataclass/brennan2018.py index d10ffae..6742d96 100644 --- a/speech_decoding/dataclass/brennan2018.py +++ b/speech_decoding/dataclass/brennan2018.py @@ -53,13 +53,11 @@ def __init__(self, args): super().__init__() # Both - chance = args.chance - force_recompute = args.rebuild_dataset self.split_mode = args.split_mode self.root_dir = args.root_dir - self.channel_wise = args.preprocs.channel_wise self.seq_len_sec = args.preprocs.seq_len_sec # EEG + self.channel_wise = args.preprocs.channel_wise self.filter_brain = args.preprocs.filter self.brain_filter_low = args.preprocs.brain_filter_low self.brain_filter_high = args.preprocs.brain_filter_high @@ -72,8 +70,12 @@ def __init__(self, args): self.lowpass_filter_width = args.preprocs.lowpass_filter_width self.wav2vec = Wav2Vec2Model.from_pretrained(args.wav2vec_model) # Data Paths - self.matfile_paths = natsorted(glob.glob(f"{self.root_dir}/data/Brennan2018/raw/*.mat")) - self.audio_paths = natsorted(glob.glob(f"{self.root_dir}/data/Brennan2018/audio/*.wav")) + self.matfile_paths = natsorted( + glob.glob(f"{self.root_dir}/data/Brennan2018/raw/*.mat") + ) + self.audio_paths = natsorted( + glob.glob(f"{self.root_dir}/data/Brennan2018/audio/*.wav") + ) self.onsets_path = f"{self.root_dir}/data/Brennan2018/AliceChapterOne-EEG.csv" # Save Paths X_path = f"{self.root_dir}/data/Brennan2018/X.pt" @@ -81,7 +83,9 @@ def __init__(self, args): sentence_idxs_path = f"{self.root_dir}/data/Brennan2018/sentence_idxs.npy" # Rebuild dataset - if force_recompute or not (os.path.exists(X_path) and os.path.exists(Y_path)): + if args.rebuild_dataset or not ( + os.path.exists(X_path) and os.path.exists(Y_path) + ): cprint(f"> Preprocessing EEG and audio.", color="cyan") self.X, self.Y, self.sentence_idxs = self.rebuild_dataset( @@ -109,7 +113,10 @@ def __init__(self, args): self.num_subjects = self.X.shape[1] cprint(f">>> Number of subjects: {self.num_subjects}", color="cyan") - cprint(f">> Upsampling audio embedding with: {args.preprocs.y_upsample}", color="cyan") + cprint( + f">> Upsampling audio embedding with: {args.preprocs.y_upsample}", + color="cyan", + ) if args.preprocs.y_upsample == "interpolate": self.Y = interpolate_y_time(self.Y, self.brain_num_samples) elif args.preprocs.y_upsample == "pad": @@ -117,7 +124,7 @@ def __init__(self, args): else: raise ValueError(f"Unknown upsampling strategy: {args.preprocs.y_upsample}") - if chance: + if args.chance: self.Y = self.Y[torch.randperm(len(self.Y))] def __len__(self): @@ -159,7 +166,9 @@ def rebuild_dataset( # EEG Loading # ---------------------- matfile_paths = [ - path for path in matfile_paths if not path.split(".")[0][-3:] in EXCLUDED_SUBJECTS + path + for path in matfile_paths + if not path.split(".")[0][-3:] in EXCLUDED_SUBJECTS ] mat_raws = [scipy.io.loadmat(path)["raw"][0, 0] for path in matfile_paths] eeg_raws = [mat_raw["trial"][0, 0] for mat_raw in mat_raws] @@ -216,7 +225,9 @@ def drop_last_segments( sentence_ends = np.where(np.diff(sentence_idxs) > 0)[0] - drop_idxs = np.concatenate([np.arange(i - num_drops, i) + 1 for i in sentence_ends]) + drop_idxs = np.concatenate( + [np.arange(i - num_drops, i) + 1 for i in sentence_ends] + ) # NOTE: to boolean array drop_bools = np.ones(len(X), dtype=bool) @@ -316,7 +327,6 @@ def resample_brain( eeg_raw = torch.from_numpy(eeg_raw.astype(np.float32)) - # NOTE: in the paper they say they downsampled to exactly 120Hz with Torchaudio, so I'll stick to that eeg_resampled = F.resample( waveform=eeg_raw, orig_freq=fsample, @@ -338,6 +348,8 @@ def get_audio_rate(self, waveform: List[Tuple[torch.Tensor, int]]) -> int: def get_eeg_rate(self, mat_raws: List) -> int: sample_rates = np.array([mat_raw["fsample"][0, 0] for mat_raw in mat_raws]) # is all 500Hz - assert np.all(sample_rates == sample_rates[0]), "Wrong EEG sampling rate detected." + assert np.all( + sample_rates == sample_rates[0] + ), "Wrong EEG sampling rate detected." return sample_rates[0] diff --git a/speech_decoding/dataclass/gwilliams2022.py b/speech_decoding/dataclass/gwilliams2022.py index 3a8ac58..6845454 100644 --- a/speech_decoding/dataclass/gwilliams2022.py +++ b/speech_decoding/dataclass/gwilliams2022.py @@ -29,6 +29,7 @@ continuous, scale_and_clamp, ) +from speech_decoding.constants import BRAIN_RESAMPLE_RATE, AUDIO_RESAMPLE_RATE mne.set_log_level(verbose="WARNING") @@ -42,8 +43,10 @@ class Gwilliams2022DatasetBase(Dataset): def __init__(self, args): super().__init__() + # Both + self.root_dir = args.root_dir # + "/data/Gwilliams2022/" + # MEG self.wav2vec_model = args.wav2vec_model - self.root_dir = args.root_dir + "/data/Gwilliams2022/" self.brain_orig_rate = 1000 self.brain_resample_rate = args.preprocs["brain_resample_rate"] self.brain_filter_low = args.preprocs["brain_filter_low"] @@ -74,7 +77,7 @@ def __init__(self, args): # Preprocess X (MEG) # --------------------------- if args.rebuild_dataset or not args.preprocs["x_done"]: - _out = self.brain_preproc_handler() + _out = self.brain_preproc() self.X, self.meg_onsets, self.speech_onsets, self.sentence_idxs = _out np.save(self.x_path, self.X) @@ -89,8 +92,12 @@ def __init__(self, args): else: self.X = np.load(self.x_path, allow_pickle=True).item() self.meg_onsets = np.load(self.meg_onsets_path, allow_pickle=True).item() - self.speech_onsets = np.load(self.speech_onsets_path, allow_pickle=True).item() - self.sentence_idxs = np.load(self.sentence_idxs_path, allow_pickle=True).item() + self.speech_onsets = np.load( + self.speech_onsets_path, allow_pickle=True + ).item() + self.sentence_idxs = np.load( + self.sentence_idxs_path, allow_pickle=True + ).item() # ---------------------------------------- # Preprocess Y (embedded speech) @@ -117,19 +124,23 @@ def __init__(self, args): assert len(self.X) == len(self.meg_onsets) - self.valid_subjects = np.array(list(set([k.split("_")[0] for k in self.X.keys()]))) + self.valid_subjects = np.array( + list(set([k.split("_")[0] for k in self.X.keys()])) + ) self.num_subjects = len(self.valid_subjects) cprint(f"X keys: {self.X.keys()}", color="cyan") cprint(f"Y: {self.Y.shape}", color="cyan") - cprint(f"num_subjects: {self.num_subjects} (each has 2 or 1 sessions)", color="cyan") + cprint( + f"num_subjects: {self.num_subjects} (each has 2 or 1 sessions)", color="cyan" + ) print(self.valid_subjects) def __len__(self): return len(self.Y) def __getitem__(self, i): # NOTE: i is id of a speech segment - i_in_task, task = self.segment_to_task(i) + i_in_task, task = self._segment_to_task(i) key_no_task = np.random.choice(list(self.X.keys())) X = self.X[key_no_task][task] # ( 208, ~100000 ) @@ -142,7 +153,7 @@ def __getitem__(self, i): # NOTE: i is id of a speech segment return X, self.Y[i], subject_idx - def segment_to_task(self, i) -> Tuple[int, str]: + def _segment_to_task(self, i) -> Tuple[int, str]: nseg_task_accum = np.cumsum(self.num_segments_foreach_task) task = np.searchsorted(nseg_task_accum, i + 1) @@ -162,7 +173,9 @@ def segment_speech(self, data: torch.Tensor, key: str) -> torch.Tensor: def sentence_to_word_idxs(self, _sentence_idxs, key): return [ i - for si, i in zip(self.sentence_idxs[key], np.arange(len(self.sentence_idxs[key]))) + for si, i in zip( + self.sentence_idxs[key], np.arange(len(self.sentence_idxs[key])) + ) if si in _sentence_idxs ] @@ -189,18 +202,21 @@ def drop_task_missing_sessions(self) -> None: self.meg_onsets.pop(key) @staticmethod - def brain_preproc(dat): - subject_idx, d, speech_onsets, meg_onsets, sentence_idxs, session_idx, task_idx = dat - - num_channels = d["num_channels"] - brain_orig_rate = d["brain_orig_rate"] - brain_filter_low = d["brain_filter_low"] - brain_filter_high = d["brain_filter_high"] - brain_resample_rate = d["brain_resample_rate"] - root_dir = d["root_dir"] - preproc_dir = d["preproc_dir"] - - description = f"subject{str(subject_idx+1).zfill(2)}_sess{session_idx}_task{task_idx}" + def _brain_preproc( + args: dict, + subject_idx: int, + speech_onsets: np.ndarray, + meg_onsets: np.ndarray, + sentence_idxs: np.ndarray, + session_idx: int, + task_idx: int, + num_channels: int, + root_dir: str, + preproc_dir: str, + ) -> None: + description = ( + f"subject{str(subject_idx+1).zfill(2)}_sess{session_idx}_task{task_idx}" + ) bids_path = mne_bids.BIDSPath( subject=str(subject_idx + 1).zfill(2), @@ -215,7 +231,7 @@ def brain_preproc(dat): raw = mne_bids.read_raw_bids(bids_path) except: cprint("No .con data was found", color="yellow") - return 1 + return None cprint(description, color="cyan") @@ -244,43 +260,48 @@ def brain_preproc(dat): speech_onsets.update({task_str: _speech_onsets}) sentence_idxs.update({task_str: _sentence_idxs}) - meg_raw = np.stack([df[key] for key in df.keys() if "MEG" in key]) # ( 224, ~396000 ) + meg_raw = np.stack( + [df[key] for key in df.keys() if "MEG" in key] + ) # ( 224, ~396000 ) # NOTE: (kind of) confirmed that last 16 channels are REF meg_raw = meg_raw[:num_channels] # ( 208, ~396000 ) - meg_filtered = mne.filter.filter_data( - meg_raw, - sfreq=brain_orig_rate, - l_freq=brain_filter_low, - h_freq=brain_filter_high, - ) + if filter: + meg_raw = mne.filter.filter_data( + meg_raw, + sfreq=args.brain_orig_rate, + l_freq=args.brain_filter_low, + h_freq=args.brain_filter_high, + ) # To 120 Hz - meg_resampled = mne.filter.resample( - meg_filtered, - down=brain_orig_rate / brain_resample_rate, + meg_resampled = F.resample( + waveform=meg_raw, + orig_freq=args.brain_orig_rate, + new_freq=args.brain_resample_rate, + lowpass_filter_width=args.lowpass_filter_width, ) # ( 208, 37853 ) np.save( f"{preproc_dir}_parts/{description}", meg_resampled, ) - return 0 + # return 0 - def brain_preproc_handler(self, num_subjects=27, num_channels=208): + def brain_preproc(self, args, num_subjects: int, num_channels: int = 208): tmp_dir = self.preproc_dir + "_parts/" if not os.path.exists(tmp_dir): os.mkdir(tmp_dir) - consts = dict( - num_channels=num_channels, - brain_orig_rate=self.brain_orig_rate, - brain_filter_low=self.brain_filter_low, - brain_filter_high=self.brain_filter_high, - brain_resample_rate=self.brain_resample_rate, - root_dir=self.root_dir, - preproc_dir=self.preproc_dir, - ) + # consts = dict( + # num_channels=num_channels, + # brain_orig_rate=self.brain_orig_rate, + # brain_filter_low=self.brain_filter_low, + # brain_filter_high=self.brain_filter_high, + # brain_resample_rate=self.brain_resample_rate, + # root_dir=self.root_dir, + # preproc_dir=self.preproc_dir, + # ) subj_list = [] for subj in range(num_subjects): @@ -288,8 +309,8 @@ def brain_preproc_handler(self, num_subjects=27, num_channels=208): for task_idx in range(4): subj_list.append( ( + args.preprocs, subj, - consts, global_speech_onsets, global_meg_onsets, global_sentence_idxs, @@ -301,7 +322,7 @@ def brain_preproc_handler(self, num_subjects=27, num_channels=208): with Pool(processes=20) as p: res = list( tqdm( - p.imap(self.brain_preproc, subj_list), + p.imap(self._brain_preproc, subj_list), total=len(subj_list), bar_format="{desc:<5.5}{percentage:3.0f}%|{bar:10}{r_bar}", ) @@ -316,16 +337,22 @@ def brain_preproc_handler(self, num_subjects=27, num_channels=208): # NOTE: assemble files into one and clean up fnames = natsorted(os.listdir(tmp_dir)) - # cprint(fnames, color='yellow') + + # NOTE: data MUST be task0, ... taskN, task0, ..., taskN (N=4) X = dict() - for fname in fnames: # NOTE: data MUST be task0, ... taskN, task0, ..., taskN (N=4) + for fname in fnames: key = os.path.splitext(fname)[0] X[key] = np.load(tmp_dir + fname, allow_pickle=True) cprint("removing temp files for EEG data", color="white") shutil.rmtree(tmp_dir) - return X, dict(global_meg_onsets), dict(global_speech_onsets), dict(global_sentence_idxs) + return ( + X, + dict(global_meg_onsets), + dict(global_speech_onsets), + dict(global_sentence_idxs), + ) @torch.no_grad() def audio_preproc(self): @@ -341,7 +368,9 @@ def audio_preproc(self): task_idx_ID = int(task_idx[-1]) audio_paths = natsorted( - glob.glob(f"{self.root_dir}stimuli/audio/{self.task_prefixes[task_idx_ID]}*.wav") + glob.glob( + f"{self.root_dir}stimuli/audio/{self.task_prefixes[task_idx_ID]}*.wav" + ) ) audio_raw = [] @@ -647,7 +676,9 @@ def __init__(self, args): super(Gwilliams2022Collator, self).__init__() self.brain_resample_rate = args.preprocs["brain_resample_rate"] - self.baseline_len_samp = int(self.brain_resample_rate * args.preprocs["baseline_len_sec"]) + self.baseline_len_samp = int( + self.brain_resample_rate * args.preprocs["baseline_len_sec"] + ) self.clamp = args.preprocs["clamp"] self.clamp_lim = args.preprocs["clamp_lim"] diff --git a/speech_decoding/utils/preproc_utils.py b/speech_decoding/utils/preproc_utils.py index aa3a718..53d0b68 100644 --- a/speech_decoding/utils/preproc_utils.py +++ b/speech_decoding/utils/preproc_utils.py @@ -146,7 +146,7 @@ def interpolate_y_time(Y: torch.Tensor, num_samples: int) -> torch.Tensor: return F.interpolate(Y, size=num_samples, mode="linear") -# NOTE currently only works for gwilliams2022.yml +# NOTE: Works only for Gwilliams2022 dataset def check_preprocs(args, data_dir): is_processed = False preproc_dirs = glob.glob(data_dir + "*/") From f61bf0900b29405a3999d082fb0563ac2941e956 Mon Sep 17 00:00:00 2001 From: SeanNobel Date: Fri, 30 Jun 2023 10:30:09 +0000 Subject: [PATCH 2/7] [WIP] put methods that Gw and Br share to Base class --- speech_decoding/dataclass/base.py | 26 ++++++++++ speech_decoding/dataclass/gwilliams2022.py | 56 +++++++++++++++++++--- 2 files changed, 75 insertions(+), 7 deletions(-) create mode 100644 speech_decoding/dataclass/base.py diff --git a/speech_decoding/dataclass/base.py b/speech_decoding/dataclass/base.py new file mode 100644 index 0000000..3c0d5d0 --- /dev/null +++ b/speech_decoding/dataclass/base.py @@ -0,0 +1,26 @@ +import torch +import torchaudio.functional as F + +from termcolor import cprint + + +class SpeechDecodingDatasetBase(torch.utils.data.Dataset): + def __init__(self, args): + super().__init__() + + def _resample_audio( + self, waveform: torch.Tensor, sample_rate: int, resample_rate: int = 16000 + ) -> torch.Tensor: + """Resamples audio to 16kHz. (16kHz is required by wav2vec2.0)""" + + waveform = F.resample( + waveform, + sample_rate, + resample_rate, + lowpass_filter_width=self.lowpass_filter_width, + ) + + len_audio_s = waveform.shape[1] / resample_rate + cprint(f">>> Audio length: {len_audio_s} s.", color="cyan") + + return waveform diff --git a/speech_decoding/dataclass/gwilliams2022.py b/speech_decoding/dataclass/gwilliams2022.py index 6845454..dd7ba28 100644 --- a/speech_decoding/dataclass/gwilliams2022.py +++ b/speech_decoding/dataclass/gwilliams2022.py @@ -14,7 +14,7 @@ import mne, mne_bids from tqdm import tqdm import ast -from typing import Union, Tuple, List +from typing import Union, Tuple, List, Dict from psutil import virtual_memory as vm from termcolor import cprint from pprint import pprint @@ -23,6 +23,7 @@ from itertools import repeat from omegaconf import open_dict +from speech_decoding.dataclass.base import SpeechDecodingDatasetBase from speech_decoding.utils.wav2vec_util import get_last4layers_avg from speech_decoding.utils.preproc_utils import ( check_preprocs, @@ -39,7 +40,7 @@ global_sentence_idxs = manager.dict() -class Gwilliams2022DatasetBase(Dataset): +class Gwilliams2022DatasetBase(SpeechDecodingDatasetBase): def __init__(self, args): super().__init__() @@ -153,6 +154,12 @@ def __getitem__(self, i): # NOTE: i is id of a speech segment return X, self.Y[i], subject_idx + def rebuild_dataset(self): + audio_tasks = self.load_resample_audio() + + _X = self.load_resample_brain() + self.X, self.meg_onsets, self.speech_onsets, self.sentence_idxs = _X + def _segment_to_task(self, i) -> Tuple[int, str]: nseg_task_accum = np.cumsum(self.num_segments_foreach_task) task = np.searchsorted(nseg_task_accum, i + 1) @@ -202,7 +209,7 @@ def drop_task_missing_sessions(self) -> None: self.meg_onsets.pop(key) @staticmethod - def _brain_preproc( + def _load_resample_brain( args: dict, subject_idx: int, speech_onsets: np.ndarray, @@ -219,8 +226,7 @@ def _brain_preproc( ) bids_path = mne_bids.BIDSPath( - subject=str(subject_idx + 1).zfill(2), - # '01', '02', ... + subject=str(subject_idx + 1).zfill(2), # '01', '02', ... session=str(session_idx), task=str(task_idx), datatype="meg", @@ -288,7 +294,7 @@ def _brain_preproc( ) # return 0 - def brain_preproc(self, args, num_subjects: int, num_channels: int = 208): + def load_resample_brain(self, args, num_subjects: int, num_channels: int = 208): tmp_dir = self.preproc_dir + "_parts/" if not os.path.exists(tmp_dir): os.mkdir(tmp_dir) @@ -322,7 +328,7 @@ def brain_preproc(self, args, num_subjects: int, num_channels: int = 208): with Pool(processes=20) as p: res = list( tqdm( - p.imap(self._brain_preproc, subj_list), + p.imap(self._load_resample_brain, subj_list), total=len(subj_list), bar_format="{desc:<5.5}{percentage:3.0f}%|{bar:10}{r_bar}", ) @@ -354,6 +360,42 @@ def brain_preproc(self, args, num_subjects: int, num_channels: int = 208): dict(global_sentence_idxs), ) + def load_resample_audio(self) -> Dict[str, torch.Tensor]: + audio_tasks = {} + assert os.path.exists( + f"{self.root_dir}stimuli/audio" + ), "Path data/Gwilliams2022/stimuli/audio doesn't exist." + + for task_idx in self.speech_onsets.keys(): # 4 tasks for each subject + task_idx_ID = int(task_idx[-1]) + + audio_paths = natsorted( + glob.glob( + f"{self.root_dir}stimuli/audio/{self.task_prefixes[task_idx_ID]}*.wav" + ) + ) + + audio_list = [] + for path in audio_paths: + waveform, sample_rate = torchaudio.load(path) + + # Upsample to 16000Hz + # waveform = F.resample( + # waveform, + # orig_freq=sample_rate, + # new_freq=self.audio_resample_rate, + # lowpass_filter_width=self.lowpass_filter_width, + # ) + audio = self._resample_audio(waveform, sample_rate, AUDIO_RESAMPLE_RATE) + + audio_list.append(audio) + + audio = torch.cat(audio_list, dim=-1) + + audio_tasks.update({task_idx: audio}) + + return audio_tasks + @torch.no_grad() def audio_preproc(self): wav2vec = load_wav2vec_model(self.wav2vec_model) From 8f6b220e1e8cc075216de5f696e4749bc1694d18 Mon Sep 17 00:00:00 2001 From: SeanNobel Date: Fri, 30 Jun 2023 10:32:58 +0000 Subject: [PATCH 3/7] review Brennan dataclass --- speech_decoding/dataclass/brennan2018.py | 61 +++++++++++++----------- tests/test_brennan_dataclass.py | 22 +++++++++ 2 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 tests/test_brennan_dataclass.py diff --git a/speech_decoding/dataclass/brennan2018.py b/speech_decoding/dataclass/brennan2018.py index 6742d96..1320d0b 100644 --- a/speech_decoding/dataclass/brennan2018.py +++ b/speech_decoding/dataclass/brennan2018.py @@ -20,6 +20,7 @@ from transformers import Wav2Vec2Model +from speech_decoding.dataclass.base import SpeechDecodingDatasetBase from speech_decoding.utils.wav2vec_util import get_last4layers_avg from speech_decoding.utils.preproc_utils import ( shift_brain_signal, @@ -48,9 +49,9 @@ """ -class Brennan2018Dataset(Dataset): +class Brennan2018Dataset(SpeechDecodingDatasetBase): def __init__(self, args): - super().__init__() + super().__init__(args) # Both self.split_mode = args.split_mode @@ -151,11 +152,11 @@ def rebuild_dataset( # ---------------------- waveform = [torchaudio.load(path) for path in audio_paths] - audio_rate = self.get_audio_rate(waveform) + audio_rate = self._get_audio_rate(waveform) waveform = torch.cat([w[0] for w in waveform], dim=1) # ( 1, time@44.1kHz ) - audio = self.resample_audio(waveform, audio_rate, AUDIO_RESAMPLE_RATE) + audio = self._resample_audio(waveform, audio_rate, AUDIO_RESAMPLE_RATE) cprint( f">>> Resampled audio {audio_rate}Hz -> {AUDIO_RESAMPLE_RATE}Hz | shape: {waveform.shape} -> {audio.shape}", @@ -173,7 +174,7 @@ def rebuild_dataset( mat_raws = [scipy.io.loadmat(path)["raw"][0, 0] for path in matfile_paths] eeg_raws = [mat_raw["trial"][0, 0] for mat_raw in mat_raws] - eeg_rate = self.get_eeg_rate(mat_raws) + eeg_rate = self._get_eeg_rate(mat_raws) # ---------------------- # Preprocessing @@ -192,7 +193,9 @@ def rebuild_dataset( if self.split_mode == "sentence": cprint(">> Dropping last segments of each sentence.", color="cyan") - X, audio, sentence_idxs = self.drop_last_segments(X, audio, onsets_path) + + X, audio, sentence_idxs = self._drop_last_segments(X, audio, onsets_path) + cprint(f">>> X (EEG): {X.shape} | Audio: {audio.shape}", color="cyan") else: sentence_idxs = None @@ -210,13 +213,20 @@ def rebuild_dataset( return X, Y, sentence_idxs - def drop_last_segments( - self, X: torch.Tensor, audio: torch.Tensor, onsets_path: str + @staticmethod + def _drop_last_segments( + X: torch.Tensor, audio: torch.Tensor, onsets_path: str ) -> Tuple[torch.Tensor, torch.Tensor, np.ndarray]: """Drops last segments of each sentence. FIXME: currently drops last 5 words, but this number should be variable to cover 3 secs. + Args: + X: ( segment, subject, channel, time@120Hz//segment ) + audio: ( segment, 1, time@16kHz//segment ) + Returns: + X: ( _segment, subject, channel, time@120Hz//segment ) + audio: ( _segment, 1, time@16kHz//segment ) """ - num_drops = 5 + NUM_DROPS = 5 sentence_idxs = pd.read_csv(onsets_path).Sentence.to_numpy() assert np.all( @@ -224,9 +234,17 @@ def drop_last_segments( ), "sentence_idxs is not a non-decreasing step sequence." sentence_ends = np.where(np.diff(sentence_idxs) > 0)[0] + # NOTE: end idx for the last sentence + sentence_ends = np.append(sentence_ends, sentence_idxs.shape[0] - 1) + + # NOTE: There are sentences that are shorter than NUM_DROPS, but the overlap is not + # a problem as we convert it to a boolean array. + # assert np.all( + # np.diff(np.append(-1, sentence_ends)) > NUM_DROPS + # ), f"Some sentence(s) are not longer than NUM_DROPS={NUM_DROPS}." drop_idxs = np.concatenate( - [np.arange(i - num_drops, i) + 1 for i in sentence_ends] + [np.arange(i - NUM_DROPS, i) + 1 for i in sentence_ends] ) # NOTE: to boolean array @@ -235,23 +253,6 @@ def drop_last_segments( return X[drop_bools], audio[drop_bools], sentence_idxs[drop_bools] - def resample_audio( - self, waveform: torch.Tensor, sample_rate: int, resample_rate: int = 16000 - ) -> torch.Tensor: - """Resamples audio to 16kHz. (16kHz is required by wav2vec2.0)""" - - waveform = F.resample( - waveform, - sample_rate, - resample_rate, - lowpass_filter_width=self.lowpass_filter_width, - ) - - len_audio_s = waveform.shape[1] / resample_rate - cprint(f">>> Audio length: {len_audio_s} s.", color="cyan") - - return waveform - def embed_audio(self, audio: torch.Tensor) -> torch.Tensor: """ Args: @@ -338,14 +339,16 @@ def resample_brain( return torch.stack(X) - def get_audio_rate(self, waveform: List[Tuple[torch.Tensor, int]]) -> int: + @staticmethod + def _get_audio_rate(waveform: List[Tuple[torch.Tensor, int]]) -> int: sample_rates = np.array([w[1] for w in waveform]) # is all 44.1kHz assert np.all(sample_rates == sample_rates[0]) return sample_rates[0] - def get_eeg_rate(self, mat_raws: List) -> int: + @staticmethod + def _get_eeg_rate(mat_raws: List) -> int: sample_rates = np.array([mat_raw["fsample"][0, 0] for mat_raw in mat_raws]) # is all 500Hz assert np.all( diff --git a/tests/test_brennan_dataclass.py b/tests/test_brennan_dataclass.py new file mode 100644 index 0000000..a1ca9de --- /dev/null +++ b/tests/test_brennan_dataclass.py @@ -0,0 +1,22 @@ +import torch +from hydra import initialize, compose + +from speech_decoding.dataclass.brennan2018 import Brennan2018Dataset + +with initialize(version_base=None, config_path="../configs/"): + args = compose(config_name="config.yaml") + + +def test_drop_last_segments(): + _X = torch.rand(2129, 33, 60, 360) + _audio = torch.rand(2129, 1, 48000) + onsets_path = "/home/sensho/speech_decoding/data/Brennan2018/AliceChapterOne-EEG.csv" + + X, audio, sentence_idxs = Brennan2018Dataset._drop_last_segments( + _X, _audio, onsets_path + ) + + print(X.shape) + + assert X.shape[0] < _X.shape[0] + assert X.shape[1:] == _X.shape[1:] From 6cb59ef4b8268b005649986fb9f7c8cfbe96a4ca Mon Sep 17 00:00:00 2001 From: SeanNobel Date: Fri, 30 Jun 2023 10:33:24 +0000 Subject: [PATCH 4/7] update questions --- assets/questioned_lines1.png | Bin 0 -> 129579 bytes assets/reports.md | 28 ++++++++++++++++------------ 2 files changed, 16 insertions(+), 12 deletions(-) create mode 100644 assets/questioned_lines1.png diff --git a/assets/questioned_lines1.png b/assets/questioned_lines1.png new file mode 100644 index 0000000000000000000000000000000000000000..459385ea96a12abd7279f8fb1030b1119f7bb79a GIT binary patch literal 129579 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%0AJ`ue@`5Uc{J^ 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 A`v3p{ literal 0 HcmV?d00001 diff --git a/assets/reports.md b/assets/reports.md index 8f2759f..3ee7154 100644 --- a/assets/reports.md +++ b/assets/reports.md @@ -1,6 +1,19 @@ -# Brennan2018 +# Questions -## Experiments +- About "We ensure that there is no identical sentences across splits" below, can it be rephrased as "We ensure that there is no two segments across splits that are coming from the same sentence"? + +- About "we restrict the test segments to those that contain a word at a fixed location (here 500ms into the sample)" below, can it be rephrased as "we dropped the test segments that don't contain any word until 500ms"? In that case why does it happend when we segment with word onsets? + + + +- After wav2vec2.0 embedding, audios become something like 50Hz (because wav2vec2.0 requires them to be originally 16kHz and it downsamples them a lot), so we need to upsample them to match brains' 120Hz. Do you actually do that? If so, which method do you use? We've tried linear interpolation by torchaudio and zero-padding but neither worked well. + +- Learnable temperature of CLIP loss was not mentioned and absent in equation (2). It was mentioned in the original CLIP paper but do you actually use it? + + +# Experiment results + +## Brennan2018 - Basically couldn't achieve performance in the paper. @@ -29,14 +42,5 @@ - Channel-wise - Robust Scaler was applied channel-wise -## Questions - -- After wav2vec2.0 embedding, audios become something like 50Hz (because wav2vec2.0 requires them to be originally 16kHz and it downsamples them a lot), so we need to upsample them to match brains' 120Hz. Do you actually do that? If so, which method do you use? We've tried linear interpolation by torchaudio and zero-padding but neither worked well. - -- Learnable temperature of CLIP loss was not mentioned and absent in equation (2). It was mentioned in the original CLIP paper but do you actually use it? - - -# Gwilliams2022 - -## Experiments +## Gwilliams2022 From 32a581d91527a9cc5a18e8ebfb79bb52b1c96562 Mon Sep 17 00:00:00 2001 From: SeanNobel Date: Fri, 30 Jun 2023 10:35:16 +0000 Subject: [PATCH 5/7] minor updates --- configs/config.yaml | 2 +- speech_decoding/utils/get_dataloaders.py | 1 + speech_decoding/utils/preproc_utils.py | 9 +++++++-- train.py | 13 ++++++++----- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/configs/config.yaml b/configs/config.yaml index 66b41c5..d2d79f9 100644 --- a/configs/config.yaml +++ b/configs/config.yaml @@ -18,7 +18,7 @@ split_mode: sentence # sentence, shallow, deep num_workers: 6 batch_size: 64 updates: 1200 -lr: 3e-4 +lr: 3.0e-4 epochs: 300 reduction: mean diff --git a/speech_decoding/utils/get_dataloaders.py b/speech_decoding/utils/get_dataloaders.py index 69a89b1..427520c 100644 --- a/speech_decoding/utils/get_dataloaders.py +++ b/speech_decoding/utils/get_dataloaders.py @@ -1,4 +1,5 @@ from torch.utils.data import DataLoader, RandomSampler, BatchSampler +from termcolor import cprint def get_dataloaders(train_set, test_set, args, g, seed_worker, test_bsz=None): diff --git a/speech_decoding/utils/preproc_utils.py b/speech_decoding/utils/preproc_utils.py index 53d0b68..063f1e1 100644 --- a/speech_decoding/utils/preproc_utils.py +++ b/speech_decoding/utils/preproc_utils.py @@ -104,7 +104,8 @@ def scale_and_clamp(X: torch.Tensor, clamp_lim: Union[int, float], channel_wise= if orig_dim == 4: num_segments = X.shape[0] - X = X.clone().flatten(end_dim=1) # ( segment * subject, channel, time//segment ) + X = X.clone().flatten(end_dim=1) + # ( segment * subject, channel, time//segment ) res = [] @@ -170,7 +171,11 @@ def check_preprocs(args, data_dir): # is_processed = np.all([v == args.preprocs[k] for k, v in settings.items() if not k in excluded_keys]) excluded_keys = ["preceding_chunk_for_baseline", "mode"] is_processed = np.all( - [v == args.preprocs[k] for k, v in settings.items() if k not in excluded_keys] + [ + v == args.preprocs[k] + for k, v in settings.items() + if k not in excluded_keys + ] ) if is_processed: cprint( diff --git a/train.py b/train.py index 2b41911..1056e79 100644 --- a/train.py +++ b/train.py @@ -130,11 +130,13 @@ def run(args: DictConfig) -> None: elif args.split_mode == "deep": train_set = torch.utils.data.Subset(dataset, range(train_size)) - test_set = torch.utils.data.Subset(dataset, range(train_size, train_size + test_size)) + test_set = torch.utils.data.Subset( + dataset, range(train_size, train_size + test_size) + ) elif args.split_mode == "sentence": # NOTE: sentence_idxs starts from 1 - num_sentences = dataset.sentence_idxs.max() + num_sentences = dataset.sentence_idxs.max() # 84 num_train_sentences = int(num_sentences * args.split_ratio) train_sentences, test_sentences = torch.utils.data.random_split( @@ -173,7 +175,9 @@ def run(args: DictConfig) -> None: raise ValueError("Unknown dataset") if args.use_wandb: - wandb.config = {k: v for k, v in dict(args).items() if k not in ["root_dir", "wandb"]} + wandb.config = { + k: v for k, v in dict(args).items() if k not in ["root_dir", "wandb"] + } wandb.init( project=args.wandb.project, entity=args.wandb.entity, @@ -200,8 +204,7 @@ def run(args: DictConfig) -> None: # Optimizer # -------------------- optimizer = torch.optim.Adam( - list(brain_encoder.parameters()) + list(loss_func.parameters()), - lr=float(args.lr), + list(brain_encoder.parameters()) + list(loss_func.parameters()), lr=args.lr ) # -------------------- From 394a29732692a757a8bf8dbd215eb4b3de8d4d1a Mon Sep 17 00:00:00 2001 From: SeanNobel Date: Fri, 30 Jun 2023 10:35:32 +0000 Subject: [PATCH 6/7] update TODOs --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bd1ef49..81b6cf1 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,8 @@ Works for Gwilliams2022 dataset and Brennan2018 dataset. ## TODOs -- [ ] Full reproducibility support. Will be useful for HP tuning. -- [ ] Match accuracy to numbers reported in the paper. -- [ ] Work with huge memory consumption issue in Gwilliams multiprocessing +- [ ] Achieve accuracies in the paper (Brennan -> Gwilliams). +- [ ] Reorganize Gwilliams dataclass to look more similar to Brennan (using Base class). # Usage From bf8d420e5478ed908d1e238081fd41bc43795685 Mon Sep 17 00:00:00 2001 From: SeanNobel Date: Fri, 30 Jun 2023 10:38:51 +0000 Subject: [PATCH 7/7] :+1: Spatial Attention tested --- tests/modules_for_test/models.py | 129 ++++++++++++------------------- tests/test_models.py | 45 +++++++---- 2 files changed, 77 insertions(+), 97 deletions(-) diff --git a/tests/modules_for_test/models.py b/tests/modules_for_test/models.py index 8440ec1..2b37a6d 100644 --- a/tests/modules_for_test/models.py +++ b/tests/modules_for_test/models.py @@ -17,10 +17,14 @@ def __init__(self, args): self.D1 = args.D1 self.K = args.K self.spatial_attention = SpatialAttention(args) - self.conv = nn.Conv1d(in_channels=self.D1, out_channels=self.D1, kernel_size=1, stride=1) + self.conv = nn.Conv1d( + in_channels=self.D1, out_channels=self.D1, kernel_size=1, stride=1 + ) # NOTE: The below implementations are equivalent to learning a matrix: - self.subject_matrix = nn.Parameter(torch.rand(self.num_subjects, self.D1, self.D1)) + self.subject_matrix = nn.Parameter( + torch.rand(self.num_subjects, self.D1, self.D1) + ) # self.subject_layer = [ # nn.Conv1d(in_channels=self.D1, out_channels=self.D1, kernel_size=1, stride=1, device=device) # for _ in range(self.num_subjects) @@ -54,11 +58,19 @@ def __init__(self, num_subjects, D1, K, dataset_name, d_drop): # self.spatial_attention = SpatialAttentionX(D1, K, dataset_name) self.spatial_attention = SpatialAttention(D1, K, dataset_name, d_drop) - self.conv = nn.Conv1d(in_channels=self.D1, out_channels=self.D1, kernel_size=1, stride=1) - self.subject_matrix = nn.Parameter(torch.rand(self.num_subjects, self.D1, self.D1)) + self.conv = nn.Conv1d( + in_channels=self.D1, out_channels=self.D1, kernel_size=1, stride=1 + ) + self.subject_matrix = nn.Parameter( + torch.rand(self.num_subjects, self.D1, self.D1) + ) self.subject_layer = [ nn.Conv1d( - in_channels=self.D1, out_channels=self.D1, kernel_size=1, stride=1, device=device + in_channels=self.D1, + out_channels=self.D1, + kernel_size=1, + stride=1, + device=device, ) for _ in range(self.num_subjects) ] @@ -85,22 +97,20 @@ class SpatialAttentionTest1(nn.Module): I reimplemented to SpatialAttentionVer2 (which is not the final version). """ - def __init__(self, D1, K, dataset_name, z_re=None, z_im=None): + def __init__(self, args, z_re, z_im): super(SpatialAttentionTest1, self).__init__() - self.D1 = D1 - self.K = K + self.D1 = args.D1 + self.K = args.K - if z_re is None or z_im is None: - self.z_re = nn.Parameter(torch.Tensor(self.D1, self.K, self.K)) - self.z_im = nn.Parameter(torch.Tensor(self.D1, self.K, self.K)) - nn.init.kaiming_uniform_(self.z_re, a=np.sqrt(5)) - nn.init.kaiming_uniform_(self.z_im, a=np.sqrt(5)) - else: - self.z_re = z_re - self.z_im = z_im + # self.z_re = nn.Parameter(torch.Tensor(self.D1, self.K, self.K)) + # self.z_im = nn.Parameter(torch.Tensor(self.D1, self.K, self.K)) + # nn.init.kaiming_uniform_(self.z_re, a=np.sqrt(5)) + # nn.init.kaiming_uniform_(self.z_im, a=np.sqrt(5)) + self.z_re = z_re + self.z_im = z_im - self.ch_locations_2d = ch_locations_2d(dataset_name).to(device) + self.ch_locations_2d = ch_locations_2d(args).to(device) def fourier_space(self, j, x: torch.Tensor, y: torch.Tensor): # x: ( 60, ) y: ( 60, ) a_j = 0 @@ -130,16 +140,18 @@ def forward(self, X): # ( B, C, T ) (=( 128, 60, 256 )) class SpatialAttentionTest2(nn.Module): """Faster version of SpatialAttentionVer1""" - def __init__(self, args): + def __init__(self, args, z_re, z_im): super(SpatialAttentionTest2, self).__init__() self.D1 = args.D1 self.K = args.K - self.z_re = nn.Parameter(torch.Tensor(self.D1, self.K, self.K)) - self.z_im = nn.Parameter(torch.Tensor(self.D1, self.K, self.K)) - nn.init.kaiming_uniform_(self.z_re, a=np.sqrt(5)) - nn.init.kaiming_uniform_(self.z_im, a=np.sqrt(5)) + # self.z_re = nn.Parameter(torch.Tensor(self.D1, self.K, self.K)) + # self.z_im = nn.Parameter(torch.Tensor(self.D1, self.K, self.K)) + # nn.init.kaiming_uniform_(self.z_re, a=np.sqrt(5)) + # nn.init.kaiming_uniform_(self.z_im, a=np.sqrt(5)) + self.z_re = z_re + self.z_im = z_im self.K_arange = torch.arange(self.K).to(device) @@ -153,12 +165,16 @@ def fourier_space(self, x: torch.Tensor, y: torch.Tensor): # x: ( 60, ) y: ( 60 # ( 32, 1, 60 ) + ( 1, 32, 60 ) -> ( 32, 32, 60 ) rad = rad1.unsqueeze(1) + rad2.unsqueeze(0) - real = torch.einsum("dkl,klc->dc", self.z_re, torch.cos(2 * torch.pi * rad)) # ( 270, 60 ) + real = torch.einsum( + "dkl,klc->dc", self.z_re, torch.cos(2 * torch.pi * rad) + ) # ( 270, 60 ) imag = torch.einsum("dkl,klc->dc", self.z_im, torch.sin(2 * torch.pi * rad)) return real + imag # ( 270, 60 ) - def fourier_space_orig(self, x: torch.Tensor, y: torch.Tensor): # x: ( 60, ) y: ( 60, ) + def fourier_space_orig( + self, x: torch.Tensor, y: torch.Tensor + ): # x: ( 60, ) y: ( 60, ) """Slower version of fourier_space""" a = torch.zeros(self.D1, x.shape[0], device=device) # ( 270, 60 ) @@ -166,10 +182,14 @@ def fourier_space_orig(self, x: torch.Tensor, y: torch.Tensor): # x: ( 60, ) y: for l in range(self.K): # This einsum is same as torch.stack([_d * c for _d in d]) a += torch.einsum( - "d,c->dc", self.z_re[:, k, l], torch.cos(2 * torch.pi * (k * x + l * y)) + "d,c->dc", + self.z_re[:, k, l], + torch.cos(2 * torch.pi * (k * x + l * y)), ) # ( 270, 60 ) a += torch.einsum( - "d,c->dc", self.z_im[:, k, l], torch.sin(2 * torch.pi * (k * x + l * y)) + "d,c->dc", + self.z_im[:, k, l], + torch.sin(2 * torch.pi * (k * x + l * y)), ) return a # ( 270, 60 ) @@ -200,7 +220,8 @@ def forward(self, SA_wts): drop_center_id = np.random.randint(self.num_channels) distances = np.sqrt( - (self.x - self.x[drop_center_id]) ** 2 + (self.y - self.y[drop_center_id]) ** 2 + (self.x - self.x[drop_center_id]) ** 2 + + (self.y - self.y[drop_center_id]) ** 2 ) is_dropped = torch.where(distances < self.d_drop, 0.0, 1.0).to(device) # cprint( @@ -210,60 +231,6 @@ def forward(self, SA_wts): return SA_wts * is_dropped -class SpatialAttentionTest(nn.Module): - """ - Same as SpatialAttentionVer2, but a little more concise. - Also SpatialAttention is added. - """ - - def __init__(self, D1, K, dataset_name, d_drop): - super(SpatialAttentionTest, self).__init__() - - # vectorize of k's and l's - a = [] - for k in range(K): - for l in range(K): - a.append((k, l)) - a = torch.tensor(a) - k, l = a[:, 0], a[:, 1] - - # vectorize x- and y-positions of the sensors - loc = ch_locations_2d(dataset_name) - x, y = loc[:, 0], loc[:, 1] - - # make a complex-valued parameter, reshape k,l into one dimension - self.z = nn.Parameter(torch.rand(size=(D1, K**2), dtype=torch.cfloat)).to(device) - - # NOTE: pre-compute the values of cos and sin (they depend on k, l, x and y which repeat) - phi = ( - 2 * torch.pi * (torch.einsum("k,x->kx", k, x) + torch.einsum("l,y->ly", l, y)) - ) # torch.Size([1024, 60])) - self.cos = torch.cos(phi).to(device) - self.sin = torch.cos(phi).to(device) - - self.spatial_dropout = SpatialDropout(x, y, d_drop) - - def forward(self, X): - # NOTE: do hadamard product and and sum over l and m (i.e. m, which is l X m) - re = torch.einsum("jm, me -> je", self.z.real, self.cos) # torch.Size([270, 60]) - im = torch.einsum("jm, me -> je", self.z.imag, self.sin) - a = ( - re + im - ) # essentially (unnormalized) weights with which to mix input channels into ouput channels - # ( D1, num_channels ) - - # NOTE: to get the softmax spatial attention weights over input electrodes, - # we don't compute exp, etc (as in the eq. 5), we take softmax instead: - SA_wts = F.softmax(a, dim=-1) # each row sums to 1 - # ( D1, num_channels ) - - SA_wts = self.spatial_dropout(SA_wts) - - return torch.einsum( - "oi,bit->bot", SA_wts, X - ) # each output is a diff weighted sum over each input channel - - class ConvBlockTest(nn.Module): def __init__(self, k, D1, D2): super(ConvBlockTest, self).__init__() diff --git a/tests/test_models.py b/tests/test_models.py index 5a0f008..806241c 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -5,22 +5,35 @@ from speech_decoding.models import * from tests.modules_for_test.models import * +torch.manual_seed(0) + +device = "cuda:0" if torch.cuda.is_available() else "cpu" + with initialize(version_base=None, config_path="../configs/"): - args = compose(config_name="config.yaml") + args = compose(config_name="config") + + with open_dict(args): + args.root_dir = "/home/sensho/speech_decoding" + + +def test_spatial_attention() -> None: + # NOTE: 60 channels is for Brennan2018 + input = torch.rand(8, 60, 360).to(device) + + sa = SpatialAttention(args).eval().to(device) + z_re = sa.z.real.reshape(args.D1, args.K, args.K) + z_im = sa.z.imag.reshape(args.D1, args.K, args.K) -# def test_spatial_attention() -> None: -# with initialize(version_base=None, config_path="../configs"): -# args = compose(config_name="config") -# with open_dict(args): -# # FIXME: get_original_cwd() can't be called -# args.root_dir = "/home/sensho/speech_decoding" # get_original_cwd() + sa_test1 = SpatialAttentionTest1(args, z_re, z_im).eval().to(device) + sa_test2 = SpatialAttentionTest2(args, z_re, z_im).eval().to(device) -# input = torch.rand(8, 208, 256).to(device) -# output = SpatialAttention(args)(input) -# output_test = SpatialAttentionTest2(args)(input) + output = sa(input) + output_test1 = sa_test1(input) + output_test2 = sa_test2(input) -# assert output == output_test + assert torch.allclose(output, output_test1, rtol=1e-4, atol=1e-5) + assert torch.allclose(output, output_test2) def test_classifier(): @@ -35,10 +48,10 @@ def test_classifier(): assert torch.allclose(similarity_train, similarity_test) -def test_standard_normalization(): - input = torch.rand(64, 1024, 360) - output = BrainEncoder._standard_normalization(input) +# def test_standard_normalization(): +# input = torch.rand(64, 1024, 360) +# output = BrainEncoder._standard_normalization(input) - input0_norm = (input[0] - input[0].mean()) / input[0].std() +# input0_norm = (input[0] - input[0].mean()) / input[0].std() - assert torch.equal(output[0], input0_norm) +# assert torch.equal(output[0], input0_norm)