{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":59093,"databundleVersionId":7469972,"sourceType":"competition"},{"sourceId":7392733,"sourceType":"datasetVersion","datasetId":4297749},{"sourceId":7637636,"sourceType":"datasetVersion","datasetId":4450985}],"dockerImageVersionId":30636,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> HMS: <span style='color:#F1A424'>WaveNet</span><span style='color:#ABABAB'> [Inference]</span></b> \n\n***\n\n- [Train notebook](https://www.kaggle.com/code/alejopaullier/hms-wavenet-pytorch-train)\n\nYour goal in this competition is to detect and classify seizures and other types of harmful brain activity. You will develop a model trained on electroencephalography (EEG) signals recorded from critically ill hospital patients.\n\nIn this notebook you will learn how to predict seizures using a `WaveNet` PyTorch model. Hope you enjoy it and find it useful.\n\nI also made a **PyTorch 🔥 version** of Chris' `EfficientNetB0` notebook here:\n- [HMS | EfficientNetB0 PyTorch [Train]](https://www.kaggle.com/code/alejopaullier/hms-efficientnetb0-pytorch-train)\n- [HMS | EfficientNetB0 PyTorch [Inference]](https://www.kaggle.com/code/alejopaullier/hms-efficientnetb0-pytorch-inference)\n\n### <b><span style='color:#F1A424'>Table of Contents</span></b> <a class='anchor' id='top'></a>\n<div style=\" background-color:#3b3745; padding: 13px 13px; border-radius: 8px; color: white\">\n<li><a href=\"#import_libraries\">Import Libraries</a></li>\n<li><a href=\"#configuration\">Configuration</a></li>\n<li><a href=\"#utils\">Utils</a></li>\n<li><a href=\"#load_data\">Load Data</a></li>\n<li><a href=\"#dataset\">Dataset</a></li>\n<li><a href=\"#dataloader\">DataLoader</a></li>\n<li><a href=\"#model\">Model</a></li>\n<li><a href=\"#inference_function\">Inference Function</a></li>\n<li><a href=\"#infer\">Infer</a></li>\n<li><a href=\"#submission\">Save Submission</a></li>\n</div>\n","metadata":{}},{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> Import Libraries</b><a class='anchor' id='import_libraries'></a> [↑](#top) \n\n***\n\nImport all the required libraries for this notebook.","metadata":{}},{"cell_type":"code","source":"import gc\nimport math\nimport matplotlib.pyplot as plt\nimport multiprocessing\nimport numpy as np\nimport os\nimport pandas as pd\nimport random\nimport time\nimport torch\nimport torch.nn as nn\n\n\nfrom glob import glob\nfrom torch.utils.data import DataLoader, Dataset\nfrom tqdm import tqdm\nfrom typing import Dict, List\n\nos.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0,1\"\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\nprint('Using', torch.cuda.device_count(), 'GPU(s)')","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:25.494938Z","iopub.execute_input":"2024-02-17T00:40:25.495871Z","iopub.status.idle":"2024-02-17T00:40:28.759667Z","shell.execute_reply.started":"2024-02-17T00:40:25.495827Z","shell.execute_reply":"2024-02-17T00:40:28.758757Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> Configuration</b><a class='anchor' id='configuration'></a> [↑](#top) \n\n***","metadata":{}},{"cell_type":"code","source":"class config:\n    BATCH_SIZE_TEST = 32\n    NUM_WORKERS = 0 # multiprocessing.cpu_count()\n    PRINT_FREQ = 20\n    SEED = 20\n    VISUALIZE = False\n    \n    \nclass paths:\n    OUTPUT_DIR = \"/kaggle/working/\"\n    TEST_CSV = \"/kaggle/input/hms-harmful-brain-activity-classification/test.csv\"\n    TEST_EEGS = \"/kaggle/input/hms-harmful-brain-activity-classification/test_eegs/\"\n    \n    \nmodel_weights = [x for x in glob(\"/kaggle/input/hms-wavenet/*.pth\")]\nmodel_weights","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:28.761575Z","iopub.execute_input":"2024-02-17T00:40:28.762Z","iopub.status.idle":"2024-02-17T00:40:28.780503Z","shell.execute_reply.started":"2024-02-17T00:40:28.761975Z","shell.execute_reply":"2024-02-17T00:40:28.779671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> Utils</b><a class='anchor' id='utils'></a> [↑](#top) \n\n***\n\nUtility functions.","metadata":{}},{"cell_type":"code","source":"def eeg_from_parquet(parquet_path: str) -> np.ndarray:\n    \"\"\"\n    This function reads a parquet file and extracts the middle 50 seconds of readings. Then it fills NaN values\n    with the mean value (ignoring NaNs).\n    :param parquet_path: path to parquet file.\n    :param display: whether to display EEG plots or not.\n    :return data: np.array of shape  (time_steps, eeg_features) -> (10_000, 8)\n    \"\"\"\n    # === Extract middle 50 seconds ===\n    eeg = pd.read_parquet(parquet_path, columns=eeg_features)\n    rows = len(eeg)\n    offset = (rows - 10_000) // 2 # 50 * 200 = 10_000\n    eeg = eeg.iloc[offset:offset+10_000] # middle 50 seconds, has the same amount of readings to left and right\n    # === Convert to numpy ===\n    data = np.zeros((10_000, len(eeg_features))) # create placeholder of same shape with zeros\n    for index, feature in enumerate(eeg_features):\n        x = eeg[feature].values.astype('float32') # convert to float32\n        mean = np.nanmean(x) # arithmetic mean along the specified axis, ignoring NaNs\n        nan_percentage = np.isnan(x).mean() # percentage of NaN values in feature\n        # === Fill nan values ===\n        if nan_percentage < 1: # if some values are nan, but not all\n            x = np.nan_to_num(x, nan=mean)\n        else: # if all values are nan\n            x[:] = 0\n        data[:, index] = x\n   \n    return data\n\n\ndef seed_everything(seed: int):\n    random.seed(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed) \n    \n    \ndef sep():\n    print(\"-\"*100)\n\n    \ntarget_preds = [x + \"_pred\" for x in ['seizure_vote', 'lpd_vote', 'gpd_vote', 'lrda_vote', 'grda_vote', 'other_vote']]\nlabel_to_num = {'Seizure': 0, 'LPD': 1, 'GPD': 2, 'LRDA': 3, 'GRDA': 4, 'Other':5}\nnum_to_label = {v: k for k, v in label_to_num.items()}\nseed_everything(config.SEED)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-02-17T00:40:28.781518Z","iopub.execute_input":"2024-02-17T00:40:28.781795Z","iopub.status.idle":"2024-02-17T00:40:28.795266Z","shell.execute_reply.started":"2024-02-17T00:40:28.781771Z","shell.execute_reply":"2024-02-17T00:40:28.794527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> Load Data</b><a class='anchor' id='load_data'></a> [↑](#top) \n\n***\n\nLoad the competition's data.","metadata":{}},{"cell_type":"code","source":"test_df = pd.read_csv(paths.TEST_CSV)\nprint(f\"Test dataframe shape is: {test_df.shape}\")\ntest_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:28.796225Z","iopub.execute_input":"2024-02-17T00:40:28.796506Z","iopub.status.idle":"2024-02-17T00:40:28.823761Z","shell.execute_reply.started":"2024-02-17T00:40:28.796475Z","shell.execute_reply":"2024-02-17T00:40:28.822903Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### <b><span style='color:#F1A424'>Read one EEG parquet</span></b>\n\nAll of the EEG data (for both train and test) was collected at a frequency of 200 samples per second,\n\nEach EEG parquet results in a dataframe with `seconds` rows and 20 columns.\n\n- EEG features are: `['Fp1', 'F3', 'C3', 'P3', 'F7', 'T3', 'T5', 'O1', 'Fz', 'Cz', 'Pz', 'Fp2', 'F4', 'C4', 'P4', 'F8', 'T4', 'T6', 'O2', 'EKG']`\n- We will use these features: `['Fp1','T3','C3','O1','Fp2','C4','T4','O2']`\n\n","metadata":{}},{"cell_type":"code","source":"eeg_parquet_paths = glob(paths.TEST_EEGS + \"*.parquet\")\neeg_df = pd.read_parquet(eeg_parquet_paths[0])\neeg_features = eeg_df.columns\nprint(f'There are {len(eeg_features)} raw eeg features')\nprint(list(eeg_features))\neeg_features = ['Fp1','T3','C3','O1','Fp2','C4','T4','O2']\nfeature_to_index = {x:y for x,y in zip(eeg_features, range(len(eeg_features)))}","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:28.826057Z","iopub.execute_input":"2024-02-17T00:40:28.826316Z","iopub.status.idle":"2024-02-17T00:40:29.012576Z","shell.execute_reply.started":"2024-02-17T00:40:28.826294Z","shell.execute_reply":"2024-02-17T00:40:29.011677Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### <b><span style='color:#F1A424'>Read all EEG parquets</span></b>","metadata":{}},{"cell_type":"code","source":"%%time\n\nCREATE_EEGS = False\nall_eegs = {}\nvisualize = 1\neeg_paths = glob(paths.TEST_EEGS + \"*.parquet\")\neeg_ids = test_df.eeg_id.unique()\n\nfor i, eeg_id in tqdm(enumerate(eeg_ids)):  \n    # Save EEG to Python dictionary of numpy arrays\n    eeg_path = paths.TEST_EEGS + str(eeg_id) + \".parquet\"\n    data = eeg_from_parquet(eeg_path)              \n    all_eegs[eeg_id] = data","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:29.013678Z","iopub.execute_input":"2024-02-17T00:40:29.013963Z","iopub.status.idle":"2024-02-17T00:40:29.03289Z","shell.execute_reply.started":"2024-02-17T00:40:29.01394Z","shell.execute_reply":"2024-02-17T00:40:29.032003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> Butter Low-Pass Filter</b><a class='anchor' id='filter'></a> [↑](#top) \n\n***\n\n- [scipy.signal.butter()][1]\n- [scipy.signal.lfilter()][2]\n\n[1]: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.butter.html#scipy.signal.butter\n[2]: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.lfilter.html#scipy.signal.lfilter","metadata":{}},{"cell_type":"code","source":"from scipy.signal import butter, lfilter\n\ndef butter_lowpass_filter(data, cutoff_freq: int = 20, sampling_rate: int = 200, order: int = 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","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:29.034035Z","iopub.execute_input":"2024-02-17T00:40:29.034296Z","iopub.status.idle":"2024-02-17T00:40:29.39829Z","shell.execute_reply.started":"2024-02-17T00:40:29.034273Z","shell.execute_reply":"2024-02-17T00:40:29.397523Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> Dataset</b><a class='anchor' id='dataset'></a> [↑](#top) \n\n***\n\nCreate a custom `Dataset` to load data.\n\n- [How to Convert EEG to Spectrograms][1]: to understand the feature engineering performed in the generation method.\n- [How To Create Spectrogram From Eeg?][2]: original post on how to create Spectrograms from EEGs.\n- [Introduction to EEG][3]: short video to better understand EEGs.\n\n[1]: https://www.kaggle.com/competitions/hms-harmful-brain-activity-classification/discussion/469760\n[2]: https://www.kaggle.com/competitions/hms-harmful-brain-activity-classification/discussion/467877\n[3]: https://www.youtube.com/watch?v=XMizSSOejg0","metadata":{}},{"cell_type":"code","source":"class CustomDataset(Dataset):\n    def __init__(\n        self, df: pd.DataFrame, config,\n        eegs: Dict[int, np.ndarray] = all_eegs, downsample: int = 5\n    ): \n        self.df = df\n        self.config = config\n        self.batch_size = self.config.BATCH_SIZE_TEST\n        self.eegs = eegs\n        self.downsample = downsample\n        \n    def __len__(self):\n        \"\"\"\n        Length of dataset.\n        \"\"\"\n        return len(self.df)\n        \n    def __getitem__(self, index):\n        \"\"\"\n        Get one item.\n        \"\"\"\n        X = self.__data_generation(index)\n        X = X[::self.downsample, :]\n        output = {\n            \"X\": torch.tensor(X, dtype=torch.float32)\n        }\n        return output\n                        \n    def __data_generation(self, index):\n        row = self.df.iloc[index]\n        X = np.zeros((10_000, 8), dtype='float32')\n        data = self.eegs[row.eeg_id]\n\n        # === Feature engineering ===\n        X[:,0] = data[:,feature_to_index['Fp1']] - data[:,feature_to_index['T3']]\n        X[:,1] = data[:,feature_to_index['T3']] - data[:,feature_to_index['O1']]\n\n        X[:,2] = data[:,feature_to_index['Fp1']] - data[:,feature_to_index['C3']]\n        X[:,3] = data[:,feature_to_index['C3']] - data[:,feature_to_index['O1']]\n\n        X[:,4] = data[:,feature_to_index['Fp2']] - data[:,feature_to_index['C4']]\n        X[:,5] = data[:,feature_to_index['C4']] - data[:,feature_to_index['O2']]\n\n        X[:,6] = data[:,feature_to_index['Fp2']] - data[:,feature_to_index['T4']]\n        X[:,7] = data[:,feature_to_index['T4']] - data[:,feature_to_index['O2']]\n\n        # === Standarize ===\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 = butter_lowpass_filter(X)\n            \n        return X","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:29.399402Z","iopub.execute_input":"2024-02-17T00:40:29.399693Z","iopub.status.idle":"2024-02-17T00:40:29.412634Z","shell.execute_reply.started":"2024-02-17T00:40:29.399668Z","shell.execute_reply":"2024-02-17T00:40:29.411654Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> DataLoader</b><a class='anchor' id='dataloader'></a> [↑](#top) \n\n***","metadata":{}},{"cell_type":"code","source":"test_dataset = CustomDataset(test_df, config)\ntest_loader = DataLoader(\n    test_dataset,\n    batch_size=config.BATCH_SIZE_TEST,\n    shuffle=False,\n    num_workers=config.NUM_WORKERS,\n    pin_memory=True,\n    drop_last=False\n)\noutput = test_dataset[0]\nX = output[\"X\"]\nprint(f\"X shape: {X.shape}\")","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:29.413838Z","iopub.execute_input":"2024-02-17T00:40:29.414514Z","iopub.status.idle":"2024-02-17T00:40:29.457567Z","shell.execute_reply.started":"2024-02-17T00:40:29.414455Z","shell.execute_reply":"2024-02-17T00:40:29.456756Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> Model</b><a class='anchor' id='model'></a> [↑](#top) \n\n***\n\n<center><img width = 800 src=\"https://raw.githubusercontent.com/cdeotte/Kaggle_Images/main/Jan-2024/wave-model.png\"></center>","metadata":{}},{"cell_type":"code","source":"class Wave_Block(nn.Module):\n    def __init__(self, in_channels: int, out_channels: int, dilation_rates: int, kernel_size: int = 3):\n        \"\"\"\n        WaveNet building block.\n        :param in_channels: number of input channels.\n        :param out_channels: number of output channels.\n        :param dilation_rates: how many levels of dilations are used.\n        :param kernel_size: size of the convolving kernel.\n        \"\"\"\n        super(Wave_Block, self).__init__()\n        self.num_rates = dilation_rates\n        self.convs = nn.ModuleList()\n        self.filter_convs = nn.ModuleList()\n        self.gate_convs = nn.ModuleList()\n        self.convs.append(nn.Conv1d(in_channels, out_channels, kernel_size=1, bias=True))\n        \n        dilation_rates = [2 ** i for i in range(dilation_rates)]\n        for dilation_rate in dilation_rates:\n            self.filter_convs.append(\n                nn.Conv1d(out_channels, out_channels, kernel_size=kernel_size,\n                          padding=int((dilation_rate*(kernel_size-1))/2), dilation=dilation_rate))\n            self.gate_convs.append(\n                nn.Conv1d(out_channels, out_channels, kernel_size=kernel_size,\n                          padding=int((dilation_rate*(kernel_size-1))/2), dilation=dilation_rate))\n            self.convs.append(nn.Conv1d(out_channels, out_channels, kernel_size=1, bias=True))\n        \n        for i in range(len(self.convs)):\n            nn.init.xavier_uniform_(self.convs[i].weight, gain=nn.init.calculate_gain('relu'))\n            nn.init.zeros_(self.convs[i].bias)\n\n        for i in range(len(self.filter_convs)):\n            nn.init.xavier_uniform_(self.filter_convs[i].weight, gain=nn.init.calculate_gain('relu'))\n            nn.init.zeros_(self.filter_convs[i].bias)\n\n        for i in range(len(self.gate_convs)):\n            nn.init.xavier_uniform_(self.gate_convs[i].weight, gain=nn.init.calculate_gain('relu'))\n            nn.init.zeros_(self.gate_convs[i].bias)\n\n    def forward(self, x):\n        x = self.convs[0](x)\n        res = x\n        for i in range(self.num_rates):\n            tanh_out = torch.tanh(self.filter_convs[i](x))\n            sigmoid_out = torch.sigmoid(self.gate_convs[i](x))\n            x = tanh_out * sigmoid_out\n            x = self.convs[i + 1](x) \n            res = res + x\n        return res\n    \nclass WaveNet(nn.Module):\n    def __init__(self, input_channels: int = 1, kernel_size: int = 3):\n        super(WaveNet, self).__init__()\n        self.model = nn.Sequential(\n                Wave_Block(input_channels, 8, 12, kernel_size),\n                Wave_Block(8, 16, 8, kernel_size),\n                Wave_Block(16, 32, 4, kernel_size),\n                Wave_Block(32, 64, 1, kernel_size) \n        )\n    def forward(self, x: torch.Tensor) -> torch.Tensor:\n        x = x.permute(0, 2, 1) \n        output = self.model(x)\n        return output\n\n\nclass CustomModel(nn.Module):\n    def __init__(self):\n        super(CustomModel, self).__init__()\n        self.model = WaveNet()\n        self.global_avg_pooling = nn.AdaptiveAvgPool1d(1)\n        self.dropout = 0.0\n        self.head = nn.Sequential(\n            nn.Linear(256, 64),\n            nn.BatchNorm1d(64),\n            nn.ReLU(),\n            nn.Dropout(self.dropout),\n            nn.Linear(64, 6)\n        )\n        \n    def forward(self, x: torch.Tensor):\n        \"\"\"\n        Forwward pass.\n        \"\"\"\n        x1 = self.model(x[:, :, 0:1])\n        x1 = self.global_avg_pooling(x1)\n        x1 = x1.squeeze(dim=2)\n        x2 = self.model(x[:, :, 1:2])\n        x2 = self.global_avg_pooling(x2)\n        x2 = x2.squeeze(dim=2)\n        z1 = torch.mean(torch.stack([x1, x2]), dim=0)\n\n        x1 = self.model(x[:, :, 2:3])\n        x1 = self.global_avg_pooling(x1)\n        x1 = x1.squeeze(dim=2)\n        x2 = self.model(x[:, :, 3:4])\n        x2 = self.global_avg_pooling(x2)\n        x2 = x2.squeeze(dim=2)\n        z2 = torch.mean(torch.stack([x1, x2]), dim=0)\n        \n        x1 = self.model(x[:, :, 4:5])\n        x1 = self.global_avg_pooling(x1)\n        x1 = x1.squeeze(dim=2)\n        x2 = self.model(x[:, :, 5:6])\n        x2 = self.global_avg_pooling(x2)\n        x2 = x2.squeeze(dim=2)\n        z3 = torch.mean(torch.stack([x1, x2]), dim=0)\n        \n        x1 = self.model(x[:, :, 6:7])\n        x1 = self.global_avg_pooling(x1)\n        x1 = x1.squeeze(dim=2)\n        x2 = self.model(x[:, :, 7:8])\n        x2 = self.global_avg_pooling(x2)\n        x2 = x2.squeeze(dim=2)\n        z4 = torch.mean(torch.stack([x1, x2]), dim=0)\n        \n        y = torch.cat([z1, z2, z3, z4], dim=1)\n        y = self.head(y)\n        \n        return y\n\nmodel = CustomModel()\ntotal_params = sum(p.numel() for p in model.parameters())\nprint(f\"Total number of parameters: {total_params}\")","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:29.458856Z","iopub.execute_input":"2024-02-17T00:40:29.459112Z","iopub.status.idle":"2024-02-17T00:40:29.524594Z","shell.execute_reply.started":"2024-02-17T00:40:29.459088Z","shell.execute_reply":"2024-02-17T00:40:29.523768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> Inference Function</b><a class='anchor' id='inference_function'></a> [↑](#top) \n\n***","metadata":{}},{"cell_type":"code","source":"def inference_function(test_loader, model, device):\n    model.eval() # set model in evaluation mode\n    softmax = nn.Softmax(dim=1)\n    prediction_dict = {}\n    preds = []\n    with tqdm(test_loader, unit=\"test_batch\", desc='Inference') as tqdm_test_loader:\n        for step, batch in enumerate(tqdm_test_loader):\n            X = batch.pop(\"X\").to(device) # send inputs to `device`\n            batch_size = X.size(0)\n            with torch.no_grad():\n                y_preds = model(X) # forward propagation pass\n            y_preds = softmax(y_preds)\n            preds.append(y_preds.to('cpu').numpy()) # save predictions\n                \n    prediction_dict[\"predictions\"] = np.concatenate(preds) # np.array() of shape (fold_size, target_cols)\n    return prediction_dict","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:29.525808Z","iopub.execute_input":"2024-02-17T00:40:29.526398Z","iopub.status.idle":"2024-02-17T00:40:29.533171Z","shell.execute_reply.started":"2024-02-17T00:40:29.526365Z","shell.execute_reply":"2024-02-17T00:40:29.532281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> Inference</b><a class='anchor' id='infer'></a> [↑](#top) \n\n***","metadata":{}},{"cell_type":"code","source":"predictions = []\n\nfor model_weight in model_weights:\n    test_dataset = CustomDataset(test_df, config)\n    train_loader = DataLoader(\n        test_dataset,\n        batch_size=config.BATCH_SIZE_TEST,\n        shuffle=False,\n        num_workers=config.NUM_WORKERS,\n        pin_memory=True,\n        drop_last=False\n    )\n    model = CustomModel()\n    checkpoint = torch.load(model_weight)\n    model.load_state_dict(checkpoint[\"model\"])\n    model.to(device)\n    prediction_dict = inference_function(test_loader, model, device)\n    predictions.append(prediction_dict[\"predictions\"])\n    torch.cuda.empty_cache()\n    gc.collect()\n    \npredictions = np.array(predictions)\npredictions = np.mean(predictions, axis=0)","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:29.534212Z","iopub.execute_input":"2024-02-17T00:40:29.53447Z","iopub.status.idle":"2024-02-17T00:40:31.416654Z","shell.execute_reply.started":"2024-02-17T00:40:29.534447Z","shell.execute_reply":"2024-02-17T00:40:31.41577Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <b><span style='color:#F1A424'>|</span> Submission</b><a class='anchor' id='submission'></a> [↑](#top) \n\n***","metadata":{"execution":{"iopub.status.busy":"2024-02-15T22:27:03.071166Z","iopub.execute_input":"2024-02-15T22:27:03.071564Z","iopub.status.idle":"2024-02-15T22:27:03.084649Z","shell.execute_reply.started":"2024-02-15T22:27:03.071534Z","shell.execute_reply":"2024-02-15T22:27:03.083623Z"}}},{"cell_type":"code","source":"TARGETS = ['seizure_vote', 'lpd_vote', 'gpd_vote', 'lrda_vote', 'grda_vote', 'other_vote']\nsub = pd.DataFrame({'eeg_id': test_df.eeg_id.values})\nsub[TARGETS] = predictions\nsub.to_csv('submission.csv',index=False)\nprint(f'Submission shape: {sub.shape}')\nsub.head()","metadata":{"execution":{"iopub.status.busy":"2024-02-17T00:40:31.41791Z","iopub.execute_input":"2024-02-17T00:40:31.418566Z","iopub.status.idle":"2024-02-17T00:40:31.43815Z","shell.execute_reply.started":"2024-02-17T00:40:31.418531Z","shell.execute_reply":"2024-02-17T00:40:31.437308Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}