{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":59093,"databundleVersionId":7469972,"sourceType":"competition"},{"sourceId":7526248,"sourceType":"datasetVersion","datasetId":4308295},{"sourceId":6072,"sourceType":"modelInstanceVersion","modelInstanceId":4590}],"dockerImageVersionId":30648,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        os.path.join(dirname, filename)\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-04-08T06:26:45.677162Z","iopub.execute_input":"2024-04-08T06:26:45.677483Z","iopub.status.idle":"2024-04-08T06:26:58.801348Z","shell.execute_reply.started":"2024-04-08T06:26:45.677455Z","shell.execute_reply":"2024-04-08T06:26:58.800086Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Install Libraries**","metadata":{}},{"cell_type":"code","source":"pip install keras","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:27:15.978827Z","iopub.execute_input":"2024-04-08T06:27:15.979316Z","iopub.status.idle":"2024-04-08T06:27:29.579000Z","shell.execute_reply.started":"2024-04-08T06:27:15.979285Z","shell.execute_reply":"2024-04-08T06:27:29.577795Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -q /kaggle/input/kerasv3-lib-ds/keras_cv-0.8.2-py3-none-any.whl --no-deps\n!pip install -q /kaggle/input/kerasv3-lib-ds/tensorflow-2.15.0.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl --no-deps\n!pip install -q /kaggle/input/kerasv3-lib-ds/keras-3.0.4-py3-none-any.whl --no-deps","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:27:40.015775Z","iopub.execute_input":"2024-04-08T06:27:40.016638Z","iopub.status.idle":"2024-04-08T06:28:34.468790Z","shell.execute_reply.started":"2024-04-08T06:27:40.016599Z","shell.execute_reply":"2024-04-08T06:28:34.467595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Import Libraries**","metadata":{}},{"cell_type":"code","source":"import os\nos.environ[\"KERAS_BACKEND\"] = \"jax\" # you can also use tensorflow or torch\n\nimport keras_cv\nimport keras\n# from keras import ops\nimport tensorflow as tf\nimport cv2\nimport pandas as pd\nimport numpy as np\nfrom glob import glob\nfrom tqdm.notebook import tqdm\nimport joblib\nimport matplotlib.pyplot as plt \nimport seaborn as sns\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import train_test_split\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D,BatchNormalization, Flatten, Dense, Dropout,GlobalAveragePooling2D\nfrom sklearn.tree import DecisionTreeClassifier\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.svm import SVC\nfrom sklearn.metrics import accuracy_score","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:30:12.006415Z","iopub.execute_input":"2024-04-08T06:30:12.006805Z","iopub.status.idle":"2024-04-08T06:30:23.701482Z","shell.execute_reply.started":"2024-04-08T06:30:12.006770Z","shell.execute_reply":"2024-04-08T06:30:23.700668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Library Versions** ","metadata":{}},{"cell_type":"code","source":"print(\"TensorFlow:\", tf.__version__)\nprint(\"Keras:\", keras.__version__)\nprint(\"KerasCV:\", keras_cv.__version__)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:30:46.716091Z","iopub.execute_input":"2024-04-08T06:30:46.717082Z","iopub.status.idle":"2024-04-08T06:30:46.722066Z","shell.execute_reply.started":"2024-04-08T06:30:46.717031Z","shell.execute_reply":"2024-04-08T06:30:46.721187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"\n## **Configurations**","metadata":{}},{"cell_type":"code","source":"class CFG:\n    verbose = 1  # Verbosity\n    seed = 42  # Random seed\n    preset = \"densenet121_imagenet\"  # Name of pretrained classifier\n    image_size = [400, 300]  # Input image size\n    epochs = 13 # Training epochs\n    batch_size = 64  # Batch size\n    lr_mode = \"cos\" # LR scheduler mode from one of \"cos\", \"step\", \"exp\"\n    drop_remainder = True  # Drop incomplete batches\n    num_classes = 6 # Number of classes in the dataset\n    fold = 0 # Which fold to set as validation data\n    class_names = ['Seizure', 'LPD', 'GPD', 'LRDA','GRDA', 'Other']\n    label2name = dict(enumerate(class_names))\n    name2label = {v:k for k, v in label2name.items()}","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:30:48.734964Z","iopub.execute_input":"2024-04-08T06:30:48.735792Z","iopub.status.idle":"2024-04-08T06:30:48.743061Z","shell.execute_reply.started":"2024-04-08T06:30:48.735764Z","shell.execute_reply":"2024-04-08T06:30:48.742100Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### **Sets value for random seed to produce similar result in each run.**","metadata":{}},{"cell_type":"code","source":"keras.utils.set_random_seed(CFG.seed)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:30:51.724750Z","iopub.execute_input":"2024-04-08T06:30:51.725679Z","iopub.status.idle":"2024-04-08T06:30:51.730410Z","shell.execute_reply.started":"2024-04-08T06:30:51.725639Z","shell.execute_reply":"2024-04-08T06:30:51.729465Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Dataset Paths**","metadata":{}},{"cell_type":"code","source":"BASE_PATH = \"/kaggle/input/hms-harmful-brain-activity-classification\"\n\nSPEC_DIR = \"/tmp/dataset/hms-hbac\"\nos.makedirs(SPEC_DIR+'/train_spectrograms', exist_ok=True)\nos.makedirs(SPEC_DIR+'/test_spectrograms', exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:30:53.355330Z","iopub.execute_input":"2024-04-08T06:30:53.356206Z","iopub.status.idle":"2024-04-08T06:30:53.362456Z","shell.execute_reply.started":"2024-04-08T06:30:53.356174Z","shell.execute_reply":"2024-04-08T06:30:53.361659Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train + Valid\ndf = pd.read_csv(f'{BASE_PATH}/train.csv')\ndf['eeg_path'] = f'{BASE_PATH}/train_eegs/'+df['eeg_id'].astype(str)+'.parquet'\ndf['spec_path'] = f'{BASE_PATH}/train_spectrograms/'+df['spectrogram_id'].astype(str)+'.parquet'\ndf['spec2_path'] = f'{SPEC_DIR}/train_spectrograms/'+df['spectrogram_id'].astype(str)+'.npy'\ndf['class_name'] = df.expert_consensus.copy()\ndf['class_label'] = df.expert_consensus.map(CFG.name2label)\ndisplay(df.head(2))\n\n# Test\ntest_df = pd.read_csv(f'{BASE_PATH}/test.csv')\ntest_df['eeg_path'] = f'{BASE_PATH}/test_eegs/'+test_df['eeg_id'].astype(str)+'.parquet'\ntest_df['spec_path'] = f'{BASE_PATH}/test_spectrograms/'+test_df['spectrogram_id'].astype(str)+'.parquet'\ntest_df['spec2_path'] = f'{SPEC_DIR}/test_spectrograms/'+test_df['spectrogram_id'].astype(str)+'.npy'\ndisplay(test_df.head(2))","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:30:54.235490Z","iopub.execute_input":"2024-04-08T06:30:54.236136Z","iopub.status.idle":"2024-04-08T06:30:54.781541Z","shell.execute_reply.started":"2024-04-08T06:30:54.236104Z","shell.execute_reply":"2024-04-08T06:30:54.780550Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.isnull().sum()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:30:54.783374Z","iopub.execute_input":"2024-04-08T06:30:54.784004Z","iopub.status.idle":"2024-04-08T06:30:54.845712Z","shell.execute_reply.started":"2024-04-08T06:30:54.783966Z","shell.execute_reply":"2024-04-08T06:30:54.844944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:30:55.871523Z","iopub.execute_input":"2024-04-08T06:30:55.871925Z","iopub.status.idle":"2024-04-08T06:30:55.904904Z","shell.execute_reply.started":"2024-04-08T06:30:55.871881Z","shell.execute_reply":"2024-04-08T06:30:55.903792Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:30:56.395122Z","iopub.execute_input":"2024-04-08T06:30:56.395473Z","iopub.status.idle":"2024-04-08T06:30:56.406163Z","shell.execute_reply.started":"2024-04-08T06:30:56.395446Z","shell.execute_reply":"2024-04-08T06:30:56.405108Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Coverting dataset datatype(.parquet to .npy)**","metadata":{}},{"cell_type":"code","source":"# Define a function to process a single eeg_id\n\ndef process_spec(spec_id, split=\"train\"):\n    spec_path = f\"{BASE_PATH}/{split}_spectrograms/{spec_id}.parquet\"\n    spec = pd.read_parquet(spec_path)\n    spec = spec.fillna(0).values[:, 1:].T # fill NaN values with 0, transpose for (Time, Freq) -> (Freq, Time)\n    spec = spec.astype(\"float32\")\n    np.save(f\"{SPEC_DIR}/{split}_spectrograms/{spec_id}.npy\", spec)\n\n# Get unique spec_ids of train and valid data\nspec_ids = df[\"spectrogram_id\"].unique()\n\n# Parallelize the processing using joblib for training data\n_ = joblib.Parallel(n_jobs=-1, backend=\"loky\")(\n    joblib.delayed(process_spec)(spec_id, \"train\")\n    for spec_id in tqdm(spec_ids,total=len(spec_ids))\n)\n\n# Get unique spec_ids of test data\ntest_spec_ids = test_df[\"spectrogram_id\"].unique()\n\n# Parallelize the processing using joblib for test data\n_ = joblib.Parallel(n_jobs=-1, backend=\"loky\")(\n    joblib.delayed(process_spec)(spec_id, \"test\")\n    for spec_id in tqdm(test_spec_ids, total=len(test_spec_ids))\n)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:30:57.560120Z","iopub.execute_input":"2024-04-08T06:30:57.560937Z","iopub.status.idle":"2024-04-08T06:33:59.457208Z","shell.execute_reply.started":"2024-04-08T06:30:57.560892Z","shell.execute_reply":"2024-04-08T06:33:59.456331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **EDA using visual graphs**","metadata":{}},{"cell_type":"code","source":"# Remove all the warnings\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:34:07.200792Z","iopub.execute_input":"2024-04-08T06:34:07.201646Z","iopub.status.idle":"2024-04-08T06:34:07.206280Z","shell.execute_reply.started":"2024-04-08T06:34:07.201611Z","shell.execute_reply":"2024-04-08T06:34:07.205478Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Shape of the dataset\ndf.shape","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:34:09.115033Z","iopub.execute_input":"2024-04-08T06:34:09.115959Z","iopub.status.idle":"2024-04-08T06:34:09.121769Z","shell.execute_reply.started":"2024-04-08T06:34:09.115902Z","shell.execute_reply":"2024-04-08T06:34:09.120817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.describe()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:34:10.094871Z","iopub.execute_input":"2024-04-08T06:34:10.095218Z","iopub.status.idle":"2024-04-08T06:34:10.194302Z","shell.execute_reply.started":"2024-04-08T06:34:10.095192Z","shell.execute_reply":"2024-04-08T06:34:10.193339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check unique values of `expert_consensus`\ndf['expert_consensus'].unique()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:34:11.154988Z","iopub.execute_input":"2024-04-08T06:34:11.155783Z","iopub.status.idle":"2024-04-08T06:34:11.169358Z","shell.execute_reply.started":"2024-04-08T06:34:11.155752Z","shell.execute_reply":"2024-04-08T06:34:11.168257Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Plotting**","metadata":{}},{"cell_type":"code","source":"# Plot the distribution of `expert_consensus`\nsns.countplot(x='expert_consensus', data=df)\nplt.title('Distribution of expert consensus')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:34:16.374751Z","iopub.execute_input":"2024-04-08T06:34:16.375588Z","iopub.status.idle":"2024-04-08T06:34:16.739819Z","shell.execute_reply.started":"2024-04-08T06:34:16.375558Z","shell.execute_reply":"2024-04-08T06:34:16.738863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Apply LabelEncoder**","metadata":{}},{"cell_type":"code","source":"# Encode the `expert_consensus` column\nlabel_encoder = LabelEncoder()\ndf['expert_consensus'] = label_encoder.fit_transform(df['expert_consensus'])","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:34:18.395343Z","iopub.execute_input":"2024-04-08T06:34:18.395983Z","iopub.status.idle":"2024-04-08T06:34:18.428136Z","shell.execute_reply.started":"2024-04-08T06:34:18.395949Z","shell.execute_reply":"2024-04-08T06:34:18.427238Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Number of unique patients\nnum_patients = df['patient_id'].nunique()\nprint(f\"Number of unique patients in train dataset: {num_patients}\")\n\n# Number of unique EEG IDs\nnum_eeg_ids = df['eeg_id'].nunique()\nprint(f\"Number of unique EEG IDs in train dataset: {num_eeg_ids}\")","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:34:25.535699Z","iopub.execute_input":"2024-04-08T06:34:25.536077Z","iopub.status.idle":"2024-04-08T06:34:25.543922Z","shell.execute_reply.started":"2024-04-08T06:34:25.536048Z","shell.execute_reply":"2024-04-08T06:34:25.543084Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Histograms for numerical columns\ndf.hist(figsize=(15, 10))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:34:26.595003Z","iopub.execute_input":"2024-04-08T06:34:26.595365Z","iopub.status.idle":"2024-04-08T06:34:29.255733Z","shell.execute_reply.started":"2024-04-08T06:34:26.595337Z","shell.execute_reply":"2024-04-08T06:34:29.254798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Class Distribution\ndf['expert_consensus'].value_counts().plot(kind='bar')\nplt.title('Class Distribution')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:34:30.635347Z","iopub.execute_input":"2024-04-08T06:34:30.635699Z","iopub.status.idle":"2024-04-08T06:34:30.843862Z","shell.execute_reply.started":"2024-04-08T06:34:30.635671Z","shell.execute_reply":"2024-04-08T06:34:30.842949Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load an EEG file\neeg = pd.read_parquet('/kaggle/input/hms-harmful-brain-activity-classification/train_eegs/1484166292.parquet')\neeg\n# List of columns to plot\ncolumns_to_plot = ['Fp1', 'F3', 'C3', 'P3', 'F7', 'T3', 'T5', 'O1', 'Fz', 'Cz', 'Pz', 'Fp2', 'F4', 'C4', 'P4', 'F8', 'T4', 'T6', 'O2', 'EKG']\n# Determine the number of rows/columns needed for subplots\nnum_plots = len(columns_to_plot)\nnum_columns = 2  # Set to 2 as per the previous code\nnum_rows = num_plots // num_columns + (num_plots % num_columns > 0)\n# Create subplots\nfig, axes = plt.subplots(num_rows, num_columns, figsize=(20, num_rows * 4))\n# Flatten the axes array for easy iteration\naxes = axes.flatten()\n# Plot each column in a subplot\nfor i, col in enumerate(columns_to_plot):\n    axes[i].plot(eeg[col])\n    axes[i].set_title(f'Electrode: {col}', fontsize=14)\n# Hide any unused subplots\nfor ax in axes[len(columns_to_plot):]:\n    ax.set_visible(False)\n# Set the overall figure title\nfig.suptitle('EEG Data Visualization Based on the International 10-20 System', fontsize=30, y=1.02)\n# Adjust layout to prevent overlap\nplt.tight_layout()\n# Show the plot\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:34:31.270156Z","iopub.execute_input":"2024-04-08T06:34:31.270507Z","iopub.status.idle":"2024-04-08T06:34:37.261385Z","shell.execute_reply.started":"2024-04-08T06:34:31.270478Z","shell.execute_reply":"2024-04-08T06:34:37.260442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_egg_id = 3911565283\ntest_spec_id = 853520\n\neeg_test = pd.read_parquet(f'/kaggle/input/hms-harmful-brain-activity-classification/test_eegs/{test_egg_id}.parquet')    \nplt.figure(figsize=(20,5))\nplt.plot(eeg_test['Fp1'])\n\nspec_test = pd.read_parquet(f'/kaggle/input/hms-harmful-brain-activity-classification/test_spectrograms/{test_spec_id}.parquet')    \nplt.figure(figsize=(20,5))\nplt.plot(spec_test['time'], spec_test['LL_0.59'])","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:34:37.262992Z","iopub.execute_input":"2024-04-08T06:34:37.263306Z","iopub.status.idle":"2024-04-08T06:34:37.830251Z","shell.execute_reply.started":"2024-04-08T06:34:37.263281Z","shell.execute_reply":"2024-04-08T06:34:37.829207Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Load data**","metadata":{}},{"cell_type":"code","source":"def build_augmenter(dim=CFG.image_size):\n    augmenters = [\n        keras_cv.layers.MixUp(alpha=2.0),\n        keras_cv.layers.RandomCutout(height_factor=(1.0, 1.0),\n                                     width_factor=(0.06, 0.1)), # freq-masking\n        keras_cv.layers.RandomCutout(height_factor=(0.06, 0.1),\n                                     width_factor=(1.0, 1.0)), # time-masking\n    ]\n    \n    def augment(img, label):\n        data = {\"images\":img, \"labels\":label}\n        for augmenter in augmenters:\n            if tf.random.uniform([]) < 0.5:\n                data = augmenter(data, training=True)\n        return data[\"images\"], data[\"labels\"]\n    \n    return augment","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:35:40.997563Z","iopub.execute_input":"2024-04-08T06:35:40.998030Z","iopub.status.idle":"2024-04-08T06:35:41.008395Z","shell.execute_reply.started":"2024-04-08T06:35:40.997989Z","shell.execute_reply":"2024-04-08T06:35:41.006740Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def build_decoder(with_labels=True, target_size=CFG.image_size, dtype=32):\n    def decode_signal(path, offset=None):\n        # Read .npy files and process the signal\n        file_bytes = tf.io.read_file(path)\n        sig = tf.io.decode_raw(file_bytes, tf.float32)\n        sig = sig[1024//dtype:]  # Remove header tag\n        sig = tf.reshape(sig, [400, -1])\n        \n        # Extract labeled subsample from full spectrogram using \"offset\"\n        if offset is not None: \n            offset = offset // 2  # Only odd values are given\n            sig = sig[:, offset:offset+300]\n            \n            # Pad spectrogram to ensure the same input shape of [400, 300]\n            pad_size = tf.math.maximum(0, 300 - tf.shape(sig)[1])\n            sig = tf.pad(sig, [[0, 0], [0, pad_size]])\n            sig = tf.reshape(sig, [400, 300])\n        \n        # Log spectrogram \n        sig = tf.clip_by_value(sig, tf.math.exp(-4.0), tf.math.exp(8.0)) # avoid 0 in log\n        sig = tf.math.log(sig)\n        # Normalize spectrogram\n        sig -= tf.math.reduce_mean(sig)\n        sig /= tf.math.reduce_std(sig) + 1e-6\n        \n        # Mono channel to 3 channels to use \"ImageNet\" weights\n        sig = tf.tile(sig[..., None], [1, 1, 3])\n        return sig\n    \n    def decode_label(label):\n        label = tf.one_hot(label, CFG.num_classes)\n        label = tf.cast(label, tf.float32)\n        label = tf.reshape(label, [CFG.num_classes])\n        return label\n    \n    def decode_with_labels(path, offset=None, label=None):\n        sig = decode_signal(path, offset)\n        label = decode_label(label)\n        return (sig, label)\n    \n    return decode_with_labels if with_labels else decode_signal","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:35:43.405764Z","iopub.execute_input":"2024-04-08T06:35:43.406364Z","iopub.status.idle":"2024-04-08T06:35:43.417551Z","shell.execute_reply.started":"2024-04-08T06:35:43.406333Z","shell.execute_reply":"2024-04-08T06:35:43.416609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def build_dataset(paths, offsets=None, labels=None, batch_size=32, cache=True,\n                  decode_fn=None, augment_fn=None,\n                  augment=False, repeat=True, shuffle=1024, \n                  cache_dir=\"\", drop_remainder=False):\n    if cache_dir != \"\" and cache is True:\n        os.makedirs(cache_dir, exist_ok=True)\n    \n    if decode_fn is None:\n        decode_fn = build_decoder(labels is not None)\n    \n    if augment_fn is None:\n        augment_fn = build_augmenter()\n    \n    AUTO = tf.data.experimental.AUTOTUNE\n    slices = (paths, offsets) if labels is None else (paths, offsets, labels)\n    \n    ds = tf.data.Dataset.from_tensor_slices(slices)\n    ds = ds.map(decode_fn, num_parallel_calls=AUTO)\n    ds = ds.cache(cache_dir) if cache else ds\n    ds = ds.repeat() if repeat else ds\n    if shuffle: \n        ds = ds.shuffle(shuffle, seed=CFG.seed)\n        opt = tf.data.Options()\n        opt.experimental_deterministic = False\n        ds = ds.with_options(opt)\n    ds = ds.batch(batch_size, drop_remainder=drop_remainder)\n    ds = ds.map(augment_fn, num_parallel_calls=AUTO) if augment else ds\n    ds = ds.prefetch(AUTO)\n    return ds","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:35:46.339361Z","iopub.execute_input":"2024-04-08T06:35:46.340064Z","iopub.status.idle":"2024-04-08T06:35:46.349232Z","shell.execute_reply.started":"2024-04-08T06:35:46.340033Z","shell.execute_reply":"2024-04-08T06:35:46.348329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Splitting Data**","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import StratifiedGroupKFold\n\nsgkf = StratifiedGroupKFold(n_splits=5, shuffle=True, random_state=CFG.seed)\n\ndf[\"fold\"] = -1\ndf.reset_index(drop=True, inplace=True)\nfor fold, (train_idx, valid_idx) in enumerate(\n    sgkf.split(df, y=df[\"class_label\"], groups=df[\"patient_id\"])\n):\n    df.loc[valid_idx, \"fold\"] = fold\ndf.groupby([\"fold\", \"class_name\"])[[\"eeg_id\"]].count().T","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:35:48.579804Z","iopub.execute_input":"2024-04-08T06:35:48.580624Z","iopub.status.idle":"2024-04-08T06:35:49.789130Z","shell.execute_reply.started":"2024-04-08T06:35:48.580591Z","shell.execute_reply":"2024-04-08T06:35:49.788102Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Train and Valid Dataset**","metadata":{}},{"cell_type":"code","source":"# Sample from full data\nsample_df = df.groupby(\"spectrogram_id\").head(1).reset_index(drop=True)\ntrain_df = sample_df[sample_df.fold != CFG.fold]\nvalid_df = sample_df[sample_df.fold == CFG.fold]\nprint(f\"# Num Train: {len(train_df)} | Num Valid: {len(valid_df)}\")\n\n# Train\ntrain_paths = train_df.spec2_path.values\ntrain_offsets = train_df.spectrogram_label_offset_seconds.values.astype(int)\ntrain_labels = train_df.class_label.values\ntrain_ds = build_dataset(train_paths, train_offsets, train_labels, batch_size=CFG.batch_size,\n                         repeat=True, shuffle=True, augment=True, cache=True)\n\n# Valid\nvalid_paths = valid_df.spec2_path.values\nvalid_offsets = valid_df.spectrogram_label_offset_seconds.values.astype(int)\nvalid_labels = valid_df.class_label.values\nvalid_ds = build_dataset(valid_paths, valid_offsets, valid_labels, batch_size=CFG.batch_size,\n                         repeat=False, shuffle=False, augment=False, cache=True)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:36:03.995660Z","iopub.execute_input":"2024-04-08T06:36:03.996516Z","iopub.status.idle":"2024-04-08T06:36:06.922021Z","shell.execute_reply.started":"2024-04-08T06:36:03.996481Z","shell.execute_reply":"2024-04-08T06:36:06.921048Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Sample Images**","metadata":{}},{"cell_type":"code","source":"imgs, tars = next(iter(train_ds))\n\nnum_imgs = 8\nplt.figure(figsize=(4*4, num_imgs//4*5))\nfor i in range(num_imgs):\n    plt.subplot(num_imgs//4, 4, i + 1)\n    img = imgs[i].numpy()[...,0]  # Adjust as per your image data format\n    img -= img.min()\n    img /= img.max() + 1e-4\n    tar = CFG.label2name[np.argmax(tars[i].numpy())]\n    plt.imshow(img)\n    plt.title(f\"Target: {tar}\")\n    plt.axis('off')\n    \nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:36:07.134965Z","iopub.execute_input":"2024-04-08T06:36:07.135302Z","iopub.status.idle":"2024-04-08T06:36:09.958588Z","shell.execute_reply.started":"2024-04-08T06:36:07.135277Z","shell.execute_reply":"2024-04-08T06:36:09.957394Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **DenseNet Model**","metadata":{}},{"cell_type":"code","source":"LOSS = keras.losses.KLDivergence()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:36:14.200625Z","iopub.execute_input":"2024-04-08T06:36:14.206835Z","iopub.status.idle":"2024-04-08T06:36:14.211591Z","shell.execute_reply.started":"2024-04-08T06:36:14.206799Z","shell.execute_reply":"2024-04-08T06:36:14.210402Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import keras_cv\n\n# Build DenseNet model using keras_cv\nmodel = keras_cv.models.ImageClassifier.from_preset(\n    CFG.preset, num_classes=CFG.num_classes\n)\n\n# Compile the model  \nmodel.compile(optimizer=keras.optimizers.Adam(learning_rate=1e-4),\n              loss=LOSS,metrics=['accuracy'])\n\n# Model Summary\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:36:20.005784Z","iopub.execute_input":"2024-04-08T06:36:20.006645Z","iopub.status.idle":"2024-04-08T06:36:33.873009Z","shell.execute_reply.started":"2024-04-08T06:36:20.006612Z","shell.execute_reply":"2024-04-08T06:36:33.872045Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **LR Scheduling**","metadata":{}},{"cell_type":"code","source":"import math\ndef get_lr_callback(batch_size=8, mode='cos', epochs=10, plot=False):\n    lr_start, lr_max, lr_min = 5e-5, 6e-6 * batch_size, 1e-5\n    lr_ramp_ep, lr_sus_ep, lr_decay = 3, 0, 0.75\n\n    def lrfn(epoch):  # Learning rate update function\n        if epoch < lr_ramp_ep: lr = (lr_max - lr_start) / lr_ramp_ep * epoch + lr_start\n        elif epoch < lr_ramp_ep + lr_sus_ep: lr = lr_max\n        elif mode == 'exp': lr = (lr_max - lr_min) * lr_decay**(epoch - lr_ramp_ep - lr_sus_ep) + lr_min\n        elif mode == 'step': lr = lr_max * lr_decay**((epoch - lr_ramp_ep - lr_sus_ep) // 2)\n        elif mode == 'cos':\n            decay_total_epochs, decay_epoch_index = epochs - lr_ramp_ep - lr_sus_ep + 3, epoch - lr_ramp_ep - lr_sus_ep\n            phase = math.pi * decay_epoch_index / decay_total_epochs\n            lr = (lr_max - lr_min) * 0.5 * (1 + math.cos(phase)) + lr_min\n        return lr\n\n    if plot:  # Plot lr curve if plot is True\n        plt.figure(figsize=(10, 5))\n        plt.plot(np.arange(epochs), [lrfn(epoch) for epoch in np.arange(epochs)], marker='o')\n        plt.xlabel('epoch'); plt.ylabel('lr')\n        plt.title('LR Scheduler')\n        plt.show()\n    return keras.callbacks.LearningRateScheduler(lrfn, verbose=False)  # Create lr callback","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:36:41.870734Z","iopub.execute_input":"2024-04-08T06:36:41.871377Z","iopub.status.idle":"2024-04-08T06:36:41.882936Z","shell.execute_reply.started":"2024-04-08T06:36:41.871343Z","shell.execute_reply":"2024-04-08T06:36:41.881969Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lr_cb = get_lr_callback(CFG.batch_size, mode=CFG.lr_mode, plot=True)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:36:44.605385Z","iopub.execute_input":"2024-04-08T06:36:44.605737Z","iopub.status.idle":"2024-04-08T06:36:44.815171Z","shell.execute_reply.started":"2024-04-08T06:36:44.605709Z","shell.execute_reply":"2024-04-08T06:36:44.814281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ckpt_cb = keras.callbacks.ModelCheckpoint(\"best_model.keras\",\n                                         monitor='val_loss',\n                                         save_best_only=True,\n                                         save_weights_only=False,\n                                         mode='min')","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:36:45.975176Z","iopub.execute_input":"2024-04-08T06:36:45.975537Z","iopub.status.idle":"2024-04-08T06:36:45.980116Z","shell.execute_reply.started":"2024-04-08T06:36:45.975509Z","shell.execute_reply":"2024-04-08T06:36:45.979164Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(\n    train_ds, \n    epochs=CFG.epochs,\n    callbacks=[lr_cb, ckpt_cb], \n    steps_per_epoch=len(train_df)//CFG.batch_size,\n    validation_data=valid_ds, \n    verbose=CFG.verbose\n)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T06:36:47.350080Z","iopub.execute_input":"2024-04-08T06:36:47.350434Z","iopub.status.idle":"2024-04-08T07:26:18.053998Z","shell.execute_reply.started":"2024-04-08T06:36:47.350406Z","shell.execute_reply":"2024-04-08T07:26:18.053023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Prediction**","metadata":{}},{"cell_type":"code","source":"model.load_weights(\"best_model.keras\")","metadata":{"execution":{"iopub.status.busy":"2024-04-08T07:26:27.277314Z","iopub.execute_input":"2024-04-08T07:26:27.277924Z","iopub.status.idle":"2024-04-08T07:26:37.432988Z","shell.execute_reply.started":"2024-04-08T07:26:27.277877Z","shell.execute_reply":"2024-04-08T07:26:37.431966Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_paths = test_df.spec2_path.values\ntest_ds = build_dataset(test_paths, batch_size=min(CFG.batch_size, len(test_df)),\n                         repeat=False, shuffle=False, cache=False, augment=False)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T07:26:44.740869Z","iopub.execute_input":"2024-04-08T07:26:44.741656Z","iopub.status.idle":"2024-04-08T07:26:44.788826Z","shell.execute_reply.started":"2024-04-08T07:26:44.741624Z","shell.execute_reply":"2024-04-08T07:26:44.787892Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds = model.predict(test_ds)","metadata":{"execution":{"iopub.status.busy":"2024-04-08T07:26:57.192229Z","iopub.execute_input":"2024-04-08T07:26:57.192602Z","iopub.status.idle":"2024-04-08T07:27:10.453271Z","shell.execute_reply.started":"2024-04-08T07:26:57.192569Z","shell.execute_reply":"2024-04-08T07:27:10.452344Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred_df = test_df[[\"eeg_id\"]].copy()\ntarget_cols = [x.lower()+'_vote' for x in CFG.class_names]\npred_df[target_cols] = preds.tolist()\n\nsub_df = pd.read_csv(f'{BASE_PATH}/sample_submission.csv')\nsub_df = sub_df[[\"eeg_id\"]].copy()\nsub_df = sub_df.merge(pred_df, on=\"eeg_id\", how=\"left\")\nsub_df.to_csv(\"submission.csv\", index=False)\nsub_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T07:27:20.656656Z","iopub.execute_input":"2024-04-08T07:27:20.657331Z","iopub.status.idle":"2024-04-08T07:27:20.717981Z","shell.execute_reply.started":"2024-04-08T07:27:20.657296Z","shell.execute_reply":"2024-04-08T07:27:20.717097Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **Submission**","metadata":{}},{"cell_type":"code","source":"# Prepare submission DataFrame (same as before)\npred_df = test_df[[\"eeg_id\"]].copy()\ntarget_cols = [x.lower() + '_vote' for x in CFG.class_names]\npred_df[target_cols] = preds.tolist()\n\n# Merge with the sample submission DataFrame (same as before)\nsub_df = pd.read_csv(f'{BASE_PATH}/sample_submission.csv')\nsub_df = sub_df[[\"eeg_id\"]].copy()\nsub_df = sub_df.merge(pred_df, on=\"eeg_id\", how=\"left\")\n# Save the submission DataFrame to a CSV file (same as before)\nsub_df.to_csv(\"submission.csv\", index=False)\nsub_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-04-08T07:27:25.935987Z","iopub.execute_input":"2024-04-08T07:27:25.936413Z","iopub.status.idle":"2024-04-08T07:27:25.961408Z","shell.execute_reply.started":"2024-04-08T07:27:25.936380Z","shell.execute_reply":"2024-04-08T07:27:25.960363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}