{"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":"none","dataSources":[{"sourceId":128792,"databundleVersionId":15494745,"sourceType":"competition"}],"dockerImageVersionId":31259,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# ================================\n# IMPORTS\n# ================================\nimport os\nimport json\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport pandas as pd\nfrom PIL import Image\nfrom torchvision import transforms\nfrom torchvision.models import mobilenet_v2\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-29T06:25:14.411725Z","iopub.execute_input":"2026-01-29T06:25:14.412043Z","iopub.status.idle":"2026-01-29T06:25:14.417023Z","shell.execute_reply.started":"2026-01-29T06:25:14.412006Z","shell.execute_reply":"2026-01-29T06:25:14.415791Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================\n# DEVICE\n# ================================\ndevice = torch.device(\"cpu\")\nprint(\"Using device:\", device)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-29T06:25:28.594468Z","iopub.execute_input":"2026-01-29T06:25:28.594770Z","iopub.status.idle":"2026-01-29T06:25:28.600352Z","shell.execute_reply.started":"2026-01-29T06:25:28.594745Z","shell.execute_reply":"2026-01-29T06:25:28.599316Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================\n# PATHS\n# ================================\nBASE_PATH = \"/kaggle/input/vista26/Vistas Dataset Public/Vistas Dataset Public\"\n\nTRAIN_DIR = os.path.join(BASE_PATH, \"train\")\nVAL_DIR   = os.path.join(BASE_PATH, \"validation\")\n\nINSTANCES_TRAIN = os.path.join(BASE_PATH, \"instances_train.json\")\nCATEGORIES_JSON = os.path.join(BASE_PATH, \"Categories.json\")\n\nprint(\"Train images:\", len(os.listdir(TRAIN_DIR)))\nprint(\"Validation images:\", len(os.listdir(VAL_DIR)))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-29T06:25:59.204197Z","iopub.execute_input":"2026-01-29T06:25:59.204564Z","iopub.status.idle":"2026-01-29T06:26:01.794376Z","shell.execute_reply.started":"2026-01-29T06:25:59.204533Z","shell.execute_reply":"2026-01-29T06:26:01.793376Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================\n# CATEGORY MAPPING\n# ================================\nwith open(CATEGORIES_JSON, \"r\") as f:\n    categories_data = json.load(f)[\"categories\"]\n\ncategory_ids = sorted([c[\"id\"] for c in categories_data])\ncatid_to_idx = {cid: i for i, cid in enumerate(category_ids)}\nidx_to_catid = {i: cid for cid, i in catid_to_idx.items()}\n\nNUM_CLASSES = len(category_ids)\nprint(\"Number of classes:\", NUM_CLASSES)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-29T06:26:13.964944Z","iopub.execute_input":"2026-01-29T06:26:13.965347Z","iopub.status.idle":"2026-01-29T06:26:13.989121Z","shell.execute_reply.started":"2026-01-29T06:26:13.965317Z","shell.execute_reply":"2026-01-29T06:26:13.988148Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================\n# TRANSFORMS\n# ================================\ntransform = transforms.Compose([\n    transforms.Resize((128, 128)),\n    transforms.ToTensor()\n])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-29T06:26:36.249115Z","iopub.execute_input":"2026-01-29T06:26:36.250072Z","iopub.status.idle":"2026-01-29T06:26:36.254692Z","shell.execute_reply.started":"2026-01-29T06:26:36.250021Z","shell.execute_reply":"2026-01-29T06:26:36.253839Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================\n# MODEL\n# ================================\nmodel = mobilenet_v2(weights=None)\nmodel.classifier[1] = nn.Linear(model.last_channel, NUM_CLASSES)\nmodel = model.to(device)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=1e-3)\n\nprint(\"Model initialized\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-29T06:27:07.228565Z","iopub.execute_input":"2026-01-29T06:27:07.228893Z","iopub.status.idle":"2026-01-29T06:27:07.316499Z","shell.execute_reply.started":"2026-01-29T06:27:07.228863Z","shell.execute_reply":"2026-01-29T06:27:07.315181Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================\n# LOAD TRAIN ANNOTATIONS\n# ================================\nwith open(INSTANCES_TRAIN, \"r\") as f:\n    train_data = json.load(f)\n\nimage_id_to_cat = {}\nfor ann in train_data[\"annotations\"]:\n    image_id_to_cat[ann[\"image_id\"]] = ann[\"category_id\"]\n\nid_to_filename = {img[\"id\"]: img[\"file_name\"] for img in train_data[\"images\"]}\n\nprint(\"Training samples:\", len(image_id_to_cat))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-29T06:27:21.401134Z","iopub.execute_input":"2026-01-29T06:27:21.401502Z","iopub.status.idle":"2026-01-29T06:27:22.222524Z","shell.execute_reply.started":"2026-01-29T06:27:21.401472Z","shell.execute_reply":"2026-01-29T06:27:22.221383Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================\n# TRAIN (1 EPOCH BASELINE)\n# ================================\nmodel.train()\n\nfor i, (img_id, cat_id) in enumerate(list(image_id_to_cat.items())[:1000]):  # small subset\n    img_path = os.path.join(TRAIN_DIR, id_to_filename[img_id])\n    img = Image.open(img_path).convert(\"RGB\")\n\n    x = transform(img).unsqueeze(0).to(device)\n    y = torch.tensor([catid_to_idx[cat_id]]).to(device)\n\n    optimizer.zero_grad()\n    logits = model(x)\n    loss = criterion(logits, y)\n    loss.backward()\n    optimizer.step()\n\n    if i % 100 == 0:\n        print(f\"Step {i}, Loss: {loss.item():.4f}\")\n\nprint(\"Training done\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-29T06:27:36.656520Z","iopub.execute_input":"2026-01-29T06:27:36.656820Z","iopub.status.idle":"2026-01-29T06:30:05.454401Z","shell.execute_reply.started":"2026-01-29T06:27:36.656795Z","shell.execute_reply":"2026-01-29T06:30:05.453386Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================\n# CREATE SUBMISSION\n# ================================\nmodel.eval()\nval_images = sorted(os.listdir(VAL_DIR))\n\nsubmission = []\n\nwith torch.no_grad():\n    for idx, img_name in enumerate(val_images):\n        img_path = os.path.join(VAL_DIR, img_name)\n        img = Image.open(img_path).convert(\"RGB\")\n\n        x = transform(img).unsqueeze(0).to(device)\n        logits = model(x)\n        probs = torch.softmax(logits, dim=1).squeeze()\n\n        # baseline: top-3 predictions\n        topk = torch.topk(probs, k=3).indices.tolist()\n        categories = sorted([idx_to_catid[i] for i in topk])\n\n        submission.append({\n            \"image_id\": idx + 1,              # 🔑 ALWAYS 1..6000\n            \"categories\": str(categories)     # JSON STRING\n        })\n\ndf = pd.DataFrame(submission, columns=[\"image_id\", \"categories\"])\ndf.to_csv(\"submission.csv\", index=False)\n\nprint(\"submission.csv CREATED\")\ndf.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-29T06:30:56.024831Z","iopub.execute_input":"2026-01-29T06:30:56.025369Z","iopub.status.idle":"2026-01-29T06:35:47.077588Z","shell.execute_reply.started":"2026-01-29T06:30:56.025331Z","shell.execute_reply":"2026-01-29T06:35:47.076638Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================\n# FINAL CHECK\n# ================================\ndf = pd.read_csv(\"submission.csv\")\n\nprint(\"Total rows:\", len(df))\nprint(\"First image_id:\", df.image_id.iloc[0])\nprint(\"Last image_id:\", df.image_id.iloc[-1])\n\nwith open(\"submission.csv\") as f:\n    for _ in range(5):\n        print(f.readline().strip())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-29T06:35:52.641161Z","iopub.execute_input":"2026-01-29T06:35:52.641550Z","iopub.status.idle":"2026-01-29T06:35:52.654363Z","shell.execute_reply.started":"2026-01-29T06:35:52.641519Z","shell.execute_reply":"2026-01-29T06:35:52.652994Z"}},"outputs":[],"execution_count":null}]}