{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":94147,"databundleVersionId":11390004,"sourceType":"competition"}],"dockerImageVersionId":31012,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 🧪 Global AI Hackathon'25","metadata":{}},{"cell_type":"markdown","source":"  ## 📌 Step 1: Import Libraries","metadata":{}},{"cell_type":"code","source":"import h5py\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import transforms\nfrom sklearn.model_selection import train_test_split\nfrom torch.utils.data import DataLoader, Dataset","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T18:53:17.315321Z","iopub.execute_input":"2025-05-12T18:53:17.316962Z","iopub.status.idle":"2025-05-12T18:53:17.322871Z","shell.execute_reply.started":"2025-05-12T18:53:17.316910Z","shell.execute_reply":"2025-05-12T18:53:17.321915Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"PATCH_SIZE = 64\nBATCH_SIZE = 64\nEPOCHS = 200\nLR = 1e-3\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nclass PatchDataset(Dataset):\n    def __init__(self, image_patches, labels=None, transform=None):\n        self.image_patches = image_patches\n        self.labels = labels\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.image_patches)\n\n    def __getitem__(self, idx):\n        img = self.image_patches[idx]\n        if self.transform:\n            img = self.transform(img)\n        if self.labels is not None:\n            return img, self.labels[idx]\n        return img","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T18:53:22.841799Z","iopub.execute_input":"2025-05-12T18:53:22.842159Z","iopub.status.idle":"2025-05-12T18:53:22.855761Z","shell.execute_reply.started":"2025-05-12T18:53:22.842134Z","shell.execute_reply":"2025-05-12T18:53:22.854337Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomVerticalFlip(),\n    transforms.RandomRotation(10),\n    transforms.ColorJitter(brightness=0.1, contrast=0.1),\n])\n\nclass CellTypeDataset(Dataset):\n    def __init__(self, coordinates, labels, patch_size=64, transform=None):\n        self.coordinates = coordinates\n        self.labels = labels\n        self.patch_size = patch_size\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.coordinates)\n\n    def __getitem__(self, idx):\n        x, y = self.coordinates[idx]\n        patch = np.zeros((self.patch_size, self.patch_size), dtype=np.float32)\n        patch[x % self.patch_size, y % self.patch_size] = 1.0\n\n        patch = (patch - patch.mean()) / patch.std()\n        patch = torch.tensor(patch, dtype=torch.float32).unsqueeze(0) \n\n        if self.transform:\n            patch = self.transform(patch)\n\n        label = torch.tensor(np.argmax(self.labels[idx]), dtype=torch.long)\n        return patch, label\n\n\n\nclass CNNModel(nn.Module):\n    def __init__(self):\n        super(CNNModel, self).__init__()\n        self.conv_block1 = nn.Sequential(\n            nn.Conv2d(1, 16, kernel_size=3, padding=1),\n            nn.BatchNorm2d(16),\n            nn.ReLU(),\n            nn.MaxPool2d(2),\n            nn.Dropout(0.2)\n        )\n        self.conv_block2 = nn.Sequential(\n            nn.Conv2d(16, 32, kernel_size=3, padding=1),\n            nn.BatchNorm2d(32),\n            nn.ReLU(),\n            nn.MaxPool2d(2),\n            nn.Dropout(0.2)\n        )\n        self.conv_block3 = nn.Sequential(\n            nn.Conv2d(32, 64, kernel_size=3, padding=1),\n            nn.BatchNorm2d(64),\n            nn.ReLU(),\n            nn.MaxPool2d(2),\n            nn.Dropout(0.3)\n        )\n        self.conv_block4 = nn.Sequential(\n            nn.Conv2d(64, 128, kernel_size=3, padding=1),\n            nn.BatchNorm2d(128),\n            nn.ReLU(),\n            nn.MaxPool2d(2),\n            nn.Dropout(0.4)\n        )\n        \n        self.fc1 = nn.Linear(128 * 4 * 4, 512)  \n        self.dropout_fc = nn.Dropout(0.5)\n        self.fc2 = nn.Linear(512, 128)\n        self.fc3 = nn.Linear(128, 35)\n\n    def forward(self, x):\n        x = self.conv_block1(x)\n        x = self.conv_block2(x)\n        x = self.conv_block3(x)\n        x = self.conv_block4(x)\n        x = x.view(x.size(0), -1)\n        x = torch.relu(self.fc1(x))\n        x = self.dropout_fc(x)\n        x = torch.relu(self.fc2(x))\n        return self.fc3(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T18:53:53.926387Z","iopub.execute_input":"2025-05-12T18:53:53.926784Z","iopub.status.idle":"2025-05-12T18:53:53.942938Z","shell.execute_reply.started":"2025-05-12T18:53:53.926759Z","shell.execute_reply":"2025-05-12T18:53:53.941841Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with h5py.File(\"/kaggle/input/el-hackathon-2025/elucidata_ai_challenge_data.h5\", \"r\") as f:\n    train_spots = f[\"spots/Train\"]\n    train_spot_tables = {slide: pd.DataFrame(np.array(train_spots[slide])) for slide in train_spots.keys()}\n\ntrain_df = pd.concat(train_spot_tables.values(), ignore_index=True)\n\nX = train_df[['x', 'y']].values\ny = train_df.iloc[:, 2:].values\n\nX_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.1, random_state=42)\n\ntrain_dataset = CellTypeDataset(X_train, y_train, patch_size=PATCH_SIZE, transform=transform)\nvalid_dataset = CellTypeDataset(X_valid, y_valid, patch_size=PATCH_SIZE) \n\ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)\nvalid_loader = DataLoader(valid_dataset, batch_size=BATCH_SIZE)\n\nmodel = CNNModel().to(DEVICE)\noptimizer = optim.Adam(model.parameters(), lr=LR, weight_decay=1e-5)\ncriterion = nn.CrossEntropyLoss(label_smoothing=0.1)\n\nbest_val_loss = float('inf')\npatience = 5\nwait = 0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T18:54:22.882613Z","iopub.execute_input":"2025-05-12T18:54:22.883045Z","iopub.status.idle":"2025-05-12T18:54:23.057885Z","shell.execute_reply.started":"2025-05-12T18:54:22.883018Z","shell.execute_reply":"2025-05-12T18:54:23.056950Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for epoch in range(EPOCHS):\n    model.train()\n    train_loss = 0\n    for inputs, targets in train_loader:\n        inputs, targets = inputs.to(DEVICE), targets.to(DEVICE)\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, targets)\n        loss.backward()\n        optimizer.step()\n        train_loss += loss.item()\n\n    model.eval()\n    valid_loss = 0\n    with torch.no_grad():\n        for inputs, targets in valid_loader:\n            inputs, targets = inputs.to(DEVICE), targets.to(DEVICE)\n            outputs = model(inputs)\n            loss = criterion(outputs, targets)\n            valid_loss += loss.item()\n\n    train_loss /= len(train_loader)\n    valid_loss /= len(valid_loader)\n    print(f\"Epoch {epoch + 1}/{EPOCHS}, Train Loss: {train_loss:.4f}, Valid Loss: {valid_loss:.4f}\")\n\n    if valid_loss < best_val_loss:\n        best_val_loss = valid_loss\n        wait = 0\n        torch.save(model.state_dict(), \"best_model.pt\")\n    else:\n        wait += 1\n        if wait >= patience:\n            print(\"Early stopping triggered.\")\n            break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T18:54:39.332071Z","iopub.execute_input":"2025-05-12T18:54:39.332409Z","iopub.status.idle":"2025-05-12T18:59:38.870483Z","shell.execute_reply.started":"2025-05-12T18:54:39.332386Z","shell.execute_reply":"2025-05-12T18:59:38.869187Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.load_state_dict(torch.load(\"best_model.pt\"))\nmodel.eval()\n\nwith h5py.File(\"/kaggle/input/el-hackathon-2025/elucidata_ai_challenge_data.h5\", \"r\") as f:\n    test_spots = f[\"spots/Test\"]\n    test_spot_table = pd.DataFrame(np.array(test_spots['S_7']))\n\nX_test = test_spot_table[['x', 'y']].values\nX_test_resized = np.zeros((X_test.shape[0], 1, PATCH_SIZE, PATCH_SIZE))\n\nfor i, (x, y) in enumerate(X_test):\n    patch = np.zeros((PATCH_SIZE, PATCH_SIZE))\n    patch[x % PATCH_SIZE, y % PATCH_SIZE] = 1\n    patch = (patch - 0.5) / 0.5  # Normalize\n    X_test_resized[i] = patch.reshape(1, PATCH_SIZE, PATCH_SIZE)\n\nX_test_tensor = torch.tensor(X_test_resized, dtype=torch.float32).to(DEVICE)\n\nwith torch.no_grad():\n    test_preds = model(X_test_tensor)\n    test_preds_softmax = torch.softmax(test_preds, dim=1).cpu().numpy()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T18:59:38.872416Z","iopub.execute_input":"2025-05-12T18:59:38.872804Z","iopub.status.idle":"2025-05-12T18:59:44.094982Z","shell.execute_reply.started":"2025-05-12T18:59:38.872777Z","shell.execute_reply":"2025-05-12T18:59:44.094067Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission_df = pd.DataFrame(test_preds, columns=[f\"C{i+1}\" for i in range(35)])\nsubmission_df.insert(0, 'ID', test_spot_table.index)\nsubmission_df.to_csv(\"/kaggle/working/submission.csv\", index=False)\n\nprint(\"Submission file 'submission.csv' created!\")\nsubmission_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T18:59:44.096477Z","iopub.execute_input":"2025-05-12T18:59:44.096845Z","iopub.status.idle":"2025-05-12T18:59:44.229732Z","shell.execute_reply.started":"2025-05-12T18:59:44.096822Z","shell.execute_reply":"2025-05-12T18:59:44.228691Z"}},"outputs":[],"execution_count":null}]}