{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","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"}],"dockerImageVersionId":31154,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport os","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-11-05T08:22:21.429152Z","iopub.execute_input":"2025-11-05T08:22:21.429719Z","iopub.status.idle":"2025-11-05T08:22:21.433122Z","shell.execute_reply.started":"2025-11-05T08:22:21.429694Z","shell.execute_reply":"2025-11-05T08:22:21.432351Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\npath = '/kaggle/input/csiro-biomass'\n\nsample = pd.read_csv(os.path.join(path, 'sample_submission.csv'))\ntrain_df = pd.read_csv(os.path.join(path, 'train.csv'))\ntest_df = pd.read_csv(os.path.join(path, 'test.csv'))\n\n# Fix image paths\ntrain_df[\"image_path\"] = train_df[\"image_path\"].apply(lambda x: os.path.join(path, str(x)))\ntest_df[\"image_path\"]  = test_df[\"image_path\"].apply(lambda x: os.path.join(path, str(x)))\n\n# Drop unnecessary columns\ncols_to_drop = [\"Sampling_Date\", \"State\", \"Species\", \"Pre_GSHH_NDVI\", \"Height_Ave_cm\"]\ntrain_df = train_df.drop(columns=cols_to_drop, errors='ignore')  # safe if some columns missing\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T08:22:23.111851Z","iopub.execute_input":"2025-11-05T08:22:23.112148Z","iopub.status.idle":"2025-11-05T08:22:23.130392Z","shell.execute_reply.started":"2025-11-05T08:22:23.112089Z","shell.execute_reply":"2025-11-05T08:22:23.129781Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import Dataset\nfrom PIL import Image\n\nclass CloverDataset(Dataset):\n    def __init__(self, df, transforms=None):\n        self.df = df\n        self.transforms = transforms\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        img = Image.open(row[\"image_path\"]).convert(\"RGB\")\n\n        if self.transforms:\n            img = self.transforms(img)\n\n        target = torch.tensor(row[\"target\"], dtype=torch.float32)\n        return img, target\n\nimport torch.nn as nn\nimport torchvision.models as models\n\nclass SimpleCNN(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.backbone = models.resnet18(weights=None)\n        self.backbone.fc = nn.Linear(self.backbone.fc.in_features, 1)\n\n    def forward(self, x):\n        return self.backbone(x).squeeze(1)\n\nfrom torch.utils.data import DataLoader\nfrom sklearn.model_selection import train_test_split\nimport torch.optim as optim\nimport torchvision.transforms as T\nfrom tqdm import tqdm\nfrom sklearn.metrics import r2_score\n\n# Image augmentations\ntrain_tfms = T.Compose([\n    T.Resize((224, 224)),\n    T.RandomHorizontalFlip(),\n    T.ToTensor(),\n])\n\nvalid_tfms = T.Compose([\n    T.Resize((224, 224)),\n    T.ToTensor(),\n])\n\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nmodel = SimpleCNN().to(device)\ncriterion = nn.MSELoss()\noptimizer = optim.Adam(model.parameters(), lr=1e-4)\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torchvision.transforms as T\nfrom torch.utils.data import DataLoader\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import r2_score\nfrom tqdm import tqdm\nimport numpy as np\n\nEPOCHS=1\n\n# List of all 5 biomass targets\ntarget_names = [\"Dry_Clover_g\", \"Dry_Dead_g\", \"Dry_Green_g\", \"Dry_Total_g\", \"GDM_g\"]\n\n# Add placeholder target in test\ntest_df[\"target\"] = np.nan\n\nimport pandas as pd\n\nall_test_preds = []  # ✅ Will store all subsets with predictions\n\n# Loop over each target name\nfor target_name in target_names:\n    print(f\"\\n==================== {target_name} ====================\")\n\n    # 1️⃣ Filter train & test subsets\n    df_sub = train_df[train_df[\"target_name\"] == target_name].reset_index(drop=True)\n    test_sub = test_df[test_df[\"target_name\"] == target_name].reset_index(drop=True)\n\n    # 2️⃣ Split train/valid\n    train_df_c, valid_df_c = train_test_split(df_sub, test_size=0.2, random_state=42)\n\n    # 3️⃣ Datasets & loaders\n    train_ds = CloverDataset(train_df_c, transforms=train_tfms)\n    valid_ds = CloverDataset(valid_df_c, transforms=valid_tfms)\n    train_dl = DataLoader(train_ds, batch_size=16, shuffle=True)\n    valid_dl = DataLoader(valid_ds, batch_size=16, shuffle=False)\n\n    # 4️⃣ Model, loss, optim\n    model = SimpleCNN().to(device)\n    criterion = nn.MSELoss()\n    optimizer = optim.Adam(model.parameters(), lr=1e-4)\n\n    # 5️⃣ Training loop\n    for epoch in range(EPOCHS):\n        model.train()\n        train_loss = 0\n        for imgs, targets in tqdm(train_dl, desc=f\"{target_name} Epoch {epoch+1}/{EPOCHS}\"):\n            imgs, targets = imgs.to(device), targets.to(device)\n            preds = model(imgs)\n            loss = criterion(preds, targets)\n            optimizer.zero_grad()\n            loss.backward()\n            optimizer.step()\n            train_loss += loss.item()\n\n        # Validation\n        model.eval()\n        valid_preds, valid_targets = [], []\n        with torch.no_grad():\n            for imgs, targets in valid_dl:\n                imgs, targets = imgs.to(device), targets.to(device)\n                preds = model(imgs)\n                valid_preds.extend(preds.cpu().numpy())\n                valid_targets.extend(targets.cpu().numpy())\n\n        valid_loss = criterion(torch.tensor(valid_preds), torch.tensor(valid_targets)).item()\n        r2 = r2_score(valid_targets, valid_preds)\n        print(f\"Train Loss: {train_loss/len(train_dl):.4f} | Valid Loss: {valid_loss:.4f} | R²: {r2:.4f}\")\n\n    # 6️⃣ Predict on test subset\n    test_ds = CloverDataset(test_sub, transforms=valid_tfms)\n    test_dl = DataLoader(test_ds, batch_size=16, shuffle=False)\n\n    preds = []\n    model.eval()\n    with torch.no_grad():\n        for imgs, _ in test_dl:\n            imgs = imgs.to(device)\n            pred = model(imgs).cpu().numpy()\n            preds.extend(pred)\n\n    # 7️⃣ Create a DataFrame for this target with predictions\n    test_sub_preds = test_sub.copy()\n    test_sub_preds[\"target\"] = np.array(preds).reshape(-1)\n    all_test_preds.append(test_sub_preds)\n\n# 8️⃣ Combine all subsets into a single DataFrame\ntest_preds_df = pd.concat(all_test_preds, axis=0).reset_index(drop=True)\nprint(\"\\n✅ All 5 models done and combined into test_preds_df!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T08:05:06.743283Z","iopub.execute_input":"2025-11-05T08:05:06.743879Z","iopub.status.idle":"2025-11-05T08:07:03.050246Z","shell.execute_reply.started":"2025-11-05T08:05:06.743855Z","shell.execute_reply":"2025-11-05T08:07:03.049572Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create a mapping from sample_id to predicted target\npred_map = dict(zip(test_preds_df[\"sample_id\"], test_preds_df[\"target\"]))\n\n# Fill the target column in test_df\ntest_df[\"target\"] = test_df[\"sample_id\"].map(pred_map)\n\nprint(\"✅ test_df['target'] updated from test_preds_df!\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T08:08:13.821922Z","iopub.execute_input":"2025-11-05T08:08:13.822205Z","iopub.status.idle":"2025-11-05T08:08:13.828521Z","shell.execute_reply.started":"2025-11-05T08:08:13.822186Z","shell.execute_reply":"2025-11-05T08:08:13.827639Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = test_df[[\"sample_id\", \"target\"]].copy()\nsubmission.to_csv(\"submission.csv\", index=False)\nprint(\"\\n✅ submission.csv created!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T08:08:31.429926Z","iopub.execute_input":"2025-11-05T08:08:31.430179Z","iopub.status.idle":"2025-11-05T08:08:31.441300Z","shell.execute_reply.started":"2025-11-05T08:08:31.430161Z","shell.execute_reply":"2025-11-05T08:08:31.440488Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-05T08:08:33.384789Z","iopub.execute_input":"2025-11-05T08:08:33.385071Z","iopub.status.idle":"2025-11-05T08:08:33.392427Z","shell.execute_reply.started":"2025-11-05T08:08:33.385053Z","shell.execute_reply":"2025-11-05T08:08:33.391757Z"}},"outputs":[],"execution_count":null}]}