{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":59093,"databundleVersionId":7469972,"sourceType":"competition"}],"dockerImageVersionId":30635,"isInternetEnabled":true,"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)\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport torch\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\nimport glob\nfrom tqdm.notebook import tqdm, trange\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(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","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# preprocessing and loading functionalities","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv('/kaggle/input/hms-harmful-brain-activity-classification/train.csv')\n\nprocessed_train = train_df.groupby('eeg_id')[['patient_id']].agg('first')\nclass_score_train = train_df.groupby('eeg_id')[train_df.columns[-6:]].agg('sum')\nclass_score_train[train_df.columns[-6:]] = class_score_train.values / class_score_train.sum(axis=1).values.reshape(-1, 1)\n\nprocessed_train = pd.concat([processed_train, class_score_train], axis=1)\nprocessed_train = processed_train.reset_index()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"EEG_PATH = '/kaggle/input/hms-harmful-brain-activity-classification/train_eegs/'\nCOLS_INTEREST = ['Fp1', 'C3', 'F7', 'T5', 'Fz', 'Cz', 'Pz', 'Fp2', 'F4', 'C4', 'P4', 'F8', 'T4', 'T6', 'O2', 'EKG']","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import Dataset, DataLoader\nfrom scipy.signal import butter, sosfilt\nfrom sklearn.preprocessing import MinMaxScaler\nfrom sklearn.impute import SimpleImputer\n\nclass EEGDataset(Dataset):\n    def __init__(self, csv, eeg_path):\n        super().__init__()\n        self.csv = csv\n        self.eeg_path = eeg_path\n        self.eeg_file_paths = glob.glob(self.eeg_path+'*')\n        \n    def __len__(self):\n        return len(self.csv)\n    \n    def standarize(self, eeg):\n        scaler = MinMaxScaler()\n        eeg = scaler.fit_transform(eeg)\n        \n        return eeg\n    \n    def butter_lowpass_filter(self, eeg):\n        filtered_eeg = np.zeros(eeg.shape)\n        for i, signal in enumerate(eeg):\n            sos = butter(4, 30, output='sos', fs=200)\n            filtered_signal = sosfilt(sos, signal)\n            \n            filtered_eeg[i,:] = filtered_signal\n            \n        del eeg\n        return filtered_eeg\n        \n    def read_eeg(self, eeg_file_path):\n        eeg = pd.read_parquet(eeg_file_path)\n        \n        imputer = SimpleImputer()\n        eeg = imputer.fit_transform(eeg)\n        #eeg = eeg.values\n        eeg = self.standarize(eeg)\n        eeg = eeg.T\n        \n        #select slice of len 10_000\n        offset = int((np.clip(np.random.randn(), -2, 2) + 2)*(eeg.shape[1] - 10_000) / 4)\n        eeg = eeg[:, offset:offset+10_000]\n        \n        #clean eeg\n        eeg = self.butter_lowpass_filter(eeg)\n        \n        eeg = np.expand_dims(eeg, axis=0)\n        \n        return eeg \n    \n    def __getitem__(self, idx):\n        y = self.csv.loc[idx, self.csv.columns[-6:]].values.reshape(-1,)\n        eeg_id = self.csv.loc[idx, 'eeg_id']\n        \n        eeg_file_path = self.eeg_path + str(eeg_id) + '.parquet'\n        X = self.read_eeg(eeg_file_path)\n        \n        return X, y\n        \n        \ndataset = EEGDataset(processed_train, EEG_PATH)\nX, y = dataset[10]\nX.shape, y.shape","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Some Visualization","metadata":{}},{"cell_type":"code","source":"X,_ = dataset[100]\n\nplt.subplots(20, 1, figsize=(15, 10))\nfor i, signal in enumerate(X):\n    plt.subplot(20, 1, i+1)\n    plt.plot(signal[:,0])\nplt.show()    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\nimport torch.nn as nn\n\nclass EEGNet(nn.Module):\n    def __init__(self,eeg_channels, num_temporal_filters, num_spacial_channels, num_classes):\n        super().__init__()\n        self.num_temporal_filters = num_temporal_filters\n        self.num_spacial_channels = num_spacial_channels\n        self.eeg_channels = eeg_channels\n        self.num_classes = num_classes\n\n        self.parallel_networks = nn.ModuleList([nn.Sequential(\n            nn.Conv2d(1, 1, (1, 4*(2**i)), padding='same'),\n            self._spacial_filter(4*(2**i))\n        ) for i in range(num_temporal_filters)])  \n        \n        self.conv_block1 = self._conv_block(num_temporal_filters*num_spacial_channels, 64, (1, 64), (1, 4))\n        self.conv_block2 = self._conv_block(64, 16, (1, 64), (1, 2))\n        \n        self.linear1 = nn.Linear(10_000, 64)\n        self.relu = nn.ReLU()\n        \n        self.linear2 = nn.Linear(64, 1)\n        self.linear3 = nn.Linear(1, num_classes)\n        self.softmax = nn.Softmax(dim=1)\n     \n    def _conv_block(self, in_features, out_features, kernel, pool=False, padding='same'):\n        return nn.Sequential(\n            nn.Conv2d(in_features, out_features,kernel, padding=padding),\n            nn.ELU(0.5),\n            nn.AvgPool2d(pool) if pool else nn.AvgPool2d(1),\n            nn.Dropout(0.2)\n        )\n        \n    def _spacial_filter(self, kernel_width):\n        return nn.Sequential(\n            self._conv_block(1, 64, (self.eeg_channels, 1), padding='valid'),\n            self._conv_block(64, self.num_spacial_channels, (1, kernel_width), pool=(1, 2))\n        )    \n    \n    def forward(self, x, is_train=True):\n\n        x = torch.concat([parallel_filter(x) for parallel_filter in self.parallel_networks],dim=1)\n        #print(x.shape)\n        x = self.conv_block1(x)\n        x = self.conv_block2(x)\n        #print(x.shape)\n        \n        x = torch.flatten(x, start_dim=1)\n        x = self.linear1(x)\n        x = self.relu(x)\n        \n        x = self.linear2(x)\n        x = self.relu(x)\n        \n        x = self.linear3(x)\n        if not is_train:\n            x = self.softmax(x)\n            return x\n        x = nn.functional.log_softmax(x, dim=1) \n        return x\n            \nmodel = EEGNet(20, 5, 4, 6)\n\ndef test_model(model):\n    x = torch.randn((10, 1, 20, 10_000))\n    y = model(x)\n    \n    return y.shape, y, y.sum(axis=1)\n            \ntest_model(model)            \n            ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = 'cuda' if torch.cuda.is_available() else 'cpu'\ndevice","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom torch.utils.data import Subset\n\ntrain_df, test_val_df = train_test_split(processed_train, test_size=0.25)\ntest_df, val_df = train_test_split(test_val_df, test_size=0.5)\n\ntrain_data = EEGDataset(train_df.reset_index(), EEG_PATH)\ntest_data = EEGDataset(test_df.reset_index(), EEG_PATH)\nval_data = EEGDataset(val_df.reset_index(), EEG_PATH)\n\ntrain_data = DataLoader(train_data, batch_size=64)\ntest_data = DataLoader(test_data, batch_size=64)\nval_data = DataLoader(val_data, batch_size=64)\n\nlen(train_data), len(test_data), len(val_data)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.optim import Adam\nfrom torch.optim.lr_scheduler import StepLR\n\nmodel = EEGNet(20, 5, 4, 6)\nmodel.to(device)\nlr = 1e-2\noptimizer = Adam(model.parameters(), lr)\n#scheduler = StepLR(optimizer, step_size=201, gamma=0.6)\ncriterion = nn.KLDivLoss(reduction='mean')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings('ignore')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"EPOCHS=5\n\nfor epoch in trange(EPOCHS):\n    for i, (X, y) in enumerate(tqdm(train_data)):\n        X, y = X.to(device), y.to(device)\n        X, y = X.to(torch.float), y.to(torch.float) \n        model.train()\n        optimizer.zero_grad()\n        y_pred = model(X)\n        loss = criterion(y_pred, y)\n        loss.backward()\n        optimizer.step()\n        #scheduler.step()\n        if i%100==0:\n            print(loss)\n        \n    avg_loss = 0    \n    for X, y in tqdm(val_data):\n        X, y = X.to(torch.float), y.to(torch.float)\n        X, y = X.to(device), y.to(device)\n        model.eval()\n        y_pred = model(X)\n        loss = criterion(y_pred, y)\n        avg_loss += loss.detach().cpu().numpy()\n        #avg_loss = torch.tensor(avg_loss)\n    \n    print(f'EHOCH:{epoch}, VAL_LOSS: {avg_loss / len(val_data)}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.save(model.state_dict(), '/kaggle/working/model')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}