{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.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":3175,"databundleVersionId":44352,"sourceType":"competition"}],"dockerImageVersionId":31193,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os, zipfile\n\nbase = \"/kaggle/input/galaxy-zoo-the-galaxy-challenge\"\nwork = \"/kaggle/working\"\n\n# Unzip training images\nwith zipfile.ZipFile(os.path.join(base, \"images_training_rev1.zip\"), \"r\") as z:\n    z.extractall(work)\n\n# Unzip test images\nwith zipfile.ZipFile(os.path.join(base, \"images_test_rev1.zip\"), \"r\") as z:\n    z.extractall(work)\n\n# Unzip labels\nwith zipfile.ZipFile(os.path.join(base, \"training_solutions_rev1.zip\"), \"r\") as z:\n    z.extractall(work)\n\n# Unzip zero benchmark (submission template)\nwith zipfile.ZipFile(os.path.join(base, \"all_zeros_benchmark.zip\"), \"r\") as z:\n    z.extractall(work)\n\nprint(os.listdir(work))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-11-28T15:14:55.955726Z","iopub.execute_input":"2025-11-28T15:14:55.955950Z","iopub.status.idle":"2025-11-28T15:15:27.483486Z","shell.execute_reply.started":"2025-11-28T15:14:55.955927Z","shell.execute_reply":"2025-11-28T15:15:27.482826Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================================\n# TEAMMATE 1: ResNet50 + TTA → preds_resnet50.csv\n# ============================================================\n\nimport os, cv2, random, gc\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\n\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms, models\nfrom sklearn.model_selection import train_test_split\nfrom torch.cuda.amp import autocast, GradScaler\n\nIMG_SIZE = 256\nBATCH_SIZE = 24\nEPOCHS = 10\nLR = 3e-4\nSEED = 2025\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\nTRAIN_DIR = \"/kaggle/working/images_training_rev1\"\nTEST_DIR  = \"/kaggle/working/images_test_rev1\"\nLABELS    = \"/kaggle/working/training_solutions_rev1.csv\"\n\nCHECKPOINT_PATH = \"/kaggle/working/resnet50_seed2025.pth\"\nPREDS_PATH      = \"/kaggle/working/preds_resnet50.csv\"\n\ndef seed_everything(seed):\n    random.seed(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n\nseed_everything(SEED)\n\nclass GalaxyDataset(Dataset):\n    def __init__(self, galaxy_ids, img_dir, labels=None, augment=False):\n        self.galaxy_ids = galaxy_ids\n        self.img_dir = img_dir\n        self.labels = labels\n        self.augment = augment\n\n        self.aug = transforms.Compose([\n            transforms.ToPILImage(),\n            transforms.RandomRotation(360),\n            transforms.RandomHorizontalFlip(),\n            transforms.RandomVerticalFlip(),\n            transforms.ColorJitter(0.1,0.1,0.1,0.1),\n            transforms.Resize((IMG_SIZE, IMG_SIZE)),\n            transforms.ToTensor()\n        ])\n\n        self.basic = transforms.Compose([\n            transforms.ToPILImage(),\n            transforms.Resize((IMG_SIZE, IMG_SIZE)),\n            transforms.ToTensor()\n        ])\n\n    def __len__(self):\n        return len(self.galaxy_ids)\n\n    def __getitem__(self, idx):\n        gid = self.galaxy_ids[idx]\n        img_path = os.path.join(self.img_dir, f\"{gid}.jpg\")\n        img = cv2.imread(img_path)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        if self.augment:\n            img = self.aug(img)\n        else:\n            img = self.basic(img)\n\n        if self.labels is not None:\n            label = torch.tensor(self.labels[idx], dtype=torch.float32)\n            return img, label\n        return img\n\ndf = pd.read_csv(LABELS)\nall_ids = df[\"GalaxyID\"].values\ntargets = df.drop(\"GalaxyID\", axis=1).values\n\nX_train_ids, X_val_ids, y_train, y_val = train_test_split(\n    all_ids, targets, test_size=0.1, random_state=7\n)\n\ntrain_ds = GalaxyDataset(X_train_ids, TRAIN_DIR, y_train, augment=True)\nval_ds   = GalaxyDataset(X_val_ids,   TRAIN_DIR, y_val,   augment=False)\n\ntrain_loader = DataLoader(train_ds, batch_size=BATCH_SIZE, shuffle=True)\nval_loader   = DataLoader(val_ds,   batch_size=BATCH_SIZE)\n\nclass GalaxyResNet50(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.backbone = models.resnet50(pretrained=True)\n        in_features = self.backbone.fc.in_features\n        self.backbone.fc = nn.Sequential(\n            nn.Dropout(0.5),\n            nn.Linear(in_features, 37)\n        )\n\n    def forward(self, x):\n        return self.backbone(x)\n\nmodel = GalaxyResNet50().to(DEVICE)\noptimizer = torch.optim.AdamW(model.parameters(), lr=LR, weight_decay=1e-4)\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=EPOCHS)\ncriterion = nn.MSELoss()\nscaler = GradScaler()\n\nfor epoch in range(EPOCHS):\n    model.train()\n    train_loss = 0.0\n\n    for imgs, labels in tqdm(train_loader, desc=f\"[ResNet50] Epoch {epoch+1}/{EPOCHS} - train\"):\n        imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)\n\n        optimizer.zero_grad()\n        with autocast():\n            outputs = model(imgs)\n            loss = criterion(outputs, labels)\n\n        scaler.scale(loss).backward()\n        scaler.step(optimizer)\n        scaler.update()\n        train_loss += loss.item()\n\n    scheduler.step()\n\n    model.eval()\n    val_loss = 0.0\n    with torch.no_grad():\n        for imgs, labels in tqdm(val_loader, desc=f\"[ResNet50] Epoch {epoch+1}/{EPOCHS} - val\"):\n            imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)\n            with autocast():\n                outputs = model(imgs)\n                loss = criterion(outputs, labels)\n            val_loss += loss.item()\n\n    print(f\"[ResNet50] Epoch {epoch+1}/{EPOCHS} | Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f}\")\n\ntorch.save(model.state_dict(), CHECKPOINT_PATH)\nprint(f\"[ResNet50] Saved checkpoint to {CHECKPOINT_PATH}\")\n\ndef tta_predict(model, loader):\n    model.eval()\n    preds = []\n    with torch.no_grad():\n        for imgs in tqdm(loader, desc=\"[ResNet50] TTA predicting\"):\n            imgs = imgs.to(DEVICE)\n            batch_preds = []\n\n            with autocast():\n                out = model(imgs)\n            batch_preds.append(out)\n\n            imgs_h = torch.flip(imgs, dims=[3])\n            with autocast():\n                out_h = model(imgs_h)\n            batch_preds.append(out_h)\n\n            imgs_v = torch.flip(imgs, dims=[2])\n            with autocast():\n                out_v = model(imgs_v)\n            batch_preds.append(out_v)\n\n            batch_mean = torch.stack(batch_preds, dim=0).mean(dim=0)\n            preds.append(batch_mean.cpu().numpy())\n\n    return np.vstack(preds)\n\nsub_template = pd.read_csv(\"/kaggle/working/all_zeros_benchmark.csv\")\ntest_ids = sub_template[\"GalaxyID\"].values\n\ntest_ds = GalaxyDataset(test_ids, TEST_DIR, labels=None, augment=False)\ntest_loader = DataLoader(test_ds, batch_size=BATCH_SIZE)\n\npreds = tta_predict(model, test_loader)\n\npreds = np.clip(preds, 0, 1)\ngroups = [\n    (0,3),(3,5),(5,8),(8,11),(11,15),\n    (15,18),(18,25),(25,28),(28,31),(31,37)\n]\nfor start, end in groups:\n    s = preds[:, start:end].sum(axis=1, keepdims=True)\n    s[s == 0] = 1.0\n    preds[:, start:end] /= s\n\nout = sub_template.copy()\nout.iloc[:,1:] = preds\nout.to_csv(PREDS_PATH, index=False)\nout.to_csv(\"submission_single_resnet50.csv\", index=False)\n\nprint(f\"[ResNet50] Saved preds to {PREDS_PATH}\")\nprint(\"[ResNet50] Also wrote submission_single_resnet50.csv\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}