{"metadata":{"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":59093,"databundleVersionId":7469972,"sourceType":"competition"},{"sourceId":7392775,"sourceType":"datasetVersion","datasetId":4297782},{"sourceId":7570342,"sourceType":"datasetVersion","datasetId":4407194},{"sourceId":7752462,"sourceType":"datasetVersion","datasetId":4382744},{"sourceId":7776446,"sourceType":"datasetVersion","datasetId":4550181},{"sourceId":7945384,"sourceType":"datasetVersion","datasetId":4671804},{"sourceId":7987619,"sourceType":"datasetVersion","datasetId":4417235}],"dockerImageVersionId":30636,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.10.12"},"papermill":{"default_parameters":{},"duration":361.623438,"end_time":"2024-03-30T16:46:24.636183","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2024-03-30T16:40:23.012745","version":"2.4.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Features+Head Ensemble Starter for HMS Brain Comp\nWe can train 10 model and data variations: (all models included)\n\n| MODEL | DATA TYPE | CV | LB | KNOWLEDGE DISTILLATION | TRAINING TIME| NOTES |\n|----------------|-----------|----------|---|--|--|--|\n| EfficientNetB2 | K | 0.6123 | 0.41 | - | 2 hours and 58 minutes |K: Kaggle's spectrograms|\n| EfficientNetB2 | E | 0.6288 | 0.39 | - | 2 hours and 57 minutes |E: EEG's spectrograms|\n| WaveNet | R | 0.6951 | 0.4 | Yes | 1 hours and 49 minutes |R: Raw EEG signals|\n| ResNet1D GRU | R2 | 0.7899 | 0.46 | Yes | 40 minutes |R2: Raw EEG signals|\n| EfficientNetB2 | KE | 0.5323 | 0.34 | Yes | 3 hours and 12 minutes |KE: Kaggle's and EEG's spectrograms|\n| EfficientNetB2 + WaveNet | KR | 0.5912 | 0.39 | - | 4 hours and 20 minutes |KR: Kaggle's spectrograms and Raw EEG signals|\n| EfficientNetB2 + WaveNet | ER | 0.6085 | 0.38 | - | 4 hours and 22 minutes |ER: EEG's spectrograms and Raw EEG signals|\n| EfficientNetB2 + WaveNet | KER | - | 0.33 | Yes | 4 hours and 30 minutes |KER: Kaggle's, EEG's spectrograms and Raw EEG signals|\n| EfficientNetB2 | K+E | 0.5738 | 0.37 | - | 5 hours and 42 minutes |K+E: Data spectrogram augmentation|\n| EfficientNetB2 | K+E+KE | 0.5444 | 0.34 | Yes | 8 hours and 52 minutes |K+E+KE: Data spectrogram augmentation|\n\nThank you for your contribution:\nKoolo(@zijiangyang1116) JAVAZERO(@jimmyisme1) CipherMind(@chrismorel12) Pr04Ark(@pr0ark) Andrey(@andrey67)\n\nFeatures+Head Starter uses Chris Deotte's Kaggle dataset [here][1]. Also Uses Chris's EEG spectrograms [here][3] (modified version). The Raw EEG signals can be found [here][6]. A modified version of [ResNet1D][7] were added, work done by Nischay Dhankhar. This notebook is a direct descendent of Chris's notebooks [EfficientNet][2] and [WaveNet][4]\n\n[1]: https://www.kaggle.com/datasets/cdeotte/brain-spectrograms\n[2]: https://www.kaggle.com/code/cdeotte/efficientnetb2-starter-lb-0-57\n[3]: https://www.kaggle.com/datasets/nartaa/eeg-spectrograms\n[4]: https://www.kaggle.com/competitions/hms-harmful-brain-activity-classification/discussion/468684\n[6]: https://www.kaggle.com/datasets/nartaa/hms-eeg\n[7]: https://www.kaggle.com/code/nischaydnk/lightning-1d-eegnet-training-pipeline-hbs","metadata":{"papermill":{"duration":0.00767,"end_time":"2024-03-30T16:40:27.803114","exception":false,"start_time":"2024-03-30T16:40:27.795444","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import librosa\nimport os, random\nimport tensorflow\nimport tensorflow as tf\nimport albumentations as albu\nimport matplotlib.pyplot as plt\nimport pandas as pd, numpy as np\nfrom scipy.signal import butter, lfilter\nimport tensorflow.keras.backend as K, gc\nfrom tensorflow.keras.models import load_model\nfrom sklearn.model_selection import KFold, GroupKFold\n\nLOAD_BACKBONE_FROM = '/kaggle/input/efficientnetb-tf-keras/EfficientNetB2.h5'\nLOAD_MODELS_FROM = '/kaggle/input/features-head-starter-models'\nHMS_PATH = '/kaggle/input/hms-harmful-brain-activity-classification'\nMODEL = {'KER': 64} # Setup the model for Training\nfor DATA_TYPE in MODEL: pass # K|E|R|R2|KE|KR|ER|KER|K+E|K+E+KE\nUSE_PROCESSED = True # Use processed downsampled Raw EEG \nKNOWLEDGE_DISTILLATION = True # Use distilled dataset for training\nTEST_MODE = False # USE 500 samples for quick testing\nTEST_ENSEMBLE = False # Local Ensemble CV Testing\nSUBMISSION = True\n\n# Setup for ensemble\nENSEMBLE = False\nMODELS = {\n          'K'     : 43, # 'LB':0.41 Kaggle's spectrogram model version\n          'E'     : 42, # 'LB':0.39 EEG's spectrogram model version\n          'R'     : 60, # 'LB':0.4 EEG's Raw wavenet model version, trained on single GPU\n          'R2'    : 61, # 'LB':0.46 EEG's Raw ResNet1D model version, trained on single GPU\n          'KE'    : 58, # 'LB':0.34 Kaggle's and EEG's spectrogram model version\n          'KR'    : 48, # 'LB':0.39 Kaggle's spectrogram and Raw model version\n          'ER'    : 49, # 'LB':0.38 EEG's spectrogram and Raw model version\n          'KER'   : 64, # 'LB':0.33 EEG's, Kaggle's spectrograms and Raw model version\n          'K+E'   : 51, # 'LB':0.37 Data spectrogram augmentation model version\n          'K+E+KE': 59, # 'LB':0.34 Data spectrogram augmentation model version\n         }\n\nnp.random.seed(42)\nrandom.seed(42)\ntf.random.set_seed(42)\n\n# USE SINGLE GPU, MULTIPLE GPUS \ngpus = tf.config.list_physical_devices('GPU')\n# WE USE MIXED PRECISION\ntf.config.optimizer.set_experimental_options({\"auto_mixed_precision\": True})\nif len(gpus)>1:\n    strategy = tf.distribute.MirroredStrategy()\n    print(f'Using {len(gpus)} GPUs')\nelse:\n    strategy = tf.distribute.OneDeviceStrategy(device=\"/gpu:0\")\n    print(f'Using {len(gpus)} GPU')","metadata":{"papermill":{"duration":24.731825,"end_time":"2024-03-30T16:40:52.541845","exception":false,"start_time":"2024-03-30T16:40:27.810020","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load and create Non-Overlapping Eeg Id Train Data\nThe competition data description says that test data does not have multiple crops from the same `eeg_id`. Therefore we will train and validate using only 1 crop per `eeg_id`. There is a discussion about this [here][1].\n\n[1]: https://www.kaggle.com/competitions/hms-harmful-brain-activity-classification/discussion/467021","metadata":{"papermill":{"duration":0.007285,"end_time":"2024-03-30T16:40:52.556589","exception":false,"start_time":"2024-03-30T16:40:52.549304","status":"completed"},"tags":[]}},{"cell_type":"code","source":"TARGETS = ['seizure_vote', 'lpd_vote', 'gpd_vote', 'lrda_vote', 'grda_vote', 'other_vote']\nFEATS2 = ['Fp1','T3','C3','O1','Fp2','C4','T4','O2']\n\ndef eeg_from_parquet(parquet_path):\n\n    eeg = pd.read_parquet(parquet_path, columns=FEATS2)\n    rows = len(eeg)\n    offset = (rows-10_000)//2\n    eeg = eeg.iloc[offset:offset+10_000]\n    data = np.zeros((10_000,len(FEATS2)))\n    for j,col in enumerate(FEATS2):\n        \n        # FILL NAN\n        x = eeg[col].values.astype('float32')\n        m = np.nanmean(x)\n        if np.isnan(x).mean()<1: x = np.nan_to_num(x,nan=m)\n        else: x[:] = 0\n        \n        data[:,j] = x\n\n    return data\n\ndef add_kl(data):\n    labels = data[TARGETS].values + 1e-5\n    data['kl'] = tf.keras.losses.KLDivergence(reduction='none')(\n        np.array([[1/6]*6]*len(data)),labels)\n    return data\n    \nif not SUBMISSION:\n    train = pd.read_csv('/kaggle/input/hms-harmful-brain-activity-classification/train.csv')\n    TARGETS = ['seizure_vote', 'lpd_vote', 'gpd_vote', 'lrda_vote', 'grda_vote', 'other_vote']\n    META = ['spectrogram_id','spectrogram_label_offset_seconds','patient_id','expert_consensus']\n    train = train.groupby('eeg_id')[META+TARGETS\n                           ].agg({**{m:'first' for m in META},**{t:'sum' for t in TARGETS}}).reset_index() \n    train[TARGETS] = train[TARGETS]/train[TARGETS].values.sum(axis=1,keepdims=True)\n    train.columns = ['eeg_id','spec_id','offset','patient_id','target'] + TARGETS\n    train = add_kl(train)\n    pred = pd.read_csv('/kaggle/input/knowledge-distillation/dataset_KD.csv')\n    train_KD = train.copy()\n    train_KD[TARGETS] = pred[TARGETS]\n    print(train.head(1).to_string())\n    print(train_KD.head(1).to_string())","metadata":{"papermill":{"duration":0.022949,"end_time":"2024-03-30T16:40:52.586771","exception":false,"start_time":"2024-03-30T16:40:52.563822","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Read Train Spectrograms and EEGs\n\nWe can read 3 file from Chris's [Kaggle dataset here][1] which contains all the 11k spectrograms. From Chris's modified EEG spectrogram [here][2]. From Raw EEG signals [here][3]\n\n[1]: https://www.kaggle.com/datasets/cdeotte/brain-spectrograms\n[2]: https://www.kaggle.com/datasets/nartaa/eeg-spectrograms\n[3]: https://www.kaggle.com/datasets/nartaa/hms-eeg","metadata":{"papermill":{"duration":0.00695,"end_time":"2024-03-30T16:40:52.600701","exception":false,"start_time":"2024-03-30T16:40:52.593751","status":"completed"},"tags":[]}},{"cell_type":"code","source":"%%time\nif not SUBMISSION:\n    # FOR TESTING SET TEST_MODE TO TRUE\n    if TEST_MODE:\n        USE_PROCESSED = False\n        train = train.sample(500,random_state=42).reset_index(drop=True)\n        spectrograms = {}\n        for i,e in enumerate(train.spec_id.values):\n            if i%100==0: print(i,', ',end='')\n            x = pd.read_parquet(f'{HMS_PATH}/train_spectrograms/{e}.parquet')\n            spectrograms[e] = x.values\n        all_eegs = {}\n        for i,e in enumerate(train.eeg_id.values):\n            if i%100==0: print(i,', ',end='')\n            x = np.load(f'/kaggle/input/eeg-spectrograms/EEG_Spectrograms/{e}.npy')\n            all_eegs[e] = x\n        all_raw_eegs = {}\n        for i,e in enumerate(train.eeg_id.values):\n            if i%100==0: print(i,', ',end='')\n            x = eeg_from_parquet(f'{HMS_PATH}/train_eegs/{e}.parquet')              \n            all_raw_eegs[e] = x\n    else:\n        spectrograms = None\n        all_eegs = None\n        all_raw_eegs = None\n        if TEST_ENSEMBLE or DATA_TYPE in ['K','KE','K+E','K+E+KE','KR','KER']:\n            spectrograms = np.load('/kaggle/input/brain-spectrograms/specs.npy',allow_pickle=True).item()\n        if TEST_ENSEMBLE or DATA_TYPE in ['E','KE','K+E','K+E+KE','ER','KER']:\n            all_eegs = np.load('/kaggle/input/eeg-spectrograms/eeg_specs.npy',allow_pickle=True).item()\n        if TEST_ENSEMBLE or DATA_TYPE in ['R','R2','KR','ER','KER']:\n            if USE_PROCESSED:\n                all_raw_eegs = np.load('/kaggle/input/hms-eeg/eegs_processed.npy',allow_pickle=True).item()\n            else:\n                all_raw_eegs = np.load('/kaggle/input/hms-eeg/eegs.npy',allow_pickle=True).item()","metadata":{"papermill":{"duration":0.02183,"end_time":"2024-03-30T16:40:52.629747","exception":false,"start_time":"2024-03-30T16:40:52.607917","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# DATA GENERATOR\nThis data generator outputs 512x512x3, the spectrogram and eeg images are concatenated all togother in a single image. For using data augmention you can set `augment = True` when creating the train data generator.","metadata":{"papermill":{"duration":0.007197,"end_time":"2024-03-30T16:40:52.644058","exception":false,"start_time":"2024-03-30T16:40:52.636861","status":"completed"},"tags":[]}},{"cell_type":"code","source":"FEATS2 = ['Fp1','T3','C3','O1','Fp2','C4','T4','O2']\nFEAT2IDX = {x:y for x,y in zip(FEATS2,range(len(FEATS2)))}\nFEATS = [['Fp1','F7','T3','T5','O1'],\n         ['Fp1','F3','C3','P3','O1'],\n         ['Fp2','F8','T4','T6','O2'],\n         ['Fp2','F4','C4','P4','O2']]\n    \nclass DataGenerator():\n    'Generates data for Keras'\n    def __init__(self, data, specs=None, eeg_specs=None, raw_eegs=None , augment=False, mode='train', data_type=DATA_TYPE): \n        self.augment = augment\n        self.mode = mode\n        self.data_type = data_type\n        self.data = self.build_data(data.copy())\n        self.specs = specs\n        self.eeg_specs = eeg_specs\n        self.raw_eegs = raw_eegs\n        self.on_epoch_end()\n    \n    def build_data(self,data):\n        if self.data_type in ['K+E']:\n            data_dup = pd.concat([data] * 2, ignore_index=True)\n            data_dup.loc[:len(data),'data_type'] = 'K'\n            data_dup.loc[len(data):,'data_type'] = 'E'\n            data = data_dup\n        elif self.data_type in ['K+E+KE']:\n            data_trp = pd.concat([data] * 3, ignore_index=True)\n            data_trp.loc[:len(data),'data_type'] = 'K'\n            data_trp.loc[len(data):len(data)*2,'data_type'] = 'E'\n            data_trp.loc[len(data)*2:,'data_type'] = 'KE'\n            data = data_trp\n        else:\n            data['data_type'] = self.data_type\n        return data\n        \n    def __len__(self):\n        return self.data.shape[0]\n\n    def __getitem__(self, index):\n        X, y = self.data_generation(index)\n        if self.augment: X = self.augmentation(X)\n        return X, y\n    \n    def __call__(self):\n        for i in range(self.__len__()):\n            yield self.__getitem__(i)\n            \n            if i == self.__len__()-1:\n                self.on_epoch_end()\n                \n    def on_epoch_end(self):\n        if self.mode=='train': \n            self.data = self.data.sample(frac=1).reset_index(drop=True)\n    \n    def data_generation(self, index):\n        row = self.data.iloc[index]\n        if row.data_type == 'KE':\n            X,y = self.generate_all_specs(index)\n        elif row.data_type in ['K','E']:\n            X,y = self.generate_specs(index)\n        elif row.data_type in ['R','R2']:\n            X,y = self.generate_raw(index)\n        elif row.data_type in ['ER','KR']:\n            X1,y = self.generate_specs(index)\n            X2,y = self.generate_raw(index)\n            X = (X1,X2)\n        elif row.data_type in ['KER']:\n            X1,y = self.generate_all_specs(index)\n            X2,y = self.generate_raw(index)\n            X = (X1,X2)\n        return X,y\n    \n    def generate_all_specs(self, index):\n        X = np.zeros((512,512,3),dtype='float32')\n        y = np.zeros((6,),dtype='float32')\n        \n        row = self.data.iloc[index]\n        if self.mode=='test': \n            offset = 0\n        else:\n            offset = int(row.offset/2)\n        \n        eeg = self.eeg_specs[row.eeg_id]\n        spec = self.specs[row.spec_id]\n        \n        imgs = [spec[offset:offset+300,k*100:(k+1)*100].T for k in [0,2,1,3]] # to match kaggle with eeg\n        img = np.stack(imgs,axis=-1)\n        # LOG TRANSFORM SPECTROGRAM\n        img = np.clip(img,np.exp(-4),np.exp(8))\n        img = np.log(img)\n            \n        # STANDARDIZE PER IMAGE\n        img = np.nan_to_num(img, nan=0.0)    \n            \n        mn = img.flatten().min()\n        mx = img.flatten().max()\n        ep = 1e-5\n        img = 255 * (img - mn) / (mx - mn + ep)\n        \n        X[0_0+56:100+56,:256,0] = img[:,22:-22,0] # LL_k\n        X[100+56:200+56,:256,0] = img[:,22:-22,2] # RL_k\n        X[0_0+56:100+56,:256,1] = img[:,22:-22,1] # LP_k\n        X[100+56:200+56,:256,1] = img[:,22:-22,3] # RP_k\n        X[0_0+56:100+56,:256,2] = img[:,22:-22,2] # RL_k\n        X[100+56:200+56,:256,2] = img[:,22:-22,1] # LP_k\n        \n        X[0_0+56:100+56,256:,0] = img[:,22:-22,0] # LL_k\n        X[100+56:200+56,256:,0] = img[:,22:-22,2] # RL_k\n        X[0_0+56:100+56,256:,1] = img[:,22:-22,1] # LP_k\n        X[100+56:200+56,256:,1] = img[:,22:-22,3] # RP_K\n        \n        # EEG\n        img = eeg\n        mn = img.flatten().min()\n        mx = img.flatten().max()\n        ep = 1e-5\n        img = 255 * (img - mn) / (mx - mn + ep)\n        X[200+56:300+56,:256,0] = img[:,22:-22,0] # LL_e\n        X[300+56:400+56,:256,0] = img[:,22:-22,2] # RL_e\n        X[200+56:300+56,:256,1] = img[:,22:-22,1] # LP_e\n        X[300+56:400+56,:256,1] = img[:,22:-22,3] # RP_e\n        X[200+56:300+56,:256,2] = img[:,22:-22,2] # RL_e\n        X[300+56:400+56,:256,2] = img[:,22:-22,1] # LP_e\n        \n        X[200+56:300+56,256:,0] = img[:,22:-22,0] # LL_e\n        X[300+56:400+56,256:,0] = img[:,22:-22,2] # RL_e\n        X[200+56:300+56,256:,1] = img[:,22:-22,1] # LP_e\n        X[300+56:400+56,256:,1] = img[:,22:-22,3] # RP_e\n\n        if self.mode!='test':\n            y[:] = row[TARGETS]\n        \n        return X,y\n    \n    def generate_specs(self, index):\n        X = np.zeros((512,512,3),dtype='float32')\n        y = np.zeros((6,),dtype='float32')\n        \n        row = self.data.iloc[index]\n        if self.mode=='test': \n            offset = 0\n        else:\n            offset = int(row.offset/2)\n        \n        if row.data_type in ['E','ER']:\n            img = self.eeg_specs[row.eeg_id]\n        elif row.data_type in ['K','KR']:\n            spec = self.specs[row.spec_id]\n            imgs = [spec[offset:offset+300,k*100:(k+1)*100].T for k in [0,2,1,3]] # to match kaggle with eeg\n            img = np.stack(imgs,axis=-1)\n            # LOG TRANSFORM SPECTROGRAM\n            img = np.clip(img,np.exp(-4),np.exp(8))\n            img = np.log(img)\n            \n            # STANDARDIZE PER IMAGE\n            img = np.nan_to_num(img, nan=0.0)    \n            \n        mn = img.flatten().min()\n        mx = img.flatten().max()\n        ep = 1e-5\n        img = 255 * (img - mn) / (mx - mn + ep)\n        \n        X[0_0+56:100+56,:256,0] = img[:,22:-22,0]\n        X[100+56:200+56,:256,0] = img[:,22:-22,2]\n        X[0_0+56:100+56,:256,1] = img[:,22:-22,1]\n        X[100+56:200+56,:256,1] = img[:,22:-22,3]\n        X[0_0+56:100+56,:256,2] = img[:,22:-22,2]\n        X[100+56:200+56,:256,2] = img[:,22:-22,1]\n        \n        X[0_0+56:100+56,256:,0] = img[:,22:-22,0]\n        X[100+56:200+56,256:,0] = img[:,22:-22,1]\n        X[0_0+56:100+56,256:,1] = img[:,22:-22,2]\n        X[100+56:200+56,256:,1] = img[:,22:-22,3]\n        \n        X[200+56:300+56,:256,0] = img[:,22:-22,0]\n        X[300+56:400+56,:256,0] = img[:,22:-22,1]\n        X[200+56:300+56,:256,1] = img[:,22:-22,2]\n        X[300+56:400+56,:256,1] = img[:,22:-22,3]\n        X[200+56:300+56,:256,2] = img[:,22:-22,3]\n        X[300+56:400+56,:256,2] = img[:,22:-22,2]\n        \n        X[200+56:300+56,256:,0] = img[:,22:-22,0]\n        X[300+56:400+56,256:,0] = img[:,22:-22,2]\n        X[200+56:300+56,256:,1] = img[:,22:-22,1]\n        X[300+56:400+56,256:,1] = img[:,22:-22,3]\n        \n        if self.mode!='test':\n            y[:] = row[TARGETS]\n        \n        return X,y\n    \n    def generate_raw(self,index):\n        if USE_PROCESSED and self.mode!='test':\n            X = np.zeros((2_000,8),dtype='float32')\n            y = np.zeros((6,),dtype='float32')\n            row = self.data.iloc[index]\n            X = self.raw_eegs[row.eeg_id]\n            y[:] = row[TARGETS]\n            return X,y\n        \n        X = np.zeros((10_000,8),dtype='float32')\n        y = np.zeros((6,),dtype='float32')\n        \n        row = self.data.iloc[index]\n        eeg = self.raw_eegs[row.eeg_id]\n            \n        # FEATURE ENGINEER\n        X[:,0] = eeg[:,FEAT2IDX['Fp1']] - eeg[:,FEAT2IDX['T3']]\n        X[:,1] = eeg[:,FEAT2IDX['T3']] - eeg[:,FEAT2IDX['O1']]\n            \n        X[:,2] = eeg[:,FEAT2IDX['Fp1']] - eeg[:,FEAT2IDX['C3']]\n        X[:,3] = eeg[:,FEAT2IDX['C3']] - eeg[:,FEAT2IDX['O1']]\n            \n        X[:,4] = eeg[:,FEAT2IDX['Fp2']] - eeg[:,FEAT2IDX['C4']]\n        X[:,5] = eeg[:,FEAT2IDX['C4']] - eeg[:,FEAT2IDX['O2']]\n            \n        X[:,6] = eeg[:,FEAT2IDX['Fp2']] - eeg[:,FEAT2IDX['T4']]\n        X[:,7] = eeg[:,FEAT2IDX['T4']] - eeg[:,FEAT2IDX['O2']]\n            \n        # STANDARDIZE\n        X = np.clip(X,-1024,1024)\n        X = np.nan_to_num(X, nan=0) / 32.0\n            \n        # BUTTER LOW-PASS FILTER\n        X = self.butter_lowpass_filter(X)\n        # Downsample\n        X = X[::5,:]\n        \n        if self.mode!='test':\n            y[:] = row[TARGETS]\n                \n        return X,y\n        \n    def butter_lowpass_filter(self, data, cutoff_freq=20, sampling_rate=200, order=4):\n        nyquist = 0.5 * sampling_rate\n        normal_cutoff = cutoff_freq / nyquist\n        b, a = butter(order, normal_cutoff, btype='low', analog=False)\n        filtered_data = lfilter(b, a, data, axis=0)\n        return filtered_data\n    \n    def resize(self, img,size):\n        composition = albu.Compose([\n                albu.Resize(size[0],size[1])\n            ])\n        return composition(image=img)['image']\n            \n    def augmentation(self, img):\n        composition = albu.Compose([\n                albu.HorizontalFlip(p=0.4)\n            ])\n        return composition(image=img)['image']\n\ndef spectrogram_from_eeg(parquet_path):\n    \n    # LOAD MIDDLE 50 SECONDS OF EEG SERIES\n    eeg = pd.read_parquet(parquet_path)\n    middle = (len(eeg)-10_000)//2\n    eeg = eeg.iloc[middle:middle+10_000]\n    \n    # VARIABLE TO HOLD SPECTROGRAM\n    img = np.zeros((100,300,4),dtype='float32')\n\n    for k in range(4):\n        COLS = FEATS[k]\n        \n        for kk in range(4):\n            # FILL NANS\n            x1 = eeg[COLS[kk]].values\n            x2 = eeg[COLS[kk+1]].values\n            m = np.nanmean(x1)\n            if np.isnan(x1).mean()<1: x1 = np.nan_to_num(x1,nan=m)\n            else: x1[:] = 0\n            m = np.nanmean(x2)\n            if np.isnan(x2).mean()<1: x2 = np.nan_to_num(x2,nan=m)\n            else: x2[:] = 0\n                \n            # COMPUTE PAIR DIFFERENCES\n            x = x1 - x2\n\n            # RAW SPECTROGRAM\n            mel_spec = librosa.feature.melspectrogram(y=x, sr=200, hop_length=len(x)//300, \n                  n_fft=1024, n_mels=100, fmin=0, fmax=20, win_length=128)\n            \n            # LOG TRANSFORM\n            width = (mel_spec.shape[1]//30)*30\n            mel_spec_db = librosa.power_to_db(mel_spec, ref=np.max).astype(np.float32)[:,:width]\n            img[:,:,k] += mel_spec_db\n                \n        # AVERAGE THE 4 MONTAGE DIFFERENCES\n        img[:,:,k] /= 4.0\n          \n    return img\n\ndef eeg_from_parquet(parquet_path):\n\n    eeg = pd.read_parquet(parquet_path, columns=FEATS2)\n    rows = len(eeg)\n    offset = (rows-10_000)//2\n    eeg = eeg.iloc[offset:offset+10_000]\n    data = np.zeros((10_000,len(FEATS2)))\n    for j,col in enumerate(FEATS2):\n        \n        # FILL NAN\n        x = eeg[col].values.astype('float32')\n        m = np.nanmean(x)\n        if np.isnan(x).mean()<1: x = np.nan_to_num(x,nan=m)\n        else: x[:] = 0\n        \n        data[:,j] = x\n\n    return data","metadata":{"papermill":{"duration":0.078108,"end_time":"2024-03-30T16:40:52.729451","exception":false,"start_time":"2024-03-30T16:40:52.651343","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# DISPLAY DATA GENERATOR\nBelow we display example data generator spectrogram images and raw EEG signals.","metadata":{"papermill":{"duration":0.007184,"end_time":"2024-03-30T16:40:52.744217","exception":false,"start_time":"2024-03-30T16:40:52.737033","status":"completed"},"tags":[]}},{"cell_type":"code","source":"if not SUBMISSION: \n    params = {'specs':spectrograms, 'eeg_specs':all_eegs, 'raw_eegs':all_raw_eegs}\n    gen = DataGenerator(train, augment=False, **params)\n    for x,y in gen:\n        break\n        \n    if DATA_TYPE in ['E','K','KE','K+E','K+E+KE','KR','ER','KER']:\n        x1 = x[0] if DATA_TYPE in ['KR','ER','KER'] else x\n        plt.imshow(x1[:,:,0])\n        plt.title(f'Target = {y.round(1)}',size=12)\n        plt.yticks([])\n        plt.ylabel('Frequencies (Hz)',size=12)\n        plt.xlabel('Time (sec)',size=12)\n    \n    if DATA_TYPE in ['R','R2','KR','ER','KER']:\n        x1 = x[1] if DATA_TYPE in ['KR','ER','KER'] else x\n        plt.figure(figsize=(20,4))\n        offset = 0\n        for j in range(x1.shape[-1]):\n            if j!=0: offset -= x1[:,j].min()\n            plt.plot(range(2_000),x1[:,j]+offset,label=f'feature {j+1}')\n            offset += x1[:,j].max()\n        plt.legend()\n        \n    plt.show()","metadata":{"papermill":{"duration":0.019545,"end_time":"2024-03-30T16:40:52.771029","exception":false,"start_time":"2024-03-30T16:40:52.751484","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# TRAINING","metadata":{"papermill":{"duration":0.007958,"end_time":"2024-03-30T16:40:52.786456","exception":false,"start_time":"2024-03-30T16:40:52.778498","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## LEARNING RATE","metadata":{"papermill":{"duration":0.007382,"end_time":"2024-03-30T16:40:52.801104","exception":false,"start_time":"2024-03-30T16:40:52.793722","status":"completed"},"tags":[]}},{"cell_type":"code","source":"\nif not SUBMISSION:\n\n    def lrfn(epoch):\n        e3 = 1e-3 if DATA_TYPE in ['R'] else 1e-4\n        return [1e-3,1e-3,e3,1e-4,1e-5][epoch]\n\n    LR = tf.keras.callbacks.LearningRateScheduler(lrfn, verbose = True)\n    \n    def lrfn2(epoch):\n        return [1e-5,1e-5,1e-6][epoch]\n\n    LR2 = tf.keras.callbacks.LearningRateScheduler(lrfn2, verbose = True)","metadata":{"papermill":{"duration":0.015102,"end_time":"2024-03-30T16:40:52.823761","exception":false,"start_time":"2024-03-30T16:40:52.808659","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## MODEL AND UTILITY FUNCTIONS","metadata":{"papermill":{"duration":0.007285,"end_time":"2024-03-30T16:40:52.838476","exception":false,"start_time":"2024-03-30T16:40:52.831191","status":"completed"},"tags":[]}},{"cell_type":"code","source":"from tensorflow.keras.layers import Input, Dense, Multiply, Add, Conv1D, Concatenate\nfrom tensorflow.keras.layers import BatchNormalization, Bidirectional,GRU, MaxPooling1D, ReLU\n\ndef build_model(data_type=DATA_TYPE):\n    K.clear_session()\n    with strategy.scope():\n        if data_type in ['R']:\n            model = build_wave_model()\n        if data_type in ['R2']:\n            model = build_Resnet1D_GRU_model()\n        elif data_type in ['K','E','KE','K+E','K+E+KE']:\n            model = build_spec_model()\n        elif data_type in ['KR','ER','KER']:\n            model = build_hybrid_model()\n    return model\n\ndef build_spec_model(hybrid=False):  \n    inp = tf.keras.layers.Input((512,512,3))\n    base_model = load_model(f'{LOAD_BACKBONE_FROM}')    \n    x = base_model(inp)\n    x = tf.keras.layers.GlobalAveragePooling2D()(x)\n    if not hybrid:\n        x = tf.keras.layers.Dense(6,activation='softmax', dtype='float32')(x)\n    model = tf.keras.Model(inputs=inp, outputs=x)\n    opt = tf.keras.optimizers.Adam(learning_rate = 1e-3)\n    loss = tf.keras.losses.KLDivergence()\n    model.compile(loss=loss, optimizer=opt)  \n    return model\n\ndef wave_block(x, filters, kernel_size, n):\n    dilation_rates = [2**i for i in range(n)]\n    x = Conv1D(filters = filters,\n               kernel_size = 1,\n               padding = 'same')(x)\n    res_x = x\n    for dilation_rate in dilation_rates:\n        tanh_out = Conv1D(filters = filters,\n                          kernel_size = kernel_size,\n                          padding = 'same', \n                          activation = 'tanh', \n                          dilation_rate = dilation_rate)(x)\n        sigm_out = Conv1D(filters = filters,\n                          kernel_size = kernel_size,\n                          padding = 'same',\n                          activation = 'sigmoid', \n                          dilation_rate = dilation_rate)(x)\n        x = Multiply()([tanh_out, sigm_out])\n        x = Conv1D(filters = filters,\n                   kernel_size = 1,\n                   padding = 'same')(x)\n        res_x = Add()([res_x, x])\n    return res_x\n\ndef build_wave_model(hybrid=False):\n        \n    # INPUT \n    inp = tf.keras.Input(shape=(2_000,8))\n    \n    ############\n    # FEATURE EXTRACTION SUB MODEL\n    inp2 = tf.keras.Input(shape=(2_000,1))\n    x = wave_block(inp2, 8, 4, 6)\n    x = wave_block(x, 16, 4, 6)\n    x = wave_block(x, 32, 4, 6)\n    x = wave_block(x, 64, 4, 6)\n    model2 = tf.keras.Model(inputs=inp2, outputs=x)\n    ###########\n    \n    # LEFT TEMPORAL CHAIN\n    x1 = model2(inp[:,:,0:1])\n    x1 = tf.keras.layers.GlobalAveragePooling1D()(x1)\n    x2 = model2(inp[:,:,1:2])\n    x2 = tf.keras.layers.GlobalAveragePooling1D()(x2)\n    z1 = tf.keras.layers.Average()([x1,x2])\n    \n    # LEFT PARASAGITTAL CHAIN\n    x1 = model2(inp[:,:,2:3])\n    x1 = tf.keras.layers.GlobalAveragePooling1D()(x1)\n    x2 = model2(inp[:,:,3:4])\n    x2 = tf.keras.layers.GlobalAveragePooling1D()(x2)\n    z2 = tf.keras.layers.Average()([x1,x2])\n    \n    # RIGHT PARASAGITTAL CHAIN\n    x1 = model2(inp[:,:,4:5])\n    x1 = tf.keras.layers.GlobalAveragePooling1D()(x1)\n    x2 = model2(inp[:,:,5:6])\n    x2 = tf.keras.layers.GlobalAveragePooling1D()(x2)\n    z3 = tf.keras.layers.Average()([x1,x2])\n    \n    # RIGHT TEMPORAL CHAIN\n    x1 = model2(inp[:,:,6:7])\n    x1 = tf.keras.layers.GlobalAveragePooling1D()(x1)\n    x2 = model2(inp[:,:,7:8])\n    x2 = tf.keras.layers.GlobalAveragePooling1D()(x2)\n    z4 = tf.keras.layers.Average()([x1,x2])\n    \n    # COMBINE CHAINS\n    y = tf.keras.layers.Concatenate()([z1,z2,z3,z4])\n    if not hybrid:\n        y = tf.keras.layers.Dense(64, activation='relu')(y)\n        y = tf.keras.layers.Dense(6,activation='softmax', dtype='float32')(y)\n    \n    # COMPILE MODEL\n    model = tf.keras.Model(inputs=inp, outputs=y)\n    opt = tf.keras.optimizers.Adam(learning_rate = 1e-3)\n    loss = tf.keras.losses.KLDivergence()\n    model.compile(loss=loss, optimizer = opt)\n    \n    return model\n\ndef build_hybrid_model():\n    model_spec = build_spec_model(True)\n    model_wave = build_wave_model(True)\n    inputs = [model_spec.input, model_wave.input]\n    x = [model_spec.output, model_wave.output]\n    x = tf.keras.layers.Concatenate()(x)\n    x = tf.keras.layers.Dense(6,activation='softmax', dtype='float32')(x)\n    \n    # COMPILE MODEL\n    model = tf.keras.Model(inputs=inputs, outputs=x)\n    opt = tf.keras.optimizers.Adam(learning_rate = 1e-3)\n    loss = tf.keras.losses.KLDivergence()\n    model.compile(loss=loss, optimizer = opt)\n    \n    return model\n\ndef build_Resnet1D_GRU_model():\n    inp = tf.keras.Input(shape=(2_000,8))\n    x = [Conv1D(filters=24, kernel_size=kernel, padding='same', \n                use_bias=False)(inp) for kernel in [3, 5, 7, 9, 11]]\n    x = Concatenate()(x)\n    x = BatchNormalization()(x)\n    x = ReLU()(x)\n    x = Conv1D(filters=24, kernel_size=5, strides=2, padding='same', use_bias=False)(x)\n    \n    for i in range(9): \n        x_res = x\n        x = BatchNormalization()(x)\n        x = ReLU()(x)\n        x = Conv1D(filters=24, kernel_size=5, strides=1, padding='same', use_bias=False)(x)\n        x = BatchNormalization()(x)\n        x = ReLU()(x)\n        x = Conv1D(filters=24, kernel_size=5, strides=1, padding='same', use_bias=False)(x)\n        if i%2:\n            x = MaxPooling1D(pool_size=2, strides=2, padding='same')(x)\n            x_res = MaxPooling1D(pool_size=2, strides=2, padding='same')(x_res)\n        x += x_res\n        \n    x = BatchNormalization()(x)\n    x = ReLU()(x)\n    x = Bidirectional(GRU(128))(x)\n    x = Dense(6,activation='softmax', dtype='float32')(x)\n    \n    # COMPILE MODEL\n    model = tf.keras.Model(inputs=inp, outputs=x)\n    opt = tf.keras.optimizers.Adam(learning_rate = 1e-3)\n    loss = tf.keras.losses.KLDivergence()\n    model.compile(loss=loss, optimizer = opt)\n    \n    return model\n\ndef score(y_true, y_pred):\n    kl = tf.keras.metrics.KLDivergence()\n    return kl(y_true, y_pred)\n\ndef plot_hist(hist):\n    metrics = ['loss']\n    for i,metric in enumerate(metrics):\n        plt.figure(figsize=(10,4))\n        plt.subplot(1,2,i+1)\n        plt.plot(hist[metric])\n        plt.plot(hist[f'val_{metric}'])\n        plt.title(f'{metric}',size=12)\n        plt.ylabel(f'{metric}',size=12)\n        plt.xlabel('epoch',size=12)\n        plt.legend([\"train\", \"validation\"], loc=\"upper left\")\n        plt.show()\n        \ndef dataset(data, mode='train', batch_size=8, data_type=DATA_TYPE, \n            augment=False, specs=None, eeg_specs=None, raw_eegs=None):\n    \n    BATCH_SIZE_PER_REPLICA = batch_size\n    BATCH_SIZE = BATCH_SIZE_PER_REPLICA * strategy.num_replicas_in_sync\n    gen = DataGenerator(data,mode=mode, data_type=data_type, augment=augment,\n                       specs=specs, eeg_specs=eeg_specs, raw_eegs=raw_eegs)\n    if data_type in ['K','E','KE','K+E','K+E+KE']: \n        inp = tf.TensorSpec(shape=(512,512,3), dtype=tf.float32)\n    elif data_type in ['KR','ER','KER']:\n        inp = (tf.TensorSpec(shape=(512,512,3), dtype=tf.float32),tf.TensorSpec(shape=(2000,8), dtype=tf.float32))\n    elif data_type in ['R','R2']:\n        inp = tf.TensorSpec(shape=(2000,8), dtype=tf.float32)\n        \n    output_signature = (inp,tf.TensorSpec(shape=(6,), dtype=tf.float32))\n    dataset = tf.data.Dataset.from_generator(generator=gen, output_signature=output_signature).batch(\n        BATCH_SIZE)\n    return dataset\n\ndef reset_seed(seed):\n    np.random.seed(seed)\n    random.seed(seed)\n    tf.random.set_seed(seed)\n        \ndef get_size(x):\n    if DATA_TYPE in ['K+E']:\n        size = 2*len(x)\n    elif  DATA_TYPE in ['K+E+KE']:\n        size = 3*len(x)\n    else:\n        size = len(x)\n    return size\n\ndef predict(models, params, fold, models_path=None):\n    preds = []\n    if models_path is None: models_path = LOAD_MODELS_FROM\n    model_wave = build_wave_model()\n    model_spec = build_spec_model()\n    model_hybrid = build_hybrid_model()\n    model_resnet = build_Resnet1D_GRU_model()\n    for data_type in models:\n        data = params['data']\n        ver = models[data_type]\n        ds = dataset(data_type=data_type, **params)\n        if data_type in ['R']:\n            model = model_wave\n        if data_type in ['R2']:\n            model = model_resnet\n        elif data_type in ['K','E','KE','K+E','K+E+KE']:\n            model = model_spec\n        elif data_type in ['KR','ER','KER']:\n            model = model_hybrid\n        model.load_weights(f'{models_path}/model_{data_type}_{ver}_{fold}.weights.h5')\n        pred = model.predict(ds)\n        if data_type in ['K+E']:\n            pred = (pred[:len(data)] + pred[len(data):])/2\n        if data_type in ['K+E+KE']:\n            pred = (pred[:len(data)] + pred[len(data):len(data)*2] + pred[len(data)*2:])/3\n        preds.append(pred)\n    pred = np.mean(preds,axis=0)\n    del model_wave, model_spec, model_hybrid\n    gc.collect()\n    return pred","metadata":{"papermill":{"duration":0.057561,"end_time":"2024-03-30T16:40:52.903499","exception":false,"start_time":"2024-03-30T16:40:52.845938","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## TRANSFER LEARNING","metadata":{"papermill":{"duration":0.007043,"end_time":"2024-03-30T16:40:52.918069","exception":false,"start_time":"2024-03-30T16:40:52.911026","status":"completed"},"tags":[]}},{"cell_type":"code","source":"if not SUBMISSION and not TEST_ENSEMBLE:\n    reset_seed(42)\n    all_oof = []\n    all_true = []\n    val_sizes = []\n    losses = []\n    val_losses = []\n    total_hist = {}\n\n    gkf = GroupKFold(n_splits=5)\n    for i, (train_index, valid_index) in enumerate(gkf.split(train, train.target, train.patient_id)):   \n        print('#'*25)\n        print(f'### Fold {i+1}')\n        \n        params = {'specs':spectrograms, 'eeg_specs':all_eegs, 'raw_eegs':all_raw_eegs}\n        data = train_KD.iloc[train_index] if KNOWLEDGE_DISTILLATION else train.iloc[train_index]\n        val = train.iloc[valid_index]\n        train_dataset = dataset(data, **params)\n        val_dataset = dataset(val,mode='valid', **params)\n        data = data[data['kl']<5.5]\n        train_dataset2 = dataset(data, **params)\n        train_size = get_size(train_index)\n        valid_size = get_size(valid_index)\n        print(f'### train size {train_size}, valid size {valid_size}')\n        print('#'*25)\n        model = build_model()\n        hist = model.fit(train_dataset, validation_data = val_dataset, \n                         epochs=5, callbacks=[LR])\n        train_size = get_size(data)\n        print(f'### seconds stage train size {train_size}, valid size {valid_size}')\n        print('#'*25)\n        hist2 = model.fit(train_dataset2, validation_data = val_dataset, \n                         epochs=3, callbacks=[LR2])\n        losses.append(hist.history['loss']+hist2.history['loss'])\n        val_losses.append(hist.history['val_loss']+hist2.history['val_loss'])\n        with strategy.scope():\n            model.save_weights(f'model_{DATA_TYPE}_{MODEL[DATA_TYPE]}_{i}.weights.h5')\n        params = {'mode':'valid','data':val,'specs':spectrograms, 'eeg_specs':all_eegs, 'raw_eegs':all_raw_eegs}\n        oof = predict(MODEL, params, i, models_path='./')\n        all_oof.append(oof)\n        all_true.append(train.iloc[valid_index][TARGETS].values)\n        val_sizes.append(len(valid_index))\n        del model, oof\n        gc.collect()\n        \n    total_hist['loss'] = np.mean(losses,axis=0)\n    total_hist['val_loss'] = np.mean(val_losses,axis=0)\n    all_oof = np.concatenate(all_oof)\n    all_true = np.concatenate(all_true)\n    plot_hist(total_hist)\n    print(f'CV KL SCORE: {score(all_true,all_oof):.4f}')","metadata":{"papermill":{"duration":0.02304,"end_time":"2024-03-30T16:40:52.948379","exception":false,"start_time":"2024-03-30T16:40:52.925339","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Local Ensemble Testing on CV","metadata":{"papermill":{"duration":0.007255,"end_time":"2024-03-30T16:40:52.962945","exception":false,"start_time":"2024-03-30T16:40:52.955690","status":"completed"},"tags":[]}},{"cell_type":"code","source":"if not SUBMISSION and TEST_ENSEMBLE:\n    MODELS = {\n          'K'     : 43, # 'LB':0.41 Kaggle's spectrogram model version\n          'E'     : 42, # 'LB':0.39 EEG's spectrogram model version\n          'R'     : 60, # 'LB':0.4 EEG's Raw wavenet model version, trained on single GPU\n          'R2'    : 61, # 'LB':0.46 EEG's Raw wavenet model version, trained on single GPU\n          'KE'    : 58, # 'LB':0.34 Kaggle's and EEG's spectrogram model version\n          'KR'    : 48, # 'LB':0.39 Kaggle's spectrogram and Raw model version\n          'ER'    : 49, # 'LB':0.38 EEG's spectrogram and Raw model version\n          'KER'   : 64, # 'LB':0.33 EEG's, Kaggle's spectrograms and Raw model version\n          'K+E'   : 51, # 'LB':0.37 Data spectrogram augmentation model version\n          'K+E+KE': 59, # 'LB':0.34 Data spectrogram augmentation model version\n         }\n    reset_seed(42)\n    gkf = GroupKFold(n_splits=5)\n    all_oof = []\n    all_true = []\n    for i, (_, valid_index) in enumerate(gkf.split(train, train.target, train.patient_id)):   \n        print(f'Fold {i+1}')\n        val_data = train.iloc[valid_index].copy()\n        params = {'mode':'valid','data':val_data,'specs':spectrograms, 'eeg_specs':all_eegs, 'raw_eegs':all_raw_eegs}\n        oof = predict(MODELS,params,i)\n        all_oof.append(oof)\n        all_true.append(val_data[TARGETS].values)\n    \n    all_oof = np.concatenate(all_oof)\n    all_true = np.concatenate(all_true)\n    print(f'CV KL SCORE: {score(all_true,all_oof):.4f}')","metadata":{"papermill":{"duration":0.01803,"end_time":"2024-03-30T16:40:52.988438","exception":false,"start_time":"2024-03-30T16:40:52.970408","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Infer Test and Create Submission CSV\nInfer the test data and create a `submission.csv` file.","metadata":{"papermill":{"duration":0.007487,"end_time":"2024-03-30T16:40:53.003492","exception":false,"start_time":"2024-03-30T16:40:52.996005","status":"completed"},"tags":[]}},{"cell_type":"code","source":"if SUBMISSION:\n    test = pd.read_csv('/kaggle/input/hms-harmful-brain-activity-classification/test.csv')\n    print('Test shape',test.shape)\n    test.head()","metadata":{"papermill":{"duration":0.032643,"end_time":"2024-03-30T16:40:53.043490","exception":false,"start_time":"2024-03-30T16:40:53.010847","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# READ ALL SPECTROGRAMS\nif SUBMISSION:\n    PATH2 = '/kaggle/input/hms-harmful-brain-activity-classification/test_spectrograms'\n    files2 = os.listdir(PATH2)\n    print(f'There are {len(files2)} test spectrogram parquets')\n    \n    spectrograms2 = {}\n    for i,f in enumerate(files2):\n        if i%100==0: print(i,', ',end='')\n        tmp = pd.read_parquet(f'{PATH2}/{f}')\n        name = int(f.split('.')[0])\n        spectrograms2[name] = tmp.iloc[:,1:].values\n    \n    # RENAME FOR DATA GENERATOR\n    test = test.rename({'spectrogram_id':'spec_id'},axis=1)","metadata":{"papermill":{"duration":0.322168,"end_time":"2024-03-30T16:40:53.373554","exception":false,"start_time":"2024-03-30T16:40:53.051386","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# READ ALL EEG SPECTROGRAMS\nif SUBMISSION:\n    PATH2 = '/kaggle/input/hms-harmful-brain-activity-classification/test_eegs'\n    DISPLAY = 0\n    EEG_IDS2 = test.eeg_id.unique()\n    all_eegs2 = {}\n\n    print('Converting Test EEG to Spectrograms...'); print()\n    for i,eeg_id in enumerate(EEG_IDS2):\n        \n        # CREATE SPECTROGRAM FROM EEG PARQUET\n        img = spectrogram_from_eeg(f'{PATH2}/{eeg_id}.parquet')\n        all_eegs2[eeg_id] = img","metadata":{"papermill":{"duration":10.484088,"end_time":"2024-03-30T16:41:03.866125","exception":false,"start_time":"2024-03-30T16:40:53.382037","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# READ ALL RAW EEG SIGNALS\nif SUBMISSION :\n    all_raw_eegs2 = {}\n    EEG_IDS2 = test.eeg_id.unique()\n    PATH2 = '/kaggle/input/hms-harmful-brain-activity-classification/test_eegs'\n\n    print('Processing Test EEG parquets...'); print()\n    for i,eeg_id in enumerate(EEG_IDS2):\n        \n        # SAVE EEG TO PYTHON DICTIONARY OF NUMPY ARRAYS\n        data = eeg_from_parquet(f'{PATH2}/{eeg_id}.parquet')\n        all_raw_eegs2[eeg_id] = data","metadata":{"papermill":{"duration":0.059916,"end_time":"2024-03-30T16:41:03.944257","exception":false,"start_time":"2024-03-30T16:41:03.884341","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Submission ON TEST\nif SUBMISSION:\n    preds = []\n    params = {'data':test,'mode':'test','specs':spectrograms2, 'eeg_specs':all_eegs2, 'raw_eegs':all_raw_eegs2} \n    models = MODELS if ENSEMBLE else MODEL\n    for i in range(5):\n        print(f'Fold {i+1}')\n        pred = predict(models,params,i)\n        preds.append(pred)\n        \n    pred = np.mean(preds,axis=0)\n    print('Test preds shape',pred.shape)","metadata":{"papermill":{"duration":317.619929,"end_time":"2024-03-30T16:46:21.583422","exception":false,"start_time":"2024-03-30T16:41:03.963493","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if SUBMISSION:\n    sub = pd.DataFrame({'eeg_id':test.eeg_id.values})\n    sub[TARGETS] = pred\n    sub.to_csv('submission.csv',index=False)\n    print('Submissionn shape',sub.shape)\n    print()\n    print(sub.head().to_string())","metadata":{"papermill":{"duration":0.046617,"end_time":"2024-03-30T16:46:21.642257","exception":false,"start_time":"2024-03-30T16:46:21.595640","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# SANITY CHECK TO CONFIRM PREDICTIONS SUM TO ONE\nif SUBMISSION:\n    print(sub.iloc[:,-6:].sum(axis=1).to_string())","metadata":{"papermill":{"duration":0.022561,"end_time":"2024-03-30T16:46:21.677391","exception":false,"start_time":"2024-03-30T16:46:21.654830","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]}]}