{"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":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":132732,"databundleVersionId":16583342}],"dockerImageVersionId":31328,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom PIL import Image\nfrom torchvision import transforms, models\nfrom tqdm import tqdm\nfrom sklearn.model_selection import train_test_split","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-04-11T12:02:41.616161Z","iopub.execute_input":"2026-04-11T12:02:41.616662Z","iopub.status.idle":"2026-04-11T12:02:43.245971Z","shell.execute_reply.started":"2026-04-11T12:02:41.616626Z","shell.execute_reply":"2026-04-11T12:02:43.245283Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CFG:\n    root = \"/kaggle/input/competitions/dlmmdd-workshop-synthetic-source-attribution-challenge/Data/Data\"\n    train_csv = os.path.join(root, \"training.csv\")\n    test_csv = os.path.join(root, \"test.csv\")\n    train_dir = os.path.join(root, \"Training\")\n    test_dir = os.path.join(root, \"Test\")\n    device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n    batch_size = 64\n    epochs = 5\n    lr = 3e-4\n    num_classes = 10\n    img_size = 224\n\ndef resolve_path(p):\n    for c in [\n        os.path.join(CFG.root, p),\n        os.path.join(CFG.train_dir, os.path.basename(p)),\n        os.path.join(CFG.test_dir, os.path.basename(p)),\n        p\n    ]:\n        if os.path.exists(c):\n            return c\n    return None","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-04-11T12:02:43.247124Z","iopub.execute_input":"2026-04-11T12:02:43.247906Z","iopub.status.idle":"2026-04-11T12:02:43.253655Z","shell.execute_reply.started":"2026-04-11T12:02:43.247876Z","shell.execute_reply":"2026-04-11T12:02:43.253023Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TrainDataset(Dataset):\n    def __init__(self, df, tfm):\n        self.df = df\n        self.tfm = tfm\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, i):\n        r = self.df.iloc[i]\n        path = resolve_path(r[\"path\"])\n        img = Image.open(path).convert(\"RGB\").resize((CFG.img_size, CFG.img_size))\n        return self.tfm(img), torch.tensor(r[\"y\"]).long()\n\nclass TestDataset(Dataset):\n    def __init__(self, df, tfm):\n        self.df = df\n        self.tfm = tfm\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, i):\n        r = self.df.iloc[i]\n        path = resolve_path(r[\"path\"])\n        img = Image.open(path).convert(\"RGB\").resize((CFG.img_size, CFG.img_size))\n        return self.tfm(img), r[\"ID\"]\n\ndef get_tfm():\n    return transforms.Compose([\n        transforms.ToTensor(),\n        transforms.Normalize([0.5]*3, [0.5]*3)\n    ])","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-04-11T12:02:43.254609Z","iopub.execute_input":"2026-04-11T12:02:43.255115Z","iopub.status.idle":"2026-04-11T12:02:43.273493Z","shell.execute_reply.started":"2026-04-11T12:02:43.255068Z","shell.execute_reply":"2026-04-11T12:02:43.272836Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Model(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.net = models.efficientnet_b0(weights=models.EfficientNet_B0_Weights.DEFAULT)\n        self.net.classifier = nn.Linear(1280, CFG.num_classes)\n\n    def forward(self, x):\n        return self.net(x)\n\ndef train(model, loader, opt):\n    model.train()\n    loss_fn = nn.CrossEntropyLoss()\n    \n    total_loss = 0\n    correct = 0\n    total = 0\n\n    pbar = tqdm(loader, desc=\"Train\")\n\n    for x, y in pbar:\n        x, y = x.to(CFG.device), y.to(CFG.device)\n\n        opt.zero_grad()\n        logits = model(x)\n        loss = loss_fn(logits, y)\n        loss.backward()\n        opt.step()\n\n        total_loss += loss.item() * x.size(0)\n\n        preds = logits.argmax(1)\n        correct += (preds == y).sum().item()\n        total += y.size(0)\n\n        pbar.set_postfix({\n            \"loss\": total_loss / total,\n            \"acc\": correct / total\n        })\n\n    return total_loss / total, correct / total\n\ndef valid(model, loader):\n    model.eval()\n    loss_fn = nn.CrossEntropyLoss()\n\n    total_loss = 0\n    correct = 0\n    total = 0\n\n    pbar = tqdm(loader, desc=\"Valid\")\n\n    with torch.no_grad():\n        for x, y in pbar:\n            x, y = x.to(CFG.device), y.to(CFG.device)\n\n            logits = model(x)\n            loss = loss_fn(logits, y)\n\n            total_loss += loss.item() * x.size(0)\n\n            preds = logits.argmax(1)\n            correct += (preds == y).sum().item()\n            total += y.size(0)\n\n            pbar.set_postfix({\n                \"val_loss\": total_loss / total,\n                \"val_acc\": correct / total\n            })\n\n    return total_loss / total, correct / total\n\ndef predict(model, loader):\n    model.eval()\n    ids, preds = [], []\n    with torch.no_grad():\n        for x, i in loader:\n            x = x.to(CFG.device)\n            p = model(x).argmax(1).cpu().numpy()\n            ids.extend(i.numpy())\n            preds.extend(p)\n    return ids, preds","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-04-11T12:02:43.275080Z","iopub.execute_input":"2026-04-11T12:02:43.275445Z","iopub.status.idle":"2026-04-11T12:02:43.289626Z","shell.execute_reply.started":"2026-04-11T12:02:43.275422Z","shell.execute_reply":"2026-04-11T12:02:43.288842Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def main():\n\n    print(f\"Using device: {CFG.device}\")\n    \n    train_df = pd.read_csv(CFG.train_csv)\n    train_df, val_df = train_test_split(\n        train_df,\n        test_size=0.2,\n        stratify=train_df[\"y\"],\n        random_state=42\n    )\n    test_df = pd.read_csv(CFG.test_csv)\n\n    tfm = get_tfm()\n\n    train_loader = DataLoader(\n        TrainDataset(train_df, tfm),\n        batch_size=CFG.batch_size,\n        shuffle=True,\n        num_workers=2,\n        pin_memory=True\n    )\n    \n    val_loader = DataLoader(\n        TrainDataset(val_df, tfm),\n        batch_size=CFG.batch_size,\n        shuffle=False,\n        num_workers=2,\n        pin_memory=True\n    )\n\n    test_loader = DataLoader(\n        TestDataset(test_df, tfm),\n        batch_size=CFG.batch_size,\n        shuffle=False,\n        num_workers=2,\n        pin_memory=True\n    )\n\n    model = Model().to(CFG.device)\n    opt = optim.AdamW(model.parameters(), lr=CFG.lr)\n    best_acc = 0.0\n\n    for epoch in range(CFG.epochs):\n        print(f\"\\nEpoch {epoch+1}/{CFG.epochs}\")\n        train_loss, train_acc = train(model, train_loader, opt)\n        print(f\"Train: loss={train_loss:.4f}, acc={train_acc:.4f}\")\n        val_loss, val_acc = valid(model, val_loader)\n        print(f\"Valid: loss={val_loss:.4f}, acc={val_acc:.4f}\")\n        if val_acc > best_acc:\n            best_acc = val_acc\n            torch.save(model.state_dict(), \"best_model.pth\")\n\n    model.load_state_dict(torch.load(\"best_model.pth\"))\n    ids, preds = predict(model, test_loader)\n\n    pd.DataFrame({\"ID\": ids, \"TARGET\": preds}).to_csv(\"submission.csv\", index=False)\n\nif __name__ == \"__main__\":\n    main()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-04-11T12:05:32.906520Z","iopub.execute_input":"2026-04-11T12:05:32.907308Z","iopub.status.idle":"2026-04-11T12:19:10.717932Z","shell.execute_reply.started":"2026-04-11T12:05:32.907268Z","shell.execute_reply":"2026-04-11T12:19:10.716847Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null}]}