{"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,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":643246,"sourceType":"modelInstanceVersion","isSourceIdPinned":false,"modelInstanceId":485029,"modelId":500508}],"dockerImageVersionId":31193,"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 numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms, models\nfrom PIL import Image\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Configuration\nclass Config:\n    batch_size = 32\n    image_width = 600\n    image_height = 300\n    num_workers = 4\n\nconfig = Config()\n\n# Set device\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint(f\"Using device: {device}\")\n\n# Model definition (same as training)\nclass PositiveResNet(nn.Module):\n    def __init__(self, pretrained=False):\n        super(PositiveResNet, self).__init__()\n        self.backbone = models.resnet50(pretrained=pretrained)\n        self.backbone.fc = nn.Sequential(\n            nn.Linear(self.backbone.fc.in_features, 512),\n            nn.ReLU(),\n            nn.Dropout(0.3),\n            nn.Linear(512, 256),\n            nn.ReLU(),\n            nn.Dropout(0.2),\n            nn.Linear(256, 128),\n            nn.ReLU(),\n            nn.Linear(128, 1)\n        )\n        \n    def forward(self, x):\n        x = self.backbone(x)\n        x = F.relu(x)  # Ensure non-negative output\n        return x\n\n# Test Dataset\nclass TestBiomassDataset(Dataset):\n    def __init__(self, dataframe, image_dir, transform=None):\n        self.data = dataframe\n        self.image_dir = image_dir\n        self.transform = transform\n        \n        # Create a mapping from image to unique samples\n        self.unique_images = self.data['image_path'].unique()\n        \n    def __len__(self):\n        return len(self.unique_images)\n    \n    def __getitem__(self, idx):\n        image_path = self.unique_images[idx]\n        full_image_path = os.path.join(self.image_dir, image_path)\n        \n        # Load image\n        try:\n            image = Image.open(full_image_path).convert('RGB')\n        except Exception as e:\n            print(f\"Error loading image {full_image_path}: {e}\")\n            # Return a blank image as fallback\n            image = Image.new('RGB', (config.image_width, config.image_height), color='white')\n        \n        # Apply transformations\n        if self.transform:\n            image = self.transform(image)\n        \n        return image, image_path\n\n# Load trained models\ndef load_model(model_path, device):\n    model = PositiveResNet(pretrained=False)\n    \n    try:\n        # Handle DataParallel wrapping if needed\n        state_dict = torch.load(model_path, map_location=device)\n        if all(key.startswith('module.') for key in state_dict.keys()):\n            # Model was saved as DataParallel\n            from collections import OrderedDict\n            new_state_dict = OrderedDict()\n            for k, v in state_dict.items():\n                name = k[7:]  # remove 'module.' prefix\n                new_state_dict[name] = v\n            state_dict = new_state_dict\n        \n        model.load_state_dict(state_dict)\n        model = model.to(device)\n        model.eval()\n        print(f\"Successfully loaded model from {model_path}\")\n        return model\n    except Exception as e:\n        print(f\"Error loading model from {model_path}: {e}\")\n        return None\n\n# Inference function\ndef run_inference():\n    # Paths\n    test_csv = '/kaggle/input/csiro-biomass/test.csv'\n    test_image_dir = '/kaggle/input/csiro-biomass/'\n    submission_path = 'submission.csv'\n    \n    # Load test data\n    test_df = pd.read_csv(test_csv)\n    print(f\"Test data shape: {test_df.shape}\")\n    print(f\"Unique images in test: {test_df['image_path'].nunique()}\")\n    print(f\"Test data preview:\")\n    print(test_df.head())\n    \n    # Data transformation\n    test_transform = transforms.Compose([\n        transforms.Resize((config.image_height, config.image_width)),\n        transforms.ToTensor(),\n        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n    ])\n    \n    # Create test dataset and loader\n    test_dataset = TestBiomassDataset(test_df, test_image_dir, test_transform)\n    test_loader = DataLoader(\n        test_dataset, \n        batch_size=config.batch_size, \n        shuffle=False, \n        num_workers=config.num_workers\n    )\n    \n    # Load trained models\n    print(\"Loading trained models...\")\n    model_files = {\n        'clover': '/kaggle/input/csiro-seperate-models/pytorch/v1/1/clover-model.pth',\n        'green': '/kaggle/input/csiro-seperate-models/pytorch/v1/1/green-model.pth', \n        'dead': '/kaggle/input/csiro-seperate-models/pytorch/v1/1/dead-model.pth'\n    }\n    \n    models_dict = {}\n    for model_type, model_file in model_files.items():\n        model = load_model(model_file, device)\n        if model is not None:\n            models_dict[model_type] = model\n        else:\n            print(f\"Failed to load {model_type} model!\")\n    \n    if len(models_dict) == 0:\n        print(\"No models loaded successfully. Exiting.\")\n        return\n    \n    # Run inference\n    print(\"Running inference...\")\n    predictions_dict = {}\n    \n    with torch.no_grad():\n        for images, image_paths in test_loader:\n            images = images.to(device)\n            \n            # Get predictions from all available models\n            batch_predictions = {}\n            \n            if 'clover' in models_dict:\n                clover_preds = models_dict['clover'](images).squeeze().cpu().numpy()\n                batch_predictions['Dry_Clover_g'] = clover_preds\n            \n            if 'green' in models_dict:\n                green_preds = models_dict['green'](images).squeeze().cpu().numpy()\n                batch_predictions['Dry_Green_g'] = green_preds\n                \n            if 'dead' in models_dict:\n                dead_preds = models_dict['dead'](images).squeeze().cpu().numpy()\n                batch_predictions['Dry_Dead_g'] = dead_preds\n            \n            # Store predictions\n            for i, img_path in enumerate(image_paths):\n                predictions_dict[img_path] = {}\n                for target_type, preds in batch_predictions.items():\n                    if preds.size > 1:\n                        predictions_dict[img_path][target_type] = float(preds[i])\n                    else:\n                        predictions_dict[img_path][target_type] = float(preds)\n    \n    # Create submission dataframe\n    submission_data = []\n    \n    for _, row in test_df.iterrows():\n        sample_id = row['sample_id']\n        image_path = row['image_path']\n        target_name = row['target_name']\n        \n        target_value = 0.0\n        \n        if image_path in predictions_dict:\n            preds = predictions_dict[image_path]\n            \n            if target_name == 'Dry_Clover_g' and 'Dry_Clover_g' in preds:\n                target_value = preds['Dry_Clover_g']\n            elif target_name == 'Dry_Green_g' and 'Dry_Green_g' in preds:\n                target_value = preds['Dry_Green_g']\n            elif target_name == 'Dry_Dead_g' and 'Dry_Dead_g' in preds:\n                target_value = preds['Dry_Dead_g']\n            elif target_name == 'Dry_Total_g':\n                # Calculate total: Clover + Green + Dead\n                clover = preds.get('Dry_Clover_g', 0.0)\n                green = preds.get('Dry_Green_g', 0.0)\n                dead = preds.get('Dry_Dead_g', 0.0)\n                target_value = clover + green + dead\n            elif target_name == 'GDM_g':\n                # Calculate GDM: Total - Dead\n                clover = preds.get('Dry_Clover_g', 0.0)\n                green = preds.get('Dry_Green_g', 0.0)\n                dead = preds.get('Dry_Dead_g', 0.0)\n                total = clover + green + dead\n                target_value = total - dead\n        \n        # Ensure non-negative\n        target_value = max(0.0, target_value)\n        \n        submission_data.append({\n            'sample_id': sample_id,\n            'target': target_value\n        })\n    \n    # Create submission file\n    submission_df = pd.DataFrame(submission_data)\n    submission_df.to_csv(submission_path, index=False)\n    \n    print(f\"Submission saved to {submission_path}\")\n    print(f\"Submission shape: {submission_df.shape}\")\n    print(\"\\nSubmission preview:\")\n    print(submission_df.head(10))\n    \n    # Print some statistics\n    print(f\"\\nPrediction statistics:\")\n    for target_type in ['Dry_Clover_g', 'Dry_Green_g', 'Dry_Dead_g', 'Dry_Total_g', 'GDM_g']:\n        target_values = submission_df[submission_df['sample_id'].str.contains(target_type)]['target']\n        if len(target_values) > 0:\n            print(f\"{target_type}: min={target_values.min():.4f}, max={target_values.max():.4f}, mean={target_values.mean():.4f}\")\n\nif __name__ == '__main__':\n    run_inference()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-11-13T07:41:45.813681Z","iopub.execute_input":"2025-11-13T07:41:45.813874Z","iopub.status.idle":"2025-11-13T07:42:00.855470Z","shell.execute_reply.started":"2025-11-13T07:41:45.813855Z","shell.execute_reply":"2025-11-13T07:42:00.854556Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}