{"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":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"},{"sourceId":292506616,"sourceType":"kernelVersion"}],"dockerImageVersionId":31260,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport torch\nfrom torch.utils.data import Dataset\nfrom PIL import Image\nimport numpy as np\nimport torch.nn as nn\nimport torchvision.models as models\nfrom torch.optim import AdamW\nfrom sklearn.model_selection import train_test_split\nfrom torch.utils.data import DataLoader\nfrom torchvision import transforms\nfrom tqdm import tqdm\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-01-18T09:13:19.613676Z","iopub.execute_input":"2026-01-18T09:13:19.613969Z","iopub.status.idle":"2026-01-18T09:13:19.619306Z","shell.execute_reply.started":"2026-01-18T09:13:19.613944Z","shell.execute_reply":"2026-01-18T09:13:19.618429Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df = pd.read_csv(\"/kaggle/input/csiro-biomass/test.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-18T09:13:21.457560Z","iopub.execute_input":"2026-01-18T09:13:21.457867Z","iopub.status.idle":"2026-01-18T09:13:21.464202Z","shell.execute_reply.started":"2026-01-18T09:13:21.457841Z","shell.execute_reply":"2026-01-18T09:13:21.463440Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TARGET_ORDER = {\n    \"Dry_Green_g\": 0,\n    \"Dry_Dead_g\": 1,\n    \"Dry_Clover_g\": 2,\n    \"GDM_g\": 3,\n    \"Dry_Total_g\": 4,\n}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-18T09:13:28.393287Z","iopub.execute_input":"2026-01-18T09:13:28.393602Z","iopub.status.idle":"2026-01-18T09:13:28.398553Z","shell.execute_reply.started":"2026-01-18T09:13:28.393575Z","shell.execute_reply":"2026-01-18T09:13:28.397709Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class BiomassTestDataset(Dataset):\n    def __init__(self, df, transforms=None):\n        self.df = df\n        self.transforms = transforms\n        self.img_dir = \"/kaggle/input/csiro-biomass\"\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        full_path = os.path.join(self.img_dir, row[\"image_path\"])\n        image = Image.open(full_path).convert(\"RGB\")\n        if self.transforms:\n            image = self.transforms(image)\n\n        return image, row[\"target_name\"], row[\"sample_id\"]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-18T09:13:30.180862Z","iopub.execute_input":"2026-01-18T09:13:30.181256Z","iopub.status.idle":"2026-01-18T09:13:30.186422Z","shell.execute_reply.started":"2026-01-18T09:13:30.181230Z","shell.execute_reply":"2026-01-18T09:13:30.185584Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class GeM(nn.Module):\n    def __init__(self, p=3.0, eps=1e-6):\n        super().__init__()\n        self.p = nn.Parameter(torch.ones(1) * p)\n        self.eps = eps\n\n    def forward(self, x):\n        return torch.mean(\n            x.clamp(min=self.eps).pow(self.p),\n            dim=(-2, -1)\n        ).pow(1.0 / self.p)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-18T09:13:33.232150Z","iopub.execute_input":"2026-01-18T09:13:33.232869Z","iopub.status.idle":"2026-01-18T09:13:33.237598Z","shell.execute_reply.started":"2026-01-18T09:13:33.232824Z","shell.execute_reply":"2026-01-18T09:13:33.236907Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class BiomassModel(nn.Module):\n    def __init__(self):\n        super().__init__()\n\n        resnet = models.resnet50(\n            weights=None   # IMPORTANT: weights=None for inference\n        )\n\n        self.stem = nn.Sequential(\n            resnet.conv1,\n            resnet.bn1,\n            resnet.relu,\n            resnet.maxpool,\n        )\n\n        self.layer1 = resnet.layer1\n        self.layer2 = resnet.layer2\n        self.layer3 = resnet.layer3\n        self.layer4 = resnet.layer4\n\n        self.pool = GeM()\n        self.feature_dim = 2048\n\n        self.heads = nn.ModuleList([\n            nn.Sequential(\n                nn.Linear(self.feature_dim, 1),\n                nn.Softplus()\n            )\n            for _ in range(5)\n        ])\n\n    def forward(self, x):\n        x = self.stem(x)\n        x = self.layer1(x)\n        x = self.layer2(x)\n        x = self.layer3(x)\n        x = self.layer4(x)   # [B, 2048, H, W]\n\n        x = self.pool(x)     # [B, 2048]\n\n        outs = [h(x) for h in self.heads]\n        return torch.cat(outs, dim=1)   # log1p space\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-18T09:13:38.720560Z","iopub.execute_input":"2026-01-18T09:13:38.721311Z","iopub.status.idle":"2026-01-18T09:13:38.730356Z","shell.execute_reply.started":"2026-01-18T09:13:38.721270Z","shell.execute_reply":"2026-01-18T09:13:38.729488Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = BiomassModel().to(DEVICE)\n\nckpt_path = \"/kaggle/input/img2b-baseline/checkpoints/best_model_new-v1.pt\"\ncheckpoint = torch.load(ckpt_path, map_location=DEVICE)\n\nmodel.load_state_dict(checkpoint[\"model_state\"])\nmodel.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-18T09:13:41.047332Z","iopub.execute_input":"2026-01-18T09:13:41.047824Z","iopub.status.idle":"2026-01-18T09:13:42.615910Z","shell.execute_reply.started":"2026-01-18T09:13:41.047799Z","shell.execute_reply":"2026-01-18T09:13:42.615318Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_tfms = transforms.Compose([\n    transforms.Resize((384, 384)),\n    transforms.ToTensor(),\n    transforms.Normalize(\n        mean=[0.485, 0.456, 0.406],\n        std=[0.229, 0.224, 0.225]\n    )\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-18T09:13:48.749845Z","iopub.execute_input":"2026-01-18T09:13:48.750195Z","iopub.status.idle":"2026-01-18T09:13:48.754742Z","shell.execute_reply.started":"2026-01-18T09:13:48.750168Z","shell.execute_reply":"2026-01-18T09:13:48.753990Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_ds = BiomassTestDataset(test_df, transforms=val_tfms)\ntest_loader = DataLoader(\n    test_ds,\n    batch_size=32,\n    shuffle=False,\n    num_workers=2\n)\n\npredictions = []\n\nwith torch.no_grad():\n    for images, target_names, sample_ids in test_loader:\n        images = images.to(DEVICE)\n\n        outputs_log = model(images)           # log1p\n        outputs = torch.expm1(outputs_log)    # linear\n        outputs = torch.clamp(outputs, min=0.0)\n\n        outputs = outputs.cpu().numpy()\n\n        for i in range(len(sample_ids)):\n            tname = target_names[i]\n            idx = TARGET_ORDER[tname]\n            predictions.append({\n                \"sample_id\": sample_ids[i],\n                \"target\": outputs[i, idx]\n            })\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-18T09:14:05.179646Z","iopub.execute_input":"2026-01-18T09:14:05.179956Z","iopub.status.idle":"2026-01-18T09:14:08.225122Z","shell.execute_reply.started":"2026-01-18T09:14:05.179929Z","shell.execute_reply":"2026-01-18T09:14:08.224159Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.DataFrame(predictions)\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-18T09:14:17.896456Z","iopub.execute_input":"2026-01-18T09:14:17.897247Z","iopub.status.idle":"2026-01-18T09:14:17.914155Z","shell.execute_reply.started":"2026-01-18T09:14:17.897205Z","shell.execute_reply":"2026-01-18T09:14:17.913292Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-18T09:14:19.883594Z","iopub.execute_input":"2026-01-18T09:14:19.884374Z","iopub.status.idle":"2026-01-18T09:14:19.908798Z","shell.execute_reply.started":"2026-01-18T09:14:19.884344Z","shell.execute_reply":"2026-01-18T09:14:19.908014Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}