{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":59093,"databundleVersionId":7469972,"sourceType":"competition"},{"sourceId":7392733,"sourceType":"datasetVersion","datasetId":4297749},{"sourceId":7392775,"sourceType":"datasetVersion","datasetId":4297782}],"dockerImageVersionId":30699,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"The code in this notebook is based on code from [Chris Deotte's \"EfficientNetB0 Starter\" notebook](https://www.kaggle.com/code/cdeotte/efficientnetb0-starter-lb-0-43?scriptVersionId=159911317).","metadata":{}},{"cell_type":"code","source":"\"\"\"\nInitialize usage of two Kaggle T4s and usage of mixed precision.\nMixed precision allows the training process to use float16 in some operations\ninstead of the default float32, which speeds up training time.\nUsage of both T4s that Kaggle offers to each user allows for better use of hardware.\n\"\"\"\n\nimport os, gc\nos.environ[\"CUDA_VISIBLE_DEVICES\"]=\"0,1\"\nimport tensorflow as tf\nimport pandas as pd, numpy as np\nimport matplotlib.pyplot as plt\nprint('TensorFlow version =',tf.__version__)\n\n# USE MULTIPLE GPUS\ngpus = tf.config.list_physical_devices('GPU')\nif len(gpus)<=1: \n    strategy = tf.distribute.OneDeviceStrategy(device=\"/gpu:0\")\n    print(f'Using {len(gpus)} GPU')\nelse: \n    strategy = tf.distribute.MirroredStrategy()\n    print(f'Using {len(gpus)} GPUs')\n\nVER = 5\n\n# IF THIS EQUALS NONE, THEN WE TRAIN NEW MODELS\n# IF THIS EQUALS DISK PATH, THEN WE LOAD PREVIOUSLY TRAINED MODELS\n#LOAD_MODELS_FROM = '/kaggle/input/brain-efficientnet-models-v3-v4-v5/'\nLOAD_MODELS_FROM = False\n\nUSE_KAGGLE_SPECTROGRAMS = True\nUSE_EEG_SPECTROGRAMS = False\n# We are training only with Chris Deotte's \"all the Kaggle specs in one file\" dataset.\n# Mainly because it is a direct and otherwise unmodified compilation of the competition data.\n\n# USE MIXED PRECISION\nMIX = True\nif MIX:\n    tf.config.optimizer.set_experimental_options({\"auto_mixed_precision\": True})\n    print('Mixed precision enabled')\nelse:\n    print('Using full precision')","metadata":{"execution":{"iopub.status.busy":"2024-05-24T23:02:51.096357Z","iopub.execute_input":"2024-05-24T23:02:51.096637Z","iopub.status.idle":"2024-05-24T23:03:05.673805Z","shell.execute_reply.started":"2024-05-24T23:02:51.096611Z","shell.execute_reply":"2024-05-24T23:03:05.672851Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"LOAD_MODELS_FROM=False","metadata":{"execution":{"iopub.status.busy":"2024-05-24T23:03:11.695292Z","iopub.execute_input":"2024-05-24T23:03:11.695661Z","iopub.status.idle":"2024-05-24T23:03:11.699933Z","shell.execute_reply.started":"2024-05-24T23:03:11.695632Z","shell.execute_reply":"2024-05-24T23:03:11.698950Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\"\nLoad training data.\n\"\"\"\n\ndf = pd.read_csv('/kaggle/input/hms-harmful-brain-activity-classification/train.csv')\nTARGETS = df.columns[-6:]\nprint('Train shape:', df.shape )\nprint('Targets', list(TARGETS))\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2024-05-24T23:03:13.748402Z","iopub.execute_input":"2024-05-24T23:03:13.749315Z","iopub.status.idle":"2024-05-24T23:03:14.029425Z","shell.execute_reply.started":"2024-05-24T23:03:13.749273Z","shell.execute_reply":"2024-05-24T23:03:14.028270Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\"\n'Create Non-Overlapping EEG Id Train Data'\n\nThe source material states that since the competition description says\ntest data only uses one crop per EEG, it would be best to do the same in training.\n\"\"\"\n\n# Group by eeg_id, take spec_id and offset columns, aggregate by first and minimum respectively\n# Each eeg_id now points to its first spec and the spec's min time offset\ntrain = df.groupby('eeg_id')[['spectrogram_id','spectrogram_label_offset_seconds']].agg(\n    {'spectrogram_id':'first','spectrogram_label_offset_seconds':'min'})\n# rename columns\ntrain.columns = ['spec_id','min']\n\n# Add \"max\" column using the max value of the spec offset for every eeg \ntmp = df.groupby('eeg_id')[['spectrogram_id','spectrogram_label_offset_seconds']].agg(\n    {'spectrogram_label_offset_seconds':'max'})\ntrain['max'] = tmp\n\n# take the first patient id of each eeg\ntmp = df.groupby('eeg_id')[['patient_id']].agg('first')\ntrain['patient_id'] = tmp\n\n# take the sum of each {disorder}_vote per eeg_id and add to train\ntmp = df.groupby('eeg_id')[TARGETS].agg('sum')\nfor t in TARGETS:\n    train[t] = tmp[t].values\n\n# divides total {disorder}_votes by total amount of votes\n# to create a proportion decimal for training (labels)\ny_data = train[TARGETS].values\ny_data = y_data / y_data.sum(axis=1,keepdims=True)\ntrain[TARGETS] = y_data\n\n# take the expert consensus per eeg\ntmp = df.groupby('eeg_id')[['expert_consensus']].agg('first')\ntrain['target'] = tmp\n\n# Reset indexes and show head.\ntrain = train.reset_index()\nprint('Train non-overlapp eeg_id shape:', train.shape )\ntrain.head()","metadata":{"execution":{"iopub.status.busy":"2024-05-24T23:03:16.126911Z","iopub.execute_input":"2024-05-24T23:03:16.127746Z","iopub.status.idle":"2024-05-24T23:03:16.229631Z","shell.execute_reply.started":"2024-05-24T23:03:16.127706Z","shell.execute_reply":"2024-05-24T23:03:16.228663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\nREAD_SPEC_FILES = False\n# We will be using the \"all specs in one file\" dataset Chris provided.\n\n# READ ALL SPECTROGRAMS\nPATH = '/kaggle/input/hms-harmful-brain-activity-classification/train_spectrograms/'\nfiles = os.listdir(PATH)\nprint(f'There are {len(files)} spectrogram parquets')\n\nif READ_SPEC_FILES:    \n    spectrograms = {}\n    for i,f in enumerate(files):\n        if i%100==0: print(i,', ',end='')\n        tmp = pd.read_parquet(f'{PATH}{f}')\n        name = int(f.split('.')[0])\n        spectrograms[name] = tmp.iloc[:,1:].values\nelse:\n    spectrograms = np.load('/kaggle/input/brain-spectrograms/specs.npy',allow_pickle=True).item()\n    \n# We will not be reading the EEG-Specs Chris generated from the competition data.","metadata":{"execution":{"iopub.status.busy":"2024-05-24T23:03:20.357318Z","iopub.execute_input":"2024-05-24T23:03:20.358256Z","iopub.status.idle":"2024-05-24T23:04:12.872122Z","shell.execute_reply.started":"2024-05-24T23:03:20.358218Z","shell.execute_reply":"2024-05-24T23:04:12.871102Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\"\"\"\nCreate a DataLoader.\n\"\"\"\n\nimport albumentations as albu\nTARS = {'Seizure':0, 'LPD':1, 'GPD':2, 'LRDA':3, 'GRDA':4, 'Other':5}\nTARS2 = {x:y for y,x in TARS.items()}\n\nclass DataGenerator(tf.keras.utils.Sequence):\n    'Generates data for Keras'\n    def __init__(self, data, batch_size=32, shuffle=False, augment=False, mode='train',\n                 specs = spectrograms, eeg_specs = None): \n\n        self.data = data\n        self.batch_size = batch_size\n        self.shuffle = shuffle\n        self.augment = augment\n        self.mode = mode\n        self.specs = specs\n        self.eeg_specs = eeg_specs\n        self.on_epoch_end()\n        \n    def __len__(self):\n        'Denotes the number of batches per epoch'\n        ct = int( np.ceil( len(self.data) / self.batch_size ) )\n        return ct\n\n    def __getitem__(self, index):\n        'Generate one batch of data'\n        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]\n        X, y = self.__data_generation(indexes)\n        if self.augment: X = self.__augment_batch(X) \n        return X, y\n\n    def on_epoch_end(self):\n        'Updates indexes after each epoch'\n        self.indexes = np.arange( len(self.data) )\n        if self.shuffle: np.random.shuffle(self.indexes)\n                        \n    def __data_generation(self, indexes):\n        'Generates data containing batch_size samples' \n        # Using 4 instead of 8 because we are not using the eeg-specs\n        X = np.zeros((len(indexes),128,256,4),dtype='float32')\n        y = np.zeros((len(indexes),6),dtype='float32')\n        img = np.ones((128,256),dtype='float32')\n        \n        for j,i in enumerate(indexes):\n            row = self.data.iloc[i]\n            if self.mode=='test': \n                r = 0\n            else: \n                r = int( (row['min'] + row['max'])//4 )\n\n            # Extract and preprocess images.\n            for k in range(4):\n                # EXTRACT 300 ROWS OF SPECTROGRAM\n                img = self.specs[row.spec_id][r:r+300,k*100:(k+1)*100].T\n                \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                ep = 1e-6\n                m = np.nanmean(img.flatten())\n                s = np.nanstd(img.flatten())\n                img = (img-m)/(s+ep)\n                img = np.nan_to_num(img, nan=0.0)\n                \n                # CROP TO 256 TIME STEPS\n                X[j,14:-14,:,k] = img[:,22:-22] / 2.0\n        \n            # EEG SPECTROGRAMS\n#             img = self.eeg_specs[row.eeg_id]\n#             X[j,:,:,4:] = img\n                \n            if self.mode!='test':\n                y[j,] = row[TARGETS]\n            \n        return X,y\n    \n    def __random_transform(self, img):\n        composition = albu.Compose([\n            albu.HorizontalFlip(p=0.5),\n            #albu.CoarseDropout(max_holes=8,max_height=32,max_width=32,fill_value=0,p=0.5),\n        ])\n        return composition(image=img)['image']\n            \n    def __augment_batch(self, img_batch):\n        for i in range(img_batch.shape[0]):\n            img_batch[i, ] = self.__random_transform(img_batch[i, ])\n        return img_batch","metadata":{"execution":{"iopub.status.busy":"2024-05-24T23:04:37.033763Z","iopub.execute_input":"2024-05-24T23:04:37.034463Z","iopub.status.idle":"2024-05-24T23:04:38.141320Z","shell.execute_reply.started":"2024-05-24T23:04:37.034435Z","shell.execute_reply":"2024-05-24T23:04:38.140560Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Code to show a few specs. Copied over without change.\n\ngen = DataGenerator(train, batch_size=32, shuffle=False)\nROWS=2; COLS=3; BATCHES=2\n\nfor i,(x,y) in enumerate(gen):\n    plt.figure(figsize=(20,8))\n    for j in range(ROWS):\n        for k in range(COLS):\n            plt.subplot(ROWS,COLS,j*COLS+k+1)\n            t = y[j*COLS+k]\n            img = x[j*COLS+k,:,:,0][::-1,]\n            mn = img.flatten().min()\n            mx = img.flatten().max()\n            img = (img-mn)/(mx-mn)\n            plt.imshow(img)\n            tars = f'[{t[0]:0.2f}'\n            for s in t[1:]: tars += f', {s:0.2f}'\n            eeg = train.eeg_id.values[i*32+j*COLS+k]\n            plt.title(f'EEG = {eeg}\\nTarget = {tars}',size=12)\n            plt.yticks([])\n            plt.ylabel('Frequencies (Hz)',size=14)\n            plt.xlabel('Time (sec)',size=16)\n    plt.show()\n    if i==BATCHES-1: break","metadata":{"execution":{"iopub.status.busy":"2024-05-24T23:04:41.411025Z","iopub.execute_input":"2024-05-24T23:04:41.411945Z","iopub.status.idle":"2024-05-24T23:04:43.874452Z","shell.execute_reply.started":"2024-05-24T23:04:41.411913Z","shell.execute_reply":"2024-05-24T23:04:43.873558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Chris offers this learning rate scheduler. I made a few changes of my own.\n\nLR_START = 1e-4\nLR_MAX = 1e-3\nLR_RAMPUP_EPOCHS = 0\nLR_SUSTAIN_EPOCHS = 0\nLR_STEP_DECAY = 0.1\nLR_MIN = 1e-5\nEVERY = 1\nEPOCHS = 4\n\ndef lrfn(epoch):\n    if epoch < LR_RAMPUP_EPOCHS:\n        lr = (LR_MAX - LR_START) / LR_RAMPUP_EPOCHS * epoch + LR_START\n    elif epoch < LR_RAMPUP_EPOCHS + LR_SUSTAIN_EPOCHS:\n        lr = LR_MAX\n    else:\n        lr = LR_MAX * LR_STEP_DECAY**((epoch - LR_RAMPUP_EPOCHS - LR_SUSTAIN_EPOCHS)//EVERY)\n    if lr < LR_MIN: lr = LR_MIN\n    return lr\n\nrng = [i for i in range(EPOCHS)]\ny = [lrfn(x) for x in rng]\nplt.figure(figsize=(10, 4))\nplt.plot(rng, y, 'o-'); \nplt.xlabel('epoch',size=14); plt.ylabel('learning rate',size=14)\nplt.title('Step Training Schedule',size=16); plt.show()\n\nLR = tf.keras.callbacks.LearningRateScheduler(lrfn, verbose = True)","metadata":{"execution":{"iopub.status.busy":"2024-05-24T23:04:48.979028Z","iopub.execute_input":"2024-05-24T23:04:48.979767Z","iopub.status.idle":"2024-05-24T23:04:49.256050Z","shell.execute_reply.started":"2024-05-24T23:04:48.979735Z","shell.execute_reply":"2024-05-24T23:04:49.255155Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import keras_cv\n\nmodel_type = \"densenet121_imagenet\"\n\ndef build_base_model():\n    \"\"\"\n    Function to build the base model that the preprocessing stuff goes around.\n    Modify this function if you are using a custom architecture you made or found.\n    Otherwise, feel free to directly call build_model.\n    \"\"\"\n    base_model = keras_cv.models.DenseNetBackbone(\n        stackwise_num_repeats=[3, 6, 12, 8],\n        include_rescaling=False,\n        #input_shape=(512,256,3),\n        input_tensor=None,\n        compression_ratio=0.5,\n        growth_rate=32,\n        **kwargs\n    )\n    return base_model\n\ndef build_model():\n    \n    inp = tf.keras.Input(shape=(128,256,4))\n    # https://keras.io/api/keras_cv/models/backbones/densenet/\n    base_model = keras_cv.models.DenseNetBackbone(\n        stackwise_num_repeats=[3, 6, 12, 8,],\n        include_rescaling=False,\n        #input_shape=(512,256,3),\n        input_tensor=None,\n        compression_ratio=0.5,\n        growth_rate=32,\n    )\n    #base_model.load_weights('/kaggle/input/tf-efficientnet-imagenet-weights/efficientnet-b0_weights_tf_dim_ordering_tf_kernels_autoaugment_notop.h5')\n    \n    # RESHAPE INPUT 128x256x8 => 512x512x3 MONOTONE IMAGE\n    # KAGGLE SPECTROGRAMS\n    x1 = [inp[:,:,:,i:i+1] for i in range(4)]\n    x1 = tf.keras.layers.Concatenate(axis=1)(x1)\n    # EEG SPECTROGRAMS\n    x2 = [inp[:,:,:,i+4:i+5] for i in range(4)]\n    x2 = tf.keras.layers.Concatenate(axis=1)(x2)\n    # MAKE 512X512X3\n    if USE_KAGGLE_SPECTROGRAMS & USE_EEG_SPECTROGRAMS:\n        x = tf.keras.layers.Concatenate(axis=2)([x1,x2])\n    elif USE_EEG_SPECTROGRAMS: x = x2\n    else: x = x1\n    # x = x1 # just using the competition specs this time\n    x = tf.keras.layers.Concatenate(axis=3)([x,x,x])\n    \n    # OUTPUT\n    x = base_model(x)\n    x = tf.keras.layers.GlobalAveragePooling2D()(x)\n    x = tf.keras.layers.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\n    model.compile(loss=loss, optimizer = opt) \n        \n    return model","metadata":{"execution":{"iopub.status.busy":"2024-05-24T23:04:51.744374Z","iopub.execute_input":"2024-05-24T23:04:51.744740Z","iopub.status.idle":"2024-05-24T23:04:57.201338Z","shell.execute_reply.started":"2024-05-24T23:04:51.744711Z","shell.execute_reply":"2024-05-24T23:04:57.200559Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import KFold, GroupKFold\nimport tensorflow.keras.backend as K, gc\nfrom tensorflow.keras.saving import load_model\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint\n\nall_oof = []\nall_true = []\n\n# Training.\n\ncurrent_densenet_filename = \"/kaggle/working/hms_densenet2_best_model_val_loss.keras\"\ncheckpoint = ModelCheckpoint(\n    current_densenet_filename,\n    monitor='val_loss',\n    verbose=1,\n    save_best_only=True,\n    save_weights_only=False,\n    mode='auto',\n    save_freq='epoch',\n    initial_value_threshold=None\n)\n\ngkf = GroupKFold(n_splits=5)\nfor i, (train_index, valid_index) in enumerate(gkf.split(train, train.target, train.patient_id)):  \n    # This splits the train set and labels and patient id\n    # into a training subset and validation subset.\n    \n    # Explanation for this snippet of code can be found in the next cell.\n    if len(valid_index) % 2 == 1:\n        valid_index = valid_index[1:]\n    \n    print('#'*25)\n    print(f'### Fold {i+1}')\n    \n    train_gen = DataGenerator(train.iloc[train_index], shuffle=True, batch_size=32, augment=False)\n    valid_gen = DataGenerator(train.iloc[valid_index], shuffle=False, batch_size=64, mode='valid')\n    \n    print(f'### train size {len(train_index)}, valid size {len(valid_index)}')\n    print('#'*25)\n    \n    K.clear_session()\n    with strategy.scope():\n        model = build_model()\n    if LOAD_MODELS_FROM is False:\n        model.fit(train_gen, verbose=1,\n              validation_data = valid_gen,\n              epochs=EPOCHS, callbacks = [LR, checkpoint])\n        #model.save_weights(f'EffNet_v{VER}_f{i}.h5')\n    else:\n        # Using my own system of directly saving and loading models.\n        model = load_model(current_densenet_filename)\n        #model.load_weights(f'{LOAD_MODELS_FROM}EffNet_v{VER}_f{i}.h5')\n        \n    oof = model.predict(valid_gen, verbose=1)\n    all_oof.append([oof])\n    all_true.append(train.iloc[valid_index][TARGETS].values)\n    \n    del model, oof\n    gc.collect()\n    \nall_oof = np.concatenate(all_oof)\nall_true = np.concatenate(all_true)","metadata":{"execution":{"iopub.status.busy":"2024-05-24T23:04:59.831914Z","iopub.execute_input":"2024-05-24T23:04:59.833021Z","iopub.status.idle":"2024-05-25T00:10:04.251254Z","shell.execute_reply.started":"2024-05-24T23:04:59.832985Z","shell.execute_reply":"2024-05-25T00:10:04.250437Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Explanation for the `valid_index[1:]` snippet:\n\nDue to unknown causes, `valid_index` includes 3418 rows in the source but 3417 in this notebook. The odd-value-ness caused a Graph Execution Error to occur when predicting on valid_gen, with the final reason being `Shapes of all inputs must match: values[0].shape = [13,6] != values[1].shape = [12,6]`. Making `valid_index` odd by discarding one entry fixes this.\n\nThis is almost certainly not the right or elegant way to fix this, but oh well.","metadata":{}},{"cell_type":"code","source":"import sys\nsys.path.append('/kaggle/input/kaggle-kl-div/')\n# Add kaggle-kl-div using the add input functionality.\nfrom kaggle_kl_div import score\n\noof = pd.DataFrame(all_oof.copy())\noof['id'] = np.arange(len(oof))\n\ntrue = pd.DataFrame(all_true.copy())\ntrue['id'] = np.arange(len(true))\n\ncv = score(solution=true, submission=oof, row_id_column_name='id')\nprint('CV Score KL-Div for EfficientNetB2 =',cv)","metadata":{"execution":{"iopub.status.busy":"2024-05-25T00:16:14.605966Z","iopub.execute_input":"2024-05-25T00:16:14.606840Z","iopub.status.idle":"2024-05-25T00:16:14.714676Z","shell.execute_reply.started":"2024-05-25T00:16:14.606792Z","shell.execute_reply":"2024-05-25T00:16:14.713474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = load_model(current_densenet_filename)\nstandalone_true = []\nstandalone_oof = model.predict(valid_gen, verbose=1)\nstandalone_true.append(train.iloc[valid_index][TARGETS].values)","metadata":{"execution":{"iopub.status.busy":"2024-05-25T00:19:47.413398Z","iopub.execute_input":"2024-05-25T00:19:47.413760Z","iopub.status.idle":"2024-05-25T00:20:13.556783Z","shell.execute_reply.started":"2024-05-25T00:19:47.413736Z","shell.execute_reply":"2024-05-25T00:20:13.555915Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_oof = pd.DataFrame(standalone_oof.copy())\ncustom_oof['id'] = np.arange(len(custom_oof))\n\ncustom_true = pd.DataFrame(standalone_true[0].copy())\ncustom_true['id'] = np.arange(len(custom_true))","metadata":{"execution":{"iopub.status.busy":"2024-05-25T00:25:15.633232Z","iopub.execute_input":"2024-05-25T00:25:15.634175Z","iopub.status.idle":"2024-05-25T00:25:15.641989Z","shell.execute_reply.started":"2024-05-25T00:25:15.634141Z","shell.execute_reply":"2024-05-25T00:25:15.640986Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"standalone_oof","metadata":{"execution":{"iopub.status.busy":"2024-05-25T00:37:15.850733Z","iopub.execute_input":"2024-05-25T00:37:15.851113Z","iopub.status.idle":"2024-05-25T00:37:15.858012Z","shell.execute_reply.started":"2024-05-25T00:37:15.851085Z","shell.execute_reply":"2024-05-25T00:37:15.857003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Re-run the custom df generation cells before re-running this.\n# The scoring process destroys the id column.\ncv = score(solution=custom_true, submission=custom_oof, row_id_column_name='id')\nprint('CV Score KL-Div for DenseNet =',cv)\n# ","metadata":{"execution":{"iopub.status.busy":"2024-05-25T00:25:52.317755Z","iopub.execute_input":"2024-05-25T00:25:52.318438Z","iopub.status.idle":"2024-05-25T00:25:52.354312Z","shell.execute_reply.started":"2024-05-25T00:25:52.318404Z","shell.execute_reply":"2024-05-25T00:25:52.353343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"`CV Score KL-Div for DenseNet = 0.7747776892170566`\n\nFor comparison, the EfficientNet starter that Chris shared achieved:\n\n`CV Score KL-Div for EfficientNetB2 = 0.5989355021762731`\n\nPossible improvements and tweaks: \n- adding clipnorm=1.0 to the Adam optimizer\n- using the eeg-specs that Chris implemented","metadata":{}},{"cell_type":"code","source":"# Attempt to infer on the single testing spectrogram.\n\n# READ ALL SPECTROGRAMS\nPATH2 = '/kaggle/input/hms-harmful-brain-activity-classification/test_spectrograms/'\nfiles2 = os.listdir(PATH2)\nprint(f'There are {len(files2)} test spectrogram parquets')\n\ntest = pd.read_csv('/kaggle/input/hms-harmful-brain-activity-classification/test.csv')\n    \nspectrograms2 = {}\nfor 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 DATALOADER\ntest = test.rename({'spectrogram_id':'spec_id'},axis=1)\n\n# INFER EFFICIENTNET ON TEST\npreds = []\n#model = build_model()\ntest_gen = DataGenerator(test, shuffle=False, batch_size=64, mode='test',\n                         specs = spectrograms2, eeg_specs = None)\n\ncurrent_densenet_filename2 = \"/kaggle/working/hms_densenet2_best_model_val_loss.keras\"\nmodel = load_model(current_densenet_filename2)\npred = model.predict(test_gen, verbose=1)\npreds.append(pred)\npred = np.mean(preds,axis=0)\nprint()\nprint('Test preds shape',pred.shape)\n\nsub = pd.DataFrame({'eeg_id':test.eeg_id.values})\nsub[TARGETS] = pred\nsub.to_csv('submission.csv',index=False)\nprint('Submissionn shape',sub.shape)\nsub.head()","metadata":{"execution":{"iopub.status.busy":"2024-05-25T00:42:07.189085Z","iopub.execute_input":"2024-05-25T00:42:07.189681Z","iopub.status.idle":"2024-05-25T00:42:13.318077Z","shell.execute_reply.started":"2024-05-25T00:42:07.189644Z","shell.execute_reply":"2024-05-25T00:42:13.317160Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"! ls /kaggle/working/","metadata":{"execution":{"iopub.status.busy":"2024-05-25T00:41:53.468622Z","iopub.execute_input":"2024-05-25T00:41:53.468999Z","iopub.status.idle":"2024-05-25T00:41:54.816258Z","shell.execute_reply.started":"2024-05-25T00:41:53.468969Z","shell.execute_reply":"2024-05-25T00:41:54.815222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# SANITY CHECK TO CONFIRM PREDICTIONS SUM TO ONE\nsub.iloc[:,-6:].sum(axis=1)","metadata":{"execution":{"iopub.status.busy":"2024-05-25T00:42:43.339710Z","iopub.execute_input":"2024-05-25T00:42:43.340408Z","iopub.status.idle":"2024-05-25T00:42:43.349714Z","shell.execute_reply.started":"2024-05-25T00:42:43.340374Z","shell.execute_reply":"2024-05-25T00:42:43.348678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(len(train[\"patient_id\"].unique()))","metadata":{"execution":{"iopub.status.busy":"2024-05-25T00:44:10.451385Z","iopub.execute_input":"2024-05-25T00:44:10.452068Z","iopub.status.idle":"2024-05-25T00:44:10.457163Z","shell.execute_reply.started":"2024-05-25T00:44:10.452038Z","shell.execute_reply":"2024-05-25T00:44:10.456143Z"},"trusted":true},"execution_count":null,"outputs":[]}]}