{"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":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"\"\"\" Imports \"\"\"\nimport os\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport torch\nimport torchvision.transforms as transforms\nimport torch.nn.functional as F\nfrom torchvision import models, datasets\nfrom torch.utils.data import DataLoader\nfrom PIL import Image\nfrom sklearn.metrics.pairwise import cosine_similarity\nfrom transformers import ViTModel, ViTFeatureExtractor\nfrom tqdm import tqdm\n\n\nsns.set(style=\"whitegrid\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:58:03.049652Z","iopub.execute_input":"2025-04-05T05:58:03.049972Z","iopub.status.idle":"2025-04-05T05:58:03.054981Z","shell.execute_reply.started":"2025-04-05T05:58:03.049950Z","shell.execute_reply":"2025-04-05T05:58:03.054260Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"root_dir =\"/kaggle/input/animal-clef-2025\"\nmetadata_path = \"/kaggle/input/animal-clef-2025/metadata.csv\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:44:56.161979Z","iopub.execute_input":"2025-04-05T05:44:56.162297Z","iopub.status.idle":"2025-04-05T05:44:56.165836Z","shell.execute_reply.started":"2025-04-05T05:44:56.162272Z","shell.execute_reply":"2025-04-05T05:44:56.165003Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Visualizing the metadata","metadata":{}},{"cell_type":"code","source":"metadata_df = pd.read_csv(metadata_path)\nmetadata_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:45:00.071538Z","iopub.execute_input":"2025-04-05T05:45:00.071821Z","iopub.status.idle":"2025-04-05T05:45:00.190607Z","shell.execute_reply.started":"2025-04-05T05:45:00.071801Z","shell.execute_reply":"2025-04-05T05:45:00.189782Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"metadata_df.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:45:04.375446Z","iopub.execute_input":"2025-04-05T05:45:04.375722Z","iopub.status.idle":"2025-04-05T05:45:04.400061Z","shell.execute_reply.started":"2025-04-05T05:45:04.375700Z","shell.execute_reply":"2025-04-05T05:45:04.399228Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"metadata_df.isna().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:45:07.156169Z","iopub.execute_input":"2025-04-05T05:45:07.156513Z","iopub.status.idle":"2025-04-05T05:45:07.167628Z","shell.execute_reply.started":"2025-04-05T05:45:07.156485Z","shell.execute_reply":"2025-04-05T05:45:07.166797Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"metadata_df[metadata_df[\"split\"] == \"database\"].isna().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:45:13.385313Z","iopub.execute_input":"2025-04-05T05:45:13.385634Z","iopub.status.idle":"2025-04-05T05:45:13.399462Z","shell.execute_reply.started":"2025-04-05T05:45:13.385602Z","shell.execute_reply":"2025-04-05T05:45:13.398612Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"metadata_df[metadata_df[\"split\"] == \"query\"].isna().sum()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:45:24.528687Z","iopub.execute_input":"2025-04-05T05:45:24.528965Z","iopub.status.idle":"2025-04-05T05:45:24.538338Z","shell.execute_reply.started":"2025-04-05T05:45:24.528945Z","shell.execute_reply":"2025-04-05T05:45:24.537667Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Count images per class and split\nclass_distribution = metadata_df.groupby([\"dataset\", \"split\"]).size().unstack(fill_value=0)\n\n# Plot\nplt.figure(figsize=(12, 6))\nax = class_distribution.plot(kind=\"bar\", colormap=\"coolwarm\", figsize=(12, 6), edgecolor=\"black\")\n\n# Add value labels on bars\nfor p in ax.patches:\n    ax.annotate(f'{int(p.get_height())}', (p.get_x() + p.get_width() / 2, p.get_height()),  \n                ha='center', va='bottom', fontsize=10, fontweight='bold', color='black')\n\n# Labels and title\nplt.xlabel(\"Class (Dataset Column)\")\nplt.ylabel(\"Number of Images\")\nplt.title(\"Number of Images in Database vs Query per Class\")\nplt.legend(title=\"Split\")\nplt.xticks(rotation=45)\nplt.grid(axis=\"y\", linestyle=\"--\", alpha=0.7)\n\n# Show plot\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:45:29.325691Z","iopub.execute_input":"2025-04-05T05:45:29.325965Z","iopub.status.idle":"2025-04-05T05:45:29.703003Z","shell.execute_reply.started":"2025-04-05T05:45:29.325944Z","shell.execute_reply":"2025-04-05T05:45:29.702072Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Visualizing the count of images v/s orientation\n\nplt.figure(figsize=(8, 5))\nsns.countplot(data=metadata_df, x=\"orientation\", order=metadata_df[\"orientation\"].value_counts().index)\nplt.xlabel(\"Orientation\")\nplt.ylabel(\"Count\")\nplt.title(\"Image Count per Orientation\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:45:38.462996Z","iopub.execute_input":"2025-04-05T05:45:38.463406Z","iopub.status.idle":"2025-04-05T05:45:38.691427Z","shell.execute_reply.started":"2025-04-05T05:45:38.463374Z","shell.execute_reply":"2025-04-05T05:45:38.690530Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Visualizing no of images in database v/s query\n\nplt.figure(figsize=(6, 5))\nsns.countplot(data=metadata_df, x=\"split\")\nplt.xlabel(\"Dataset Split\")\nplt.ylabel(\"Count\")\nplt.title(\"Number of Images in Database vs Query\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:45:41.293764Z","iopub.execute_input":"2025-04-05T05:45:41.294047Z","iopub.status.idle":"2025-04-05T05:45:41.443260Z","shell.execute_reply.started":"2025-04-05T05:45:41.294025Z","shell.execute_reply":"2025-04-05T05:45:41.442538Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(\"/kaggle/input/animal-clef-2025/sample_submission.csv\")\ndf","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:45:45.365260Z","iopub.execute_input":"2025-04-05T05:45:45.365570Z","iopub.status.idle":"2025-04-05T05:45:45.385763Z","shell.execute_reply.started":"2025-04-05T05:45:45.365549Z","shell.execute_reply":"2025-04-05T05:45:45.384941Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Loading a pre-trained model for embeddings","metadata":{}},{"cell_type":"code","source":"# checking for device\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Using the device: {device}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:46:27.507698Z","iopub.execute_input":"2025-04-05T05:46:27.508016Z","iopub.status.idle":"2025-04-05T05:46:27.565655Z","shell.execute_reply.started":"2025-04-05T05:46:27.507991Z","shell.execute_reply":"2025-04-05T05:46:27.564737Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_name = \"google/vit-base-patch16-224-in21k\"\nfeature_extractor = ViTFeatureExtractor.from_pretrained(model_name)\nmodel = ViTModel.from_pretrained(model_name).to(device)\nmodel.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:51:10.657830Z","iopub.execute_input":"2025-04-05T05:51:10.658136Z","iopub.status.idle":"2025-04-05T05:51:13.232037Z","shell.execute_reply.started":"2025-04-05T05:51:10.658113Z","shell.execute_reply":"2025-04-05T05:51:13.231343Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Image transformation and normalization\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean = feature_extractor.image_mean, std = feature_extractor.image_std)\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:53:33.429844Z","iopub.execute_input":"2025-04-05T05:53:33.430198Z","iopub.status.idle":"2025-04-05T05:53:33.434304Z","shell.execute_reply.started":"2025-04-05T05:53:33.430155Z","shell.execute_reply":"2025-04-05T05:53:33.433404Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Function to extract embeddings \ndef extract_embeddings(image_path):\n    img = Image.open(image_path).convert(\"RGB\")\n    img_transformed = transform(img).unsqueeze(0).to(device)\n    with torch.no_grad():\n        output = model(img_transformed)\n        embeddings = output.last_hidden_state[:, 0] #CLS token\n\n    return F.normalize(embeddings, p=2, dim=1).squeeze(0) # Normalizing for cosine similarity","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:56:18.785922Z","iopub.execute_input":"2025-04-05T05:56:18.786284Z","iopub.status.idle":"2025-04-05T05:56:18.790984Z","shell.execute_reply.started":"2025-04-05T05:56:18.786254Z","shell.execute_reply":"2025-04-05T05:56:18.790097Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"database_embeddings = []\n\nfor _, row in metadata_df.iterrows():\n    if row[\"split\"] == \"database\":\n        img_path = os.path.join(root_dir, row[\"path\"])\n        embed = extract_embeddings(img_path)\n        # print(len(embed))\n        # break\n\n        database_embeddings.append({\n            \"embedding\" : embed,\n            \"identity\" : row[\"identity\"],\n            \"orientation\" : row[\"orientation\"]\n        })","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T05:58:19.062704Z","iopub.execute_input":"2025-04-05T05:58:19.063014Z","iopub.status.idle":"2025-04-05T06:03:10.871375Z","shell.execute_reply.started":"2025-04-05T05:58:19.062988Z","shell.execute_reply":"2025-04-05T06:03:10.870692Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(database_embeddings)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T06:03:18.810608Z","iopub.execute_input":"2025-04-05T06:03:18.810922Z","iopub.status.idle":"2025-04-05T06:03:18.815905Z","shell.execute_reply.started":"2025-04-05T06:03:18.810896Z","shell.execute_reply":"2025-04-05T06:03:18.815224Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"database_embeddings[0]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T06:04:53.650034Z","iopub.execute_input":"2025-04-05T06:04:53.650387Z","iopub.status.idle":"2025-04-05T06:04:53.850836Z","shell.execute_reply.started":"2025-04-05T06:04:53.650360Z","shell.execute_reply":"2025-04-05T06:04:53.849968Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# identifying similar patterns in query images \n\nthreshold = 0.97\nquery_results = []\nfor _, row in metadata_df.iterrows():\n    if row[\"split\"] == \"query\":\n        img_path = os.path.join(root_dir, row[\"path\"])\n        query_embed = extract_embeddings(img_path)\n        query_orientation = row[\"orientation\"]\n\n        if pd.isna(query_orientation):\n            filtered_embeddings = database_embeddings\n        else:\n            filtered_embeddings = [\n                e for e in database_embeddings if e[\"orientation\"] == query_orientation\n            ]\n            if not filtered_embeddings:\n                filtered_embeddings = database_embeddings\n\n        if not filtered_embeddings:\n            query_results.append([row[\"image_id\"], \"new_individual\"])\n            continue\n\n        embed_matrix = torch.stack([e[\"embedding\"] for e in filtered_embeddings]).to(device)\n        img_identities = [e[\"identity\"] for e in filtered_embeddings]\n\n        # compute similarity scores\n        similarity_scores = torch.nn.functional.cosine_similarity(query_embed.unsqueeze(0), embed_matrix, dim=1)\n        best_indx = torch.argmax(similarity_scores)\n\n        print(f\"Image: {row['path']} | Best Similarity: {similarity_scores[best_indx].item():.4f}\")\n\n        if similarity_scores[best_indx].item() > threshold:\n            query_results.append([row[\"image_id\"], img_identities[best_indx]])\n        else:\n            query_results.append([row[\"image_id\"], \"new_individual\"])\n\n            ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T06:05:56.621319Z","iopub.execute_input":"2025-04-05T06:05:56.621624Z","iopub.status.idle":"2025-04-05T06:07:45.780906Z","shell.execute_reply.started":"2025-04-05T06:05:56.621602Z","shell.execute_reply":"2025-04-05T06:07:45.779911Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"output_df = pd.DataFrame(query_results, columns=['image_id', 'identity'])\noutput_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T06:15:24.474870Z","iopub.execute_input":"2025-04-05T06:15:24.475241Z","iopub.status.idle":"2025-04-05T06:15:24.486012Z","shell.execute_reply.started":"2025-04-05T06:15:24.475174Z","shell.execute_reply":"2025-04-05T06:15:24.485384Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"output_df[output_df[\"identity\"] == \"new_individual\"]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T06:15:31.830796Z","iopub.execute_input":"2025-04-05T06:15:31.831075Z","iopub.status.idle":"2025-04-05T06:15:31.841143Z","shell.execute_reply.started":"2025-04-05T06:15:31.831054Z","shell.execute_reply":"2025-04-05T06:15:31.840270Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"output_df.to_csv(\"submission.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-05T06:15:45.255663Z","iopub.execute_input":"2025-04-05T06:15:45.255996Z","iopub.status.idle":"2025-04-05T06:15:45.267263Z","shell.execute_reply.started":"2025-04-05T06:15:45.255969Z","shell.execute_reply":"2025-04-05T06:15:45.266441Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}