{"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":"gpu","dataSources":[{"sourceId":91451,"databundleVersionId":11223220,"sourceType":"competition"}],"dockerImageVersionId":30919,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# ====== Imports ======\nimport os\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nimport torch\nimport torchvision\nfrom PIL import Image\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import train_test_split as tts\nfrom torchvision import transforms, models\nfrom torch.utils.data import DataLoader, Dataset\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-08T14:50:55.496802Z","iopub.execute_input":"2025-04-08T14:50:55.497117Z","iopub.status.idle":"2025-04-08T14:50:55.579748Z","shell.execute_reply.started":"2025-04-08T14:50:55.497090Z","shell.execute_reply":"2025-04-08T14:50:55.579126Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Device setup\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ndevice","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-08T14:50:24.509529Z","iopub.execute_input":"2025-04-08T14:50:24.509812Z","iopub.status.idle":"2025-04-08T14:50:24.561392Z","shell.execute_reply.started":"2025-04-08T14:50:24.509791Z","shell.execute_reply":"2025-04-08T14:50:24.560444Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ==== Load metadata ====\nroot_dir = '/kaggle/input/animal-clef-2025'\nmetadata_dir = '/kaggle/input/animal-clef-2025/metadata.csv'\n\ndf = pd.read_csv(metadata_dir)\ndatabase_df = df[df[\"split\"] == \"database\"].dropna(subset=['identity'])\ndatabase_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-08T14:50:26.370212Z","iopub.execute_input":"2025-04-08T14:50:26.370570Z","iopub.status.idle":"2025-04-08T14:50:26.479969Z","shell.execute_reply.started":"2025-04-08T14:50:26.370546Z","shell.execute_reply":"2025-04-08T14:50:26.479076Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ==== Counting the no of images v/s identity in database\n\nidentity_counts = df[df['split'] == 'database']['identity'].value_counts().reset_index()\nidentity_counts.columns = ['identity', 'num_images']\nidentity_counts","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-08T14:51:06.729740Z","iopub.execute_input":"2025-04-08T14:51:06.730028Z","iopub.status.idle":"2025-04-08T14:51:06.752874Z","shell.execute_reply.started":"2025-04-08T14:51:06.730007Z","shell.execute_reply":"2025-04-08T14:51:06.751997Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# counting no of classes with only 1 image\nidentity_counts[identity_counts['num_images'] == 1].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-08T15:00:24.676961Z","iopub.execute_input":"2025-04-08T15:00:24.677273Z","iopub.status.idle":"2025-04-08T15:00:24.689690Z","shell.execute_reply.started":"2025-04-08T15:00:24.677216Z","shell.execute_reply":"2025-04-08T15:00:24.688990Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ==== Creating mappings =====\nencoder = LabelEncoder()\ndatabase_df['label'] = encoder.fit_transform(database_df['identity'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-08T14:51:11.259731Z","iopub.execute_input":"2025-04-08T14:51:11.260159Z","iopub.status.idle":"2025-04-08T14:51:11.271996Z","shell.execute_reply.started":"2025-04-08T14:51:11.260114Z","shell.execute_reply":"2025-04-08T14:51:11.271051Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"database_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-08T14:51:13.878883Z","iopub.execute_input":"2025-04-08T14:51:13.879296Z","iopub.status.idle":"2025-04-08T14:51:13.891113Z","shell.execute_reply.started":"2025-04-08T14:51:13.879261Z","shell.execute_reply":"2025-04-08T14:51:13.890308Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ==== Custom Dataset ====\nclass CustomDataset(Dataset):\n    def __init__(self, df, transform=None):\n        self.df = df.reset_index(drop=True)\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        img_path = self.df.loc[idx, 'path']\n        # print(img_path)\n        img_path = os.path.join(root_dir, img_path)\n        label = self.df.loc[idx, 'label']\n        img = Image.open(img_path).convert(\"RGB\")\n        if self.transform:\n            img = self.transform(img)\n        return img, label\n\n\n# ==== Transformations ====\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485, 0.456, 0.406],\n                         [0.229, 0.224, 0.225])\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-08T14:51:22.602304Z","iopub.execute_input":"2025-04-08T14:51:22.602608Z","iopub.status.idle":"2025-04-08T14:51:22.608388Z","shell.execute_reply.started":"2025-04-08T14:51:22.602584Z","shell.execute_reply":"2025-04-08T14:51:22.607427Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ==== Dataset and Dataloader ====\n# train_df, val_df = tts(database_df, test_size=0.2, random_state=42)\n\ntrain_dataset = CustomDataset(database_df, transform=transform)\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)\n\n# val_dataset = CustomDataset(val_df, transform=transform)\n# val_loader = DataLoader(val_dataset, batch_size=32, shuffle=True)\n\n# ==== Model ====\nmodel = models.resnet18(pretrained=True)\nmodel.fc = nn.Linear(model.fc.in_features, len(encoder.classes_))\nmodel = model.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-08T15:17:28.221568Z","iopub.execute_input":"2025-04-08T15:17:28.221913Z","iopub.status.idle":"2025-04-08T15:17:29.048858Z","shell.execute_reply.started":"2025-04-08T15:17:28.221886Z","shell.execute_reply":"2025-04-08T15:17:29.047924Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# === Training setup ====\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=1e-4)\nEPOCHS = 10\n# === Training Loop ====\nfor epoch in range(EPOCHS):\n    model.train()\n    running_loss = 0.0\n    for imgs, labels in train_loader:\n        imgs, labels = imgs.to(device), labels.to(device)\n        optimizer.zero_grad()\n        outputs = model(imgs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        running_loss += loss.item()\n    print(f\"Epoch {epoch+1}, Loss: {running_loss:.4f}\")\n\n\n# ==== save model and encoder ====\nimport joblib\ntorch.save(model.state_dict(), 'reid_classifier.pth')\njoblib.dump(encoder, 'label_encoder.pkl')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-06T14:08:18.098782Z","iopub.execute_input":"2025-04-06T14:08:18.099130Z","iopub.status.idle":"2025-04-06T14:37:20.838687Z","shell.execute_reply.started":"2025-04-06T14:08:18.099102Z","shell.execute_reply":"2025-04-06T14:37:20.837741Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Inferencing","metadata":{}},{"cell_type":"code","source":"df = pd.read_csv(metadata_dir)\nquery_df = df[df['split'] == 'query'].reset_index(drop=True)\nquery_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-06T15:08:38.282191Z","iopub.execute_input":"2025-04-06T15:08:38.282495Z","iopub.status.idle":"2025-04-06T15:08:38.332986Z","shell.execute_reply.started":"2025-04-06T15:08:38.282473Z","shell.execute_reply":"2025-04-06T15:08:38.332276Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ==== Load model and encoder ====\nmodel = models.resnet18(pretrained=False)\nmodel.fc = torch.nn.Linear(model.fc.in_features,  len(joblib.load(\"label_encoder.pkl\").classes_))\nmodel.load_state_dict(torch.load(\"reid_classifier.pth\"))\nmodel = model.to(device)\nmodel.eval()\n\nencoder = joblib.load(\"label_encoder.pkl\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-06T15:10:12.540988Z","iopub.execute_input":"2025-04-06T15:10:12.541359Z","iopub.status.idle":"2025-04-06T15:10:12.766286Z","shell.execute_reply.started":"2025-04-06T15:10:12.541334Z","shell.execute_reply":"2025-04-06T15:10:12.765426Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# === Inference ===\nthreshold = 0.5\nresults = []\n\nfor i, row in query_df.iterrows():\n    img_path = os.path.join(root_dir, row['path'])\n    img = Image.open(img_path).convert(\"RGB\")\n    img_tensor = transform(img).unsqueeze(0).to(device)\n\n    with torch.no_grad():\n        outputs = model(img_tensor)\n        probs = F.softmax(outputs, dim=1)\n        max_prob, pred_class = torch.max(probs, 1)\n\n    if max_prob.item() >= threshold:\n        identity = encoder.inverse_transform([pred_class.item()])[0]\n    else:\n        identity = \"new_individual\"\n\n    results.append({\n        \"image_id\": row[\"image_id\"],\n        \"identity\": identity\n    })\n\n# === Save to CSV ===\nsubmission_df = pd.DataFrame(results)\nsubmission_df.to_csv(\"submission.csv\", index=False)\nprint(\"Saved predictions to sample_submission.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-06T15:23:29.571155Z","iopub.execute_input":"2025-04-06T15:23:29.571452Z","iopub.status.idle":"2025-04-06T15:24:28.703128Z","shell.execute_reply.started":"2025-04-06T15:23:29.571430Z","shell.execute_reply":"2025-04-06T15:24:28.702364Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}