{"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":[{"sourceType":"competition","sourceId":59093,"databundleVersionId":7469972},{"sourceType":"kernelVersion","sourceId":220422558}],"dockerImageVersionId":30839,"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)\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        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":{"iopub.status.busy":"2025-02-02T11:02:41.167110Z","iopub.execute_input":"2025-02-02T11:02:41.167390Z","iopub.status.idle":"2025-02-02T11:03:03.980951Z","shell.execute_reply.started":"2025-02-02T11:02:41.167366Z","shell.execute_reply":"2025-02-02T11:03:03.980157Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader, Dataset, random_split\nfrom torchvision import datasets, models, transforms\nfrom sklearn.model_selection import train_test_split\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nimport warnings\nimport time\nimport cv2\nwarnings.filterwarnings('ignore')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-02T11:03:03.981859Z","iopub.execute_input":"2025-02-02T11:03:03.982190Z","iopub.status.idle":"2025-02-02T11:03:10.285428Z","shell.execute_reply.started":"2025-02-02T11:03:03.982170Z","shell.execute_reply":"2025-02-02T11:03:10.284764Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"start_time = time.time()\nBASE_DIR = \"/kaggle/input/hms-harmful-brain-activity-classification/\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-02T11:03:10.286808Z","iopub.execute_input":"2025-02-02T11:03:10.287201Z","iopub.status.idle":"2025-02-02T11:03:10.290382Z","shell.execute_reply.started":"2025-02-02T11:03:10.287178Z","shell.execute_reply":"2025-02-02T11:03:10.289643Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"brain_activities = ['Seizure', 'GPD', 'LRDA', 'Other', 'GRDA', 'LPD']\nactivity_mapping = {activity: idx for idx, activity in enumerate(brain_activities)}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-02T11:03:10.291720Z","iopub.execute_input":"2025-02-02T11:03:10.292024Z","iopub.status.idle":"2025-02-02T11:03:10.306865Z","shell.execute_reply.started":"2025-02-02T11:03:10.292003Z","shell.execute_reply":"2025-02-02T11:03:10.306116Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(f\"{BASE_DIR}train.csv\")\n# Split 80% Train, 20% Temp (Validation + Test)\ntrain_df, temp_df = train_test_split(df, test_size=0.2, random_state=42)\n\n# Split 10% Validation, 10% Test from Temp\nval_df, test_df = train_test_split(temp_df, test_size=0.5, random_state=42)\n\n# Save to CSV\ntrain_df.to_csv(\"train.csv\", index=False)\nval_df.to_csv(\"validation.csv\", index=False)\ntest_df.to_csv(\"test.csv\", index=False)\n\nprint(\"Splitting done! Train:\", len(train_df), \"Val:\", len(val_df), \"Test:\", len(test_df))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-02T11:03:10.307540Z","iopub.execute_input":"2025-02-02T11:03:10.307777Z","iopub.status.idle":"2025-02-02T11:03:10.992073Z","shell.execute_reply.started":"2025-02-02T11:03:10.307747Z","shell.execute_reply":"2025-02-02T11:03:10.991261Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ChunkedBrainActivityDataset(Dataset):\n    def __init__(self, csv_file, base_dir, activity_mapping):\n        self.df = csv_file\n        self.base_dir = base_dir\n        self.activity_mapping = activity_mapping\n        self.resize_transform = transforms.Resize((224, 224))\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        spect_id, label, offset = self.df.iloc[idx][[\"spectrogram_id\", \"expert_consensus\", \"spectrogram_label_offset_seconds\"]]\n\n        temp_df = pd.read_parquet(f'{self.base_dir}/train_spectrograms/{spect_id}.parquet')\n        temp_df.drop(['time'], axis=1, inplace=True)\n\n        start = int(offset) // 2\n        temp_df = temp_df[start:start+300]\n        temp_df = np.log1p(temp_df)\n        temp_df /= temp_df.max()\n        temp_arr = np.nan_to_num(temp_df.to_numpy(), nan=1e-4)\n\n        # Use OpenCV to apply a colormap and convert to RGB\n        temp_arr_uint8 = np.uint8(255 * temp_arr)\n        rgb_image = cv2.applyColorMap(temp_arr_uint8, cv2.COLORMAP_JET)\n\n        # Normalize to [0, 1] and convert to tensor\n        rgb_image = rgb_image.astype(np.float32) / 255.0\n        rgb_image_tensor = torch.tensor(rgb_image).permute(2, 0, 1)  # (C, H, W)\n        rgb_image_tensor = self.resize_transform(rgb_image_tensor)\n\n        y = self.activity_mapping[label]\n        y_tensor = torch.nn.functional.one_hot(torch.tensor(y, dtype=torch.long), num_classes=6).float()\n\n        return rgb_image_tensor, y_tensor","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-02T11:03:10.993118Z","iopub.execute_input":"2025-02-02T11:03:10.993483Z","iopub.status.idle":"2025-02-02T11:03:11.000888Z","shell.execute_reply.started":"2025-02-02T11:03:10.993448Z","shell.execute_reply":"2025-02-02T11:03:10.999977Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Now create DataLoader with the chunked dataset\n# chunk_size = 1000  # Adjust chunk size according to memory constraints\n\ntrain_dataset = ChunkedBrainActivityDataset(csv_file=train_df, base_dir=BASE_DIR, activity_mapping=activity_mapping)\nval_dataset = ChunkedBrainActivityDataset(csv_file=val_df, base_dir=BASE_DIR, activity_mapping=activity_mapping)\ntest_dataset = ChunkedBrainActivityDataset(csv_file=test_df, base_dir=BASE_DIR, activity_mapping=activity_mapping)\n\ntrain_loader = DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=12, pin_memory=True, prefetch_factor=2)\nval_loader = DataLoader(val_dataset, batch_size=64, shuffle=False, num_workers=12, pin_memory=True, prefetch_factor=2)\ntest_loader = DataLoader(test_dataset, batch_size=64, shuffle=False, num_workers=12, pin_memory=True, prefetch_factor=2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-02T11:03:11.001758Z","iopub.execute_input":"2025-02-02T11:03:11.002050Z","iopub.status.idle":"2025-02-02T11:03:11.016909Z","shell.execute_reply.started":"2025-02-02T11:03:11.002029Z","shell.execute_reply":"2025-02-02T11:03:11.016154Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = models.efficientnet_v2_s(pretrained=True)\nnum_features = model.classifier[1].in_features\nmodel.classifier[1] = nn.Linear(num_features, 6)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=1e-4)\nscheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-02T11:03:11.018711Z","iopub.execute_input":"2025-02-02T11:03:11.018922Z","iopub.status.idle":"2025-02-02T11:03:12.098266Z","shell.execute_reply.started":"2025-02-02T11:03:11.018905Z","shell.execute_reply":"2025-02-02T11:03:12.097251Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(device)\nmodel.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-02T11:03:12.099367Z","iopub.execute_input":"2025-02-02T11:03:12.099620Z","iopub.status.idle":"2025-02-02T11:03:12.429325Z","shell.execute_reply.started":"2025-02-02T11:03:12.099600Z","shell.execute_reply":"2025-02-02T11:03:12.428581Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"num_epochs = 101\npatience = 15\nbest_val_loss = float('inf')\npatience_counter = 0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-02T11:03:12.429995Z","iopub.execute_input":"2025-02-02T11:03:12.430193Z","iopub.status.idle":"2025-02-02T11:03:12.433768Z","shell.execute_reply.started":"2025-02-02T11:03:12.430177Z","shell.execute_reply":"2025-02-02T11:03:12.432897Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_losses, val_losses, train_accuracies, val_accuracies = [], [], [], []\n\nfor epoch in range(num_epochs):\n    model.train()\n    running_loss = 0.0\n    correct = 0\n    total = 0\n    # tr_cntr=0\n    for data in tqdm(train_loader):\n        inputs, labels = data\n        inputs, labels = inputs.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n        _, predicted = torch.max(outputs.data, 1)\n        total += labels.size(0)\n        _, labels_ = torch.max(labels.data, 1)\n        correct += (predicted == labels_).sum().item()\n                    \n        # batch_accuracy = 100 * correct / total\n        # print(f\"Train Batch: {tr_cntr}/585, Loss: {loss.item():.4f}, Accuracy: {batch_accuracy:.2f}%\")\n        # tr_cntr+=1\n        \n        torch.cuda.empty_cache()\n\n    train_loss = running_loss / len(train_loader)\n    train_accuracy = 100 * correct / total\n    train_losses.append(train_loss)\n    train_accuracies.append(train_accuracy)\n\n    model.eval()\n    val_loss = 0.0\n    correct = 0\n    total = 0\n    # val_cntr=0\n    with torch.no_grad():\n        for data in tqdm(val_loader):\n            inputs, labels = data\n            inputs, labels = inputs.to(device), labels.to(device)\n            # print(\"Data for some epoch loaded!\")\n\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n            val_loss += loss.item()\n\n            _, predicted = torch.max(outputs.data, 1)\n            total += labels.size(0)\n            _, labels_ = torch.max(labels.data, 1)\n            correct += (predicted == labels_).sum().item()\n            # batch_accuracy = 100 * correct / total\n            # print(f\"Val Batch: {val_cntr}/126, Loss: {loss.item():.4f}, Accuracy: {batch_accuracy:.2f}%\")\n            # val_cntr+=1\n            torch.cuda.empty_cache()\n\n    val_loss /= len(val_loader)\n    val_accuracy = 100 * correct / total\n    val_losses.append(val_loss)\n    val_accuracies.append(val_accuracy)\n\n    elapsed_time = time.time() - start_time\n    print(f\"Epoch {epoch+1}/{num_epochs}, Train Loss: {train_loss:.4f}, Train Accuracy: {train_accuracy:.2f}%, Val Loss: {val_loss:.4f}, Val Accuracy: {val_accuracy:.2f}%, , Time: {elapsed_time}\")\n    scheduler.step(val_loss)\n    \n    if val_loss < best_val_loss:\n        best_val_loss = val_loss\n        patience_counter = 0\n        torch.save(model.state_dict(), 'HMS_model_v1_efficientnet_v2_s.pth')\n    else:\n        patience_counter += 1\n\n    if patience_counter >= patience:\n        print(\"Early stopping triggered\")\n        break\n\n    torch.cuda.empty_cache()\n\n# Testing\nif(os.path.isfile('HMS_model_v1_efficientnet_v2_s.pth')):\n    model.load_state_dict(torch.load('HMS_model_v1_efficientnet_v2_s.pth'))\nmodel.eval()\n\ntest_loss = 0.0\ncorrect = 0\ntotal = 0\n# test_cntr=0\nwith torch.no_grad():\n    for data in test_loader:\n        inputs, labels = data\n        inputs, labels = inputs.to(device), labels.to(device)\n\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n        test_loss += loss.item()\n\n        _, predicted = torch.max(outputs.data, 1)\n        total += labels.size(0)\n        _, labels_ = torch.max(labels.data, 1)\n        correct += (predicted == labels_).sum().item()\n        # batch_accuracy = 100 * correct / total\n        # print(f\"Test Batch: {test_cntr}/126, Loss: {loss.item():.4f}, Accuracy: {batch_accuracy:.2f}%\")\n        # test_cntr+=1\n        \n        torch.cuda.empty_cache()\n\ntest_loss /= len(test_loader)\ntest_accuracy = 100 * correct / total\n\nprint(f\"Test Accuracy: {test_accuracy:.2f}%\")\n\n\nplt.figure(figsize=(12, 6))\n\nplt.subplot(1, 2, 1)\nplt.plot(train_accuracies)\nplt.plot(val_accuracies)\nplt.title('Model accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.legend(['Train', 'Validation'], loc='upper left')\n\nplt.subplot(1, 2, 2)\nplt.plot(train_losses)\nplt.plot(val_losses)\nplt.title('Model loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend(['Train', 'Validation'], loc='upper left')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-02T11:04:20.383024Z","iopub.execute_input":"2025-02-02T11:04:20.383421Z","iopub.status.idle":"2025-02-02T11:05:13.212127Z","shell.execute_reply.started":"2025-02-02T11:04:20.383390Z","shell.execute_reply":"2025-02-02T11:05:13.210789Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T06:43:38.561920Z","iopub.execute_input":"2025-03-01T06:43:38.562239Z","iopub.status.idle":"2025-03-01T06:43:38.680636Z","shell.execute_reply.started":"2025-03-01T06:43:38.562214Z","shell.execute_reply":"2025-03-01T06:43:38.679468Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}