{"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":"none","dataSources":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"}],"dockerImageVersionId":31192,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:15:00.251202Z","iopub.execute_input":"2025-12-15T06:15:00.251519Z","iopub.status.idle":"2025-12-15T06:15:02.849281Z","shell.execute_reply.started":"2025-12-15T06:15:00.251489Z","shell.execute_reply":"2025-12-15T06:15:02.848359Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data = pd.read_csv('/kaggle/input/csiro-biomass/train.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:15:20.338166Z","iopub.execute_input":"2025-12-15T06:15:20.339102Z","iopub.status.idle":"2025-12-15T06:15:20.368815Z","shell.execute_reply.started":"2025-12-15T06:15:20.339067Z","shell.execute_reply":"2025-12-15T06:15:20.367619Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:15:30.465645Z","iopub.execute_input":"2025-12-15T06:15:30.466504Z","iopub.status.idle":"2025-12-15T06:15:30.502159Z","shell.execute_reply.started":"2025-12-15T06:15:30.466469Z","shell.execute_reply":"2025-12-15T06:15:30.501183Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import re\ndata['sample_id'] = data['sample_id'].astype(str).str.split('__').str[0]\ndata","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:19:02.83619Z","iopub.execute_input":"2025-12-15T06:19:02.836619Z","iopub.status.idle":"2025-12-15T06:19:02.942945Z","shell.execute_reply.started":"2025-12-15T06:19:02.836588Z","shell.execute_reply":"2025-12-15T06:19:02.941827Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(data.columns)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:21:32.565035Z","iopub.execute_input":"2025-12-15T06:21:32.565398Z","iopub.status.idle":"2025-12-15T06:21:32.572818Z","shell.execute_reply.started":"2025-12-15T06:21:32.565372Z","shell.execute_reply":"2025-12-15T06:21:32.57138Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data.drop(columns=['Sampling_Date'], inplace=True)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:22:03.02968Z","iopub.execute_input":"2025-12-15T06:22:03.029972Z","iopub.status.idle":"2025-12-15T06:22:03.04047Z","shell.execute_reply.started":"2025-12-15T06:22:03.029952Z","shell.execute_reply":"2025-12-15T06:22:03.038878Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data.drop(columns=['State'], inplace=True)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:22:20.801958Z","iopub.execute_input":"2025-12-15T06:22:20.802306Z","iopub.status.idle":"2025-12-15T06:22:20.809955Z","shell.execute_reply.started":"2025-12-15T06:22:20.802263Z","shell.execute_reply":"2025-12-15T06:22:20.808827Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(data.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:22:42.472611Z","iopub.execute_input":"2025-12-15T06:22:42.472897Z","iopub.status.idle":"2025-12-15T06:22:42.481695Z","shell.execute_reply.started":"2025-12-15T06:22:42.472878Z","shell.execute_reply":"2025-12-15T06:22:42.480244Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pip install torch torchvision pillow tqdm\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:29:54.417703Z","iopub.execute_input":"2025-12-15T06:29:54.417972Z","iopub.status.idle":"2025-12-15T06:31:27.298427Z","shell.execute_reply.started":"2025-12-15T06:29:54.417955Z","shell.execute_reply":"2025-12-15T06:31:27.296245Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torchvision import models, transforms\nfrom PIL import Image\nimport os\nimport pandas as pd\nfrom tqdm import tqdm\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:31:27.302322Z","iopub.execute_input":"2025-12-15T06:31:27.302835Z","iopub.status.idle":"2025-12-15T06:31:39.112352Z","shell.execute_reply.started":"2025-12-15T06:31:27.30279Z","shell.execute_reply":"2025-12-15T06:31:39.111393Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\nresnet = models.resnet50(weights=models.ResNet50_Weights.IMAGENET1K_V2)\nresnet.fc = nn.Identity()   # remove classification head\nresnet = resnet.to(device)\nresnet.eval()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:31:49.400566Z","iopub.execute_input":"2025-12-15T06:31:49.401135Z","iopub.status.idle":"2025-12-15T06:31:51.209213Z","shell.execute_reply.started":"2025-12-15T06:31:49.4011Z","shell.execute_reply":"2025-12-15T06:31:51.20811Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(\n        mean=[0.485, 0.456, 0.406],\n        std=[0.229, 0.224, 0.225]\n    )\n])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:32:08.622154Z","iopub.execute_input":"2025-12-15T06:32:08.622955Z","iopub.status.idle":"2025-12-15T06:32:08.628047Z","shell.execute_reply.started":"2025-12-15T06:32:08.622922Z","shell.execute_reply":"2025-12-15T06:32:08.627063Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def extract_embedding(image_path):\n    image = Image.open(image_path).convert(\"RGB\")\n    image = transform(image).unsqueeze(0).to(device)\n\n    with torch.no_grad():\n        embedding = resnet(image)\n\n    return embedding.squeeze(0).cpu()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:32:17.510056Z","iopub.execute_input":"2025-12-15T06:32:17.510466Z","iopub.status.idle":"2025-12-15T06:32:17.516855Z","shell.execute_reply.started":"2025-12-15T06:32:17.510434Z","shell.execute_reply":"2025-12-15T06:32:17.515205Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = data[['image_path', 'target_name', 'target']].copy()\n\nunique_images = df['image_path'].unique()\n\nimage_embeddings = {}\n\nfor img_path in tqdm(unique_images):\n    image_embeddings[img_path] = extract_embedding('/kaggle/input/csiro-biomass/'+img_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:33:28.114941Z","iopub.execute_input":"2025-12-15T06:33:28.11538Z","iopub.status.idle":"2025-12-15T06:34:44.830679Z","shell.execute_reply.started":"2025-12-15T06:33:28.115351Z","shell.execute_reply":"2025-12-15T06:34:44.829604Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['embedding'] = df['image_path'].map(image_embeddings)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:34:48.439624Z","iopub.execute_input":"2025-12-15T06:34:48.439941Z","iopub.status.idle":"2025-12-15T06:34:48.524809Z","shell.execute_reply.started":"2025-12-15T06:34:48.439919Z","shell.execute_reply":"2025-12-15T06:34:48.523767Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['embedding']","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:34:56.928113Z","iopub.execute_input":"2025-12-15T06:34:56.928501Z","iopub.status.idle":"2025-12-15T06:34:57.190775Z","shell.execute_reply.started":"2025-12-15T06:34:56.928469Z","shell.execute_reply":"2025-12-15T06:34:57.189515Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X = torch.stack(df['embedding'].tolist())  # [N, 2048]\ny = torch.tensor(df['target'].values, dtype=torch.float32)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:35:19.027774Z","iopub.execute_input":"2025-12-15T06:35:19.028212Z","iopub.status.idle":"2025-12-15T06:35:19.039222Z","shell.execute_reply.started":"2025-12-15T06:35:19.028183Z","shell.execute_reply":"2025-12-15T06:35:19.038173Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save({\n    \"embeddings\": X,\n    \"targets\": y,\n    \"target_names\": df['target_name'].values\n}, \"image_embeddings.pt\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:35:25.969436Z","iopub.execute_input":"2025-12-15T06:35:25.969838Z","iopub.status.idle":"2025-12-15T06:35:26.009284Z","shell.execute_reply.started":"2025-12-15T06:35:25.969803Z","shell.execute_reply":"2025-12-15T06:35:26.008279Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:37:01.387837Z","iopub.execute_input":"2025-12-15T06:37:01.388657Z","iopub.status.idle":"2025-12-15T06:37:01.393446Z","shell.execute_reply.started":"2025-12-15T06:37:01.388621Z","shell.execute_reply":"2025-12-15T06:37:01.392308Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data = torch.load(\"/kaggle/working/image_embeddings.pt\",weights_only = False)\n\nX = data['embeddings']          # shape: [N, 2048]\ny = data['targets']             # shape: [N]\ntarget_names = data['target_names']\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:38:01.734642Z","iopub.execute_input":"2025-12-15T06:38:01.734991Z","iopub.status.idle":"2025-12-15T06:38:01.771424Z","shell.execute_reply.started":"2025-12-15T06:38:01.734965Z","shell.execute_reply":"2025-12-15T06:38:01.770475Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\nunique_targets = sorted(set(target_names))\ntarget_to_idx = {t: i for i, t in enumerate(unique_targets)}\n\ntarget_idx = torch.tensor([target_to_idx[t] for t in target_names])\nnum_targets = len(unique_targets)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:38:14.57312Z","iopub.execute_input":"2025-12-15T06:38:14.573494Z","iopub.status.idle":"2025-12-15T06:38:14.580395Z","shell.execute_reply.started":"2025-12-15T06:38:14.573468Z","shell.execute_reply":"2025-12-15T06:38:14.579276Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class EmbeddingDataset(Dataset):\n    def __init__(self, X, target_idx, y):\n        self.X = X\n        self.target_idx = target_idx\n        self.y = y\n\n    def __len__(self):\n        return len(self.y)\n\n    def __getitem__(self, idx):\n        return self.X[idx], self.target_idx[idx], self.y[idx]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:38:31.201727Z","iopub.execute_input":"2025-12-15T06:38:31.202086Z","iopub.status.idle":"2025-12-15T06:38:31.208709Z","shell.execute_reply.started":"2025-12-15T06:38:31.202063Z","shell.execute_reply":"2025-12-15T06:38:31.207417Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class RegressionModel(nn.Module):\n    def __init__(self, emb_dim=2048, num_targets=5):\n        super().__init__()\n\n        self.target_emb = nn.Embedding(num_targets, 32)\n\n        self.regressor = nn.Sequential(\n            nn.Linear(emb_dim + 32, 512),\n            nn.ReLU(),\n            nn.Linear(512, 1)\n        )\n\n    def forward(self, img_emb, target_idx):\n        t_emb = self.target_emb(target_idx)\n        x = torch.cat([img_emb, t_emb], dim=1)\n        return self.regressor(x).squeeze(1)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:39:16.749646Z","iopub.execute_input":"2025-12-15T06:39:16.750539Z","iopub.status.idle":"2025-12-15T06:39:16.756659Z","shell.execute_reply.started":"2025-12-15T06:39:16.750507Z","shell.execute_reply":"2025-12-15T06:39:16.75561Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset = EmbeddingDataset(X, target_idx, y)\nloader = DataLoader(dataset, batch_size=32, shuffle=True)\n\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\nmodel = RegressionModel(\n    emb_dim=X.shape[1],\n    num_targets=num_targets\n).to(device)\n\ncriterion = nn.MSELoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-3)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:39:26.353359Z","iopub.execute_input":"2025-12-15T06:39:26.353697Z","iopub.status.idle":"2025-12-15T06:39:26.372363Z","shell.execute_reply.started":"2025-12-15T06:39:26.353673Z","shell.execute_reply":"2025-12-15T06:39:26.371122Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"epochs = 50\n\nfor epoch in range(epochs):\n    model.train()\n    total_loss = 0\n\n    for img_emb, t_idx, target in loader:\n        img_emb = img_emb.to(device)\n        t_idx = t_idx.to(device)\n        target = target.to(device)\n\n        pred = model(img_emb, t_idx)\n        loss = criterion(pred, target)\n\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item()\n\n    print(f\"Epoch {epoch+1}/{epochs} | Loss: {total_loss/len(loader):.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:39:54.370934Z","iopub.execute_input":"2025-12-15T06:39:54.371407Z","iopub.status.idle":"2025-12-15T06:40:32.45063Z","shell.execute_reply.started":"2025-12-15T06:39:54.371381Z","shell.execute_reply":"2025-12-15T06:40:32.449636Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.save({\n    \"model_state\": model.state_dict(),\n    \"target_to_idx\": target_to_idx\n}, \"regression_model.pt\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:40:44.167654Z","iopub.execute_input":"2025-12-15T06:40:44.167981Z","iopub.status.idle":"2025-12-15T06:40:44.190629Z","shell.execute_reply.started":"2025-12-15T06:40:44.167959Z","shell.execute_reply":"2025-12-15T06:40:44.189002Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def run_csv_inference(csv_path, output_csv):\n    df = pd.read_csv(csv_path)\n\n    predictions = []\n\n    for _, row in tqdm(df.iterrows(), total=len(df)):\n        img_path = row['image_path']\n        target_name = row['target_name']\n        sample_id = row['sample_id']  # keep sample_id\n\n        if target_name not in target_to_idx:\n            raise ValueError(f\"Unknown target_name: {target_name}\")\n\n        img_emb = extract_embedding('/kaggle/input/csiro-biomass/' + img_path)\n        t_idx = torch.tensor([target_to_idx[target_name]], device=device)\n\n        with torch.no_grad():\n            pred = model(img_emb, t_idx).item()\n\n        predictions.append((sample_id, pred))\n\n    # Create submission DataFrame\n    submission_df = pd.DataFrame(predictions, columns=['sample_id', 'target'])\n\n    # Save CSV\n    submission_df.to_csv(output_csv, index=False)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:52:29.104475Z","iopub.execute_input":"2025-12-15T06:52:29.104874Z","iopub.status.idle":"2025-12-15T06:52:29.112561Z","shell.execute_reply.started":"2025-12-15T06:52:29.104846Z","shell.execute_reply":"2025-12-15T06:52:29.111396Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"run_csv_inference(\n    csv_path=\"/kaggle/input/csiro-biomass/test.csv\",\n    output_csv=\"test_predictions.csv\"\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T06:52:29.957995Z","iopub.execute_input":"2025-12-15T06:52:29.958406Z","iopub.status.idle":"2025-12-15T06:52:29.977322Z","shell.execute_reply.started":"2025-12-15T06:52:29.958377Z","shell.execute_reply":"2025-12-15T06:52:29.976425Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}