{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:41:39.188759Z","iopub.execute_input":"2026-01-21T05:41:39.189434Z","iopub.status.idle":"2026-01-21T05:41:39.858795Z","shell.execute_reply.started":"2026-01-21T05:41:39.189409Z","shell.execute_reply":"2026-01-21T05:41:39.858182Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Step 1: Data Preparation and EDA Refinement","metadata":{}},{"cell_type":"code","source":"# ================================\n# Core libraries\n# ================================\nimport os\nimport random\nfrom pathlib import Path\n\nimport numpy as np\nimport pandas as pd\n\n# ================================\n# Visualization\n# ================================\nimport matplotlib.pyplot as plt\n\n# ================================\n# PyTorch & Vision\n# ================================\nimport torch\nimport torch.nn as nn\nfrom torchvision import models, transforms\nfrom PIL import Image\n\n# ================================\n# ML / CV\n# ================================\nfrom sklearn.model_selection import GroupKFold\nfrom sklearn.linear_model import Ridge\nfrom sklearn.metrics import r2_score\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:42:51.263761Z","iopub.execute_input":"2026-01-21T05:42:51.264351Z","iopub.status.idle":"2026-01-21T05:42:51.268378Z","shell.execute_reply.started":"2026-01-21T05:42:51.264326Z","shell.execute_reply":"2026-01-21T05:42:51.267777Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"SEED = 42\n\ndef seed_everything(seed=SEED):\n    random.seed(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed_all(seed)\n\nseed_everything()\n\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(\"Using device:\", DEVICE)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:43:06.825425Z","iopub.execute_input":"2026-01-21T05:43:06.825809Z","iopub.status.idle":"2026-01-21T05:43:06.837116Z","shell.execute_reply.started":"2026-01-21T05:43:06.825788Z","shell.execute_reply":"2026-01-21T05:43:06.836577Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_ROOT = Path(\"/kaggle/input/csiro-biomass\")\n\nTRAIN_CSV = DATA_ROOT / \"train.csv\"\nTEST_CSV  = DATA_ROOT / \"test.csv\"\n\nTRAIN_IMG_DIR = DATA_ROOT / \"train\"\nTEST_IMG_DIR  = DATA_ROOT / \"test\"\n\nSAMPLE_SUBMISSION = DATA_ROOT / \"sample_submission.csv\"\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:43:16.348416Z","iopub.execute_input":"2026-01-21T05:43:16.349003Z","iopub.status.idle":"2026-01-21T05:43:16.352751Z","shell.execute_reply.started":"2026-01-21T05:43:16.348983Z","shell.execute_reply":"2026-01-21T05:43:16.352018Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train = pd.read_csv(TRAIN_CSV)\ndf_test  = pd.read_csv(TEST_CSV)\n\nprint(\"Train shape:\", df_train.shape)\nprint(\"Test shape:\", df_test.shape)\n\ndf_train.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:43:23.403846Z","iopub.execute_input":"2026-01-21T05:43:23.404475Z","iopub.status.idle":"2026-01-21T05:43:23.452051Z","shell.execute_reply.started":"2026-01-21T05:43:23.404453Z","shell.execute_reply":"2026-01-21T05:43:23.451506Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Each image must appear exactly 5 times (one per target)\nassert df_train.groupby(\"image_path\").size().nunique() == 1\n\nTARGET_NAMES = df_train[\"target_name\"].unique().tolist()\nprint(\"Targets:\", TARGET_NAMES)\n\n# Confirm long-format submission logic\nassert set(df_test.columns) == {\"sample_id\", \"image_path\", \"target_name\"}\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:43:31.140361Z","iopub.execute_input":"2026-01-21T05:43:31.140660Z","iopub.status.idle":"2026-01-21T05:43:31.150717Z","shell.execute_reply.started":"2026-01-21T05:43:31.140640Z","shell.execute_reply":"2026-01-21T05:43:31.150148Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_train.groupby(\"target_name\")[\"target\"].describe()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:43:39.875896Z","iopub.execute_input":"2026-01-21T05:43:39.876146Z","iopub.status.idle":"2026-01-21T05:43:39.904845Z","shell.execute_reply.started":"2026-01-21T05:43:39.876127Z","shell.execute_reply":"2026-01-21T05:43:39.903961Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"row = df_train.sample(1).iloc[0]\nimg_path = DATA_ROOT / row[\"image_path\"]\n\nimg = Image.open(img_path).convert(\"RGB\")\nplt.figure(figsize=(4, 4))\nplt.imshow(img)\nplt.title(row[\"target_name\"])\nplt.axis(\"off\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:43:47.523979Z","iopub.execute_input":"2026-01-21T05:43:47.524221Z","iopub.status.idle":"2026-01-21T05:43:47.849932Z","shell.execute_reply.started":"2026-01-21T05:43:47.524203Z","shell.execute_reply":"2026-01-21T05:43:47.849343Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"baseline_means = (\n    df_train\n    .groupby(\"target_name\")[\"target\"]\n    .mean()\n    .reset_index()\n)\n\nbaseline_submission = (\n    df_test\n    .merge(baseline_means, on=\"target_name\", how=\"left\")\n    [[\"sample_id\", \"target\"]]\n)\n\nbaseline_submission.to_csv(\"submission.csv\", index=False)\nbaseline_submission.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:43:57.357234Z","iopub.execute_input":"2026-01-21T05:43:57.357557Z","iopub.status.idle":"2026-01-21T05:43:57.380599Z","shell.execute_reply.started":"2026-01-21T05:43:57.357501Z","shell.execute_reply":"2026-01-21T05:43:57.379876Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMG_SIZE = 224\n\nimage_tfms = transforms.Compose([\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.ToTensor(),\n    transforms.Normalize(\n        mean=[0.485, 0.456, 0.406],\n        std=[0.229, 0.224, 0.225]\n    )\n])\n\ndef load_image(image_path):\n    img = Image.open(DATA_ROOT / image_path).convert(\"RGB\")\n    return image_tfms(img)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:44:05.597020Z","iopub.execute_input":"2026-01-21T05:44:05.597270Z","iopub.status.idle":"2026-01-21T05:44:05.602067Z","shell.execute_reply.started":"2026-01-21T05:44:05.597251Z","shell.execute_reply":"2026-01-21T05:44:05.601362Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class EfficientNetExtractor(nn.Module):\n    def __init__(self):\n        super().__init__()\n        base = models.efficientnet_b0(weights=\"IMAGENET1K_V1\")\n        self.features = base.features\n        self.pool = nn.AdaptiveAvgPool2d(1)\n\n        for p in self.parameters():\n            p.requires_grad = False\n\n    def forward(self, x):\n        x = self.features(x)\n        x = self.pool(x)\n        return x.view(x.size(0), -1)\n\nextractor = EfficientNetExtractor().to(DEVICE)\nextractor.eval()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:44:17.276757Z","iopub.execute_input":"2026-01-21T05:44:17.277182Z","iopub.status.idle":"2026-01-21T05:44:17.516890Z","shell.execute_reply.started":"2026-01-21T05:44:17.277164Z","shell.execute_reply":"2026-01-21T05:44:17.515550Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def extract_embeddings(image_paths, batch_size=16):\n    embeddings = {}\n    \n    for i in range(0, len(image_paths), batch_size):\n        batch_paths = image_paths[i:i+batch_size]\n        imgs = torch.stack([load_image(p) for p in batch_paths]).to(DEVICE)\n\n        with torch.no_grad():\n            feats = extractor(imgs).cpu().numpy()\n\n        for p, f in zip(batch_paths, feats):\n            embeddings[p] = f\n\n    return embeddings\n\n\nunique_train_images = df_train[\"image_path\"].unique().tolist()\ntrain_embeddings = extract_embeddings(unique_train_images)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:44:31.545492Z","iopub.execute_input":"2026-01-21T05:44:31.546186Z","iopub.status.idle":"2026-01-21T05:44:58.502892Z","shell.execute_reply.started":"2026-01-21T05:44:31.546161Z","shell.execute_reply":"2026-01-21T05:44:58.502170Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"emb_df = pd.DataFrame.from_dict(\n    train_embeddings, orient=\"index\"\n)\nemb_df.index.name = \"image_path\"\n\ndf_train_emb = df_train.merge(\n    emb_df,\n    left_on=\"image_path\",\n    right_index=True,\n    how=\"left\"\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:45:20.612303Z","iopub.execute_input":"2026-01-21T05:45:20.612580Z","iopub.status.idle":"2026-01-21T05:45:20.732298Z","shell.execute_reply.started":"2026-01-21T05:45:20.612562Z","shell.execute_reply":"2026-01-21T05:45:20.731570Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X = df_train_emb.drop(columns=[\"target\"])\ny = df_train_emb[\"target\"]\ngroups = df_train_emb[\"image_path\"]\n\nX = X.copy()\nX.columns = X.columns.astype(str)\n\ngkf = GroupKFold(n_splits=5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:45:47.594690Z","iopub.execute_input":"2026-01-21T05:45:47.595160Z","iopub.status.idle":"2026-01-21T05:45:47.603379Z","shell.execute_reply.started":"2026-01-21T05:45:47.595114Z","shell.execute_reply":"2026-01-21T05:45:47.602628Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"scores = []\n\nfor fold, (trn_idx, val_idx) in enumerate(gkf.split(X, y, groups)):\n    X_tr = X.iloc[trn_idx].select_dtypes(include=[np.number])\n    X_val = X.iloc[val_idx].select_dtypes(include=[np.number])\n    y_tr = y.iloc[trn_idx]\n    y_val = y.iloc[val_idx]\n\n    model = Ridge(alpha=1.0)\n    model.fit(X_tr, y_tr)\n\n    preds = model.predict(X_val)\n    score = r2_score(y_val, preds)\n\n    scores.append(score)\n    print(f\"Fold {fold}: R² = {score:.4f}\")\n\nprint(\"Mean CV R²:\", np.mean(scores))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-21T05:45:57.756321Z","iopub.execute_input":"2026-01-21T05:45:57.756624Z","iopub.status.idle":"2026-01-21T05:45:58.843917Z","shell.execute_reply.started":"2026-01-21T05:45:57.756599Z","shell.execute_reply":"2026-01-21T05:45:58.843400Z"}},"outputs":[],"execution_count":null}]}