{"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.11.13"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"},{"sourceId":293868408,"sourceType":"kernelVersion"}],"dockerImageVersionId":31193,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true},"papermill":{"default_parameters":{},"duration":292.253165,"end_time":"2025-12-03T21:45:35.846052","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2025-12-03T21:40:43.592887","version":"2.6.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"","metadata":{"papermill":{"duration":0.003716,"end_time":"2025-12-03T21:40:47.443631","exception":false,"start_time":"2025-12-03T21:40:47.439915","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **FOREWORD**\n\nInference and submission for single models using SGKF scheme **AFTER TEAM-UP**\n\n|Version Number|Model ID|CV score|LB score - CV | LB score - Refit | Comment - Other heads |\n|----| ---- | :-: | :-: | :-: | -----|\n|1 | DINOV7_4 |0.75507303  | |0.60 | |\n|2 | DINOV7_5 |0.76339157  | |0.69 | |\n|5 | DINOV7_6 |0.77635298  | |0.67 | |\n|6 | DINOV7_9 |0.77229399  | |0.70 | |\n|7 | DINOV7_8 |0.76519673  | |0.72 | Auxillary target|\n|9 | DINOV7_12 |0.78850280  | |0.72 | 5-stream model|\n|10 | DINOV7_11 |0.78615998  | | 0.73 | 4-stream model|\n|11 | DINOV7_13 |0.81000210  | |0.71 | Separate model for each target, 2-stream|\n|12 | DINOV7_16 |0.76748763  | |0.71  | 4-stream model DINOV3 Large|\n|13 | DINOV7_17 | 0.79288902 | |0.74  | Architecture changes - refer GitHub repo|\n|14 | DINOV7_18 | 0.77561781 | |0.71  | Architecture changes - refer GitHub repo|\n|16 | DINOV7_19 | 0.79059144 | |0.73  | Auxillary targets - 4 stream model <br> Architecture changes - refer GitHub repo|\n|17 | DINOV7_20 | 0.77607815 | |0.72  | 2-stream 3+2 target model with new architecture|\n|19 | DINOV7_22 | 0.77112656 | |0.73  | 4-stream 3+2 target model with new architecture with linear scheduler|\n|20 | DINOV7_27 | 0.76874797 | |0.72  | 3-stream 3+2 target model with new architecture with linear scheduler|\n|21 | DINOV7_28 | 0.78719720 | |0.73  | 3-stream 3+2 target model with new architecture with cosine scheduler|\n|22 | DINOV7_30 |0.78498377  | |0.73  | 5-stream 3+2 target model with old architecture with cosine scheduler|\n|23 | DINOV7_31 |0.78246404  | |0.70  | 6-stream 3+2 target model with old architecture with cosine scheduler|\n|24 | DINOV7_32 |0.78981390  | |0.71  | 4-stream 3+2 target model with new architecture with cosine scheduler and 0.75 hidden ratio|\n|25 | DINOV7_33 | 0.70495819 | |0.67  | 5-stream 3+2 target model with new architecture with cosine scheduler|\n|26 | DINOV7_34 | 0.78237804 | |0.73  | 5-stream 3+2 target model with new architecture with cosine scheduler with extra preprocessing|\n|27 | DINOV7_36 | 0.78187030 | |0.73  | 4-stream 3+2 target model with new architecture with cosine scheduler with progressive unfreezing|\n|29 | DINOV9_3 |  || 0.66   | 4-stream 5 target model with new architecture with cosine scheduler|\n|30 | DINOV9_4 |0.74963798  |  | 0.72 | 2-stream 4 target model with old architecture with cosine scheduler, auxillary target ratio|\n|32 | DINOV9_5 |0.80434083  |  |0.72  | 4-stream 4 target model with new architecture with cosine scheduler, auxillary target ratio|\n|34 | DINOV9_6 | 0.78530612 |  |0.73 | 4-stream 3 target model with new architecture with cosine scheduler, different targets|\n|35 | DINOV9_7 |0.78805735  |  | 0.72| 4-stream 3 target model with new architecture with cosine scheduler, different targets|\n|36 | DINOV9_8 | 0.781451  |  |0.72 | 3-stream 5 target model with new architecture with cosine scheduler|\n|37 | EVA02V8_3 | 0.73975521  | | 0.66  | 4-stream 3+2 target model with new architecture with cosine scheduler with fp32|\n|38 | DINOV9_9 | 0.78936479  | | 0.66  | 4-stream 5 target model with height prediction and dead derivation based on height|\n|40 | DINOV9_10 | 0.79041560  | |  | 4-stream 3 target model with residual connections between input layer and heads|","metadata":{"papermill":{"duration":0.002654,"end_time":"2025-12-03T21:40:47.448013","exception":false,"start_time":"2025-12-03T21:40:47.445359","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"# **SCRIPTS**","metadata":{}},{"cell_type":"markdown","source":"## **DINOV7_11**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov7_11.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\nbatch_size        = 2\ndropout           = 0.10\nhidden_ratio      = 0.25\nuse_swiglu        = True\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV7_11\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v17/{version_lbl}\" \nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        quarter = W // 4\n        part1 = img[:, :quarter, :]\n        part2 = img[:, quarter:2*quarter, :]\n        part3 = img[:, 2*quarter:3*quarter, :]\n        part4 = img[:, 3*quarter:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        part4 = self.transform(image=part4)[\"image\"]\n        \n        return part1, part2, part3, part4\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        gate = self.silu(self.gate_proj(x))\n        value = self.value_proj(x)\n        hidden = gate * value\n        hidden = self.dropout(hidden)\n        output = self.down_proj(hidden)\n        return output\n\nclass MultiStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 4\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_green = make_head()\n        self.head_clover = make_head()\n        self.head_dead = make_head()\n\n        self.softplus = nn.Softplus(beta=1.0)\n\n    def forward(self, part1, part2, part3, part4):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        feat4 = self.backbone(part4)\n        combined = torch.cat([feat1, feat2, feat3, feat4], dim=1)\n\n        green = self.softplus(self.head_green(combined))\n        clover = self.softplus(self.head_clover(combined))\n        dead = self.softplus(self.head_dead(combined))\n\n        outputs = torch.cat([green, clover, dead], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_3, states=None):\n    pred_green = preds_3[:, 0]\n    pred_clover = preds_3[:, 1]\n    pred_dead = preds_3[:, 2]\n\n    pred_gdm = pred_green + pred_clover\n    pred_total = pred_gdm + pred_dead\n\n    preds_5 = np.zeros((len(preds_3), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = MultiStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3, part4 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        part4 = part4.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3, part4)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_3 = np.mean(tta_preds, axis=0)\n    preds_3 = np.maximum(preds_3, 0)\n    preds_5 = calculate_derived_targets(preds_3)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.289443Z","iopub.execute_input":"2026-01-25T19:20:48.290153Z","iopub.status.idle":"2026-01-25T19:20:48.302150Z","shell.execute_reply.started":"2026-01-25T19:20:48.290129Z","shell.execute_reply":"2026-01-25T19:20:48.301412Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV7_16**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov7_16.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.25\nuse_swiglu        = True\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV7_16\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v21/{version_lbl}\"  \nmodel_name        = \"timm/vit_large_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        quarter = W // 4\n        part1 = img[:, :quarter, :]\n        part2 = img[:, quarter:2*quarter, :]\n        part3 = img[:, 2*quarter:3*quarter, :]\n        part4 = img[:, 3*quarter:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        part4 = self.transform(image=part4)[\"image\"]\n        \n        return part1, part2, part3, part4\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        gate = self.silu(self.gate_proj(x))\n        value = self.value_proj(x)\n        hidden = gate * value\n        hidden = self.dropout(hidden)\n        output = self.down_proj(hidden)\n        return output\n\nclass MultiStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 4\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_green = make_head()\n        self.head_clover = make_head()\n        self.head_dead = make_head()\n\n        self.softplus = nn.Softplus(beta=1.0)\n\n    def forward(self, part1, part2, part3, part4):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        feat4 = self.backbone(part4)\n        combined = torch.cat([feat1, feat2, feat3, feat4], dim=1)\n\n        green = self.softplus(self.head_green(combined))\n        clover = self.softplus(self.head_clover(combined))\n        dead = self.softplus(self.head_dead(combined))\n\n        outputs = torch.cat([green, clover, dead], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_3, states=None):\n    pred_green = preds_3[:, 0]\n    pred_clover = preds_3[:, 1]\n    pred_dead = preds_3[:, 2]\n\n    pred_gdm = pred_green + pred_clover\n    pred_total = pred_gdm + pred_dead\n\n    preds_5 = np.zeros((len(preds_3), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = MultiStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3, part4 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        part4 = part4.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3, part4)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_3 = np.mean(tta_preds, axis=0)\n    preds_3 = np.maximum(preds_3, 0)\n    preds_5 = calculate_derived_targets(preds_3)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.392854Z","iopub.execute_input":"2026-01-25T19:20:48.393569Z","iopub.status.idle":"2026-01-25T19:20:48.401723Z","shell.execute_reply.started":"2026-01-25T19:20:48.393546Z","shell.execute_reply":"2026-01-25T19:20:48.401155Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV7_17**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov7_17.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\n# Configuration\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\nuse_swiglu        = True\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV7_17\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v22/{version_lbl}\"  \nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        quarter = W // 4\n        part1 = img[:, :quarter, :]\n        part2 = img[:, quarter:2*quarter, :]\n        part3 = img[:, 2*quarter:3*quarter, :]\n        part4 = img[:, 3*quarter:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        part4 = self.transform(image=part4)[\"image\"]\n        \n        return part1, part2, part3, part4\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        gate = self.silu(self.gate_proj(x))\n        value = self.value_proj(x)\n        hidden = gate * value\n        hidden = self.dropout(hidden)\n        output = self.down_proj(hidden)\n        return output\n\nclass MultiStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 4\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_green = make_head()\n        self.head_clover = make_head()\n        self.head_dead = make_head()\n\n        self.softplus = nn.Softplus(beta=1.0)\n\n    def forward(self, part1, part2, part3, part4):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        feat4 = self.backbone(part4)\n        combined = torch.cat([feat1, feat2, feat3, feat4], dim=1)\n\n        green = self.softplus(self.head_green(combined))\n        clover = self.softplus(self.head_clover(combined))\n        dead = self.softplus(self.head_dead(combined))\n\n        outputs = torch.cat([green, clover, dead], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_3, states=None):\n    pred_green = preds_3[:, 0]\n    pred_clover = preds_3[:, 1]\n    pred_dead = preds_3[:, 2]\n\n    pred_gdm = pred_green + pred_clover\n    pred_total = pred_gdm + pred_dead\n\n    preds_5 = np.zeros((len(preds_3), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = MultiStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3, part4 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        part4 = part4.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3, part4)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_3 = np.mean(tta_preds, axis=0)\n    preds_3 = np.maximum(preds_3, 0)\n    preds_5 = calculate_derived_targets(preds_3)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)\n\n","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.402902Z","iopub.execute_input":"2026-01-25T19:20:48.403140Z","iopub.status.idle":"2026-01-25T19:20:48.422626Z","shell.execute_reply.started":"2026-01-25T19:20:48.403123Z","shell.execute_reply":"2026-01-25T19:20:48.421963Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV7_19**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov7_19.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\nuse_swiglu        = True\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV7_19\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v23/{version_lbl}\"\nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        quarter = W // 4\n        part1 = img[:, :quarter, :]\n        part2 = img[:, quarter:2*quarter, :]\n        part3 = img[:, 2*quarter:3*quarter, :]\n        part4 = img[:, 3*quarter:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        part4 = self.transform(image=part4)[\"image\"]\n        \n        return part1, part2, part3, part4\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        gate = self.silu(self.gate_proj(x))\n        value = self.value_proj(x)\n        hidden = gate * value\n        hidden = self.dropout(hidden)\n        output = self.down_proj(hidden)\n        return output\n\nclass MultiStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 4\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_total = make_head()\n        self.head_gdm = make_head()\n        self.head_green = make_head()\n        self.head_dead_ratio = nn.Sequential(\n            SwiGLU(combined, hidden_expanded, 1, dropout) if use_swiglu else nn.Sequential(\n                nn.Linear(combined, hidden),\n                nn.ReLU(inplace=True),\n                nn.Dropout(dropout),\n                nn.Linear(hidden, 1)\n            ),\n            nn.Sigmoid()\n        )\n\n    def forward(self, part1, part2, part3, part4):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        feat4 = self.backbone(part4)\n        combined = torch.cat([feat1, feat2, feat3, feat4], dim=1)\n\n        out_total = self.head_total(combined)\n        out_gdm = self.head_gdm(combined)\n        out_green = self.head_green(combined)\n        out_dead_ratio = self.head_dead_ratio(combined)\n\n        return torch.cat([out_total, out_gdm, out_green, out_dead_ratio], dim=1)\n\ndef calculate_derived_targets(preds_4, states=None):\n    pred_total = preds_4[:, 0]\n    pred_gdm = preds_4[:, 1]\n    pred_green = preds_4[:, 2]\n    pred_dead_ratio = preds_4[:, 3]\n\n    pred_dead_ratio = np.clip(pred_dead_ratio, 0.0, 1.0)\n    pred_dead = pred_total * pred_dead_ratio\n\n    pred_clover = np.clip(pred_gdm - pred_green, a_min=0.0, a_max=np.inf)\n    max_dead = np.clip(pred_total - pred_green - pred_clover, a_min=0.0, a_max=np.inf)\n    pred_dead = np.minimum(pred_dead, max_dead)\n\n    preds_5 = np.zeros((len(preds_4), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = MultiStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3, part4 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        part4 = part4.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3, part4)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_4 = np.mean(tta_preds, axis=0)\n    preds_4[:, :3] = np.maximum(preds_4[:, :3], 0)\n    preds_5 = calculate_derived_targets(preds_4)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(f\"refit{version_lbl}\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.496107Z","iopub.execute_input":"2026-01-25T19:20:48.496361Z","iopub.status.idle":"2026-01-25T19:20:48.504947Z","shell.execute_reply.started":"2026-01-25T19:20:48.496339Z","shell.execute_reply":"2026-01-25T19:20:48.504111Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV7_20**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov7_20.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\nuse_swiglu        = True\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV7_20\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v24/{version_lbl}\"\nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        h, w, _ = img.shape\n        mid = w // 2\n        left_img = img[:, :mid]\n        right_img = img[:, mid:]\n\n        left_tensor = self.transform(image=left_img)[\"image\"]\n        right_tensor = self.transform(image=right_img)[\"image\"]\n        \n        return left_tensor, right_tensor\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        gate = self.silu(self.gate_proj(x))\n        value = self.value_proj(x)\n        hidden = gate * value\n        hidden = self.dropout(hidden)\n        output = self.down_proj(hidden)\n        return output\n\nclass TwoStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.10, hidden_ratio=0.50, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.use_swiglu = use_swiglu\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 2\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1)\n                )\n\n        self.head_green = make_head()\n        self.head_clover = make_head()\n        self.head_dead = make_head()\n        self.softplus = nn.Softplus(beta=1.0)\n\n    def forward(self, left, right):\n        feat_left = self.backbone(left)\n        feat_right = self.backbone(right)\n        combined = torch.cat([feat_left, feat_right], dim=1)\n\n        green = self.softplus(self.head_green(combined))\n        clover = self.softplus(self.head_clover(combined))\n        dead = self.softplus(self.head_dead(combined))\n\n        outputs = torch.cat([green, clover, dead], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_3):\n    pred_green = preds_3[:, 0]\n    pred_clover = preds_3[:, 1]\n    pred_dead = preds_3[:, 2]\n\n    pred_gdm = pred_green + pred_clover\n    pred_total = pred_gdm + pred_dead\n\n    preds_5 = np.zeros((len(preds_3), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = TwoStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for left_imgs, right_imgs in tqdm(loader, desc=\"Infer\", leave=False):\n        left_imgs = left_imgs.to(device, non_blocking=True)\n        right_imgs = right_imgs.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(left_imgs, right_imgs)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_3 = np.mean(tta_preds, axis=0)\n    preds_3 = np.maximum(preds_3, 0)\n    preds_5 = calculate_derived_targets(preds_3)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.506796Z","iopub.execute_input":"2026-01-25T19:20:48.507067Z","iopub.status.idle":"2026-01-25T19:20:48.530032Z","shell.execute_reply.started":"2026-01-25T19:20:48.507037Z","shell.execute_reply":"2026-01-25T19:20:48.529415Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV7_22**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov7_22.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\nuse_swiglu        = True\nuse_rmsnorm       = False\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV7_22\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v26/{version_lbl}\"\nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        quarter = W // 4\n        part1 = img[:, :quarter, :]\n        part2 = img[:, quarter:2*quarter, :]\n        part3 = img[:, 2*quarter:3*quarter, :]\n        part4 = img[:, 3*quarter:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        part4 = self.transform(image=part4)[\"image\"]\n        \n        return part1, part2, part3, part4\n\nclass RMSNorm(nn.Module):\n    def __init__(self, dim, eps=1e-6):\n        super().__init__()\n        self.eps = eps\n        self.weight = nn.Parameter(torch.ones(dim))\n\n    def forward(self, x):\n        norm = torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)\n        return x * norm * self.weight\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        \n        if use_rmsnorm:\n            self.input_norm = RMSNorm(input_dim)\n            self.hidden_norm = RMSNorm(hidden_dim)\n            \n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        if use_rmsnorm:\n            x = self.input_norm(x)\n            gate = self.silu(self.gate_proj(x))\n            value = self.value_proj(x)\n            hidden = gate * value\n            hidden = self.hidden_norm(hidden)\n            hidden = self.dropout(hidden)\n            output = self.down_proj(hidden)\n        else:\n            gate = self.silu(self.gate_proj(x))\n            value = self.value_proj(x)\n            hidden = gate * value\n            hidden = self.dropout(hidden)\n            output = self.down_proj(hidden)\n        return output\n\nclass MultiStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 4\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_green = make_head()\n        self.head_clover = make_head()\n        self.head_dead = make_head()\n\n        self.softplus = nn.Softplus(beta=1.0)\n\n    def forward(self, part1, part2, part3, part4):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        feat4 = self.backbone(part4)\n        combined = torch.cat([feat1, feat2, feat3, feat4], dim=1)\n\n        green = self.softplus(self.head_green(combined))\n        clover = self.softplus(self.head_clover(combined))\n        dead = self.softplus(self.head_dead(combined))\n\n        outputs = torch.cat([green, clover, dead], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_3, states=None):\n    pred_green = preds_3[:, 0]\n    pred_clover = preds_3[:, 1]\n    pred_dead = preds_3[:, 2]\n\n    pred_gdm = pred_green + pred_clover\n    pred_total = pred_gdm + pred_dead\n\n    preds_5 = np.zeros((len(preds_3), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = MultiStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3, part4 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        part4 = part4.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3, part4)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_3 = np.mean(tta_preds, axis=0)\n    preds_3 = np.maximum(preds_3, 0)\n    preds_5 = calculate_derived_targets(preds_3)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.530661Z","iopub.execute_input":"2026-01-25T19:20:48.530905Z","iopub.status.idle":"2026-01-25T19:20:48.554780Z","shell.execute_reply.started":"2026-01-25T19:20:48.530889Z","shell.execute_reply":"2026-01-25T19:20:48.554168Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV7_27**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov7_27.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\n# Configuration\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\nuse_swiglu        = True\nuse_rmsnorm       = False\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV7_27\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v27/{version_lbl}\"\nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        third = W // 3\n        part1 = img[:, :third, :]\n        part2 = img[:, third:2*third, :]\n        part3 = img[:, 2*third:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        \n        return part1, part2, part3\n\nclass RMSNorm(nn.Module):\n    def __init__(self, dim, eps=1e-6):\n        super().__init__()\n        self.eps = eps\n        self.weight = nn.Parameter(torch.ones(dim))\n\n    def forward(self, x):\n        norm = torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)\n        return x * norm * self.weight\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        \n        if use_rmsnorm:\n            self.input_norm = RMSNorm(input_dim)\n            self.hidden_norm = RMSNorm(hidden_dim)\n            \n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        if use_rmsnorm:\n            x = self.input_norm(x)\n            gate = self.silu(self.gate_proj(x))\n            value = self.value_proj(x)\n            hidden = gate * value\n            hidden = self.hidden_norm(hidden)\n            hidden = self.dropout(hidden)\n            output = self.down_proj(hidden)\n        else:\n            gate = self.silu(self.gate_proj(x))\n            value = self.value_proj(x)\n            hidden = gate * value\n            hidden = self.dropout(hidden)\n            output = self.down_proj(hidden)\n        return output\n\nclass MultiStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 3\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_green = make_head()\n        self.head_clover = make_head()\n        self.head_dead = make_head()\n\n        self.softplus = nn.Softplus(beta=1.0)\n\n    def forward(self, part1, part2, part3):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        combined = torch.cat([feat1, feat2, feat3], dim=1)\n\n        green = self.softplus(self.head_green(combined))\n        clover = self.softplus(self.head_clover(combined))\n        dead = self.softplus(self.head_dead(combined))\n\n        outputs = torch.cat([green, clover, dead], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_3, states=None):\n    pred_green = preds_3[:, 0]\n    pred_clover = preds_3[:, 1]\n    pred_dead = preds_3[:, 2]\n\n    pred_gdm = pred_green + pred_clover\n    pred_total = pred_gdm + pred_dead\n\n    preds_5 = np.zeros((len(preds_3), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = MultiStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_3 = np.mean(tta_preds, axis=0)\n    preds_3 = np.maximum(preds_3, 0)\n    preds_5 = calculate_derived_targets(preds_3)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(1, 5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)\n","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.555443Z","iopub.execute_input":"2026-01-25T19:20:48.555604Z","iopub.status.idle":"2026-01-25T19:20:48.576250Z","shell.execute_reply.started":"2026-01-25T19:20:48.555591Z","shell.execute_reply":"2026-01-25T19:20:48.575697Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV7_28**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov7_28.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\n# Configuration\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\nuse_swiglu        = True\nuse_rmsnorm       = False\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV7_28\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v28/{version_lbl}\"\nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        third = W // 3\n        part1 = img[:, :third, :]\n        part2 = img[:, third:2*third, :]\n        part3 = img[:, 2*third:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        \n        return part1, part2, part3\n\nclass RMSNorm(nn.Module):\n    def __init__(self, dim, eps=1e-6):\n        super().__init__()\n        self.eps = eps\n        self.weight = nn.Parameter(torch.ones(dim))\n\n    def forward(self, x):\n        norm = torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)\n        return x * norm * self.weight\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        \n        if use_rmsnorm:\n            self.input_norm = RMSNorm(input_dim)\n            self.hidden_norm = RMSNorm(hidden_dim)\n            \n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        if use_rmsnorm:\n            x = self.input_norm(x)\n            gate = self.silu(self.gate_proj(x))\n            value = self.value_proj(x)\n            hidden = gate * value\n            hidden = self.hidden_norm(hidden)\n            hidden = self.dropout(hidden)\n            output = self.down_proj(hidden)\n        else:\n            gate = self.silu(self.gate_proj(x))\n            value = self.value_proj(x)\n            hidden = gate * value\n            hidden = self.dropout(hidden)\n            output = self.down_proj(hidden)\n        return output\n\nclass MultiStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 3\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_green = make_head()\n        self.head_clover = make_head()\n        self.head_dead = make_head()\n\n        self.softplus = nn.Softplus(beta=1.0)\n\n    def forward(self, part1, part2, part3):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        combined = torch.cat([feat1, feat2, feat3], dim=1)\n\n        green = self.softplus(self.head_green(combined))\n        clover = self.softplus(self.head_clover(combined))\n        dead = self.softplus(self.head_dead(combined))\n\n        outputs = torch.cat([green, clover, dead], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_3, states=None):\n    pred_green = preds_3[:, 0]\n    pred_clover = preds_3[:, 1]\n    pred_dead = preds_3[:, 2]\n\n    pred_gdm = pred_green + pred_clover\n    pred_total = pred_gdm + pred_dead\n\n    preds_5 = np.zeros((len(preds_3), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = MultiStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_3 = np.mean(tta_preds, axis=0)\n    preds_3 = np.maximum(preds_3, 0)\n    preds_5 = calculate_derived_targets(preds_3)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(1, 5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)\n","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.577807Z","iopub.execute_input":"2026-01-25T19:20:48.577970Z","iopub.status.idle":"2026-01-25T19:20:48.597158Z","shell.execute_reply.started":"2026-01-25T19:20:48.577956Z","shell.execute_reply":"2026-01-25T19:20:48.596455Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV7_30**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov7_30.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\nuse_swiglu        = True\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV7_30\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v29/{version_lbl}\"\nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        quarter = W // 4\n        part1 = img[:, :quarter, :]\n        part2 = img[:, quarter:2*quarter, :]\n        part3 = img[:, 2*quarter:3*quarter, :]\n        part4 = img[:, 3*quarter:, :]\n        full_img = img\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        part4 = self.transform(image=part4)[\"image\"]\n        full_img = self.transform(image=full_img)[\"image\"]\n        \n        return part1, part2, part3, part4, full_img\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        gate = self.silu(self.gate_proj(x))\n        value = self.value_proj(x)\n        hidden = gate * value\n        hidden = self.dropout(hidden)\n        output = self.down_proj(hidden)\n        return output\n\nclass MultiStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 5\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_green = make_head()\n        self.head_clover = make_head()\n        self.head_dead = make_head()\n\n        self.softplus = nn.Softplus(beta=1.0)\n\n    def forward(self, part1, part2, part3, part4, full):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        feat4 = self.backbone(part4)\n        feat_full = self.backbone(full)\n        combined = torch.cat([feat1, feat2, feat3, feat4, feat_full], dim=1)\n\n        green = self.softplus(self.head_green(combined))\n        clover = self.softplus(self.head_clover(combined))\n        dead = self.softplus(self.head_dead(combined))\n\n        outputs = torch.cat([green, clover, dead], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_3, states=None):\n    pred_green = preds_3[:, 0]\n    pred_clover = preds_3[:, 1]\n    pred_dead = preds_3[:, 2]\n\n    pred_gdm = pred_green + pred_clover\n    pred_total = pred_gdm + pred_dead\n\n    preds_5 = np.zeros((len(preds_3), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = MultiStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3, part4, full_img in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        part4 = part4.to(device, non_blocking=True)\n        full_img = full_img.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3, part4, full_img)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_3 = np.mean(tta_preds, axis=0)\n    preds_3 = np.maximum(preds_3, 0)\n    preds_5 = calculate_derived_targets(preds_3)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.599568Z","iopub.execute_input":"2026-01-25T19:20:48.600385Z","iopub.status.idle":"2026-01-25T19:20:48.618585Z","shell.execute_reply.started":"2026-01-25T19:20:48.600368Z","shell.execute_reply":"2026-01-25T19:20:48.617832Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV7_34**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov7_34.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\nuse_swiglu        = True\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV7_34\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v33/{version_lbl}\"\nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        quarter = W // 4\n        part1 = img[:, :quarter, :]\n        part2 = img[:, quarter:2*quarter, :]\n        part3 = img[:, 2*quarter:3*quarter, :]\n        part4 = img[:, 3*quarter:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        part4 = self.transform(image=part4)[\"image\"]\n        \n        return part1, part2, part3, part4\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        gate = self.silu(self.gate_proj(x))\n        value = self.value_proj(x)\n        hidden = gate * value\n        hidden = self.dropout(hidden)\n        output = self.down_proj(hidden)\n        return output\n\nclass MultiStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 4\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_green = make_head()\n        self.head_clover = make_head()\n        self.head_dead = make_head()\n\n        self.softplus = nn.Softplus(beta=1.0)\n\n    def forward(self, part1, part2, part3, part4):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        feat4 = self.backbone(part4)\n        combined = torch.cat([feat1, feat2, feat3, feat4], dim=1)\n\n        green = self.softplus(self.head_green(combined))\n        clover = self.softplus(self.head_clover(combined))\n        dead = self.softplus(self.head_dead(combined))\n\n        outputs = torch.cat([green, clover, dead], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_3):\n    pred_green = preds_3[:, 0]\n    pred_clover = preds_3[:, 1]\n    pred_dead = preds_3[:, 2]\n\n    pred_gdm = pred_green + pred_clover\n    pred_total = pred_gdm + pred_dead\n\n    preds_5 = np.zeros((len(preds_3), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = MultiStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3, part4 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        part4 = part4.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3, part4)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_3 = np.mean(tta_preds, axis=0)\n    preds_3 = np.maximum(preds_3, 0)\n    preds_5 = calculate_derived_targets(preds_3)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.620084Z","iopub.execute_input":"2026-01-25T19:20:48.620316Z","iopub.status.idle":"2026-01-25T19:20:48.636795Z","shell.execute_reply.started":"2026-01-25T19:20:48.620300Z","shell.execute_reply":"2026-01-25T19:20:48.635966Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV7_36**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov7_36.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\nuse_swiglu        = True\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV7_36\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v34/{version_lbl}\" \nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        quarter = W // 4\n        part1 = img[:, :quarter, :]\n        part2 = img[:, quarter:2*quarter, :]\n        part3 = img[:, 2*quarter:3*quarter, :]\n        part4 = img[:, 3*quarter:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        part4 = self.transform(image=part4)[\"image\"]\n        \n        return part1, part2, part3, part4\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        gate = self.silu(self.gate_proj(x))\n        value = self.value_proj(x)\n        hidden = gate * value\n        hidden = self.dropout(hidden)\n        output = self.down_proj(hidden)\n        return output\n\nclass MultiStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 4\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_green = make_head()\n        self.head_clover = make_head()\n        self.head_dead = make_head()\n\n        self.softplus = nn.Softplus(beta=1.0)\n\n    def forward(self, part1, part2, part3, part4):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        feat4 = self.backbone(part4)\n        combined = torch.cat([feat1, feat2, feat3, feat4], dim=1)\n\n        green = self.softplus(self.head_green(combined))\n        clover = self.softplus(self.head_clover(combined))\n        dead = self.softplus(self.head_dead(combined))\n\n        outputs = torch.cat([green, clover, dead], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_3, states=None):\n    pred_green = preds_3[:, 0]\n    pred_clover = preds_3[:, 1]\n    pred_dead = preds_3[:, 2]\n\n    pred_gdm = pred_green + pred_clover\n    pred_total = pred_gdm + pred_dead\n\n    preds_5 = np.zeros((len(preds_3), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = MultiStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3, part4 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        part4 = part4.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3, part4)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_3 = np.mean(tta_preds, axis=0)\n    preds_3 = np.maximum(preds_3, 0)\n    preds_5 = calculate_derived_targets(preds_3)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(1, 5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.637676Z","iopub.execute_input":"2026-01-25T19:20:48.638190Z","iopub.status.idle":"2026-01-25T19:20:48.656665Z","shell.execute_reply.started":"2026-01-25T19:20:48.638171Z","shell.execute_reply":"2026-01-25T19:20:48.656044Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV9_4**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov9_4.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\n# Configuration\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV9_4\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v35/{version_lbl}\"\nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        h, w, _ = img.shape\n        mid = w // 2\n        left_img = img[:, :mid]\n        right_img = img[:, mid:]\n\n        left_tensor = self.transform(image=left_img)[\"image\"]\n        right_tensor = self.transform(image=right_img)[\"image\"]\n        \n        return left_tensor, right_tensor\n\nclass TwoStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.10, hidden_ratio=0.25):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0)\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 2\n        hidden = int(combined * hidden_ratio)\n\n        self.head_total = nn.Sequential(\n            nn.Linear(combined, hidden),\n            nn.ReLU(),\n            nn.Dropout(dropout),\n            nn.Linear(hidden, 1)\n        )\n\n        self.head_gdm = nn.Sequential(\n            nn.Linear(combined, hidden),\n            nn.ReLU(),\n            nn.Dropout(dropout),\n            nn.Linear(hidden, 1)\n        )\n\n        self.head_green = nn.Sequential(\n            nn.Linear(combined, hidden),\n            nn.ReLU(),\n            nn.Dropout(dropout),\n            nn.Linear(hidden, 1)\n        )\n\n        self.head_dead_ratio = nn.Sequential(\n            nn.Linear(combined, hidden),\n            nn.ReLU(),\n            nn.Dropout(dropout),\n            nn.Linear(hidden, 1),\n            nn.Sigmoid()\n        )\n\n    def forward(self, left, right):\n        feat_left = self.backbone(left)\n        feat_right = self.backbone(right)\n        combined = torch.cat([feat_left, feat_right], dim=1)\n\n        out_total = self.head_total(combined)\n        out_gdm = self.head_gdm(combined)\n        out_green = self.head_green(combined)\n        out_dead_ratio = self.head_dead_ratio(combined)\n\n        return torch.cat([out_total, out_gdm, out_green, out_dead_ratio], dim=1)\n\ndef calculate_derived_targets(preds_4):\n    pred_total = preds_4[:, 0]\n    pred_gdm = preds_4[:, 1]\n    pred_green = preds_4[:, 2]\n    pred_dead_ratio = preds_4[:, 3]\n\n    pred_dead_ratio = np.clip(pred_dead_ratio, 0.0, 1.0)\n    pred_dead = pred_total * pred_dead_ratio\n\n    pred_clover = np.clip(pred_gdm - pred_green, a_min=0.0, a_max=np.inf)\n    max_dead = np.clip(pred_total - pred_green - pred_clover, a_min=0.0, a_max=np.inf)\n    pred_dead = np.minimum(pred_dead, max_dead)\n\n    preds_5 = np.zeros((len(preds_4), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = TwoStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for left_imgs, right_imgs in tqdm(loader, desc=\"Infer\", leave=False):\n        left_imgs = left_imgs.to(device, non_blocking=True)\n        right_imgs = right_imgs.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(left_imgs, right_imgs)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_4 = np.mean(tta_preds, axis=0)\n    preds_4[:, :3] = np.maximum(preds_4[:, :3], 0)\n    preds_5 = calculate_derived_targets(preds_4)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.657480Z","iopub.execute_input":"2026-01-25T19:20:48.657808Z","iopub.status.idle":"2026-01-25T19:20:48.674800Z","shell.execute_reply.started":"2026-01-25T19:20:48.657789Z","shell.execute_reply":"2026-01-25T19:20:48.674204Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV9_5**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov9_5.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\n# Configuration\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV9_5\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v36/{version_lbl}\"\nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        quarter = W // 4\n        part1 = img[:, :quarter, :]\n        part2 = img[:, quarter:2*quarter, :]\n        part3 = img[:, 2*quarter:3*quarter, :]\n        part4 = img[:, 3*quarter:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        part4 = self.transform(image=part4)[\"image\"]\n        \n        return part1, part2, part3, part4\n\nclass FourStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 4\n        hidden = int(combined * hidden_ratio)\n\n        def make_head():\n            return nn.Sequential(\n                nn.Linear(combined, hidden),\n                nn.ReLU(inplace=True),\n                nn.Dropout(dropout),\n                nn.Linear(hidden, 1),\n            )\n\n        self.head_total = make_head()\n        self.head_gdm = make_head()\n        self.head_green = make_head()\n        self.head_dead_ratio = nn.Sequential(\n            nn.Linear(combined, hidden),\n            nn.ReLU(inplace=True),\n            nn.Dropout(dropout),\n            nn.Linear(hidden, 1),\n            nn.Sigmoid()\n        )\n\n    def forward(self, part1, part2, part3, part4):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        feat4 = self.backbone(part4)\n        combined = torch.cat([feat1, feat2, feat3, feat4], dim=1)\n\n        out_total = self.head_total(combined)\n        out_gdm = self.head_gdm(combined)\n        out_green = self.head_green(combined)\n        out_dead_ratio = self.head_dead_ratio(combined)\n\n        outputs = torch.cat([out_total, out_gdm, out_green, out_dead_ratio], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_4):\n    pred_total = preds_4[:, 0]\n    pred_gdm = preds_4[:, 1]\n    pred_green = preds_4[:, 2]\n    pred_dead_ratio = preds_4[:, 3]\n\n    pred_dead_ratio = np.clip(pred_dead_ratio, 0.0, 1.0)\n    pred_dead = pred_total * pred_dead_ratio\n\n    pred_clover = np.clip(pred_gdm - pred_green, a_min=0.0, a_max=np.inf)\n    max_dead = np.clip(pred_total - pred_green - pred_clover, a_min=0.0, a_max=np.inf)\n    pred_dead = np.minimum(pred_dead, max_dead)\n\n    preds_5 = np.zeros((len(preds_4), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = FourStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3, part4 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        part4 = part4.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3, part4)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_4 = np.mean(tta_preds, axis=0)\n    preds_4[:, :3] = np.maximum(preds_4[:, :3], 0)\n    preds_5 = calculate_derived_targets(preds_4)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.676296Z","iopub.execute_input":"2026-01-25T19:20:48.676545Z","iopub.status.idle":"2026-01-25T19:20:48.696585Z","shell.execute_reply.started":"2026-01-25T19:20:48.676528Z","shell.execute_reply":"2026-01-25T19:20:48.695848Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV9_6**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov9_6.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\nuse_swiglu        = True\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV9_6\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v37/{version_lbl}\"\nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        quarter = W // 4\n        part1 = img[:, :quarter, :]\n        part2 = img[:, quarter:2*quarter, :]\n        part3 = img[:, 2*quarter:3*quarter, :]\n        part4 = img[:, 3*quarter:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        part4 = self.transform(image=part4)[\"image\"]\n        \n        return part1, part2, part3, part4\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        gate = self.silu(self.gate_proj(x))\n        value = self.value_proj(x)\n        hidden = gate * value\n        hidden = self.dropout(hidden)\n        output = self.down_proj(hidden)\n        return output\n\nclass FourStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 4\n        hidden = int(combined * hidden_ratio)\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_total = make_head()\n        self.head_gdm = make_head()\n        self.head_green = make_head()\n        self.head_dead_ratio = nn.Sequential(\n            nn.Linear(combined, hidden),\n            nn.ReLU(inplace=True),\n            nn.Dropout(dropout),\n            nn.Linear(hidden, 1),\n            nn.Sigmoid()\n        )\n\n    def forward(self, part1, part2, part3, part4):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        feat4 = self.backbone(part4)\n        combined = torch.cat([feat1, feat2, feat3, feat4], dim=1)\n\n        out_total = self.head_total(combined)\n        out_gdm = self.head_gdm(combined)\n        out_green = self.head_green(combined)\n        out_dead_ratio = self.head_dead_ratio(combined)\n\n        outputs = torch.cat([out_total, out_gdm, out_green, out_dead_ratio], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_4):\n    pred_total = preds_4[:, 0]\n    pred_gdm = preds_4[:, 1]\n    pred_green = preds_4[:, 2]\n    pred_dead_ratio = preds_4[:, 3]\n\n    pred_dead_ratio = np.clip(pred_dead_ratio, 0.0, 1.0)\n    pred_dead = pred_total * pred_dead_ratio\n\n    pred_clover = np.clip(pred_gdm - pred_green, a_min=0.0, a_max=np.inf)\n    max_dead = np.clip(pred_total - pred_green - pred_clover, a_min=0.0, a_max=np.inf)\n    pred_dead = np.minimum(pred_dead, max_dead)\n\n    preds_5 = np.zeros((len(preds_4), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = FourStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3, part4 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        part4 = part4.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3, part4)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_4 = np.mean(tta_preds, axis=0)\n    preds_4[:, :3] = np.maximum(preds_4[:, :3], 0)\n    preds_5 = calculate_derived_targets(preds_4)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.697586Z","iopub.execute_input":"2026-01-25T19:20:48.697878Z","iopub.status.idle":"2026-01-25T19:20:48.717424Z","shell.execute_reply.started":"2026-01-25T19:20:48.697856Z","shell.execute_reply":"2026-01-25T19:20:48.716644Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **DINOV9_10**","metadata":{}},{"cell_type":"code","source":"%%writefile dinov9_10.py\n\nfrom warnings import filterwarnings\nfilterwarnings(\"ignore\")\n\nimport os\nimport cv2\nimport timm\nimport torch\nimport argparse\nimport numpy as np\nimport pandas as pd\nimport torch.nn as nn\nimport albumentations as A\nfrom tqdm import tqdm\nfrom albumentations.pytorch import ToTensorV2\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\n\n# Configuration\nbatch_size        = 8\ndropout           = 0.10\nhidden_ratio      = 0.50\nuse_swiglu        = True\ntest_csv          = \"/kaggle/input/csiro-biomass/test.csv\"\ntest_img_dir      = \"/kaggle/input/csiro-biomass/test\"\nSUBMISSION_FILE   = \"submission.csv\"\nversion_lbl       = \"DINOV9_10\"\nmodel_dir         = f\"/kaggle/input/csiro2025-sgkf-modelstore-v42/{version_lbl}\"  \nmodel_name        = \"vit_huge_plus_patch16_dinov3_qkvb.lvd1689m\"\ntargets           = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\ndevice            = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nuse_multi_gpu     = torch.cuda.device_count() > 1\n\nclass BiomassDataset(Dataset):\n    def __init__(self, df, transform, img_dir):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n        self.img_dir = img_dir\n        self.paths = self.df[\"image_path\"].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        filename = os.path.basename(self.paths[idx])\n        full_path = os.path.join(self.img_dir, filename)\n        img = cv2.imread(full_path)\n        \n        if img is None:\n            img = np.zeros((1000, 2000, 3), dtype=np.uint8)\n        else:\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        H, W = img.shape[:2]\n        quarter = W // 4\n        part1 = img[:, :quarter, :]\n        part2 = img[:, quarter:2*quarter, :]\n        part3 = img[:, 2*quarter:3*quarter, :]\n        part4 = img[:, 3*quarter:, :]\n\n        part1 = self.transform(image=part1)[\"image\"]\n        part2 = self.transform(image=part2)[\"image\"]\n        part3 = self.transform(image=part3)[\"image\"]\n        part4 = self.transform(image=part4)[\"image\"]\n        \n        return part1, part2, part3, part4\n\nclass SwiGLU(nn.Module):\n    def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1):\n        super().__init__()\n        self.gate_proj = nn.Linear(input_dim, hidden_dim)\n        self.value_proj = nn.Linear(input_dim, hidden_dim)\n        self.down_proj = nn.Linear(hidden_dim, output_dim)\n        self.dropout = nn.Dropout(dropout)\n        self.silu = nn.SiLU()\n\n    def forward(self, x):\n        gate = self.silu(self.gate_proj(x))\n        value = self.value_proj(x)\n        hidden = gate * value\n        hidden = self.dropout(hidden)\n        output = self.down_proj(hidden)\n        return output\n\nclass MultiStreamModel(nn.Module):\n    def __init__(self, model_name, dropout=0.1, hidden_ratio=0.25, use_swiglu=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=False, num_classes=0, global_pool='avg')\n        self.dropout = nn.Dropout(dropout)\n        self.use_swiglu = use_swiglu\n\n        feat_dim = self.backbone.num_features\n        combined = feat_dim * 4\n        hidden = int(combined * hidden_ratio)\n\n        # Residual projection layer\n        self.residual_proj = nn.Sequential(\n            nn.Linear(combined, combined),\n            nn.LayerNorm(combined),\n            nn.Dropout(dropout)\n        )\n\n        if use_swiglu:\n            hidden_expanded = hidden * 2\n            def make_head():\n                return SwiGLU(\n                    input_dim=combined,\n                    hidden_dim=hidden_expanded,\n                    output_dim=1,\n                    dropout=dropout\n                )\n        else:\n            def make_head():\n                return nn.Sequential(\n                    nn.Linear(combined, hidden),\n                    nn.ReLU(inplace=True),\n                    nn.Dropout(dropout),\n                    nn.Linear(hidden, 1),\n                )\n\n        self.head_green = make_head()\n        self.head_clover = make_head()\n        self.head_dead = make_head()\n\n        self.softplus = nn.Softplus(beta=1.0)\n\n    def forward(self, part1, part2, part3, part4):\n        feat1 = self.backbone(part1)\n        feat2 = self.backbone(part2)\n        feat3 = self.backbone(part3)\n        feat4 = self.backbone(part4)\n        combined = torch.cat([feat1, feat2, feat3, feat4], dim=1)\n\n        # Add residual connection\n        residual = self.residual_proj(combined)\n        combined = combined + residual\n\n        green = self.softplus(self.head_green(combined))\n        clover = self.softplus(self.head_clover(combined))\n        dead = self.softplus(self.head_dead(combined))\n\n        outputs = torch.cat([green, clover, dead], dim=1)\n        return outputs\n\ndef calculate_derived_targets(preds_3, states=None):\n    pred_green = preds_3[:, 0]\n    pred_clover = preds_3[:, 1]\n    pred_dead = preds_3[:, 2]\n\n    pred_gdm = pred_green + pred_clover\n    pred_total = pred_gdm + pred_dead\n\n    preds_5 = np.zeros((len(preds_3), 5), dtype=np.float32)\n    preds_5[:, 0] = pred_green\n    preds_5[:, 1] = pred_dead\n    preds_5[:, 2] = pred_clover\n    preds_5[:, 3] = pred_gdm\n    preds_5[:, 4] = pred_total\n\n    return preds_5\n\ndef load_model(checkpoint_path):\n    print(f\"Loading model from {checkpoint_path}\")\n    \n    if not os.path.exists(checkpoint_path):\n        raise FileNotFoundError(f\"Checkpoint not found: {checkpoint_path}\")\n    \n    model = MultiStreamModel(model_name, dropout=dropout, hidden_ratio=hidden_ratio, use_swiglu=use_swiglu)\n    checkpoint = torch.load(checkpoint_path, map_location='cpu', weights_only=False)\n    \n    if isinstance(checkpoint, dict):\n        if 'model_state_dict' in checkpoint:\n            state_dict = checkpoint['model_state_dict']\n        elif 'state_dict' in checkpoint:\n            state_dict = checkpoint['state_dict']\n        else:\n            state_dict = checkpoint\n    else:\n        state_dict = checkpoint\n    \n    model.load_state_dict(state_dict)\n    \n    if use_multi_gpu:\n        model = DataParallel(model)\n    \n    model.to(device)\n    model.eval()\n    \n    return model\n\ndef get_tta_transforms(img_size):\n    norm = [A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ToTensorV2()]\n    return [\n        A.Compose([A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.HorizontalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.VerticalFlip(p=1.0), A.Resize(img_size, img_size), *norm]),\n        A.Compose([A.RandomRotate90(p=1.0), A.Resize(img_size, img_size), *norm]),\n    ]\n\n@torch.no_grad()\ndef predict_one_view(models, loader):\n    preds = []\n    use_amp = device.type == \"cuda\"\n    \n    for part1, part2, part3, part4 in tqdm(loader, desc=\"Infer\", leave=False):\n        part1 = part1.to(device, non_blocking=True)\n        part2 = part2.to(device, non_blocking=True)\n        part3 = part3.to(device, non_blocking=True)\n        part4 = part4.to(device, non_blocking=True)\n        batch_preds = []\n        \n        with torch.amp.autocast(\"cuda\", enabled=use_amp):\n            for model in models:\n                outputs = model(part1, part2, part3, part4)\n                batch_preds.append(outputs.cpu())\n        \n        preds.append(torch.stack(batch_preds).mean(dim=0).numpy())\n    \n    return np.concatenate(preds)\n\ndef run_inference_for_ckpts(checkpoint_paths, df, img_dir, img_size):\n    models = []\n    \n    for ckpt_path in checkpoint_paths:\n        model = load_model(ckpt_path)\n        models.append(model)\n    \n    print(f\"Loaded {len(models)} models for inference\")\n    \n    tta_preds = []\n    for transform in get_tta_transforms(img_size):\n        ds = BiomassDataset(df, transform, img_dir)\n        dl = DataLoader(ds, batch_size=batch_size, shuffle=False, num_workers=2, pin_memory=True)\n        tta_preds.append(predict_one_view(models, dl))\n    \n    preds_3 = np.mean(tta_preds, axis=0)\n    preds_3 = np.maximum(preds_3, 0)\n    preds_5 = calculate_derived_targets(preds_3)\n    \n    return preds_5\n\ndef create_submission(final_preds, test_df, unique_df):\n    cols = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\n    \n    wide = pd.DataFrame({\"image_path\": unique_df[\"image_path\"]})\n    for i, col in enumerate(cols):\n        wide[col] = np.clip(final_preds[:, i], 0.05, 400.0)\n    \n    wide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\n    wide[\"Dry_Total_g\"] = wide[\"GDM_g\"] + wide[\"Dry_Dead_g\"]\n    wide[cols] = wide[cols].clip(0.05, 400.0)\n    \n    long_df = wide.melt(\n        id_vars=\"image_path\", \n        value_vars=cols, \n        var_name=\"target_name\", \n        value_name=\"target\"\n    )\n    \n    sub = test_df[[\"sample_id\", \"image_path\", \"target_name\"]].merge(\n        long_df, on=[\"image_path\", \"target_name\"], how=\"left\"\n    )[[\"sample_id\", \"target\"]]\n    \n    sub.to_csv(SUBMISSION_FILE, index=False)\n    print(f\"Saved submission to {SUBMISSION_FILE}\")\n    \n    return sub\n\ndef main(cv_req=\"Yes\", img_size=448):\n    test_df = pd.read_csv(test_csv)\n    unique_df = test_df.drop_duplicates(\"image_path\").reset_index(drop=True)\n    \n    print(f\"Test samples: {len(test_df)}\")\n    print(f\"Unique images: {len(unique_df)}\")\n    \n    if cv_req == \"Yes\":\n        model_paths = [os.path.join(model_dir, f\"best_model_fold{i}.pth\") for i in range(5)]\n        existing_models = [path for path in model_paths if os.path.exists(path)]\n        \n        if not existing_models:\n            raise FileNotFoundError(\"No CV models found\")\n        \n        print(f\"Using {len(existing_models)} CV models\")\n        final_preds = run_inference_for_ckpts(existing_models, unique_df, test_img_dir, img_size)\n    else:\n        refit_files = [f for f in os.listdir(model_dir) if f.startswith(\"refit\") and f.endswith(\".pth\")]\n        \n        if not refit_files:\n            raise FileNotFoundError(f\"No refit models found in {model_dir}\")\n        \n        refit_paths = [os.path.join(model_dir, f) for f in refit_files]\n        print(f\"Using {len(refit_paths)} refit models\")\n        \n        all_seed_preds = []\n        for refit_path in refit_paths:\n            seed_preds = run_inference_for_ckpts([refit_path], unique_df, test_img_dir, img_size)\n            all_seed_preds.append(seed_preds)\n        \n        final_preds = np.mean(all_seed_preds, axis=0)\n    \n    submission = create_submission(final_preds, test_df, unique_df)\n    return submission\n\nif __name__ == \"__main__\":\n    parser = argparse.ArgumentParser()\n    parser.add_argument('--cv_req', type=str, default=\"Yes\", help='Use CV models (Yes) or Refit model (No)')\n    parser.add_argument('--img_size', type=int, default=448, help='Image size for inference')\n    args = parser.parse_args()\n    main(cv_req=args.cv_req, img_size=args.img_size)","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.718332Z","iopub.execute_input":"2026-01-25T19:20:48.718878Z","iopub.status.idle":"2026-01-25T19:20:48.737995Z","shell.execute_reply.started":"2026-01-25T19:20:48.718854Z","shell.execute_reply":"2026-01-25T19:20:48.737402Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## **POSTPROCESSING**","metadata":{}},{"cell_type":"code","source":"%%writefile mypostprocess.py\n\nimport pandas as pd\nimport numpy as np\n\nprint(\"---> Post-processing submission file\")\nsub = pd.read_csv(\"submission.csv\")\n\n# Pivot to wide format for calculations\nwide = sub.copy()\nwide[\"image_path\"] = wide[\"sample_id\"].str.split(\"__\", expand=True)[0]\nwide[\"target_name\"] = wide[\"sample_id\"].str.split(\"__\", expand=True)[1]\nwide = wide.pivot(index=\"image_path\", columns=\"target_name\", values=\"target\").reset_index()\n\n# Apply adjustments\nwide[\"Dry_Clover_g\"] = wide[\"Dry_Clover_g\"] * 0.80\nwide[\"Dry_Dead_g\"] = np.select(\n    [wide[\"Dry_Dead_g\"] > 20.0, wide[\"Dry_Dead_g\"] < 10.0],\n    [wide[\"Dry_Dead_g\"] * 1.10, wide[\"Dry_Dead_g\"] * 0.90],\n    wide[\"Dry_Dead_g\"]\n)\n\n# Recalculate GDM and Total based on relations\nwide[\"GDM_g\"] = wide[\"Dry_Green_g\"] + wide[\"Dry_Clover_g\"]\nwide[\"Dry_Total_g\"] = wide[\"Dry_Dead_g\"] + wide[\"GDM_g\"]\n\n# Convert back to long format\ntargets = [\"Dry_Green_g\", \"Dry_Dead_g\", \"Dry_Clover_g\", \"GDM_g\", \"Dry_Total_g\"]\nlong = wide.melt(\n    id_vars=\"image_path\", \n    value_vars=targets, \n    var_name=\"target_name\", \n    value_name=\"target\"\n)\nlong[\"sample_id\"] = long[\"image_path\"] + \"__\" + long[\"target_name\"]\n\n# Match original submission order\nresult = sub[[\"sample_id\"]].merge(long[[\"sample_id\", \"target\"]], on=\"sample_id\", how=\"left\")\nresult.to_csv(\"submission.csv\", index=False)\nprint(\"Post-processing completed\")","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:48.738665Z","iopub.execute_input":"2026-01-25T19:20:48.738905Z","iopub.status.idle":"2026-01-25T19:20:48.755784Z","shell.execute_reply.started":"2026-01-25T19:20:48.738889Z","shell.execute_reply":"2026-01-25T19:20:48.755099Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **SUBMISSION**","metadata":{}},{"cell_type":"code","source":"!pip uninstall -q tensorflow --y\nimport time , os\n\nprint()\n!python3 dinov9_10.py  --cv_req \"No\" \nprint()\n!head submission.csv\n\nprint()\n!python3 mypostprocess.py \nprint()\n!head submission.csv\n\nprint()\n!ls","metadata":{"_kg_hide-input":true,"papermill":{"duration":288.149465,"end_time":"2025-12-03T21:45:35.627103","exception":false,"start_time":"2025-12-03T21:40:47.477638","status":"completed"},"tags":[],"trusted":true,"execution":{"iopub.status.busy":"2026-01-25T19:20:51.420922Z","iopub.execute_input":"2026-01-25T19:20:51.421420Z","iopub.status.idle":"2026-01-25T19:24:08.553869Z","shell.execute_reply.started":"2026-01-25T19:20:51.421396Z","shell.execute_reply":"2026-01-25T19:24:08.552812Z"}},"outputs":[],"execution_count":null}]}