{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.8.5"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"},{"sourceId":726067,"sourceType":"modelInstanceVersion","modelInstanceId":552689,"modelId":565245},{"sourceId":726136,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":552750,"modelId":565305}],"dockerImageVersionId":31260,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport torch\nimport torch.nn as nn\nfrom torchvision import transforms, models\nfrom torch.utils.data import Dataset, DataLoader\nfrom PIL import Image\nimport os\nfrom sklearn.preprocessing import OneHotEncoder, StandardScaler\n\n# Set device\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(f\"Using device: {device}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T15:54:31.734532Z","iopub.execute_input":"2026-01-20T15:54:31.735020Z","iopub.status.idle":"2026-01-20T15:54:31.740066Z","shell.execute_reply.started":"2026-01-20T15:54:31.734989Z","shell.execute_reply":"2026-01-20T15:54:31.739469Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision.models import resnet18\nimgmodel = resnet18(weights= None)\nimgmodel.fc = nn.Identity()\n# Define Model Architecture\nclass Tabularblock(nn.Module):\n    def __init__(self,inf,outf,drop=0.1):\n        super().__init__()\n        self.block = nn.Sequential(\n                nn.Linear(inf,outf),\n                nn.BatchNorm1d(outf),\n                nn.ReLU(),\n                nn.Dropout(drop),\n        )\n    def forward(self,x):\n        return self.block(x)\n\n\nclass TabularNet(nn.Module):\n    def __init__(self, input_dim=5, embedding_dim=64):\n        super().__init__()\n        \n        # Increased capacity significantly. \n        # Deep learning models often learn faster with wider layers (The \"Lottery Ticket Hypothesis\")\n        self.net = nn.Sequential(\n            Tabularblock(input_dim, 128),\n            \n            nn.Linear(128, 64),\n            nn.BatchNorm1d(64),\n            nn.ReLU(),\n            nn.Dropout(0.2), # Moderate dropout\n            \n            nn.Linear(64, embedding_dim) # Output larger embedding\n        )\n\n    def forward(self, x):\n        return self.net(x)\n\nclass CsiroNet(nn.Module):\n    def __init__(self, tabular_input_dim=5):\n        super().__init__()\n        # Ensure embedding dim matches what we set in TabularNet (default 64 now)\n        self.tabular_embedding_dim = 64\n        self.tabularnet = TabularNet(input_dim=tabular_input_dim, embedding_dim=self.tabular_embedding_dim)\n        \n        self.imgmodel = imgmodel\n        \n        # 512 (ResNet18) + 64 (Tabular) = 576\n        combined_dim = 512 + self.tabular_embedding_dim\n        \n        self.layers = nn.Sequential(\n            # Simplified head\n            nn.Linear(combined_dim, 256),\n            nn.BatchNorm1d(256),\n            nn.ReLU(),\n            nn.Dropout(0.3),\n            \n            nn.Linear(256, 64),\n            nn.ReLU(),\n            \n            nn.Linear(64, 1)\n        )\n    def forward(self,img,x):\n        imgfor = self.imgmodel(img)\n        tabfor = self.tabularnet(x)\n        x_flatten = torch.concatenate((imgfor,tabfor),dim =1)\n        return self.layers(x_flatten)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T15:54:31.741190Z","iopub.execute_input":"2026-01-20T15:54:31.741453Z","iopub.status.idle":"2026-01-20T15:54:31.887086Z","shell.execute_reply.started":"2026-01-20T15:54:31.741401Z","shell.execute_reply":"2026-01-20T15:54:31.886478Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 1. Setup Data Paths\ndata_path = '/kaggle/input/csiro-biomass'\ntrain_csv_path = os.path.join(data_path, 'train.csv')\ntest_csv_path = os.path.join(data_path, 'test.csv')\n\n# 2. Re-fit Scalers and Encoders on Training Data\n# We do this to ensure the transformations match exactly what the model was trained on.\nprint(\"Fitting scalers on training data...\")\n\ntrain_df = pd.read_csv(train_csv_path)\n\n# A. Encoder for 'target_name'\nencoder = OneHotEncoder(sparse_output=False, handle_unknown='ignore')\nencoded_train = encoder.fit_transform(train_df[['target_name']])\n\n# B. Scaler for Target 'y'\n# We need this to inverse_transform the predictions later\nsc_y = StandardScaler()\n# The model was trained on scaled targets, so we fit this on the training targets\n# Note: In your training notebook, you filtered columns. Ensure 'target' is valid.\n# Assuming standard regression target column is 'target'\nif 'target' in train_df.columns:\n    sc_y.fit(train_df['target'].values.reshape(-1, 1))\n\n# C. Scaler for Tabular Inputs\n# Create the tabular feature set from training to fit the input scaler\nencoded_df = pd.DataFrame(encoded_train, columns=encoder.get_feature_names_out(['target_name']))\n# Note: In Training, you dropped 'target_name' and concatenated. \n# Effectively the tabular input to 'sc' was just the encoded features \n# (since other columns were dropped or are images).\n# Let's verify: In training notebook, X = data.drop(columns=['target']). \n# X contained 'image_path' and the encoded columns. \n# Then X_standard = sc.fit_transform(X.iloc[:,1:]) (Ignoring image_path)\n# So we fit sc on the encoded features.\nsc_X = StandardScaler()\nsc_X.fit(encoded_df)\n\nprint(\"Preprocessing objects ready.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T15:54:31.888302Z","iopub.execute_input":"2026-01-20T15:54:31.888559Z","iopub.status.idle":"2026-01-20T15:54:31.904737Z","shell.execute_reply.started":"2026-01-20T15:54:31.888537Z","shell.execute_reply":"2026-01-20T15:54:31.903930Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 3. Process Test Data\nprint(\"Processing test data...\")\ntest_df = pd.read_csv(test_csv_path)\n\n# A. Encode\nencoded_test = encoder.transform(test_df[['target_name']])\nencoded_test_df = pd.DataFrame(encoded_test, columns=encoder.get_feature_names_out(['target_name']))\n\n# B. Scale\n# Transform the encoded test features using the scaler fitted on training data\nX_test_scaled = sc_X.transform(encoded_test_df)\n\nprint(f\"Test data shape: {X_test_scaled.shape}\")\ntest_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T15:54:31.905637Z","iopub.execute_input":"2026-01-20T15:54:31.905921Z","iopub.status.idle":"2026-01-20T15:54:31.918107Z","shell.execute_reply.started":"2026-01-20T15:54:31.905889Z","shell.execute_reply":"2026-01-20T15:54:31.917401Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torchvision import transforms\n\n# Simplified transforms for better initial convergence\nimg_transforms = transforms.Compose([\n    transforms.Resize(256),\n    transforms.CenterCrop(224), # CenterCrop is often better for testing/initial training\n    # transforms.RandomCrop(224), # Removed RandomCrop for stability\n    transforms.RandomHorizontalFlip(0.5), # Keep flip\n    transforms.RandomVerticalFlip(0.5), # Keep flip\n    \n    # Reduced intensity of color jitter and removed grayscale/sharpness for now\n    transforms.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0.05),\n    \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-20T15:54:31.919732Z","iopub.execute_input":"2026-01-20T15:54:31.920191Z","iopub.status.idle":"2026-01-20T15:54:31.927051Z","shell.execute_reply.started":"2026-01-20T15:54:31.920169Z","shell.execute_reply":"2026-01-20T15:54:31.926338Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 4. Load Model Weights\nmodel_path = '/kaggle/input/csiro-best/pytorch/default/1/csiro best .pt' \n# Assuming tabular_input_dim is 5 (based on the encoder output size of 5 categories)\ntabular_dim = encoded_test_df.shape[1] \nprint(f\"Initializing model with tabular dim: {tabular_dim}\")\n\nmodel = CsiroNet(tabular_input_dim=tabular_dim)\n\n# Load state dictionary\nif os.path.exists(model_path):\n    print(f\"Loading weights from {model_path}...\")\n    model.load_state_dict(torch.load(model_path, map_location=device))\nelse:\n    print(f\"WARNING: {model_path} not found. Please ensure the file is in the directory.\")\n\nmodel.to(device)\nmodel.eval()\nprint(\"Model loaded.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T15:54:31.927697Z","iopub.execute_input":"2026-01-20T15:54:31.927890Z","iopub.status.idle":"2026-01-20T15:54:32.033909Z","shell.execute_reply.started":"2026-01-20T15:54:31.927871Z","shell.execute_reply":"2026-01-20T15:54:32.033263Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 5. Run Inference\npredictions = []\n\nprint(f\"Running inference on {len(test_df)} samples...\")\n\nwith torch.no_grad():\n    for i in range(len(test_df)):\n        # A. Image\n        img_path = os.path.join(data_path, test_df.iloc[i]['image_path'])\n        \n        try:\n            with Image.open(img_path) as f:\n                img = f.convert('RGB')\n                img_tensor = img_transforms(img).unsqueeze(0).to(device)\n        except Exception as e:\n            print(f\"Error reading image {img_path}: {e}\")\n            continue\n\n        # B. Tabular\n        # Get the scaled features for this row\n        tab_features = X_test_scaled[i]\n        tab_tensor = torch.FloatTensor(tab_features).unsqueeze(0).to(device)\n\n        # C. Predict\n        output = model(img_tensor, tab_tensor)\n        \n        # D. Inverse Scale Target\n        # The model predicts the scaled value. We need to convert it back to real units (kg/DM/ha etc)\n        pred_scaled = output.cpu().numpy()\n        pred_real = sc_y.inverse_transform(pred_scaled)\n        \n        predictions.append(pred_real[0][0])\n\nprint(\"Inference complete.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T15:54:32.034750Z","iopub.execute_input":"2026-01-20T15:54:32.035022Z","iopub.status.idle":"2026-01-20T15:54:32.380239Z","shell.execute_reply.started":"2026-01-20T15:54:32.034998Z","shell.execute_reply":"2026-01-20T15:54:32.379576Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 6. Save Submission\nsubmission = pd.DataFrame({\n    'sample_id': test_df['sample_id'],\n    'target': predictions\n})\n\nsubmission.to_csv('submission.csv', index=False)\nprint(\"Saved submission.csv\")\nprint(submission.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T15:54:32.381112Z","iopub.execute_input":"2026-01-20T15:54:32.381318Z","iopub.status.idle":"2026-01-20T15:54:32.388342Z","shell.execute_reply.started":"2026-01-20T15:54:32.381298Z","shell.execute_reply":"2026-01-20T15:54:32.387758Z"}},"outputs":[],"execution_count":null}]}