{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.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":127713,"databundleVersionId":15291341,"sourceType":"competition"}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nfrom PIL import Image\nfrom tqdm import tqdm\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as T\nimport torchvision.models as models\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        continue","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-01-28T07:25:58.596225Z","iopub.execute_input":"2026-01-28T07:25:58.596550Z","iopub.status.idle":"2026-01-28T07:26:17.602343Z","shell.execute_reply.started":"2026-01-28T07:25:58.596515Z","shell.execute_reply":"2026-01-28T07:26:17.601404Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Cuda Configuration","metadata":{}},{"cell_type":"code","source":"if torch.cuda.is_available():\n    device = torch.device(\"cuda\")\n    print(\"Using CUDA\")\nelse:\n    device = torch.device(\"cpu\")\n    print(\"CUDA not available, using CPU\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-28T07:26:20.078724Z","iopub.execute_input":"2026-01-28T07:26:20.079109Z","iopub.status.idle":"2026-01-28T07:26:20.138797Z","shell.execute_reply.started":"2026-01-28T07:26:20.079062Z","shell.execute_reply":"2026-01-28T07:26:20.137915Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Neural Network Configuration","metadata":{}},{"cell_type":"code","source":"IMG_SIZE = 224\nBATCH_SIZE = 32\nEPOCHS = 15\nLR = 3e-4\nNUM_WORKERS = min(4, os.cpu_count())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-28T07:27:31.784723Z","iopub.execute_input":"2026-01-28T07:27:31.785090Z","iopub.status.idle":"2026-01-28T07:27:31.789851Z","shell.execute_reply.started":"2026-01-28T07:27:31.785061Z","shell.execute_reply":"2026-01-28T07:27:31.788913Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Dataset Prep","metadata":{}},{"cell_type":"code","source":"class AnimeGenderDataset(Dataset):\n    def __init__(self, csv_path, image_dir, transform=None, is_test=False):\n        self.df = pd.read_csv(csv_path)\n        self.image_dir = image_dir\n        self.transform = transform\n        self.is_test = is_test\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        img_name = self.df.iloc[idx, 0]\n        img_path = os.path.join(self.image_dir, img_name)\n\n        image = Image.open(img_path).convert(\"RGB\")\n\n        if self.transform:\n            image = self.transform(image)\n\n        if self.is_test:\n            return image, img_name\n\n        label = int(self.df.iloc[idx, 1])\n        return image, label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-28T07:27:48.866736Z","iopub.execute_input":"2026-01-28T07:27:48.867077Z","iopub.status.idle":"2026-01-28T07:27:48.874554Z","shell.execute_reply.started":"2026-01-28T07:27:48.867049Z","shell.execute_reply":"2026-01-28T07:27:48.873607Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Image Augmentation","metadata":{}},{"cell_type":"code","source":"train_tfms = T.Compose([\n    T.Resize((IMG_SIZE, IMG_SIZE)),\n    T.RandomHorizontalFlip(),\n    T.RandomRotation(10),\n    T.ColorJitter(brightness=0.15, contrast=0.15),\n    T.ToTensor(),\n    T.Normalize(mean=[0.485, 0.456, 0.406],\n                std=[0.229, 0.224, 0.225]),\n])\n\nval_tfms = T.Compose([\n    T.Resize((IMG_SIZE, IMG_SIZE)),\n    T.ToTensor(),\n    T.Normalize(mean=[0.485, 0.456, 0.406],\n                std=[0.229, 0.224, 0.225]),\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-28T07:28:06.137446Z","iopub.execute_input":"2026-01-28T07:28:06.138266Z","iopub.status.idle":"2026-01-28T07:28:06.144039Z","shell.execute_reply.started":"2026-01-28T07:28:06.138233Z","shell.execute_reply":"2026-01-28T07:28:06.143175Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Load the Data","metadata":{}},{"cell_type":"code","source":"train_ds = AnimeGenderDataset(\n    \"/kaggle/input/anime-gender-classification/dataset/train.csv\", \"/kaggle/input/anime-gender-classification/dataset/train_images\", train_tfms\n)\nval_ds = AnimeGenderDataset(\n    \"/kaggle/input/anime-gender-classification/dataset/val.csv\", \"/kaggle/input/anime-gender-classification/dataset/val_images\", val_tfms\n)\n\ntrain_loader = DataLoader(\n    train_ds, batch_size=BATCH_SIZE, shuffle=True, num_workers=NUM_WORKERS\n)\nval_loader = DataLoader(\n    val_ds, batch_size=BATCH_SIZE, shuffle=False, num_workers=NUM_WORKERS\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-28T07:28:26.313005Z","iopub.execute_input":"2026-01-28T07:28:26.313893Z","iopub.status.idle":"2026-01-28T07:28:26.352956Z","shell.execute_reply.started":"2026-01-28T07:28:26.313861Z","shell.execute_reply":"2026-01-28T07:28:26.352285Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Use PreTrained Model from IMAGENET","metadata":{}},{"cell_type":"code","source":"model = models.efficientnet_b0(weights=\"IMAGENET1K_V1\")\nmodel.classifier[1] = nn.Linear(model.classifier[1].in_features, 1)\nmodel = model.to(device)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Loss and Optimizer Config","metadata":{}},{"cell_type":"code","source":"criterion = nn.BCEWithLogitsLoss()\noptimizer = optim.AdamW(model.parameters(), lr=LR, weight_decay=1e-4)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Training Process (Loop)","metadata":{}},{"cell_type":"code","source":"def train_epoch(model, loader):\n    model.train()\n    total_loss = 0\n    correct = 0\n    total = 0\n\n    for imgs, labels in tqdm(loader, leave=False):\n        imgs = imgs.to(device)\n        labels = labels.float().unsqueeze(1).to(device)\n\n        optimizer.zero_grad()\n        logits = model(imgs)\n        loss = criterion(logits, labels)\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item()\n        preds = (torch.sigmoid(logits) > 0.5).int()\n        correct += (preds == labels.int()).sum().item()\n        total += labels.size(0)\n\n    return total_loss / len(loader), correct / total\n\n\ndef eval_epoch(model, loader):\n    model.eval()\n    total_loss = 0\n    correct = 0\n    total = 0\n\n    with torch.no_grad():\n        for imgs, labels in tqdm(loader, leave=False):\n            imgs = imgs.to(device)\n            labels = labels.float().unsqueeze(1).to(device)\n\n            logits = model(imgs)\n            loss = criterion(logits, labels)\n\n            total_loss += loss.item()\n            preds = (torch.sigmoid(logits) > 0.5).int()\n            correct += (preds == labels.int()).sum().item()\n            total += labels.size(0)\n\n    return total_loss / len(loader), correct / total\n\n\nbest_acc = 0.0\n\nfor epoch in range(EPOCHS):\n    train_loss, train_acc = train_epoch(model, train_loader)\n    val_loss, val_acc = eval_epoch(model, val_loader)\n\n    print(f\"Epoch {epoch+1}/{EPOCHS}\")\n    print(f\"Train Loss: {train_loss:.4f} | Train Acc: {train_acc:.4f}\")\n    print(f\"Val   Loss: {val_loss:.4f} | Val   Acc: {val_acc:.4f}\")\n\n    if val_acc > best_acc:\n        best_acc = val_acc\n        torch.save(model.state_dict(), \"best_model_imagenet1k.pt\")\n        print(\"Saved new best model\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Testing the Model and Saving Prediction as .csv","metadata":{}},{"cell_type":"code","source":"test_ds = AnimeGenderDataset(\n    \"/kaggle/input/anime-gender-classification/dataset/test.csv\", \"/kaggle/input/anime-gender-classification/dataset/test_images\", val_tfms, is_test=True\n)\ntest_loader = DataLoader(\n    test_ds, batch_size=BATCH_SIZE, shuffle=False, num_workers=NUM_WORKERS\n)\n\nmodel.load_state_dict(torch.load(\"best_model_imagenet1k.pt\"))\nmodel.eval()\n\npredictions = []\n\nwith torch.no_grad():\n    for imgs, names in tqdm(test_loader):\n        imgs = imgs.to(device)\n        logits = model(imgs)\n        probs = torch.sigmoid(logits)\n        preds = (probs > 0.5).int().cpu().numpy()\n\n        for name, pred in zip(names, preds):\n            predictions.append([name, int(pred[0])])\n\n\nsubmission = pd.DataFrame(predictions, columns=[\"id\", \"label\"])\nsubmission.to_csv(\"submission.csv\", index=False)\nprint(\"submission.csv saved\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-27T08:18:37.086117Z","iopub.execute_input":"2026-01-27T08:18:37.086756Z","iopub.status.idle":"2026-01-27T08:29:56.324873Z","shell.execute_reply.started":"2026-01-27T08:18:37.086731Z","shell.execute_reply":"2026-01-27T08:29:56.324084Z"}},"outputs":[],"execution_count":null}]}