{"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":"gpu","dataSources":[{"sourceType":"competition","sourceId":126777,"databundleVersionId":15314950},{"sourceType":"modelInstanceVersion","sourceId":776726,"databundleVersionId":15962787,"modelInstanceId":592942,"modelId":605228}],"dockerImageVersionId":31259,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Import Libraries\nimport pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom sklearn.manifold import TSNE\nimport os\nimport random\nimport cv2\nfrom PIL import Image , ImageEnhance\nimport imagehash\nimport torch\nfrom torch.utils.data import Dataset , DataLoader\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torchvision import transforms\nimport torchvision.models as models\nfrom sklearn.model_selection import train_test_split\nfrom torch.utils.data import DataLoader, Subset\nfrom tqdm import tqdm\nimport time\ntorch.cuda.empty_cache()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:49:46.996590Z","iopub.execute_input":"2026-03-10T21:49:46.996895Z","iopub.status.idle":"2026-03-10T21:49:47.002279Z","shell.execute_reply.started":"2026-03-10T21:49:46.996867Z","shell.execute_reply":"2026-03-10T21:49:47.001475Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Set Configurations\nInput = '/kaggle/input/jaguar-re-id'\ntrain_img = os.path.join(Input , 'train/train')\ntest_img = os.path.join(Input , 'test/test')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:07:58.843889Z","iopub.execute_input":"2026-03-10T21:07:58.844195Z","iopub.status.idle":"2026-03-10T21:07:58.848468Z","shell.execute_reply.started":"2026-03-10T21:07:58.844170Z","shell.execute_reply":"2026-03-10T21:07:58.847773Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test = pd.read_csv(os.path.join(Input , 'test.csv'))\ntest.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:07:59.817595Z","iopub.execute_input":"2026-03-10T21:07:59.818227Z","iopub.status.idle":"2026-03-10T21:07:59.930894Z","shell.execute_reply.started":"2026-03-10T21:07:59.818197Z","shell.execute_reply":"2026-03-10T21:07:59.930271Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.read_csv(os.path.join(Input , 'train.csv'))\ntrain.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:08:02.421849Z","iopub.execute_input":"2026-03-10T21:08:02.422433Z","iopub.status.idle":"2026-03-10T21:08:02.436409Z","shell.execute_reply.started":"2026-03-10T21:08:02.422405Z","shell.execute_reply":"2026-03-10T21:08:02.435853Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f'The size of train: ({str(train.shape[0])},{str(train.shape[1])})')\nprint('The number of Nan values in train data is:' , train.isna().sum().sum())\nprint('The number of types of Jaguar in dataset is: ', str(len(train.iloc[:,1].unique())))\ntypes = train.iloc[:,1].unique()\ntypes = list(types)\nprint('They are:',types)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:08:03.052249Z","iopub.execute_input":"2026-03-10T21:08:03.052831Z","iopub.status.idle":"2026-03-10T21:08:03.060920Z","shell.execute_reply.started":"2026-03-10T21:08:03.052801Z","shell.execute_reply":"2026-03-10T21:08:03.060300Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"List = []\nfor idx1 , val in enumerate(train['ground_truth']):\n    for idx2 in range(len(types)):\n        if val == types[idx2]:\n            List.append(idx2)\n            break\ntrain['ground_truth_encoded'] = List\ntrain.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:08:04.765250Z","iopub.execute_input":"2026-03-10T21:08:04.765544Z","iopub.status.idle":"2026-03-10T21:08:04.777700Z","shell.execute_reply.started":"2026-03-10T21:08:04.765517Z","shell.execute_reply":"2026-03-10T21:08:04.777127Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(train.info())\nprint('='*100)\nprint(train.describe().T)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:08:05.030414Z","iopub.execute_input":"2026-03-10T21:08:05.031094Z","iopub.status.idle":"2026-03-10T21:08:05.059562Z","shell.execute_reply.started":"2026-03-10T21:08:05.031066Z","shell.execute_reply":"2026-03-10T21:08:05.059017Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x = train['ground_truth_encoded'].value_counts()[:]\nx = pd.DataFrame(x)\nList1 = list(x.index)\nList = []\nfor idx in range(len(List1)):\n    List.append(types[List1[idx]])\nMAP = list(x['count'])\nMAP = pd.DataFrame(MAP)\nMAP['ground_truth_encoded'] = List\nMAP.columns = ['count','type of jaguar']\ndel x\nMAP.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:08:06.750800Z","iopub.execute_input":"2026-03-10T21:08:06.751141Z","iopub.status.idle":"2026-03-10T21:08:06.765984Z","shell.execute_reply.started":"2026-03-10T21:08:06.751113Z","shell.execute_reply":"2026-03-10T21:08:06.764962Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('Maximum of counts: ',str(max(MAP.iloc[:,0])))\nprint('Minimum of counts: ',str(min(MAP.iloc[:,0])))\nprint('STD of counts: ',str(np.std(MAP.iloc[:,0])))\nprint('Maximum of counts: ',str(np.mean(MAP.iloc[:,0])))\n\nplt.figure(figsize=(10,4))\nplt.bar(MAP['type of jaguar'], MAP['count'])\nplt.xticks(rotation=90)\nplt.title(\"Images per Jaguar ID\")\nplt.show()\n\nplt.figure()\ncounts = pd.DataFrame(train['ground_truth'].value_counts())\nsns.heatmap(counts, cmap='viridis')\nplt.title(\"Class imbalance heatmap\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:08:07.344141Z","iopub.execute_input":"2026-03-10T21:08:07.344456Z","iopub.status.idle":"2026-03-10T21:08:07.839839Z","shell.execute_reply.started":"2026-03-10T21:08:07.344426Z","shell.execute_reply":"2026-03-10T21:08:07.839138Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def show(filename , title):\n    img = cv2.imread(filename)\n    img = cv2.cvtColor(img , cv2.COLOR_BGR2RGB)\n    plt.imshow(img)\n    plt.axis('off')\n    plt.title(title)\n    \npos = random.randint(0,train.shape[0])\nfilename = os.path.join(train_img , train.iloc[pos , 0])\ntitle = train.iloc[pos , 1]\nshow(filename , title)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-21T10:26:48.062019Z","iopub.execute_input":"2026-02-21T10:26:48.062267Z","iopub.status.idle":"2026-02-21T10:26:48.551773Z","shell.execute_reply.started":"2026-02-21T10:26:48.062243Z","shell.execute_reply":"2026-02-21T10:26:48.550913Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def show_img(filename , title , ax):\n    img = cv2.imread(filename)\n    img = cv2.cvtColor(img , cv2.COLOR_BGR2RGB)\n    ax.imshow(img)\n    ax.axis('off')\n    ax.set_title(title)\n    \nJaguarLess = MAP[MAP['count'] == MAP['count'].min()].sample(1).iloc[0 , 1]\nFilterLess = train[train['ground_truth'] == JaguarLess]\nSubsetLess = FilterLess.sample(min(FilterLess.shape[0] , 6))\n\nJaguarMost = MAP[MAP['count'] == MAP['count'].max()].sample(1).iloc[0 , 1]\nFilterMost = train[train['ground_truth'] == JaguarMost]\nSubsetMost = FilterMost.sample(6)\n\nfig , axes = plt.subplots(1 , 6 , figsize = (20 , 20))\naxes = axes.ravel()\nfor ax, row in zip(axes, SubsetLess.itertuples()):\n    filename = os.path.join(train_img , row.filename)\n    title = row.ground_truth + ' (rare)'\n    show_img(filename , title , ax)\n\nfig , axes = plt.subplots(1 , 6 , figsize = (20 , 20))\naxes = axes.ravel()\nfor ax, row in zip(axes, SubsetMost.itertuples()):\n    filename = os.path.join(train_img , row.filename)\n    title = row.ground_truth + ' (common)'\n    show_img(filename , title , ax)\n    \nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"samples = train.shape[0]\ndef get_hash(path):\n    imag = Image.open(path)\n    hash_imag = imagehash.phash(imag)\n    return hash_imag\nhashes = {}\nduplicates = []\n\nfor row in train.sample(samples).itertuples():\n    h = get_hash(os.path.join(train_img , row.filename))\n    if h in hashes:\n        duplicates.append((hashes[h] , row.filename))\n    else:\n        hashes[h] = row.filename\nprint(f'The number of duplicate of images in train data is: {len(duplicates)}')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dup = []\nfor val in duplicates:\n    dup.append((val , train[train['filename'] == val[0]].iloc[0 , 1]))\n\nList = []\nfor val in dup:\n    List.append(val[1])\nList = pd.DataFrame(List)\nList.value_counts().plot(kind='bar')\n\nduplicate = random.choice(dup)\nimg1 = Image.open(os.path.join(train_img , duplicate[0][0]))\nimg2 = Image.open(os.path.join(train_img , duplicate[0][1]))\n\nplt.figure(figsize = (8 , 8))\nplt.subplot(1 , 2 , 1)\nplt.imshow(img1)\nplt.axis('off')\nplt.title(f'orginal ({duplicate[1]})')\nplt.subplot(1 , 2 , 2)\nplt.imshow(img2)\nplt.axis('off')\nplt.title(f'duplicated ({duplicate[1]})')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sizes = []\n\nfor row in train.itertuples():\n    img = cv2.imread(os.path.join(train_img, row.filename))\n    sizes.append(img.shape[:2])\n\npd.DataFrame(sizes, columns=[\"h\",\"w\"]).describe()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_image(path):\n    img = Image.open(path)\n    if img.mode == \"RGBA\":\n        img = img.convert(\"RGB\")\n    return img\n\ndef random_flip(img, p=0.5):\n    if random.random() < p:\n        return img.transpose(Image.FLIP_LEFT_RIGHT)\n    return img\n\ndef random_shift(img, max_shift_ratio=0.2 , p=0.6):\n    if random.random() < p:\n        w, h = img.size\n        shift_x = int(random.uniform(-max_shift_ratio, max_shift_ratio) * w)\n        shift_y = int(random.uniform(-0.02, 0.02) * h)\n    \n        affine = (1, 0, shift_x,\n                  0, 1, shift_y)\n    \n        return img.transform((w, h), Image.AFFINE, affine, resample=Image.BICUBIC)\n    return img\n\ndef pad_to_square_random(img, target_size=224, pad_color=(0,0,0)):\n    w, h = img.size\n    scale = target_size / max(w, h)\n\n    new_w = int(w * scale)\n    new_h = int(h * scale)\n    img = img.resize((new_w, new_h), Image.BILINEAR)\n\n    canvas = Image.new(\"RGB\", (target_size, target_size), pad_color)\n\n    left = random.randint(0, target_size - new_w)\n    top  = random.randint(0, target_size - new_h)\n\n    canvas.paste(img, (left, top))\n    return canvas\n\ndef random_brightness(img , p):\n    if random.random()< p:\n        factor = random.uniform(0.5 , 1.5)\n        enhancer = ImageEnhance.Brightness(img)\n        brightened_image = enhancer.enhance(factor)\n        return brightened_image\n    return img\n\ndef random_contrast(img , p):\n    if random.random() < p:\n            factor = random.uniform(0.5 , 1.5)\n            enhancer = ImageEnhance.Contrast(img)\n            contrasted_image = enhancer.enhance(factor)\n            return contrasted_image\n    return img\n\ndef preprocess_pipeline(img, target_size=224):\n    img = pad_to_square_random(img, target_size)\n\n    img = random_flip(img, p=0.5)\n    img = random_shift(img, p=0.7)\n    img = random_brightness(img, p=0.7)\n    img = random_contrast(img, p=0.7)\n\n    return img\n    \ndef preprocess_pipeline_visualize(path, target_size=224):\n    img = load_image(path)\n\n    img = random_flip(img, p=0.5)\n    img = random_shift(img, max_shift_ratio=0.15, p=0.6)\n    img = random_brightness(img, p=0.6)\n    img = random_contrast(img, p=0.6)\n\n    pad_color = tuple(np.random.randint(0, 30, size=3))\n    img = pad_to_square_random(img, target_size, pad_color)\n\n    return img","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:21:12.660843Z","iopub.execute_input":"2026-03-10T21:21:12.661423Z","iopub.status.idle":"2026-03-10T21:21:12.671809Z","shell.execute_reply.started":"2026-03-10T21:21:12.661394Z","shell.execute_reply":"2026-03-10T21:21:12.671131Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img_path = os.path.join(train_img, train.iloc[random.randint(0, len(train)-1), 0])\n\nplt.figure(figsize=(6,6))\nfor i in range(9):\n    aug = preprocess_pipeline_visualize(img_path)\n    plt.subplot(3,3,i+1)\n    plt.imshow(aug)\n    plt.axis(\"off\")\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T10:03:30.821298Z","iopub.execute_input":"2026-03-04T10:03:30.821565Z","iopub.status.idle":"2026-03-04T10:03:34.942017Z","shell.execute_reply.started":"2026-03-04T10:03:30.821544Z","shell.execute_reply":"2026-03-04T10:03:34.940895Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x = load_image(os.path.join(train_img , train.iloc[random.randint(0,train.shape[0]-1),0]))\nimg , scale , left  ,top = pad(x)\nprint(f'scale: {scale} , position as (left , top): {(left , top)}')\nprint(f'size of orginal image is: {(x.size[0] , x.size[1])} and padded one is: {(img.size[0] , img.size[1])}')\nplt.figure()\nplt.subplot(1,2,1)\nplt.imshow(img)\nplt.title('padded')\nplt.axis('off')\nplt.subplot(1,2,2)\nplt.imshow(x)\nplt.title('orginal')\nplt.axis('off')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-04T10:03:34.942865Z","iopub.status.idle":"2026-03-04T10:03:34.943247Z","shell.execute_reply.started":"2026-03-04T10:03:34.943088Z","shell.execute_reply":"2026-03-04T10:03:34.943111Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class JaguarReIdentification(Dataset):\n    def __init__(self , df , path_train , transform = None):\n        self.dataframe = df.reset_index(drop = True)\n        self.path = path_train\n        self.transform = transform\n        self.to_tensor = transforms.ToTensor()\n    def __len__(self):\n        return len(self.dataframe)\n    def __getitem__(self , idx):\n        row = train.iloc[idx]\n        img_path = os.path.join(train_img , row['filename'])\n        img = load_image(img_path)\n        if self.transform:\n            img = self.transform(img)\n        img = self.to_tensor(img)\n        label = row['ground_truth_encoded']\n        label = torch.tensor(label , dtype = torch.long)\n        return img , label\n        ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:21:19.713942Z","iopub.execute_input":"2026-03-10T21:21:19.714249Z","iopub.status.idle":"2026-03-10T21:21:19.719779Z","shell.execute_reply.started":"2026-03-10T21:21:19.714213Z","shell.execute_reply":"2026-03-10T21:21:19.719029Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset = JaguarReIdentification(\n    train , train_img , lambda x: preprocess_pipeline(x)\n)\n\ntrain_idx, valid_idx = train_test_split(\n    range(len(dataset)), test_size=0.2 , stratify = train['ground_truth_encoded']\n)\ntrain_dataset = Subset(dataset, train_idx)\nvalid_dataset = Subset(dataset, valid_idx)\n\ntrain_loader = DataLoader(\n    train_dataset , batch_size = 8 , shuffle=True, num_workers=2, pin_memory=True\n)\nvalid_loader = DataLoader(\n    valid_dataset , batch_size = 8 , shuffle=True, num_workers=2, pin_memory=True\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:21:22.295617Z","iopub.execute_input":"2026-03-10T21:21:22.296276Z","iopub.status.idle":"2026-03-10T21:21:22.304316Z","shell.execute_reply.started":"2026-03-10T21:21:22.296247Z","shell.execute_reply":"2026-03-10T21:21:22.303788Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"images, labels = next(iter(train_loader))\n\nprint(images.shape)   # (B, 3, 224, 224)\nprint(labels)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-23T16:20:22.224060Z","iopub.execute_input":"2026-02-23T16:20:22.224567Z","iopub.status.idle":"2026-02-23T16:20:26.737114Z","shell.execute_reply.started":"2026-02-23T16:20:22.224543Z","shell.execute_reply":"2026-02-23T16:20:26.736401Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ReIDBaseline(nn.Module):\n    def __init__(self , num_classes , embedding_dim):\n        super().__init__()\n        self.model = models.resnet50(pretrained = True)\n        in_features = self.model.fc.in_features\n        self.model.fc = nn.Identity()\n        self.embedder = nn.Linear(in_features , embedding_dim)\n        self.classifier = nn.Linear(embedding_dim , num_classes)\n\n    def forward(self , x):\n        x = self.model(x)\n        embedding = self.embedder(x)\n        embedding = torch.nn.functional.normalize(embedding, p=2.0, dim=1, eps=1e-12)\n        logits = self.classifier(embedding)\n        return logits , embedding\n        ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:21:23.374553Z","iopub.execute_input":"2026-03-10T21:21:23.375076Z","iopub.status.idle":"2026-03-10T21:21:23.380296Z","shell.execute_reply.started":"2026-03-10T21:21:23.375049Z","shell.execute_reply":"2026-03-10T21:21:23.379697Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"num_classes = train['ground_truth_encoded'].nunique()\nembedding_dim = 512\n\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\n\nmodel = ReIDBaseline(num_classes, embedding_dim).to(device)\n\ncriterion = nn.CrossEntropyLoss()\n\noptimizer = torch.optim.AdamW(\n    model.parameters(),\n    lr=3e-4,\n    weight_decay=1e-4\n)\n\nscheduler = torch.optim.lr_scheduler.CosineAnnealingWarmRestarts(\n    optimizer,\n    T_0=10,\n    T_mult=2,\n    eta_min=1e-6\n)\n\ndef train_one_epoch(model, dataloader, criterion, optimizer, scheduler, epoch):\n\n    model.train()\n    total_loss = 0\n    correct = 0\n    total = 0\n\n    for batch_idx, (img, label) in enumerate(dataloader):\n\n        img = img.to(device)\n        label = label.to(device)\n\n        optimizer.zero_grad()\n\n        output, _ = model(img)\n\n        loss = criterion(output, label)\n        loss.backward()\n        optimizer.step()\n\n        scheduler.step(epoch + batch_idx / len(dataloader))\n\n        total_loss += loss.item()\n\n        _, predicted = torch.max(output, 1)\n        total += label.size(0)\n        correct += (predicted == label).sum().item()\n\n    train_acc = 100 * correct / total\n\n    return total_loss / len(dataloader), train_acc\n\ndef evaluate(model, dataloader, criterion):\n\n    model.eval()\n    correct = 0\n    total = 0\n    total_loss = 0\n\n    with torch.no_grad():\n\n        for img, label in dataloader:\n\n            img = img.to(device)\n            label = label.to(device)\n\n            output, _ = model(img)\n\n            loss = criterion(output, label)\n            total_loss += loss.item()\n\n            _, predicted = torch.max(output, 1)\n\n            total += label.size(0)\n            correct += (predicted == label).sum().item()\n\n    accuracy = 100 * correct / total\n\n    return accuracy, total_loss / len(dataloader)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:21:25.023003Z","iopub.execute_input":"2026-03-10T21:21:25.023854Z","iopub.status.idle":"2026-03-10T21:21:26.008007Z","shell.execute_reply.started":"2026-03-10T21:21:25.023826Z","shell.execute_reply":"2026-03-10T21:21:26.007471Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"epochs = 100\nbest_acc = 0\n\nfor epoch in range(epochs):\n\n    train_loss, train_acc = train_one_epoch(\n        model, train_loader, criterion, optimizer, scheduler, epoch\n    )\n\n    val_acc, val_loss = evaluate(model, valid_loader, criterion)\n\n    print(f\"Epoch [{epoch+1}/{epochs}] \"\n          f\"- train_loss: {train_loss:.4f} \"\n          f\"- val_loss: {val_loss:.4f} \"\n          f\"- train_acc: {train_acc:.2f}% \"\n          f\"- val_acc: {val_acc:.2f}%\")\n\n    if val_acc > best_acc:\n        best_acc = val_acc\n\n        torch.save({\n            'epoch': epoch,\n            'model_state_dict': model.state_dict(),\n            'optimizer_state_dict': optimizer.state_dict(),\n            'scheduler_state_dict': scheduler.state_dict(),\n            'best_acc': best_acc\n        }, \"best_checkpoint.pth\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-26T14:51:24.694058Z","iopub.execute_input":"2026-02-26T14:51:24.694702Z","iopub.status.idle":"2026-02-26T20:57:45.238145Z","shell.execute_reply.started":"2026-02-26T14:51:24.694676Z","shell.execute_reply":"2026-02-26T20:57:45.235903Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import re\nimport matplotlib.pyplot as plt\n\nlog_text = \"\"\"\nEpoch [1/100] - train_loss: 3.1939 - val_loss: 3.0825 - train_acc: 25.13% - val_acc: 28.50%\nEpoch [2/100] - train_loss: 2.9708 - val_loss: 2.8804 - train_acc: 30.15% - val_acc: 30.87%\nEpoch [3/100] - train_loss: 2.7651 - val_loss: 2.6296 - train_acc: 36.08% - val_acc: 45.91%\nEpoch [4/100] - train_loss: 2.5716 - val_loss: 2.4556 - train_acc: 43.14% - val_acc: 43.54%\nEpoch [5/100] - train_loss: 2.3850 - val_loss: 2.2122 - train_acc: 49.34% - val_acc: 58.05%\nEpoch [6/100] - train_loss: 2.2076 - val_loss: 2.0547 - train_acc: 55.08% - val_acc: 60.42%\nEpoch [7/100] - train_loss: 2.0556 - val_loss: 1.9181 - train_acc: 59.50% - val_acc: 64.64%\nEpoch [8/100] - train_loss: 1.9388 - val_loss: 1.8444 - train_acc: 63.98% - val_acc: 66.75%\nEpoch [9/100] - train_loss: 1.8707 - val_loss: 1.8124 - train_acc: 66.16% - val_acc: 70.18%\nEpoch [10/100] - train_loss: 1.8509 - val_loss: 1.8079 - train_acc: 68.01% - val_acc: 68.87%\nEpoch [11/100] - train_loss: 2.1148 - val_loss: 2.0074 - train_acc: 51.65% - val_acc: 55.15%\nEpoch [12/100] - train_loss: 1.9240 - val_loss: 1.7409 - train_acc: 56.73% - val_acc: 64.64%\nEpoch [13/100] - train_loss: 1.7466 - val_loss: 1.6436 - train_acc: 59.37% - val_acc: 64.64%\nEpoch [14/100] - train_loss: 1.6055 - val_loss: 1.5901 - train_acc: 64.31% - val_acc: 62.80%\nEpoch [15/100] - train_loss: 1.4615 - val_loss: 1.3276 - train_acc: 67.35% - val_acc: 72.56%\nEpoch [16/100] - train_loss: 1.3395 - val_loss: 1.2282 - train_acc: 69.99% - val_acc: 73.35%\nEpoch [17/100] - train_loss: 1.2320 - val_loss: 1.1304 - train_acc: 73.61% - val_acc: 74.14%\nEpoch [18/100] - train_loss: 1.1134 - val_loss: 1.0220 - train_acc: 75.73% - val_acc: 79.95%\nEpoch [19/100] - train_loss: 1.0149 - val_loss: 0.9566 - train_acc: 77.57% - val_acc: 76.25%\nEpoch [20/100] - train_loss: 0.9306 - val_loss: 0.9462 - train_acc: 80.54% - val_acc: 77.31%\nEpoch [21/100] - train_loss: 0.8783 - val_loss: 0.9104 - train_acc: 81.79% - val_acc: 82.85%\nEpoch [22/100] - train_loss: 0.7943 - val_loss: 0.8353 - train_acc: 83.25% - val_acc: 82.85%\nEpoch [23/100] - train_loss: 0.7315 - val_loss: 0.8260 - train_acc: 85.42% - val_acc: 82.06%\nEpoch [24/100] - train_loss: 0.7060 - val_loss: 0.7765 - train_acc: 85.42% - val_acc: 81.27%\nEpoch [25/100] - train_loss: 0.6726 - val_loss: 0.7613 - train_acc: 86.61% - val_acc: 83.11%\nEpoch [26/100] - train_loss: 0.6485 - val_loss: 0.7250 - train_acc: 86.68% - val_acc: 84.17%\nEpoch [27/100] - train_loss: 0.6328 - val_loss: 0.7432 - train_acc: 87.47% - val_acc: 83.91%\nEpoch [28/100] - train_loss: 0.6253 - val_loss: 0.7314 - train_acc: 87.47% - val_acc: 83.64%\nEpoch [29/100] - train_loss: 0.6204 - val_loss: 0.7180 - train_acc: 88.06% - val_acc: 84.17%\nEpoch [30/100] - train_loss: 0.6218 - val_loss: 0.7123 - train_acc: 88.06% - val_acc: 85.49%\nEpoch [31/100] - train_loss: 1.2154 - val_loss: 1.3383 - train_acc: 69.06% - val_acc: 61.74%\nEpoch [32/100] - train_loss: 1.0601 - val_loss: 1.1829 - train_acc: 73.75% - val_acc: 69.66%\nEpoch [33/100] - train_loss: 0.8817 - val_loss: 1.0815 - train_acc: 78.17% - val_acc: 72.30%\nEpoch [34/100] - train_loss: 0.8454 - val_loss: 0.8811 - train_acc: 79.88% - val_acc: 79.68%\nEpoch [35/100] - train_loss: 0.6834 - val_loss: 0.8002 - train_acc: 84.30% - val_acc: 82.32%\nEpoch [36/100] - train_loss: 0.6296 - val_loss: 0.8385 - train_acc: 86.28% - val_acc: 80.74%\nEpoch [37/100] - train_loss: 0.5901 - val_loss: 0.6849 - train_acc: 86.48% - val_acc: 85.22%\nEpoch [38/100] - train_loss: 0.5216 - val_loss: 0.6582 - train_acc: 88.79% - val_acc: 85.22%\nEpoch [39/100] - train_loss: 0.5267 - val_loss: 0.6658 - train_acc: 87.66% - val_acc: 85.22%\nEpoch [40/100] - train_loss: 0.4799 - val_loss: 0.5970 - train_acc: 89.51% - val_acc: 85.75%\nEpoch [41/100] - train_loss: 0.4566 - val_loss: 0.5021 - train_acc: 89.45% - val_acc: 89.71%\nEpoch [42/100] - train_loss: 0.4108 - val_loss: 0.5624 - train_acc: 91.56% - val_acc: 87.07%\nEpoch [43/100] - train_loss: 0.3718 - val_loss: 0.5330 - train_acc: 91.89% - val_acc: 88.65%\nEpoch [44/100] - train_loss: 0.3427 - val_loss: 0.4829 - train_acc: 93.47% - val_acc: 91.03%\nEpoch [45/100] - train_loss: 0.2976 - val_loss: 0.4469 - train_acc: 94.53% - val_acc: 91.29%\nEpoch [46/100] - train_loss: 0.2872 - val_loss: 0.4932 - train_acc: 94.66% - val_acc: 88.39%\nEpoch [47/100] - train_loss: 0.2753 - val_loss: 0.5077 - train_acc: 94.85% - val_acc: 90.24%\nEpoch [48/100] - train_loss: 0.2729 - val_loss: 0.4329 - train_acc: 95.38% - val_acc: 90.24%\nEpoch [49/100] - train_loss: 0.2407 - val_loss: 0.4782 - train_acc: 96.11% - val_acc: 90.24%\nEpoch [50/100] - train_loss: 0.2136 - val_loss: 0.3928 - train_acc: 97.16% - val_acc: 92.35%\nEpoch [51/100] - train_loss: 0.1874 - val_loss: 0.3900 - train_acc: 98.42% - val_acc: 93.14%\nEpoch [52/100] - train_loss: 0.1949 - val_loss: 0.4191 - train_acc: 98.02% - val_acc: 92.61%\nEpoch [53/100] - train_loss: 0.1736 - val_loss: 0.3834 - train_acc: 98.22% - val_acc: 93.67%\nEpoch [54/100] - train_loss: 0.1627 - val_loss: 0.4259 - train_acc: 98.48% - val_acc: 93.40%\nEpoch [55/100] - train_loss: 0.1507 - val_loss: 0.3855 - train_acc: 99.08% - val_acc: 93.40%\nEpoch [56/100] - train_loss: 0.1526 - val_loss: 0.3714 - train_acc: 98.75% - val_acc: 94.46%\nEpoch [57/100] - train_loss: 0.1429 - val_loss: 0.3696 - train_acc: 98.94% - val_acc: 93.40%\nEpoch [58/100] - train_loss: 0.1445 - val_loss: 0.3616 - train_acc: 98.81% - val_acc: 93.93%\nEpoch [59/100] - train_loss: 0.1343 - val_loss: 0.3562 - train_acc: 99.08% - val_acc: 93.93%\nEpoch [60/100] - train_loss: 0.1254 - val_loss: 0.3511 - train_acc: 99.54% - val_acc: 94.20%\nEpoch [61/100] - train_loss: 0.1193 - val_loss: 0.3929 - train_acc: 99.54% - val_acc: 93.40%\nEpoch [62/100] - train_loss: 0.1145 - val_loss: 0.3434 - train_acc: 99.87% - val_acc: 93.67%\nEpoch [63/100] - train_loss: 0.1166 - val_loss: 0.3483 - train_acc: 99.74% - val_acc: 93.93%\nEpoch [64/100] - train_loss: 0.1138 - val_loss: 0.3496 - train_acc: 99.67% - val_acc: 93.67%\nEpoch [65/100] - train_loss: 0.1123 - val_loss: 0.3152 - train_acc: 99.67% - val_acc: 94.46%\nEpoch [66/100] - train_loss: 0.1104 - val_loss: 0.3494 - train_acc: 99.87% - val_acc: 94.20%\n\"\"\"\n\nepochs = []\ntrain_losses = []\nval_losses = []\ntrain_accs = []\nval_accs = []\n\npattern = r\"Epoch \\[(\\d+)/\\d+\\] - train_loss: ([\\d\\.]+) - val_loss: ([\\d\\.]+) - train_acc: ([\\d\\.]+)% - val_acc: ([\\d\\.]+)%\"\n\nmatches = re.findall(pattern, log_text)\n\nfor match in matches:\n    epoch, t_loss, v_loss, t_acc, v_acc = match\n    epochs.append(int(epoch))\n    train_losses.append(float(t_loss))\n    val_losses.append(float(v_loss))\n    train_accs.append(float(t_acc))\n    val_accs.append(float(v_acc))\n\n\nplt.figure()\nplt.plot(epochs, train_losses)\nplt.plot(epochs, val_losses)\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.title(\"Training vs Validation Loss\")\nplt.show()\n\n\nplt.figure()\nplt.plot(epochs, train_accs)\nplt.plot(epochs, val_accs)\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Accuracy (%)\")\nplt.title(\"Training vs Validation Accuracy\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-26T21:06:38.109463Z","iopub.execute_input":"2026-02-26T21:06:38.110315Z","iopub.status.idle":"2026-02-26T21:06:38.344527Z","shell.execute_reply.started":"2026-02-26T21:06:38.110274Z","shell.execute_reply":"2026-02-26T21:06:38.343638Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"all_images = []\nall_labels = []\n\nfor images, labels in valid_loader:\n    all_images.append(images)\n    all_labels.append(labels)\n\nall_images = torch.cat(all_images)\nall_labels = torch.cat(all_labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-07T11:35:34.023104Z","iopub.execute_input":"2026-03-07T11:35:34.023796Z","iopub.status.idle":"2026-03-07T11:36:49.739508Z","shell.execute_reply.started":"2026-03-07T11:35:34.023767Z","shell.execute_reply":"2026-03-07T11:36:49.738544Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from collections import defaultdict\n\nlabel_indices = defaultdict(list)\n\nfor i, label in enumerate(all_labels):\n    label_indices[int(label)].append(i)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-07T11:36:56.597172Z","iopub.execute_input":"2026-03-07T11:36:56.597493Z","iopub.status.idle":"2026-03-07T11:36:56.603138Z","shell.execute_reply.started":"2026-03-07T11:36:56.597461Z","shell.execute_reply":"2026-03-07T11:36:56.602450Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"query_idx = []\ngallery_idx = []\n\nfor label, indices in label_indices.items():\n    \n    query_idx.append(indices[0])       \n    gallery_idx.extend(indices[1:])    \n\n\nfrom torch.utils.data import TensorDataset\n\nquery_dataset = TensorDataset(\n    all_images[query_idx],\n    all_labels[query_idx]\n)\n\ngallery_dataset = TensorDataset(\n    all_images[gallery_idx],\n    all_labels[gallery_idx]\n)\n\n\nfrom torch.utils.data import DataLoader\n\nquery_loader = DataLoader(\n    query_dataset,\n    batch_size=32,\n    shuffle=False\n)\n\ngallery_loader = DataLoader(\n    gallery_dataset,\n    batch_size=32,\n    shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-07T11:37:01.903618Z","iopub.execute_input":"2026-03-07T11:37:01.903950Z","iopub.status.idle":"2026-03-07T11:37:02.006907Z","shell.execute_reply.started":"2026-03-07T11:37:01.903922Z","shell.execute_reply":"2026-03-07T11:37:02.006117Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"checkpoint = torch.load(\"/kaggle/input/models/aliwannous2021/model3/pytorch/default/1/best_checkpoint.pth\", map_location=device)\n\nmodel.load_state_dict(checkpoint[\"model_state_dict\"])\n\nmodel.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:22:43.927128Z","iopub.execute_input":"2026-03-10T21:22:43.927971Z","iopub.status.idle":"2026-03-10T21:22:44.231046Z","shell.execute_reply.started":"2026-03-10T21:22:43.927941Z","shell.execute_reply":"2026-03-10T21:22:44.230074Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f'{checkpoint[\"best_acc\"]}%')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-07T11:44:29.788512Z","iopub.execute_input":"2026-03-07T11:44:29.789028Z","iopub.status.idle":"2026-03-07T11:44:29.792876Z","shell.execute_reply.started":"2026-03-07T11:44:29.789000Z","shell.execute_reply":"2026-03-07T11:44:29.792295Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class JaguarEmbeddingModel(nn.Module):\n    def __init__(self, trained_model):\n        super().__init__()\n        self.features = trained_model.features\n        \n    def forward(self, x):\n        x = self.features(x)\n        x = x.view(x.size(0), -1)\n        x = torch.nn.functional.normalize(x, dim=1)\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-07T11:44:39.248777Z","iopub.execute_input":"2026-03-07T11:44:39.249204Z","iopub.status.idle":"2026-03-07T11:44:39.254543Z","shell.execute_reply.started":"2026-03-07T11:44:39.249177Z","shell.execute_reply":"2026-03-07T11:44:39.253640Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def extract_embeddings(model, loader):\n\n    model.eval()\n    embeddings = []\n    labels = []\n\n    with torch.no_grad():\n        for images, targets in loader:\n\n            images = images.to(device)\n\n            logits, feats = model(images)\n\n            embeddings.append(feats.cpu())\n            labels.append(targets)\n\n    embeddings = torch.cat(embeddings)\n    labels = torch.cat(labels)\n\n    return embeddings, labels\n\n# Move model to GPU before extracting embeddings\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel = model.to(device)\n\n# Now extract embeddings\nquery_emb, query_labels = extract_embeddings(model, query_loader)\ngallery_emb, gallery_labels = extract_embeddings(model, gallery_loader)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-07T11:51:09.276156Z","iopub.execute_input":"2026-03-07T11:51:09.276796Z","iopub.status.idle":"2026-03-07T11:51:10.627744Z","shell.execute_reply.started":"2026-03-07T11:51:09.276770Z","shell.execute_reply":"2026-03-07T11:51:10.627143Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"similarity = torch.mm(query_emb, gallery_emb.t())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-07T11:51:44.968804Z","iopub.execute_input":"2026-03-07T11:51:44.969406Z","iopub.status.idle":"2026-03-07T11:51:44.979028Z","shell.execute_reply.started":"2026-03-07T11:51:44.969380Z","shell.execute_reply":"2026-03-07T11:51:44.978236Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def compute_rank1(query_emb, query_labels, gallery_emb, gallery_labels):\n    sim = torch.mm(query_emb, gallery_emb.t())\n    correct = 0\n\n    for i in range(len(query_emb)):\n        idx = torch.argmax(sim[i])\n        if gallery_labels[idx] == query_labels[i]:\n            correct += 1\n\n    return correct / len(query_emb)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T09:17:17.623279Z","iopub.execute_input":"2026-03-10T09:17:17.623581Z","iopub.status.idle":"2026-03-10T09:17:17.628118Z","shell.execute_reply.started":"2026-03-10T09:17:17.623555Z","shell.execute_reply":"2026-03-10T09:17:17.627377Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def compute_map(query_emb, query_labels, gallery_emb, gallery_labels):\n    sim_matrix = torch.mm(query_emb, gallery_emb.t())\n    APs = []\n\n    for i in range(len(query_emb)):\n        sims = sim_matrix[i]\n        sorted_indices = torch.argsort(sims, descending=True)\n\n        correct = 0\n        total = 0\n        precisions = []\n\n        for rank, idx in enumerate(sorted_indices):\n            total += 1\n            if gallery_labels[idx] == query_labels[i]:\n                correct += 1\n                precisions.append(correct / total)\n\n        if len(precisions) > 0:\n            APs.append(np.mean(precisions))\n\n    return np.mean(APs)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T09:17:22.570220Z","iopub.execute_input":"2026-03-10T09:17:22.570789Z","iopub.status.idle":"2026-03-10T09:17:22.575942Z","shell.execute_reply.started":"2026-03-10T09:17:22.570762Z","shell.execute_reply":"2026-03-10T09:17:22.575390Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nrank1 = compute_rank1(\n    query_emb,\n    query_labels,\n    gallery_emb,\n    gallery_labels\n)\n\nprint(\"Rank-1 accuracy:\", rank1)\n\nmap_score = compute_map(\n    query_emb,\n    query_labels,\n    gallery_emb,\n    gallery_labels\n)\n\nprint(\"mAP:\", map_score)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-07T11:54:48.546625Z","iopub.execute_input":"2026-03-07T11:54:48.547317Z","iopub.status.idle":"2026-03-07T11:54:48.652182Z","shell.execute_reply.started":"2026-03-07T11:54:48.547289Z","shell.execute_reply":"2026-03-07T11:54:48.651535Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def retrieve(query_index):\n\n    sims = torch.mm(\n        query_emb[query_index].unsqueeze(0),\n        gallery_emb.t()\n    )\n\n    idx = torch.argsort(sims[0], descending=True)\n\n    return idx[:5]\n\nretrieve(0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-07T11:54:53.508088Z","iopub.execute_input":"2026-03-07T11:54:53.508639Z","iopub.status.idle":"2026-03-07T11:54:53.520957Z","shell.execute_reply.started":"2026-03-07T11:54:53.508613Z","shell.execute_reply":"2026-03-07T11:54:53.520265Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n\ntsne = TSNE(n_components=2)\n\nemb2d = tsne.fit_transform(gallery_emb.numpy())\n\nplt.figure(figsize=(8,6))\n\nplt.scatter(\n    emb2d[:,0],\n    emb2d[:,1],\n    c=gallery_labels.numpy(),\n    cmap=\"tab20\"\n)\n\nplt.title(\"Embedding space\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-07T11:54:57.955467Z","iopub.execute_input":"2026-03-07T11:54:57.956433Z","iopub.status.idle":"2026-03-07T11:54:59.392072Z","shell.execute_reply.started":"2026-03-07T11:54:57.956383Z","shell.execute_reply":"2026-03-07T11:54:59.391331Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = 'cuda' if torch.cuda.is_available() else 'cpu'\nmodel = ReIDBaseline(num_classes, embedding_dim)\ncheckpoint = torch.load(\"/kaggle/input/models/aliwannous2021/model3/pytorch/default/1/best_checkpoint.pth\", map_location=device)\nmodel.load_state_dict(checkpoint[\"model_state_dict\"])\nmodel.eval()\nmodel.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:47:57.814200Z","iopub.execute_input":"2026-03-10T21:47:57.814871Z","iopub.status.idle":"2026-03-10T21:47:58.534088Z","shell.execute_reply.started":"2026-03-10T21:47:57.814841Z","shell.execute_reply":"2026-03-10T21:47:58.533472Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test = pd.read_csv(os.path.join(Input , 'test.csv'))\ntest.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T21:48:11.210092Z","iopub.execute_input":"2026-03-10T21:48:11.210402Z","iopub.status.idle":"2026-03-10T21:48:11.271875Z","shell.execute_reply.started":"2026-03-10T21:48:11.210361Z","shell.execute_reply":"2026-03-10T21:48:11.271266Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def PadToSquare(img, target_size=224):\n    \n    w, h = img.size\n    \n    scale = target_size / max(w, h)\n    \n    new_w = int(w * scale)\n    new_h = int(h * scale)\n\n    img = img.resize((new_w, new_h), Image.BILINEAR)\n\n    canvas = Image.new(\"RGB\", (target_size, target_size), (0,0,0))\n\n    left = (target_size - new_w)//2\n    top  = (target_size - new_h)//2\n\n    canvas.paste(img, (left, top))\n\n    return canvas\n\ntransform = transforms.Compose([\n    transforms.Lambda(lambda img: PadToSquare(img)),\n    transforms.ToTensor()\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T22:38:39.245368Z","iopub.execute_input":"2026-03-10T22:38:39.245662Z","iopub.status.idle":"2026-03-10T22:38:39.251044Z","shell.execute_reply.started":"2026-03-10T22:38:39.245637Z","shell.execute_reply":"2026-03-10T22:38:39.250447Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"embeddings = []\nimage_names = []\n\nwith torch.no_grad():\n    \n    for img_name in tqdm(all_images):\n        \n        img_path = os.path.join(test_img, img_name)\n\n        img = Image.open(img_path).convert(\"RGB\")\n        img = transform(img).unsqueeze(0).to(device)\n\n        _, emb = model(img)  \n\n        emb = F.normalize(emb, dim=1)\n\n        embeddings.append(emb.cpu())\n        image_names.append(img_name)\n\nembeddings = torch.cat(embeddings)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T22:38:54.106437Z","iopub.execute_input":"2026-03-10T22:38:54.107229Z","iopub.status.idle":"2026-03-10T22:40:52.716748Z","shell.execute_reply.started":"2026-03-10T22:38:54.107198Z","shell.execute_reply":"2026-03-10T22:40:52.715976Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(embeddings.shape)\nprint(torch.norm(embeddings[0]))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T22:41:07.449931Z","iopub.execute_input":"2026-03-10T22:41:07.450541Z","iopub.status.idle":"2026-03-10T22:41:07.455381Z","shell.execute_reply.started":"2026-03-10T22:41:07.450513Z","shell.execute_reply":"2026-03-10T22:41:07.454790Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_to_index = {name:i for i,name in enumerate(image_names)}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T22:41:10.326802Z","iopub.execute_input":"2026-03-10T22:41:10.327305Z","iopub.status.idle":"2026-03-10T22:41:10.330991Z","shell.execute_reply.started":"2026-03-10T22:41:10.327277Z","shell.execute_reply":"2026-03-10T22:41:10.330266Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"query_idx = test.query_image.map(image_to_index).values\ngallery_idx = test.gallery_image.map(image_to_index).values\n\nsimilarity_matrix = embeddings @ embeddings.T\nsimilarities = similarity_matrix[query_idx, gallery_idx].numpy()\nsimilarities = (similarities + 1) / 2","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T22:41:12.330978Z","iopub.execute_input":"2026-03-10T22:41:12.331262Z","iopub.status.idle":"2026-03-10T22:41:12.356795Z","shell.execute_reply.started":"2026-03-10T22:41:12.331238Z","shell.execute_reply":"2026-03-10T22:41:12.356059Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(similarities.min(),similarities.max())\nprint(similarities.mean(),similarities.std())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T22:41:18.365000Z","iopub.execute_input":"2026-03-10T22:41:18.365580Z","iopub.status.idle":"2026-03-10T22:41:18.370333Z","shell.execute_reply.started":"2026-03-10T22:41:18.365553Z","shell.execute_reply":"2026-03-10T22:41:18.369715Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(similarity_matrix.shape)\nprint(similarity_matrix[:5,:5])\nprint(similarities[:10])\n\nprint(len(image_names))\nprint(len(test.query_image.unique()))\nprint(len(test.gallery_image.unique()))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T22:41:27.507614Z","iopub.execute_input":"2026-03-10T22:41:27.508255Z","iopub.status.idle":"2026-03-10T22:41:27.528121Z","shell.execute_reply.started":"2026-03-10T22:41:27.508226Z","shell.execute_reply":"2026-03-10T22:41:27.527567Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.DataFrame({\n    \"row_id\": test.row_id,\n    \"similarity\": similarities\n})\nprint(submission.head())\nprint(f'Size of my submission: {len(submission)}')\nprint(f'Size of test: {len(test)}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T22:42:03.677540Z","iopub.execute_input":"2026-03-10T22:42:03.677856Z","iopub.status.idle":"2026-03-10T22:42:03.684619Z","shell.execute_reply.started":"2026-03-10T22:42:03.677830Z","shell.execute_reply":"2026-03-10T22:42:03.683999Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-03-10T22:42:06.421099Z","iopub.execute_input":"2026-03-10T22:42:06.421637Z","iopub.status.idle":"2026-03-10T22:42:06.599018Z","shell.execute_reply.started":"2026-03-10T22:42:06.421610Z","shell.execute_reply":"2026-03-10T22:42:06.598198Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}