{"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":31259,"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":"2026-02-03T08:28:00.364414Z","iopub.execute_input":"2026-02-03T08:28:00.365180Z","iopub.status.idle":"2026-02-03T08:28:03.285566Z","shell.execute_reply.started":"2026-02-03T08:28:00.365143Z","shell.execute_reply":"2026-02-03T08:28:03.284843Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset\nfrom torchvision import transforms, models\nfrom torch.utils.data import Dataset, DataLoader\nimport torch.optim as optim\nfrom PIL import Image\n\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(f\"device used: {device}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T08:28:03.286724Z","iopub.execute_input":"2026-02-03T08:28:03.286958Z","iopub.status.idle":"2026-02-03T08:28:03.291835Z","shell.execute_reply.started":"2026-02-03T08:28:03.286936Z","shell.execute_reply":"2026-02-03T08:28:03.291085Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"###  **Preparing for Datatset**","metadata":{}},{"cell_type":"code","source":"root_path = '/kaggle/input/anime-gender-classification/dataset'\n# Image directories\nimg_paths = {\n    'train': os.path.join(root_path, \"train_images\"),\n    'test': os.path.join(root_path, \"test_images\"),\n    'val': os.path.join(root_path, \"val_images\")\n}\n\n# Label files\nlabel_paths = {\n    'train': os.path.join(root_path, \"train.csv\"),\n    'test': os.path.join(root_path, \"test.csv\"),\n    'val': os.path.join(root_path, \"val.csv\")\n}\n\n#check the count of the image directory\ndef check_count(path):\n    counts = sum(1 for f in os.scandir(path) if f.is_file())\n    return counts\n\nprint(\"Count for train images : \", check_count(img_paths['train']))\nprint(\"Count for test images : \", check_count(img_paths['test']))\nprint(\"Count for val images : \", check_count(img_paths['val']))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T08:28:03.292677Z","iopub.execute_input":"2026-02-03T08:28:03.293009Z","iopub.status.idle":"2026-02-03T08:28:03.326887Z","shell.execute_reply.started":"2026-02-03T08:28:03.292981Z","shell.execute_reply":"2026-02-03T08:28:03.326297Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class AnimeDataset(Dataset):\n    def __init__(self, csv_path, image_dir, transform=None, id_col=\"id\", label_col=\"label\", is_test=False):\n        self.image_dir = image_dir\n        self.df = pd.read_csv(csv_path)\n        self.transform = transform\n        self.id_col = id_col\n        self.label_col = label_col\n        self.is_test = is_test\n\n    def __len__(self):\n        return len(self.df)\n\n    # mapping for image and label\n    def __getitem__(self, idx):\n        dataset = self.df.iloc[idx]\n        img_path = os.path.join(self.image_dir, dataset[self.id_col])\n            \n        if os.path.isfile(img_path):\n            image = Image.open(img_path).convert(\"RGB\")\n            image = self.transform(image)\n            \n        if self.is_test:\n            return image, dataset[self.id_col]\n\n        label = dataset[self.label_col]\n            \n        return image, label\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T08:28:03.328209Z","iopub.execute_input":"2026-02-03T08:28:03.328452Z","iopub.status.idle":"2026-02-03T08:28:03.334180Z","shell.execute_reply.started":"2026-02-03T08:28:03.328432Z","shell.execute_reply":"2026-02-03T08:28:03.333492Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"###  Image argumentation and preprocessing","metadata":{}},{"cell_type":"code","source":"train_transform = transforms.Compose([transforms.Resize((256, 256)),\n    transforms.RandomHorizontalFlip(p=0.5),\n    transforms.RandomRotation(10),\n    transforms.ColorJitter(brightness=0.2, contrast=0.2),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])\n\nval_transform = transforms.Compose([\n    transforms.Resize((256, 256)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])\n\n# set the image for training, valdataion and testing\ntrain_data = AnimeDataset(label_paths['train'], img_paths['train'], train_transform)\nval_data = AnimeDataset(label_paths['val'], img_paths['val'], val_transform)\ntest_data = AnimeDataset(label_paths['test'], img_paths['test'], val_transform, is_test=True)\n\ntrain_loader = DataLoader(train_data, batch_size = 32, shuffle=True)\nval_loader = DataLoader(val_data, batch_size = 32, shuffle=True)\ntest_loader = DataLoader(test_data, batch_size = 32, shuffle=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T08:28:03.334832Z","iopub.execute_input":"2026-02-03T08:28:03.335025Z","iopub.status.idle":"2026-02-03T08:28:03.357867Z","shell.execute_reply.started":"2026-02-03T08:28:03.335006Z","shell.execute_reply":"2026-02-03T08:28:03.357270Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"###   Model Training and Evaluation","metadata":{}},{"cell_type":"code","source":"# Define the model\nmodel = models.mobilenet_v2(pretrained=True)\nmodel.classifier[1] = nn.Linear(model.last_channel, 2)\nmodel = model.to(device)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=0.0001)\n\nepochs = 5\nfor epoch in range(epochs):\n    model.train()\n    total_loss = 0\n    total = 0\n    correct = 0\n    # training the model\n    for images, labels in train_loader:\n        images, labels = images.to(device), labels.to(device)\n        optimizer.zero_grad()\n        output = model(images)\n        loss = criterion(output, labels)\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item()\n        is_has, predicted = torch.max(output, 1)\n        correct += (predicted == labels).sum().item()\n        total += labels.size(0)\n        \n    train_acc = (correct / total)\n\n    # model evaluation\n    model.eval()\n    val_loss = 0\n    val_correct = 0\n    val_total = 0\n    \n    with torch.no_grad():\n        for images, labels in val_loader:\n            images, labels = images.to(device), labels.to(device)\n            output = model(images)\n            loss = criterion(output, labels)\n            val_loss += loss.item()\n            is_has, predicted = torch.max(output, 1)\n            val_correct += (predicted == labels).sum().item()\n            val_total += labels.size(0)\n        val_acc = (val_correct / val_total)\n    print(f\"Epoch [{epoch+1}/{epochs}] | \"\n            f\"Train Loss: {total_loss:.4f} | Train Acc: {train_acc:.2f} | \"\n             f\"Val Loss: {val_loss:.4f} | Val Acc: {val_acc:.2f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T08:28:03.358714Z","iopub.execute_input":"2026-02-03T08:28:03.359028Z","iopub.status.idle":"2026-02-03T08:32:47.645267Z","shell.execute_reply.started":"2026-02-03T08:28:03.359005Z","shell.execute_reply":"2026-02-03T08:32:47.644569Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"###  Model Testing and Submission","metadata":{}},{"cell_type":"code","source":"results = []\n\n# Testing my model and \nwith torch.no_grad():\n    for images,labels in test_loader:\n        images = images.to(device)\n\n        output = model(images)\n        is_has, predicted = torch.max(output, 1)\n\n        for img_name, pred, label in zip(images, predicted, labels):\n            results.append({\"id\": label, \"prediction\": int(pred.item())})\n\n\nsubmission = pd.DataFrame(results)\nsubmission.to_csv(\"submission.csv\", index=False)\n\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T08:32:47.646191Z","iopub.execute_input":"2026-02-03T08:32:47.646452Z","iopub.status.idle":"2026-02-03T08:32:51.952717Z","shell.execute_reply.started":"2026-02-03T08:32:47.646428Z","shell.execute_reply":"2026-02-03T08:32:51.952060Z"}},"outputs":[],"execution_count":null}]}