{"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":128438,"databundleVersionId":15403795,"sourceType":"competition"}],"dockerImageVersionId":31260,"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-01-30T04:19:17.311737Z","iopub.execute_input":"2026-01-30T04:19:17.312074Z","iopub.status.idle":"2026-01-30T04:19:35.892904Z","shell.execute_reply.started":"2026-01-30T04:19:17.312046Z","shell.execute_reply":"2026-01-30T04:19:35.891972Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn as nn\nimport pandas as pd\nfrom PIL import Image\nfrom tqdm.auto import tqdm\nfrom torch.utils.data import ConcatDataset, DataLoader, random_split, Dataset\nfrom torchvision import datasets, models\nfrom torchvision.transforms import v2\n\n# 1. Define Paths (Absolute for Kaggle)\nBASE_PATH = \"/kaggle/input/drawn-apart-aicc-round-3/task_data/task_data\"\nCARTOON_DIR = os.path.join(BASE_PATH, \"cartoon\")\nPHOTO_DIR = os.path.join(BASE_PATH, \"photograph\")\nTEST_DIR = os.path.join(BASE_PATH, \"sketch_test\")\n\n# 2. Setup Data Transformations\ntransform = v2.Compose([\n    v2.ToImage(),\n    v2.Resize(256),\n    v2.CenterCrop(224)\n])\n\ngpu_transform = v2.Compose([\n    v2.RandomHorizontalFlip(p=0.5),\n    v2.ToDtype(torch.float32, scale=True),\n    v2.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n# 3. Load Labeled Source Datasets\ncartoon_ds = datasets.ImageFolder(root=CARTOON_DIR, transform=transform)\nphoto_ds = datasets.ImageFolder(root=PHOTO_DIR, transform=transform)\nclass_names = cartoon_ds.classes\n\n# Combine and Split\nds = ConcatDataset([cartoon_ds, photo_ds])\ntrain_ds, val_ds = random_split(ds, [0.7, 0.3], generator=torch.Generator().manual_seed(42))\ntrain_loader = DataLoader(train_ds, batch_size=128, shuffle=True, num_workers=2)\nval_loader = DataLoader(val_ds, batch_size=128, shuffle=False, num_workers=2)\n\n# 4. Initialize Model (ResNet34)\nmodel = models.resnet34(weights='DEFAULT')\nmodel.requires_grad_(False) # Freeze backbone\n\nnum_classes = len(class_names)\nmodel.fc = nn.Linear(model.fc.in_features, num_classes)\n\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nmodel = model.to(device)\n\n# 5. Training Loop\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n\nfor epoch in range(10): # Baseline uses 10 epochs\n    model.train()\n    for inputs, labels in tqdm(train_loader, desc=f\"Epoch {epoch+1} Training\"):\n        inputs, labels = gpu_transform(inputs.to(device)), labels.to(device)\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n# 6. Predict on Test Sketches\nclass SketchTestDataset(Dataset):\n    def __init__(self, root_dir, transform=None):\n        self.root_dir = root_dir\n        self.transform = transform\n        self.image_files = [f for f in os.listdir(root_dir) if f.endswith(('.jpg', '.jpeg', '.png'))]\n\n    def __len__(self): return len(self.image_files)\n    def __getitem__(self, idx):\n        filename = self.image_files[idx]\n        image = Image.open(os.path.join(self.root_dir, filename)).convert('RGB')\n        if self.transform: image = self.transform(image)\n        return image, filename\n\ntest_dataset = SketchTestDataset(root_dir=TEST_DIR, transform=transform)\ntest_loader = DataLoader(test_dataset, batch_size=128, shuffle=False)\n\nmodel.eval()\nall_predictions = []\nall_filenames = []\n\nwith torch.no_grad():\n    for inputs, filenames in tqdm(test_loader, desc=\"Predicting on Test Data\"):\n        inputs = gpu_transform(inputs.to(device))\n        outputs = model(inputs)\n        _, predicted_indices = torch.max(outputs, 1)\n        all_predictions.extend([class_names[i] for i in predicted_indices.cpu().numpy()])\n        all_filenames.extend(filenames)\n\n# 7. Generate Submission CSV\nsubmission_df = pd.DataFrame({'filename': all_filenames, 'class_name': all_predictions})\nsubmission_df.to_csv('submission.csv', index=False)\nprint(\"submission.csv created successfully.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-30T04:24:06.250931Z","iopub.execute_input":"2026-01-30T04:24:06.251302Z","iopub.status.idle":"2026-01-30T04:47:17.918209Z","shell.execute_reply.started":"2026-01-30T04:24:06.251273Z","shell.execute_reply":"2026-01-30T04:47:17.917292Z"}},"outputs":[],"execution_count":null}]}