{"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":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":126777,"databundleVersionId":15314950}],"dockerImageVersionId":31259,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import gc\nimport torch\n# 1. Hafıza Temizliği\ngc.collect()\ntorch.cuda.empty_cache()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.339032Z","iopub.execute_input":"2026-02-27T14:04:11.339385Z","iopub.status.idle":"2026-02-27T14:04:11.596622Z","shell.execute_reply.started":"2026-02-27T14:04:11.339355Z","shell.execute_reply":"2026-02-27T14:04:11.595714Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\ntrain = pd.read_csv(\"/kaggle/input/jaguar-re-id/train.csv\")\ntest = pd.read_csv(\"/kaggle/input/jaguar-re-id/test.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.597993Z","iopub.execute_input":"2026-02-27T14:04:11.598363Z","iopub.status.idle":"2026-02-27T14:04:11.674636Z","shell.execute_reply.started":"2026-02-27T14:04:11.598324Z","shell.execute_reply":"2026-02-27T14:04:11.673845Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.675615Z","iopub.execute_input":"2026-02-27T14:04:11.675850Z","iopub.status.idle":"2026-02-27T14:04:11.683800Z","shell.execute_reply.started":"2026-02-27T14:04:11.675827Z","shell.execute_reply":"2026-02-27T14:04:11.683091Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.685564Z","iopub.execute_input":"2026-02-27T14:04:11.685998Z","iopub.status.idle":"2026-02-27T14:04:11.701387Z","shell.execute_reply.started":"2026-02-27T14:04:11.685970Z","shell.execute_reply":"2026-02-27T14:04:11.700693Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport random\nimport numpy as np\n# Rastgeleliği sabitle (Reproducibility)\ndef seed_everything(seed=42):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n\nseed_everything()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.702272Z","iopub.execute_input":"2026-02-27T14:04:11.702470Z","iopub.status.idle":"2026-02-27T14:04:11.717881Z","shell.execute_reply.started":"2026-02-27T14:04:11.702443Z","shell.execute_reply":"2026-02-27T14:04:11.717336Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cihaz Ayarı\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Çalışma ortamı: {device}\")\n\n# Dosya Yolları (Kendi ortamına göre kontrol et!)\nTRAIN_PATH = \"/kaggle/input/jaguar-re-id/train/train\"\nTEST_PATH = \"/kaggle/input/jaguar-re-id/test/test\"\nCSV_PATH = \"/kaggle/input/jaguar-re-id/train.csv\"\nTEST_CSV_PATH = \"/kaggle/input/jaguar-re-id/test.csv\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.718754Z","iopub.execute_input":"2026-02-27T14:04:11.719071Z","iopub.status.idle":"2026-02-27T14:04:11.736258Z","shell.execute_reply.started":"2026-02-27T14:04:11.719049Z","shell.execute_reply":"2026-02-27T14:04:11.735675Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nfrom torch.utils.data import Dataset\nclass JaguarDataset(Dataset):\n    def __init__(self, df, img_dir, transforms=None, mode='train', use_mask=True):\n        self.df = df\n        self.img_dir = img_dir\n        self.transforms = transforms\n        self.mode = mode\n        self.use_mask = use_mask\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n        img_path = f\"{self.img_dir}/{row['filename']}\"\n        \n        # Görüntüyü 4 kanal (RGBA) oku\n        image = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)\n        if image is None:\n            raise FileNotFoundError(f\"Görüntü yok: {img_path}\")\n            \n        image = cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA)\n\n        # HİBRİT MASKELEME STRATEJİSİ (Overfitting Önleyici)\n        if self.use_mask and image.shape[2] == 4:\n            rgb = image[:, :, :3]\n            mask = image[:, :, 3]\n            \n            p = random.random()\n            if p < 0.4:   # %40 Siyah Arka Plan\n                rgb[mask == 0] = [0, 0, 0]\n            elif p < 0.7: # %30 Rastgele Renk (Model arka planı ezberlemesin)\n                random_color = [random.randint(0, 255) for _ in range(3)]\n                rgb[mask == 0] = random_color\n            else:         # %30 Orijinal (Test setine hazırlık)\n                pass \n            \n            image = rgb\n        else:\n            image = image[:, :, :3]\n\n        if self.transforms:\n            augmented = self.transforms(image=image)\n            image = augmented['image']\n\n        if self.mode == 'train':\n            return image, torch.tensor(row['label_idx'], dtype=torch.long)\n        else:\n            return image","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.737093Z","iopub.execute_input":"2026-02-27T14:04:11.737327Z","iopub.status.idle":"2026-02-27T14:04:11.753188Z","shell.execute_reply.started":"2026-02-27T14:04:11.737308Z","shell.execute_reply":"2026-02-27T14:04:11.752573Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nfrom torch.utils.data.sampler import Sampler\nclass BalancedBatchSampler(Sampler):\n    def __init__(self, labels, n_classes, n_samples):\n        self.labels = labels\n        self.n_classes = n_classes\n        self.n_samples = n_samples\n        self.label_to_indices = {l: np.where(self.labels == l)[0] for l in np.unique(self.labels)}\n        self.labels_list = list(self.label_to_indices.keys())\n\n    def __iter__(self):\n        num_batches = len(self.labels) // (self.n_classes * self.n_samples)\n        for _ in range(num_batches):\n            batch = []\n            classes = random.sample(self.labels_list, self.n_classes)\n            for cls in classes:\n                indices = self.label_to_indices[cls]\n                if len(indices) < self.n_samples:\n                    batch.extend(np.random.choice(indices, self.n_samples, replace=True))\n                else:\n                    batch.extend(np.random.choice(indices, self.n_samples, replace=False))\n            yield batch\n\n    def __len__(self):\n        return len(self.labels) // (self.n_classes * self.n_samples)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.753970Z","iopub.execute_input":"2026-02-27T14:04:11.754228Z","iopub.status.idle":"2026-02-27T14:04:11.772046Z","shell.execute_reply.started":"2026-02-27T14:04:11.754207Z","shell.execute_reply":"2026-02-27T14:04:11.771498Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import albumentations as A\nfrom albumentations.pytorch import ToTensorV2\ntrain_transforms = A.Compose([\n    A.Resize(384, 384),\n    A.HorizontalFlip(p=0.5),\n    A.RandomBrightnessContrast(p=0.2),\n    A.ShiftScaleRotate(shift_limit=0.1, scale_limit=0.1, rotate_limit=15, p=0.5),\n    A.HueSaturationValue(hue_shift_limit=10, sat_shift_limit=20, val_shift_limit=10, p=0.3),\n    A.CoarseDropout(max_holes=4, max_height=64, max_width=64, fill_value=0, p=0.5),\n    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ToTensorV2(),\n])\n\nval_transforms = A.Compose([\n    A.Resize(384, 384),\n    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n    ToTensorV2(),\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.773018Z","iopub.execute_input":"2026-02-27T14:04:11.773311Z","iopub.status.idle":"2026-02-27T14:04:11.795928Z","shell.execute_reply.started":"2026-02-27T14:04:11.773279Z","shell.execute_reply":"2026-02-27T14:04:11.795402Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\n# Veri Okuma\ntrain_df = pd.read_csv(CSV_PATH)\nle = LabelEncoder()\ntrain_df['label_idx'] = le.fit_transform(train_df['ground_truth'])\nnum_classes = len(le.classes_)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.798021Z","iopub.execute_input":"2026-02-27T14:04:11.798404Z","iopub.status.idle":"2026-02-27T14:04:11.811783Z","shell.execute_reply.started":"2026-02-27T14:04:11.798369Z","shell.execute_reply":"2026-02-27T14:04:11.811255Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import StratifiedKFold\n# Stratified K-Fold\nskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\nfor fold, (_, val_idx) in enumerate(skf.split(train_df, train_df['label_idx'])):\n    train_df.loc[val_idx, 'fold'] = fold","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.812560Z","iopub.execute_input":"2026-02-27T14:04:11.812839Z","iopub.status.idle":"2026-02-27T14:04:11.832314Z","shell.execute_reply.started":"2026-02-27T14:04:11.812806Z","shell.execute_reply":"2026-02-27T14:04:11.831602Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import DataLoader\n# Dataset ve Loader\ntrain_ds = JaguarDataset(train_df[train_df.fold != 0], TRAIN_PATH, transforms=train_transforms)\nval_ds = JaguarDataset(train_df[train_df.fold == 0], TRAIN_PATH, transforms=val_transforms)\n\nsampler = BalancedBatchSampler(train_ds.df['label_idx'].values, n_classes=6, n_samples=4)\ntrain_loader = DataLoader(train_ds, batch_sampler=sampler, num_workers=4,pin_memory=True)\nval_loader = DataLoader(val_ds, batch_size=16, shuffle=False, num_workers=4,pin_memory=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.833228Z","iopub.execute_input":"2026-02-27T14:04:11.833559Z","iopub.status.idle":"2026-02-27T14:04:11.846115Z","shell.execute_reply.started":"2026-02-27T14:04:11.833520Z","shell.execute_reply":"2026-02-27T14:04:11.845499Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nclass GeM(nn.Module):\n    def __init__(self, p=3, eps=1e-6):\n        super(GeM, self).__init__()\n        self.p = nn.Parameter(torch.ones(1) * p)\n        self.eps = eps\n\n    def forward(self, x):\n        x = x.clamp(min=self.eps).pow(self.p)\n        if len(x.shape) == 4: \n            x = F.avg_pool2d(x, (x.size(-2), x.size(-1)))\n            x = x.view(x.size(0), -1) \n        elif len(x.shape) == 3: \n            x = x.mean(dim=1)\n        return x.pow(1./self.p)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.846996Z","iopub.execute_input":"2026-02-27T14:04:11.847311Z","iopub.status.idle":"2026-02-27T14:04:11.858752Z","shell.execute_reply.started":"2026-02-27T14:04:11.847289Z","shell.execute_reply":"2026-02-27T14:04:11.858203Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install pytorch-metric-learning\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nimport timm\nimport math\nfrom pytorch_metric_learning import losses, miners\n\n# --- ArcFace Loss Sınıfı ---\nclass ArcFaceLossManual(nn.Module):\n    def __init__(self, num_classes, embedding_size, s=30.0, m=0.50):\n        super().__init__()\n        self.s = s\n        self.m = m\n        self.weight = nn.Parameter(torch.FloatTensor(num_classes, embedding_size))\n        nn.init.xavier_uniform_(self.weight)\n\n    def forward(self, embeddings, labels):\n        # Cosine similarity (L2 normalize edilmiş ağırlıklar ve embeddingler ile)\n        cosine = F.linear(F.normalize(embeddings), F.normalize(self.weight))\n        sine = torch.sqrt(1.0 - torch.pow(cosine, 2))\n        \n        # cos(theta + m) açılımı\n        phi = cosine * math.cos(self.m) - sine * math.sin(self.m)\n        \n        # Sadece doğru sınıfa marj uygula\n        one_hot = torch.zeros(cosine.size(), device=embeddings.device)\n        one_hot.scatter_(1, labels.view(-1, 1).long(), 1)\n        \n        output = (one_hot * phi) + ((1.0 - one_hot) * cosine)\n        return F.cross_entropy(output * self.s, labels)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:11.859738Z","iopub.execute_input":"2026-02-27T14:04:11.860147Z","iopub.status.idle":"2026-02-27T14:04:15.308287Z","shell.execute_reply.started":"2026-02-27T14:04:11.860116Z","shell.execute_reply":"2026-02-27T14:04:15.307440Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.cuda.amp import autocast, GradScaler\nclass JaguarReIDModel(nn.Module):\n    def __init__(self, model_name='hf-hub:BVRA/MegaDescriptor-L-384', pretrained=True):\n        super().__init__()\n        self.backbone = timm.create_model(model_name, pretrained=pretrained, num_classes=0)\n        self.backbone.set_grad_checkpointing(True)\n        self.pool = GeM(p=3)\n        self.num_features = self.backbone.num_features\n\n    def forward(self, x):\n        feats = self.backbone(x)\n        feats = self.pool(feats)\n        return feats \n\nprint(\"Model Yükleniyor: MegaDescriptor-L-384 (GeM Pooling ile)...\")\nmodel = JaguarReIDModel().to(device)\n\nif torch.cuda.device_count() > 1:\n    print(f\"{torch.cuda.device_count()} adet GPU bulundu! Paralel eğitim başlatılıyor...\")\n    model = nn.DataParallel(model)\n\nembedding_size = model.module.num_features if isinstance(model, nn.DataParallel) else model.num_features\n\n\n\n\n\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:15.310339Z","iopub.execute_input":"2026-02-27T14:04:15.310624Z","iopub.status.idle":"2026-02-27T14:04:20.125162Z","shell.execute_reply.started":"2026-02-27T14:04:15.310594Z","shell.execute_reply":"2026-02-27T14:04:20.124391Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\narcface_criterion = ArcFaceLossManual(num_classes=num_classes, embedding_size=embedding_size).to(device)\n\n# Triplet Loss Eklentileri\ntriplet_criterion = losses.TripletMarginLoss(margin=0.3).to(device)\nminer = miners.TripletMarginMiner(margin=0.3, type_of_triplets=\"hard\").to(device)\n\n# Optimizer artık hem modelin hem ArcFace'in ağırlıklarını eğitiyor\noptimizer = optim.AdamW([\n    {'params': model.parameters()},\n    {'params': arcface_criterion.parameters()}\n], lr=1e-4, weight_decay=1e-2)\nscaler = GradScaler()\nscheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=15)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:05:23.108435Z","iopub.execute_input":"2026-02-27T14:05:23.109021Z","iopub.status.idle":"2026-02-27T14:05:23.117414Z","shell.execute_reply.started":"2026-02-27T14:05:23.108989Z","shell.execute_reply":"2026-02-27T14:05:23.116688Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"PRINT_FREQ = 50 # Her 50 batch'te bir ekrana yazsın (Çok sık yazarsa çıktı kirlenir)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:05:30.030721Z","iopub.execute_input":"2026-02-27T14:05:30.031268Z","iopub.status.idle":"2026-02-27T14:05:30.034723Z","shell.execute_reply.started":"2026-02-27T14:05:30.031237Z","shell.execute_reply":"2026-02-27T14:05:30.034002Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import time\ndef train_one_epoch_log(model, loader, criterion, optimizer, device, scaler, epoch, total_epochs, accumulation_steps=1):\n    model.train()\n    running_loss = 0.0\n    optimizer.zero_grad()\n    \n    steps_per_epoch = len(loader)\n    start_time = time.time()\n    \n    for step, (images, labels) in enumerate(loader):\n        images, labels = images.to(device), labels.to(device)\n        \n        # Mixed Precision\n        with autocast():\n            feats = model(images)\n            \n            # ArcFace ve Triplet Loss Hesapla\n            loss_arc = arcface_criterion(feats, labels)\n            \n            hard_pairs = miner(feats, labels)\n            loss_triplet = triplet_criterion(feats, labels, hard_pairs)\n            \n            # İki loss'u topla\n            loss = loss_arc + loss_triplet \n            loss = loss / accumulation_steps\n        \n        scaler.scale(loss).backward()\n        \n        if (step + 1) % accumulation_steps == 0:\n            scaler.step(optimizer)\n            scaler.update()\n            optimizer.zero_grad()\n            \n        loss_val = loss.item() * accumulation_steps\n        running_loss += loss_val\n        \n        # --- SATIR SATIR LOGLAMA KISMI ---\n        if (step + 1) % PRINT_FREQ == 0 or (step + 1) == steps_per_epoch:\n            elapsed = time.time() - start_time\n            # Örn: Epoch: [1/15] Step: [50/240] Loss: 12.3450 Time: 15s\n            print(f\"Epoch: [{epoch+1}/{total_epochs}] \"\n                  f\"Step: [{step+1}/{steps_per_epoch}] \"\n                  f\"Loss: {loss_val:.4f} \"\n                  f\"Time: {elapsed:.0f}s\")\n            \n    return running_loss / len(loader)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:05:35.180391Z","iopub.execute_input":"2026-02-27T14:05:35.180707Z","iopub.status.idle":"2026-02-27T14:05:35.188263Z","shell.execute_reply.started":"2026-02-27T14:05:35.180677Z","shell.execute_reply":"2026-02-27T14:05:35.187670Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def validate_one_epoch_log(model, loader, criterion, device):\n    model.eval()\n    running_loss = 0.0\n    \n    with torch.no_grad():\n        for images, labels in loader: # TQDM yok, düz döngü\n            images, labels = images.to(device), labels.to(device)\n            \n            with autocast():\n                feats = model(images)\n                loss = arcface_criterion(feats, labels)\n                \n            running_loss += loss.item()\n            \n    return running_loss / len(loader)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:05:39.616246Z","iopub.execute_input":"2026-02-27T14:05:39.616855Z","iopub.status.idle":"2026-02-27T14:05:39.621581Z","shell.execute_reply.started":"2026-02-27T14:05:39.616814Z","shell.execute_reply":"2026-02-27T14:05:39.620856Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- ANA DÖNGÜ ---\n\nEPOCHS = 15\nACCUMULATION_STEPS = 2\npatience = 4\ncounter = 0\nbest_val_loss = float('inf')\nhistory = {'train_loss': [], 'val_loss': []}\n\nprint(f\"🚀 Eğitim Başlıyor (Satır Satır Log Modu)...\")\n\nfor epoch in range(EPOCHS):\n    print(f\"\\n{'='*20} Epoch {epoch+1} Başlıyor {'='*20}\")\n    \n    # 1. Eğitim (Epoch numarasını da gönderiyoruz ki loglayabilsin)\n    train_loss = train_one_epoch_log(model, train_loader, arcface_criterion, optimizer, device, scaler, epoch, EPOCHS, ACCUMULATION_STEPS)\n    \n    # 2. Validasyon\n    print(\"Validasyon yapılıyor...\")\n    val_loss = validate_one_epoch_log(model, val_loader, arcface_criterion, device)\n    \n    # 3. Scheduler\n    scheduler.step()\n    current_lr = optimizer.param_groups[0]['lr']\n    \n    # Kayıt\n    history['train_loss'].append(train_loss)\n    history['val_loss'].append(val_loss)\n    \n    print(f\"\\n>>> SONUÇ: Train Loss: {train_loss:.4f} | Val Loss: {val_loss:.4f} | LR: {current_lr:.6f}\")\n    \n    # 4. Checkpoint\n    if val_loss < best_val_loss:\n        print(f\"✅ İyileşme Var! ({best_val_loss:.4f} --> {val_loss:.4f}). Kaydediliyor...\")\n        best_val_loss = val_loss\n        counter = 0\n        if isinstance(model, nn.DataParallel):\n            torch.save(model.module.state_dict(), \"best_jaguar_model.pth\")\n        else:\n            torch.save(model.state_dict(), \"best_jaguar_model.pth\")\n    else:\n        counter += 1\n        print(f\"⚠️ İyileşme Yok. Sabır: {counter}/{patience}\")\n        if counter >= patience:\n            print(\"🛑 Erken Durdurma!\")\n            break\n\nprint(\"\\nEğitim Tamamlandı.\")\n\n# En iyi modeli geri yükle\nprint(\"En iyi model ağırlıkları yükleniyor...\")\nif isinstance(model, nn.DataParallel):\n    model.module.load_state_dict(torch.load(\"best_jaguar_model.pth\"))\nelse:\n    model.load_state_dict(torch.load(\"best_jaguar_model.pth\"))\n    \n        \n        \n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:05:44.027969Z","iopub.execute_input":"2026-02-27T14:05:44.028293Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nplt.figure(figsize=(10, 5))\nplt.plot(history['train_loss'], label='Train Loss')\nplt.plot(history['val_loss'], label='Validation Loss')\nplt.title('Training ve Validation Kayıp Grafiği')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend()\nplt.grid(True)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:20.142480Z","iopub.status.idle":"2026-02-27T14:04:20.142695Z","shell.execute_reply.started":"2026-02-27T14:04:20.142591Z","shell.execute_reply":"2026-02-27T14:04:20.142604Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.cuda.empty_cache()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:20.143972Z","iopub.status.idle":"2026-02-27T14:04:20.144311Z","shell.execute_reply.started":"2026-02-27T14:04:20.144151Z","shell.execute_reply":"2026-02-27T14:04:20.144175Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn.functional as F\nimport pandas as pd\nfrom torch.utils.data import DataLoader\n\nmodel.eval()\nall_embeddings = []\ntest_files = sorted(os.listdir(TEST_PATH))\ntest_df_real = pd.DataFrame({'filename': test_files})\n\n# Test Dataset (Önceki JaguarDataset sınıfını kullanır)\ntest_ds = JaguarDataset(df=test_df_real, img_dir=TEST_PATH, transforms=val_transforms, mode='test', use_mask=False)\ntest_loader = DataLoader(test_ds, batch_size=32, shuffle=False)\n\nprint(\"Test embeddingleri TTA (Horizontal Flip) ile çıkarılıyor...\")\nwith torch.no_grad():\n    # DÜZELTME: test_loader üzerinden dönen for döngüsü eklendi\n    for images in test_loader:\n        # DÜZELTME: Veriyi modele vermeden önce GPU'ya (veya cihazına) gönder\n        images = images.to(device)\n        \n        # 1. TTA: Batch içindeki tüm resimleri yatay çevir (Width ekseni = 3. boyut)\n        images_flipped = torch.flip(images, dims=[3])\n        \n        # 2. İleri Yayılım (Forward Pass)\n        feats_orig = model(images)\n        feats_flip = model(images_flipped)\n        \n        # 3. Sadece topla ve normalize et\n        feats_combined = feats_orig + feats_flip\n        feats_normalized = F.normalize(feats_combined, p=2, dim=1)\n        \n        # 4. Bellek (VRAM) tasarrufu için sonuçları CPU'ya alıp listeye ekle\n        all_embeddings.append(feats_normalized.cpu())\n\n# Tüm batch'lerden gelen vektörleri tek bir matriste birleştir\ntest_embeddings = torch.cat(all_embeddings)\nprint(f\"✅ TTA işlemi tamamlandı! Toplam çıkarılan özellik vektörü: {test_embeddings.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:20.145066Z","iopub.status.idle":"2026-02-27T14:04:20.145354Z","shell.execute_reply.started":"2026-02-27T14:04:20.145189Z","shell.execute_reply":"2026-02-27T14:04:20.145203Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\nif torch.cuda.is_available():\n    test_embeddings = test_embeddings.cuda()\n\n# Orijinal temiz kosinüs benzerliği matrisi\nsim_matrix = torch.mm(test_embeddings, test_embeddings.t()).cpu().numpy()\n\nsubmission_df = pd.read_csv('/kaggle/input/jaguar-re-id/test.csv')\nname_to_idx = {name: i for i, name in enumerate(test_files)}\n\nscores = []\nfor _, row in submission_df.iterrows():\n    try:\n        idx1 = name_to_idx[row['query_image']]\n        idx2 = name_to_idx[row['gallery_image']]\n        scores.append(sim_matrix[idx1, idx2])\n    except KeyError:\n        scores.append(-1.0) \n\nsubmission_df['similarity'] = scores\n\n# Güvenli Min-Max Ölçekleme\nmin_val = submission_df['similarity'].min()\nmax_val = submission_df['similarity'].max()\n\nif max_val - min_val > 0:\n    submission_df['similarity'] = (submission_df['similarity'] - min_val) / (max_val - min_val)\nelse:\n    submission_df['similarity'] = 0.0\n\nsubmission_df[['row_id', 'similarity']].to_csv('submission.csv', index=False)\nprint(\"submission.csv hazır!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-27T14:04:20.146211Z","iopub.status.idle":"2026-02-27T14:04:20.146534Z","shell.execute_reply.started":"2026-02-27T14:04:20.146379Z","shell.execute_reply":"2026-02-27T14:04:20.146401Z"}},"outputs":[],"execution_count":null}]}