{"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":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":124685,"databundleVersionId":14664296,"isSourceIdPinned":false},{"sourceType":"modelInstanceVersion","sourceId":228781,"databundleVersionId":10783539,"modelInstanceId":195042,"modelId":216938,"isSourceIdPinned":false}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"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-05-07T13:45:48.373636Z","iopub.execute_input":"2026-05-07T13:45:48.374344Z","iopub.status.idle":"2026-05-07T13:45:52.983460Z","shell.execute_reply.started":"2026-05-07T13:45:48.374307Z","shell.execute_reply":"2026-05-07T13:45:52.982170Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for root, dirs, files in os.walk(\"/kaggle/input/competitions/plantclef-2026\"):\n    print(root)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-07T13:45:52.985254Z","iopub.execute_input":"2026-05-07T13:45:52.986092Z","iopub.status.idle":"2026-05-07T13:45:53.521078Z","shell.execute_reply.started":"2026-05-07T13:45:52.986049Z","shell.execute_reply":"2026-05-07T13:45:53.520086Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nfor root, dirs, files in os.walk(\"/kaggle/input\"):\n    for f in files:\n        if \".pth\" in f or \".bin\" in f:\n            print(os.path.join(root, f))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-07T13:51:17.795217Z","iopub.execute_input":"2026-05-07T13:51:17.796039Z","iopub.status.idle":"2026-05-07T13:51:20.561754Z","shell.execute_reply.started":"2026-05-07T13:51:17.795999Z","shell.execute_reply":"2026-05-07T13:51:20.560868Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport timm\nimport numpy as np\nimport pandas as pd\nimport cv2\nimport os\nfrom tqdm import tqdm\n\n# ================= CONFIG =================\nMODEL_PATH = \"/kaggle/input/models/juliostat/dinov2_patch14_reg4_onlyclassifier_then_all/pytorch/default/3/model_best.pth.tar\"\n\nTEST_CSV = \"/kaggle/input/competitions/plantclef-2026/PlantCLEF2025_test.csv\"\n\nTEST_IMG_DIR = \"/kaggle/input/competitions/plantclef-2026/PlantCLEF2025_test_images/PlantCLEF2025_test_images\"\n\nSPECIES_CSV = \"/kaggle/input/competitions/plantclef-2026/species_ids.csv\"\n\nIMG_SIZE = 518\nTOP_K = 3\nTTA = 2\n\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\nprint(\"Using device:\", DEVICE)\n\n# ================= LOAD SPECIES =================\nspecies_df = pd.read_csv(SPECIES_CSV)\n\nidx_to_species = dict(\n    enumerate(species_df[\"species_id\"].values)\n)\n\nNUM_CLASSES = len(idx_to_species)\n\nprint(\"Number of classes:\", NUM_CLASSES)\n\n# ================= MODEL =================\nmodel = timm.create_model(\n    \"vit_base_patch14_dinov2\",\n    pretrained=False,\n    num_classes=NUM_CLASSES\n)\n\n# ================= LOAD CHECKPOINT =================\ncheckpoint = torch.load(\n    MODEL_PATH,\n    map_location=DEVICE,\n    weights_only=False\n)\n\n# extract state_dict\nif \"state_dict\" in checkpoint:\n    checkpoint = checkpoint[\"state_dict\"]\n\nnew_state = {}\n\nfor k, v in checkpoint.items():\n\n    # remove module.\n    if k.startswith(\"module.\"):\n        k = k[7:]\n\n    # skip incompatible positional embeddings\n    if \"pos_embed\" in k:\n        continue\n\n    # skip reg tokens\n    if \"reg_token\" in k:\n        continue\n\n    new_state[k] = v\n\nmsg = model.load_state_dict(\n    new_state,\n    strict=False\n)\n\nprint(msg)\n\nmodel = model.to(DEVICE)\n\nmodel.eval()\n\nprint(\"✅ Model loaded successfully!\")\n\n# ================= PREPROCESS =================\ndef preprocess(img):\n\n    img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))\n\n    img = img.astype(np.float32) / 255.0\n\n    # ImageNet normalization\n    mean = np.array([0.485, 0.456, 0.406])\n    std = np.array([0.229, 0.224, 0.225])\n\n    img = (img - mean) / std\n\n    img = img.transpose(2, 0, 1)\n\n    return torch.tensor(img, dtype=torch.float32)\n\n# ================= TTA =================\ndef apply_tta(img, t):\n\n    if t == 0:\n        return img\n\n    elif t == 1:\n        return np.fliplr(img)\n\n    else:\n        return img\n\n# ================= LOAD TEST CSV =================\ntest_df = pd.read_csv(TEST_CSV, sep=\";\")\n\nprint(test_df.head())\nprint(test_df.columns)\n\nsubmission_rows = []\n\n# ================= INFERENCE =================\nwith torch.no_grad():\n\n    for _, row in tqdm(\n        test_df.iterrows(),\n        total=len(test_df)\n    ):\n\n        quadrat_id = row[\"quadrat_id\"]\n\n        img_path = os.path.join(\n            TEST_IMG_DIR,\n            f\"{quadrat_id}.jpg\"\n        )\n\n        img = cv2.imread(img_path)\n\n        if img is None:\n            print(\"Missing:\", img_path)\n            continue\n\n        img = cv2.cvtColor(\n            img,\n            cv2.COLOR_BGR2RGB\n        )\n\n        preds = []\n\n        for t in range(TTA):\n\n            aug = apply_tta(img.copy(), t)\n\n            tensor = preprocess(aug)\n\n            tensor = tensor.unsqueeze(0).to(DEVICE)\n\n            logits = model(tensor)\n\n            probs = torch.sigmoid(logits)\n\n            probs = probs.cpu().numpy()[0]\n\n            preds.append(probs)\n\n        preds = np.mean(preds, axis=0)\n\n        # ===== THRESHOLD PREDICTIONS =====\nthreshold = 0.20\n\ntop_idx = np.where(preds > threshold)[0]\n\n# fallback if nothing selected\nif len(top_idx) == 0:\n    top_idx = [np.argmax(preds)]\n\n# sort selected classes by confidence\ntop_idx = sorted(\n    top_idx,\n    key=lambda x: preds[x],\n    reverse=True\n)\n\n# keep only strongest few predictions\ntop_idx = top_idx[:5]\n\nspecies_list = [\n    int(idx_to_species[i])\n    for i in top_idx\n]\n\n# ================= CREATE SUBMISSION =================\nsubmission = pd.DataFrame(\n    submission_rows,\n    columns=[\n        \"quadrat_id\",\n        \"species_ids\"\n    ]\n)\n\nsubmission.to_csv(\n    \"submission.csv\",\n    index=False\n)\n\nprint(\"✅ submission.csv created successfully!\")\nprint(submission.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-07T14:25:23.840506Z","iopub.execute_input":"2026-05-07T14:25:23.841327Z","iopub.status.idle":"2026-05-07T14:40:41.775870Z","shell.execute_reply.started":"2026-05-07T14:25:23.841292Z","shell.execute_reply":"2026-05-07T14:40:41.775089Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nprint(os.listdir(\"/kaggle/working\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-07T14:51:36.584045Z","iopub.execute_input":"2026-05-07T14:51:36.584501Z","iopub.status.idle":"2026-05-07T14:51:36.589571Z","shell.execute_reply.started":"2026-05-07T14:51:36.584465Z","shell.execute_reply":"2026-05-07T14:51:36.588818Z"}},"outputs":[],"execution_count":null}]}