{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":91451,"databundleVersionId":11223220,"sourceType":"competition"}],"dockerImageVersionId":31041,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"%pip install git+https://github.com/WildlifeDatasets/wildlife-datasets@develop\n%pip install git+https://github.com/WildlifeDatasets/wildlife-tools","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2025-05-16T19:44:09.156894Z","iopub.execute_input":"2025-05-16T19:44:09.157214Z","iopub.status.idle":"2025-05-16T19:44:40.889963Z","shell.execute_reply.started":"2025-05-16T19:44:09.157189Z","shell.execute_reply":"2025-05-16T19:44:40.889142Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import itertools\n\nimport pandas as pd\nimport timm\nimport torch\nimport torchvision.transforms as T\nfrom wildlife_datasets.datasets import WildlifeDataset, AnimalCLEF2025\nfrom sklearn.preprocessing import LabelEncoder\nfrom wildlife_tools.train import TripletLoss, BasicTrainer, set_seed","metadata":{"execution":{"iopub.status.busy":"2025-05-16T19:44:40.891446Z","iopub.execute_input":"2025-05-16T19:44:40.891707Z","iopub.status.idle":"2025-05-16T19:44:40.896548Z","shell.execute_reply.started":"2025-05-16T19:44:40.891671Z","shell.execute_reply":"2025-05-16T19:44:40.895709Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nset_seed(42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:44:40.897412Z","iopub.execute_input":"2025-05-16T19:44:40.897780Z","iopub.status.idle":"2025-05-16T19:44:40.919881Z","shell.execute_reply.started":"2025-05-16T19:44:40.897762Z","shell.execute_reply":"2025-05-16T19:44:40.919284Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_sample_submission(dataset_query, predictions, file_name=\"sample_submission.csv\"):\n    df = pd.DataFrame({\"image_id\": dataset_query.metadata[\"image_id\"], \"identity\": predictions})\n    df.to_csv(file_name, index=False)","metadata":{"execution":{"iopub.status.busy":"2025-05-16T19:44:40.921375Z","iopub.execute_input":"2025-05-16T19:44:40.921561Z","iopub.status.idle":"2025-05-16T19:44:40.934155Z","shell.execute_reply.started":"2025-05-16T19:44:40.921548Z","shell.execute_reply":"2025-05-16T19:44:40.933452Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"backbone = timm.create_model(\n    \"convnext_tiny.fb_in22k\",\n    pretrained=True,\n    num_classes=0,\n)\n\ndata_config = timm.data.resolve_model_data_config(backbone)\ntransforms = timm.data.create_transform(**data_config, is_training=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:44:40.934889Z","iopub.execute_input":"2025-05-16T19:44:40.935089Z","iopub.status.idle":"2025-05-16T19:44:41.623701Z","shell.execute_reply.started":"2025-05-16T19:44:40.935074Z","shell.execute_reply":"2025-05-16T19:44:41.623097Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img_root = \"/kaggle/input/animal-clef-2025\"\n\nmetadata = pd.read_csv(\"/kaggle/input/animal-clef-2025/metadata.csv\")\nmetadata = metadata.drop(columns=['orientation', 'species'])\nmetadata = metadata[metadata[\"identity\"].notna()]\n\nlabel_encoder = LabelEncoder()\nmetadata[\"identity\"] = label_encoder.fit_transform(metadata[\"identity\"])\nmetadata[\"identity\"].value_counts()\n\ndataset = WildlifeDataset(\n    df=metadata.query('split == \"database\"'), \n    root=img_root, \n    transform=transforms, \n    load_label=True, \n)","metadata":{"execution":{"iopub.status.busy":"2025-05-16T19:44:41.624421Z","iopub.execute_input":"2025-05-16T19:44:41.624655Z","iopub.status.idle":"2025-05-16T19:44:41.680868Z","shell.execute_reply.started":"2025-05-16T19:44:41.624638Z","shell.execute_reply":"2025-05-16T19:44:41.680195Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"num_epochs = 20\nbatch_size = 5","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:44:41.681880Z","iopub.execute_input":"2025-05-16T19:44:41.682512Z","iopub.status.idle":"2025-05-16T19:44:41.685604Z","shell.execute_reply.started":"2025-05-16T19:44:41.682485Z","shell.execute_reply":"2025-05-16T19:44:41.684869Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"loader = torch.utils.data.DataLoader(\n    dataset,\n    batch_size=batch_size,\n    shuffle=True,\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:44:41.686397Z","iopub.execute_input":"2025-05-16T19:44:41.686638Z","iopub.status.idle":"2025-05-16T19:44:41.702642Z","shell.execute_reply.started":"2025-05-16T19:44:41.686614Z","shell.execute_reply":"2025-05-16T19:44:41.702062Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"objective = TripletLoss(margin=0.3, mining='seminard', distance='cosine')\n\noptimizer = torch.optim.AdamW(\n    params=backbone.parameters(),\n    lr=3e-5,\n    weight_decay=1e-4,\n)\n\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=num_epochs)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:44:41.703558Z","iopub.execute_input":"2025-05-16T19:44:41.704433Z","iopub.status.idle":"2025-05-16T19:44:41.725526Z","shell.execute_reply.started":"2025-05-16T19:44:41.704407Z","shell.execute_reply":"2025-05-16T19:44:41.724959Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"counter = 0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:44:41.727382Z","iopub.execute_input":"2025-05-16T19:44:41.727560Z","iopub.status.idle":"2025-05-16T19:44:41.731364Z","shell.execute_reply.started":"2025-05-16T19:44:41.727546Z","shell.execute_reply":"2025-05-16T19:44:41.730722Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def save_model_and_print_stats(trainer, epoch_data):\n    global counter\n    trainer.save(\"/kaggle/working/\", f\"checkpoint_epoch:{counter}.pth\")\n    print(f\"Epoch data: {epoch_data}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:44:41.731946Z","iopub.execute_input":"2025-05-16T19:44:41.732106Z","iopub.status.idle":"2025-05-16T19:44:41.747203Z","shell.execute_reply.started":"2025-05-16T19:44:41.732093Z","shell.execute_reply":"2025-05-16T19:44:41.746487Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"trainer = BasicTrainer(\n    dataset=dataset,\n    model=backbone,\n    objective=objective,\n    optimizer=optimizer,\n    scheduler=scheduler,\n    epochs=num_epochs,\n    num_workers=4,\n    accumulation_steps=5,\n    epoch_callback=save_model_and_print_stats,\n    device=device,\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:45:03.181337Z","iopub.execute_input":"2025-05-16T19:45:03.181982Z","iopub.status.idle":"2025-05-16T19:45:03.339033Z","shell.execute_reply.started":"2025-05-16T19:45:03.181957Z","shell.execute_reply":"2025-05-16T19:45:03.338381Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"trainer.train()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T19:45:04.849756Z","iopub.execute_input":"2025-05-16T19:45:04.850255Z","iopub.status.idle":"2025-05-16T20:23:10.926299Z","shell.execute_reply.started":"2025-05-16T19:45:04.850230Z","shell.execute_reply":"2025-05-16T20:23:10.925266Z"}},"outputs":[],"execution_count":null}]}