{"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":639393,"sourceType":"modelInstanceVersion","isSourceIdPinned":false,"modelInstanceId":482224,"modelId":497827}],"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\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 = 16\n    image_size = 500\n\n# EfficientNet-B4 Model (MUST match training architecture exactly)\nclass EfficientNetBiomass(nn.Module):\n    def __init__(self):\n        super(EfficientNetBiomass, self).__init__()\n        self.backbone = models.efficientnet_b4(pretrained=False)\n        in_features = self.backbone.classifier[1].in_features\n        self.backbone.classifier = nn.Sequential(\n            nn.Dropout(0.4),\n            nn.Linear(in_features, 1024),\n            nn.SiLU(inplace=True),\n            nn.BatchNorm1d(1024),\n            nn.Dropout(0.3),\n            nn.Linear(1024, 512),\n            nn.SiLU(inplace=True),\n            nn.BatchNorm1d(512),\n            nn.Dropout(0.2),\n            nn.Linear(512, 3)  # Output 3 values: Clover, Dead, Green\n        )\n    \n    def forward(self, x):\n        return self.backbone(x)\n\n# Test Dataset\nclass TestBiomassDataset(Dataset):\n    def __init__(self, csv_file, base_dir, transform=None):\n        self.data = pd.read_csv(csv_file)\n        self.base_dir = base_dir\n        self.transform = transform\n        \n        # Group by image for efficient processing\n        self.image_groups = self.data.groupby('image_path')\n        self.unique_images = list(self.image_groups.groups.keys())\n        \n    def __len__(self):\n        return len(self.unique_images)\n    \n    def __getitem__(self, idx):\n        img_path = self.unique_images[idx]\n        full_img_path = os.path.join(self.base_dir, img_path)\n        \n        try:\n            image = Image.open(full_img_path).convert('RGB')\n        except Exception as e:\n            print(f\"Error loading image {full_img_path}: {e}\")\n            # Return black image as fallback\n            image = Image.new('RGB', (Config.image_size, Config.image_size), color='black')\n        \n        if self.transform:\n            image = self.transform(image)\n            \n        return image, img_path\n\ndef predict():\n    print(\"🚀 Starting EfficientNet-B4 Biomass Prediction...\")\n    \n    # Set device\n    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n    print(f\"📱 Using device: {device}\")\n    \n    # Model path - using your saved model\n    model_path = '/kaggle/input/efficientnet-b4-biomass/pytorch/default/1/best_efficientnet_biomass.pth'\n    \n    # Check if model file exists\n    if not os.path.exists(model_path):\n        print(f\"❌ Error: Model file '{model_path}' not found!\")\n        return\n    \n    print(f\"✅ Model file found: {model_path}\")\n    \n    # Test transforms (must match training preprocessing)\n    test_transform = transforms.Compose([\n        transforms.Resize((Config.image_size, Config.image_size)),\n        transforms.ToTensor(),\n        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n    ])\n    \n    # Load test data\n    test_csv = '/kaggle/input/csiro-biomass/test.csv'\n    base_dir = '/kaggle/input/csiro-biomass'\n    \n    print(\"📊 Loading test data...\")\n    test_df = pd.read_csv(test_csv)\n    print(f\"✅ Test data loaded: {len(test_df)} rows\")\n    print(f\"📸 Sample test data:\")\n    print(test_df.head())\n    \n    # Create dataset and dataloader\n    test_dataset = TestBiomassDataset(test_csv, base_dir, test_transform)\n    test_loader = DataLoader(\n        test_dataset,\n        batch_size=Config.batch_size,\n        shuffle=False,\n        num_workers=0,  # Set to 0 for stability in Kaggle\n        pin_memory=True\n    )\n    \n    print(f\"🎯 Found {len(test_dataset)} unique test images\")\n    \n    # Initialize and load model\n    print(\"🤖 Loading EfficientNet-B4 model...\")\n    model = EfficientNetBiomass()\n    \n    try:\n        # Load the trained weights\n        state_dict = torch.load(model_path, map_location=device)\n        print(f\"✅ Model weights loaded successfully!\")\n        print(f\"📊 Model architecture check:\")\n        print(f\"   - Number of parameter groups: {len(state_dict)}\")\n        print(f\"   - Sample keys: {list(state_dict.keys())[:5]}...\")\n        \n        # Handle DataParallel wrapped models\n        if all(key.startswith('module.') for key in state_dict.keys()):\n            print(\"🔧 Removing 'module.' prefix from state dict (multi-GPU model detected)...\")\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        else:\n            print(\"🔧 Single GPU model detected\")\n        \n        # Load state dict\n        model.load_state_dict(state_dict)\n        model = model.to(device)\n        model.eval()\n        print(\"✅ Model loaded and set to evaluation mode!\")\n        \n        # Test forward pass with dummy data\n        with torch.no_grad():\n            dummy_input = torch.randn(1, 3, Config.image_size, Config.image_size).to(device)\n            dummy_output = model(dummy_input)\n            print(f\"🧪 Model test - Input: {dummy_input.shape}, Output: {dummy_output.shape}\")\n        \n    except Exception as e:\n        print(f\"❌ Error loading model: {e}\")\n        import traceback\n        traceback.print_exc()\n        return\n    \n    # Predict for each image\n    print(\"\\n🎯 Starting prediction on test images...\")\n    image_predictions = {}\n    \n    with torch.no_grad():\n        for batch_idx, (images, img_paths) in enumerate(test_loader):\n            print(f\"📦 Processing batch {batch_idx + 1}/{len(test_loader)} - {len(images)} images\")\n            \n            images = images.to(device)\n            outputs = model(images)\n            \n            # Convert to numpy and ensure positive values\n            predictions = outputs.cpu().numpy()\n            \n            for i, img_path in enumerate(img_paths):\n                clover, dead, green = predictions[i]\n                image_predictions[img_path] = {\n                    'Dry_Clover_g': max(0.0, float(clover)),\n                    'Dry_Dead_g': max(0.0, float(dead)),\n                    'Dry_Green_g': max(0.0, float(green))\n                }\n                \n                # Print first prediction for verification\n                if batch_idx == 0 and i == 0:\n                    print(f\"   Sample prediction for {img_path}:\")\n                    print(f\"     Clover: {clover:.4f}, Dead: {dead:.4f}, Green: {green:.4f}\")\n    \n    print(f\"\\n✅ Prediction completed! Processed {len(image_predictions)} unique images\")\n    \n    # Create submission dataframe\n    print(\"📝 Creating submission file...\")\n    submission_data = []\n    \n    for idx, row in test_df.iterrows():\n        img_path = row['image_path']\n        target_name = row['target_name']\n        sample_id = row['sample_id']\n        \n        if img_path in image_predictions:\n            preds = image_predictions[img_path]\n            \n            if target_name == 'Dry_Clover_g':\n                target_value = preds['Dry_Clover_g']\n            elif target_name == 'Dry_Dead_g':\n                target_value = preds['Dry_Dead_g']\n            elif target_name == 'Dry_Green_g':\n                target_value = preds['Dry_Green_g']\n            elif target_name == 'Dry_Total_g':\n                # Calculate total from components\n                target_value = preds['Dry_Clover_g'] + preds['Dry_Dead_g'] + preds['Dry_Green_g']\n            elif target_name == 'GDM_g':\n                # Calculate GDM from components\n                target_value = preds['Dry_Clover_g'] + preds['Dry_Green_g']  # Total - Dead\n            else:\n                target_value = 0.0\n        else:\n            target_value = 0.0\n            print(f\"⚠️  Warning: No prediction found for {img_path}\")\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.csv', index=False)\n    print(\"✅ Submission file saved as 'submission.csv'\")\n    \n    # Print detailed statistics\n    print(\"\\n📊 Submission Statistics:\")\n    print(f\"   Total predictions: {len(submission_df)}\")\n    print(f\"   Target range: {submission_df['target'].min():.4f} to {submission_df['target'].max():.4f}\")\n    print(f\"   Mean target: {submission_df['target'].mean():.4f}\")\n    print(f\"   Std target: {submission_df['target'].std():.4f}\")\n    \n    # Show breakdown by target type\n    print(\"\\n🔍 Breakdown by target type:\")\n    target_types = ['Dry_Clover_g', 'Dry_Dead_g', 'Dry_Green_g', 'Dry_Total_g', 'GDM_g']\n    for target_type in target_types:\n        subset = submission_df[submission_df['sample_id'].str.contains(target_type)]\n        if len(subset) > 0:\n            print(f\"   {target_type:15}: {len(subset):3} samples, mean: {subset['target'].mean():8.4f}, min: {subset['target'].min():8.4f}, max: {subset['target'].max():8.4f}\")\n    \n    # Show first few rows of submission\n    print(\"\\n👀 First 10 rows of submission:\")\n    print(submission_df.head(10))\n    \n    # Save detailed predictions for analysis\n    detailed_predictions = []\n    for img_path, preds in image_predictions.items():\n        detailed_predictions.append({\n            'image_path': img_path,\n            'Dry_Clover_g': preds['Dry_Clover_g'],\n            'Dry_Dead_g': preds['Dry_Dead_g'],\n            'Dry_Green_g': preds['Dry_Green_g'],\n            'Dry_Total_g': preds['Dry_Clover_g'] + preds['Dry_Dead_g'] + preds['Dry_Green_g'],\n            'GDM_g': preds['Dry_Clover_g'] + preds['Dry_Green_g']\n        })\n    \n    \n    print(\"\\n🎉 Inference completed successfully!\")\n\n# Run the inference\nif __name__ == '__main__':\n    predict()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-11-10T23:31:48.233403Z","iopub.execute_input":"2025-11-10T23:31:48.233709Z","iopub.status.idle":"2025-11-10T23:31:48.992692Z","shell.execute_reply.started":"2025-11-10T23:31:48.233689Z","shell.execute_reply":"2025-11-10T23:31:48.992052Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}