{"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":112509,"databundleVersionId":14254895,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":707378,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":537119,"modelId":550515}],"dockerImageVersionId":31236,"isInternetEnabled":false,"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\nfrom torch.utils.data import Dataset, DataLoader\nfrom PIL import Image\nimport torchvision.transforms as T\nfrom tqdm.auto import tqdm\nimport timm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T09:19:53.337767Z","iopub.execute_input":"2026-01-03T09:19:53.338435Z","iopub.status.idle":"2026-01-03T09:19:53.342333Z","shell.execute_reply.started":"2026-01-03T09:19:53.338406Z","shell.execute_reply":"2026-01-03T09:19:53.341730Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nDATA_DIR = \"/kaggle/input/csiro-biomass\"\nTEST_CSV  = os.path.join(DATA_DIR, \"test.csv\")\n\nMODEL_NAME = \"efficientnet_b3\"\nIMG_SIZE = 384\n\ntargets = [\"Dry_Green_g\",\"Dry_Dead_g\",\"Dry_Clover_g\",\"GDM_g\",\"Dry_Total_g\"]\n\nFINETUNED_CKPT = \"/kaggle/input/efficientnet3/pytorch/default/1/efficientnet_b3_finetuned_fold0 (1).pth\"\n\nassert os.path.exists(FINETUNED_CKPT), f\"Checkpoint not found: {FINETUNED_CKPT}\"\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T09:20:11.684202Z","iopub.execute_input":"2026-01-03T09:20:11.684575Z","iopub.status.idle":"2026-01-03T09:20:11.690566Z","shell.execute_reply.started":"2026-01-03T09:20:11.684543Z","shell.execute_reply":"2026-01-03T09:20:11.689928Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_long = pd.read_csv(TEST_CSV)\n\nvalid_tfms = T.Compose([\n    T.Resize((IMG_SIZE, IMG_SIZE)),\n    T.ToTensor(),\n])\n\nclass UniqueTestDS(Dataset):\n    def __init__(self, image_paths, tfms):\n        self.image_paths = list(image_paths)\n        self.tfms = tfms\n    def __len__(self): return len(self.image_paths)\n    def __getitem__(self, idx):\n        rel = self.image_paths[idx]\n        img = Image.open(os.path.join(DATA_DIR, rel)).convert(\"RGB\")\n        img = self.tfms(img)\n        return img, rel","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T09:20:22.370673Z","iopub.execute_input":"2026-01-03T09:20:22.371207Z","iopub.status.idle":"2026-01-03T09:20:22.380389Z","shell.execute_reply.started":"2026-01-03T09:20:22.371177Z","shell.execute_reply":"2026-01-03T09:20:22.379656Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class MultiHeadReg(nn.Module):\n    def __init__(self, model_name, num_targets=5):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool=\"avg\")\n        in_features = self.backbone.num_features\n        self.head = nn.Sequential(\n            nn.LayerNorm(in_features),\n            nn.Linear(in_features, 512),\n            nn.GELU(),\n            nn.Dropout(0.25),\n            nn.Linear(512, num_targets),\n        )\n    def forward(self, x):\n        feat = self.backbone(x)\n        return self.head(feat)  # log1p grams\n\nmodel = MultiHeadReg(MODEL_NAME, num_targets=len(targets)).to(DEVICE)\n\n# Load your trained weights\nstate = torch.load(FINETUNED_CKPT, map_location=DEVICE)\n\n# Some checkpoints store {'state_dict': ...}\nif isinstance(state, dict) and \"state_dict\" in state:\n    state = state[\"state_dict\"]\n\n# Clean key prefixes if any\ncleaned = {}\nfor k, v in state.items():\n    k2 = k.replace(\"module.\", \"\")\n    cleaned[k2] = v\n\nmissing, unexpected = model.load_state_dict(cleaned, strict=False)\nprint(\"✅ Loaded finetuned checkpoint:\", FINETUNED_CKPT)\nprint(\"Missing keys:\", len(missing), \"Unexpected keys:\", len(unexpected))\n\nmodel.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T09:20:37.263083Z","iopub.execute_input":"2026-01-03T09:20:37.263809Z","iopub.status.idle":"2026-01-03T09:20:37.633035Z","shell.execute_reply.started":"2026-01-03T09:20:37.263776Z","shell.execute_reply":"2026-01-03T09:20:37.632385Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"@torch.no_grad()\ndef predict_unique(image_paths):\n    ds = UniqueTestDS(image_paths, valid_tfms)\n    dl = DataLoader(ds, batch_size=32, shuffle=False, num_workers=2, pin_memory=True)\n\n    out_map = {}\n    for imgs, paths in tqdm(dl, desc=\"predict\"):\n        imgs = imgs.to(DEVICE)\n        pred_log1p = model(imgs)\n        pred = torch.expm1(pred_log1p).clamp_min(0).cpu().numpy()  # grams\n        for p, vec in zip(paths, pred):\n            out_map[p] = vec\n    return out_map\n\nunique_imgs = sorted(test_long[\"image_path\"].unique())\npred_map = predict_unique(unique_imgs)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T09:20:55.989101Z","iopub.execute_input":"2026-01-03T09:20:55.989640Z","iopub.status.idle":"2026-01-03T09:20:57.081272Z","shell.execute_reply.started":"2026-01-03T09:20:55.989609Z","shell.execute_reply":"2026-01-03T09:20:57.080528Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pred_wide = pd.DataFrame({\n    \"image_path\": unique_imgs,\n    \"Dry_Green_g\": [pred_map[p][0] for p in unique_imgs],\n    \"Dry_Dead_g\":  [pred_map[p][1] for p in unique_imgs],\n    \"Dry_Clover_g\":[pred_map[p][2] for p in unique_imgs],\n    \"GDM_g\":       [pred_map[p][3] for p in unique_imgs],\n    \"Dry_Total_g\": [pred_map[p][4] for p in unique_imgs],\n})\n\ntmp = test_long.merge(pred_wide, on=\"image_path\", how=\"left\")\ntmp[\"target\"] = tmp.apply(lambda r: r[r[\"target_name\"]], axis=1)\n\nsub = tmp[[\"sample_id\",\"target\"]].copy()\nsub.to_csv(\"submission.csv\", index=False)\n\nprint(\"✅ submission.csv saved:\", sub.shape)\nprint(sub.head(10))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T09:21:07.886531Z","iopub.execute_input":"2026-01-03T09:21:07.886943Z","iopub.status.idle":"2026-01-03T09:21:07.926786Z","shell.execute_reply.started":"2026-01-03T09:21:07.886892Z","shell.execute_reply":"2026-01-03T09:21:07.926170Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}