{"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":13562394,"sourceType":"datasetVersion","datasetId":8614782}],"dockerImageVersionId":31153,"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,"execution":{"iopub.status.busy":"2025-10-31T06:29:14.175434Z","iopub.execute_input":"2025-10-31T06:29:14.175645Z","iopub.status.idle":"2025-10-31T06:29:16.787696Z","shell.execute_reply.started":"2025-10-31T06:29:14.175625Z","shell.execute_reply":"2025-10-31T06:29:16.786998Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nimport torch\nfrom torch import nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import models, transforms\nfrom torchvision.models import resnet18, ResNet18_Weights\nfrom PIL import Image\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import mean_absolute_error\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T06:29:16.789174Z","iopub.execute_input":"2025-10-31T06:29:16.78948Z","iopub.status.idle":"2025-10-31T06:29:25.960718Z","shell.execute_reply.started":"2025-10-31T06:29:16.789465Z","shell.execute_reply":"2025-10-31T06:29:25.95989Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMAGE_DIR = \"/kaggle/input/data-set/Data/train\"\nCSV_PATH = \"/kaggle/input/data-set/Data/train.csv\"\nTARGETS = [\"Dry_Clover_g\", \"Dry_Dead_g\", \"Dry_Green_g\", \"GDM_g\", \"Dry_Total_g\"]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T06:29:25.962262Z","iopub.execute_input":"2025-10-31T06:29:25.962808Z","iopub.status.idle":"2025-10-31T06:29:25.967329Z","shell.execute_reply.started":"2025-10-31T06:29:25.962786Z","shell.execute_reply":"2025-10-31T06:29:25.96629Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(CSV_PATH)\ndf[\"image_path\"] = df[\"image_path\"].apply(lambda x: os.path.join(IMAGE_DIR, os.path.basename(x)))\ndf = df[df[\"image_path\"].apply(os.path.exists)].copy()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T06:29:25.968093Z","iopub.execute_input":"2025-10-31T06:29:25.968416Z","iopub.status.idle":"2025-10-31T06:29:26.29625Z","shell.execute_reply.started":"2025-10-31T06:29:25.9684Z","shell.execute_reply":"2025-10-31T06:29:26.295089Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df[\"Sampling_Date\"] = pd.to_datetime(df[\"Sampling_Date\"], errors='coerce')\ndf[\"Month\"] = df[\"Sampling_Date\"].dt.month.fillna(0).astype(int)\n\nle_state = LabelEncoder()\nle_species = LabelEncoder()\ndf[\"State_enc\"] = le_state.fit_transform(df[\"State\"])\ndf[\"Species_enc\"] = le_species.fit_transform(df[\"Species\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T06:29:26.298094Z","iopub.execute_input":"2025-10-31T06:29:26.298363Z","iopub.status.idle":"2025-10-31T06:29:26.32499Z","shell.execute_reply.started":"2025-10-31T06:29:26.298342Z","shell.execute_reply":"2025-10-31T06:29:26.323733Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor()\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T06:29:26.32592Z","iopub.execute_input":"2025-10-31T06:29:26.326215Z","iopub.status.idle":"2025-10-31T06:29:26.341164Z","shell.execute_reply.started":"2025-10-31T06:29:26.326193Z","shell.execute_reply":"2025-10-31T06:29:26.340426Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class PastureDataset(Dataset):\n    def __init__(self, dataframe, transform=None):\n        self.df = dataframe.reset_index(drop=True)\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        image = Image.open(row.image_path).convert(\"RGB\")\n        if self.transform:\n            image = self.transform(image)\n        metadata = torch.tensor([\n            row.Pre_GSHH_NDVI,\n            row.Height_Ave_cm,\n            row.State_enc,\n            row.Species_enc,\n            row.Month\n        ], dtype=torch.float32)\n        label = torch.tensor(row.target, dtype=torch.float32)\n        return image, metadata, label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T06:29:26.342369Z","iopub.execute_input":"2025-10-31T06:29:26.342878Z","iopub.status.idle":"2025-10-31T06:29:26.364179Z","shell.execute_reply.started":"2025-10-31T06:29:26.342851Z","shell.execute_reply":"2025-10-31T06:29:26.363102Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class MultimodalRegressor(nn.Module):\n    def __init__(self, metadata_features):\n        super().__init__()\n        self.cnn = resnet18(weights=ResNet18_Weights.DEFAULT)\n        self.cnn.fc = nn.Identity()\n        self.mlp = nn.Sequential(\n            nn.Linear(512 + metadata_features, 128),\n            nn.ReLU(),\n            nn.Linear(128, 1)\n        )\n\n    def forward(self, image, metadata):\n        x1 = self.cnn(image)\n        x = torch.cat([x1, metadata], dim=1)\n        return self.mlp(x).squeeze()\n\n    for target_name in TARGETS:\n        df_target = df[df[\"target_name\"] == target_name].copy()\n        if df_target.empty:\n            print(f\" Skipping {target_name}: no rows found.\")\n            continue\n            ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T06:29:26.36554Z","iopub.execute_input":"2025-10-31T06:29:26.365843Z","iopub.status.idle":"2025-10-31T06:29:26.392756Z","shell.execute_reply.started":"2025-10-31T06:29:26.365818Z","shell.execute_reply":"2025-10-31T06:29:26.391653Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train_model(df_subset, transform, device):\n    train_df, val_df = train_test_split(df_subset, test_size=0.2, random_state=42)\n    train_ds = PastureDataset(train_df, transform)\n    val_ds = PastureDataset(val_df, transform)\n\n    train_loader = DataLoader(train_ds, batch_size=8, shuffle=True)\n    val_loader = DataLoader(val_ds, batch_size=8, shuffle=False)\n\n    model = MultimodalRegressor(metadata_features=5).to(device)\n    optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\n    loss_fn = nn.L1Loss()\n\n    for epoch in range(5):\n        model.train()\n        for img, meta, target in train_loader:\n            img, meta, target = img.to(device), meta.to(device), target.to(device)\n            preds = model(img, meta)\n            loss = loss_fn(preds, target)\n            optimizer.zero_grad()\n            loss.backward()\n            optimizer.step()\n\n        model.eval()\n        val_preds, val_targets = [], []\n        with torch.no_grad():\n            for img, meta, target in val_loader:\n                img, meta, target = img.to(device), meta.to(device), target.to(device)\n                preds = model(img, meta)\n                val_preds.extend(preds.cpu().numpy())\n                val_targets.extend(target.cpu().numpy())\n\n        mae = mean_absolute_error(val_targets, val_preds)\n        print(f\"Epoch {epoch+1} MAE: {mae:.2f}\")\n    \n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T06:29:26.394105Z","iopub.execute_input":"2025-10-31T06:29:26.394518Z","iopub.status.idle":"2025-10-31T06:29:26.403564Z","shell.execute_reply.started":"2025-10-31T06:29:26.39449Z","shell.execute_reply":"2025-10-31T06:29:26.402632Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nsubmission = []\n\nfor target_name in TARGETS:\n    df_target = df[df[\"target_name\"] == target_name].copy()\n    if df_target.empty:\n        print(f\"⚠️ Skipping {target_name}: no rows found.\")\n        continue\n\n    print(f\"\\n📌 Training for {target_name}\")\n    model = train_model(df_target, transform, device)\n\n    dataset = PastureDataset(df_target, transform)\n    loader = DataLoader(dataset, batch_size=8, shuffle=False)\n    preds = []\n    with torch.no_grad():\n        for img, meta, _ in loader:\n            img, meta = img.to(device), meta.to(device)\n            output = model(img, meta)\n            preds.extend(output.cpu().numpy())\n\n    df_target[\"target\"] = preds\n    submission.append(df_target[[\"sample_id\", \"target\"]])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T06:29:26.404447Z","iopub.execute_input":"2025-10-31T06:29:26.404666Z","iopub.status.idle":"2025-10-31T06:49:21.178908Z","shell.execute_reply.started":"2025-10-31T06:29:26.404647Z","shell.execute_reply":"2025-10-31T06:49:21.178296Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(df[\"target_name\"].value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T06:49:21.179559Z","iopub.execute_input":"2025-10-31T06:49:21.179739Z","iopub.status.idle":"2025-10-31T06:49:21.18937Z","shell.execute_reply.started":"2025-10-31T06:49:21.179723Z","shell.execute_reply":"2025-10-31T06:49:21.188472Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"final_df = pd.concat(submission).sort_values(\"sample_id\")\nfinal_df.to_csv(\"submission.csv\", index=False)\nprint(\"submission.csv saved!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-31T06:53:17.409157Z","iopub.execute_input":"2025-10-31T06:53:17.40944Z","iopub.status.idle":"2025-10-31T06:53:17.422338Z","shell.execute_reply.started":"2025-10-31T06:53:17.409423Z","shell.execute_reply":"2025-10-31T06:53:17.421364Z"}},"outputs":[],"execution_count":null}]}