{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.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":89850,"databundleVersionId":11256103,"sourceType":"competition"},{"sourceId":228781,"sourceType":"modelInstanceVersion","modelInstanceId":195042,"modelId":216938}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Introduction\nThe purpose of this notebook is to show how to load the Dinov2 finetunes model provided by the organisers of the PlantCLEF2025 competition and infer on a random test image.","metadata":{}},{"cell_type":"markdown","source":"Import libraries","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd \nimport os\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport timm \nimport torch","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-03-11T13:33:26.783566Z","iopub.execute_input":"2025-03-11T13:33:26.783905Z","iopub.status.idle":"2025-03-11T13:33:26.787792Z","shell.execute_reply.started":"2025-03-11T13:33:26.783873Z","shell.execute_reply":"2025-03-11T13:33:26.786902Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_species_ids = pd.read_csv('/kaggle/input/plantclef-2025/species_ids.csv')\ndf_metadata = pd.read_csv('/kaggle/input/plantclef-2025/PlantCLEF2024_single_plant_training_metadata.csv', sep=';', dtype={'partner': str})\nid_to_species = df_metadata[['species_id', 'species']].drop_duplicates().set_index('species_id')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-11T13:33:26.935997Z","iopub.execute_input":"2025-03-11T13:33:26.936252Z","iopub.status.idle":"2025-03-11T13:33:37.722010Z","shell.execute_reply.started":"2025-03-11T13:33:26.936231Z","shell.execute_reply":"2025-03-11T13:33:37.721128Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Load random image","metadata":{}},{"cell_type":"code","source":"img = Image.open('/kaggle/input/plantclef-2025/PlantCLEF2025_test_images/PlantCLEF2025_test_images/GUARDEN-CBNMed-30-4-16-3-20240428.jpg')\nplt.imshow(img)\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-11T13:33:37.723400Z","iopub.execute_input":"2025-03-11T13:33:37.723705Z","iopub.status.idle":"2025-03-11T13:33:38.401097Z","shell.execute_reply.started":"2025-03-11T13:33:37.723672Z","shell.execute_reply":"2025-03-11T13:33:38.400182Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img.size","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-11T13:33:38.402663Z","iopub.execute_input":"2025-03-11T13:33:38.402966Z","iopub.status.idle":"2025-03-11T13:33:38.408191Z","shell.execute_reply.started":"2025-03-11T13:33:38.402938Z","shell.execute_reply":"2025-03-11T13:33:38.407358Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Load model","metadata":{}},{"cell_type":"code","source":"device = torch.device('cuda')\nmodel = timm.create_model('vit_base_patch14_reg4_dinov2.lvd142m',\n                          pretrained=False,\n                          num_classes=len(df_species_ids),\n                          checkpoint_path='/kaggle/input/dinov2_patch14_reg4_onlyclassifier_then_all/pytorch/default/3/model_best.pth.tar')\nmodel = model.to(device)\nmodel = model.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-11T13:33:38.409192Z","iopub.execute_input":"2025-03-11T13:33:38.409494Z","iopub.status.idle":"2025-03-11T13:33:40.595420Z","shell.execute_reply.started":"2025-03-11T13:33:38.409463Z","shell.execute_reply":"2025-03-11T13:33:40.594770Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Print the top 5 scores.","metadata":{}},{"cell_type":"code","source":"# get model specific transforms (normalization, resize)\ndata_config = timm.data.resolve_model_data_config(model)\ntransforms = timm.data.create_transform(**data_config, is_training=False)\n\nwith torch.no_grad():\n    if img != None:\n        img = transforms(img).unsqueeze(0)\n        img = img.to(device)\n        output = model(img)  # unsqueeze single image into batch of 1\n        top5_probabilities, top5_class_indices = torch.topk(output.softmax(dim=1), k=5)\n        top5_probabilities = top5_probabilities.cpu().detach().numpy()\n        top5_class_indices = top5_class_indices.cpu().detach().numpy()\n    \n        for proba, cid in zip(top5_probabilities[0], top5_class_indices[0]):\n            species_id = df_species_ids.iloc[cid].item()\n            species = id_to_species.loc[species_id].item()\n            print(species_id, species, proba)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-11T13:33:40.596095Z","iopub.execute_input":"2025-03-11T13:33:40.596298Z","iopub.status.idle":"2025-03-11T13:33:40.813057Z","shell.execute_reply.started":"2025-03-11T13:33:40.596279Z","shell.execute_reply":"2025-03-11T13:33:40.811838Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"As observed from the predictions, since the model is trained on a mono-label dataset, two predicted species could both be present in the quadrat, or the model might be uncertain between them.","metadata":{}}]}