{"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":130681,"databundleVersionId":15683668}],"dockerImageVersionId":31287,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nfrom PIL import Image\n\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\n\nimport timm\nimport torch.optim as optim\nfrom torch.cuda.amp import GradScaler, autocast\nfrom sklearn.model_selection import StratifiedKFold","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T15:21:15.053053Z","iopub.execute_input":"2026-02-19T15:21:15.053335Z","iopub.status.idle":"2026-02-19T15:21:28.473129Z","shell.execute_reply.started":"2026-02-19T15:21:15.053303Z","shell.execute_reply":"2026-02-19T15:21:28.472442Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_PATH = \"/kaggle/input/computer-vision-homework-2026/food_cv\"\n\nTRAIN_DIR = os.path.join(DATA_PATH, \"train\")\nVAL_DIR = os.path.join(DATA_PATH, \"val\")\nTEST_DIR = os.path.join(DATA_PATH, \"test\")\n\ndevice = torch.device(\"cuda\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T15:21:28.474611Z","iopub.execute_input":"2026-02-19T15:21:28.475081Z","iopub.status.idle":"2026-02-19T15:21:28.479349Z","shell.execute_reply.started":"2026-02-19T15:21:28.475053Z","shell.execute_reply":"2026-02-19T15:21:28.478683Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class FoodDataset(Dataset):\n    def __init__(self, files, labels=None, transform=None):\n        self.files = files\n        self.labels = labels\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.files)\n\n    def __getitem__(self, idx):\n        img = Image.open(self.files[idx]).convert(\"RGB\")\n\n        if self.transform:\n            img = self.transform(img)\n\n        if self.labels is None:\n            return img\n        else:\n            return img, self.labels[idx]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T15:21:28.480317Z","iopub.execute_input":"2026-02-19T15:21:28.480731Z","iopub.status.idle":"2026-02-19T15:21:28.637581Z","shell.execute_reply.started":"2026-02-19T15:21:28.480698Z","shell.execute_reply":"2026-02-19T15:21:28.63687Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Combine train and val\n\nall_files = []\nall_labels = []\n\nfor folder in [TRAIN_DIR, VAL_DIR]:\n    for file in os.listdir(folder):\n        path = os.path.join(folder, file)\n        label = int(file.split(\"_\")[0])\n        all_files.append(path)\n        all_labels.append(label)\n\nall_files = np.array(all_files)\nall_labels = np.array(all_labels)\n\nprint(\"Total images:\", len(all_files))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T15:22:35.812408Z","iopub.execute_input":"2026-02-19T15:22:35.81274Z","iopub.status.idle":"2026-02-19T15:22:35.87984Z","shell.execute_reply.started":"2026-02-19T15:22:35.81271Z","shell.execute_reply":"2026-02-19T15:22:35.878913Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Advanced Augmentation\n\ntrain_transform = transforms.Compose([\n    transforms.RandomResizedCrop(224, scale=(0.7, 1.0)),\n    transforms.RandomHorizontalFlip(),\n    transforms.ColorJitter(0.3, 0.3, 0.3, 0.1),\n    transforms.RandAugment(2, 9),\n    transforms.ToTensor(),\n    transforms.Normalize(\n        [0.485, 0.456, 0.406],\n        [0.229, 0.224, 0.225]\n    )\n])\n\nval_transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(\n        [0.485, 0.456, 0.406],\n        [0.229, 0.224, 0.225]\n    )\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T15:22:36.841212Z","iopub.execute_input":"2026-02-19T15:22:36.841794Z","iopub.status.idle":"2026-02-19T15:22:36.846675Z","shell.execute_reply.started":"2026-02-19T15:22:36.841768Z","shell.execute_reply":"2026-02-19T15:22:36.846078Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#5 fold cross validation\n\nskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n\nfold_models = []\n\nfor fold, (train_idx, val_idx) in enumerate(skf.split(all_files, all_labels)):\n    print(f\"=============FOLD {fold+1}===============\")\n\n    train_files = all_files[train_idx]\n    val_files = all_files[val_idx]\n\n    train_labels = all_labels[train_idx]\n    val_labels = all_labels[val_idx]\n\n    train_dataset = FoodDataset(\n        train_files, train_labels, train_transform\n    )\n    val_dataset = FoodDataset(\n        val_files, val_labels, val_transform\n    )\n    train_loader = DataLoader(\n        train_dataset,\n        batch_size = 32,\n        shuffle = True,\n        num_workers = 4,\n        pin_memory = True\n    )\n    val_loader = DataLoader(\n        val_dataset,\n        batch_size = 32,\n        shuffle = False,\n        num_workers = 4,\n        pin_memory = True\n    )\n\n    model = timm.create_model(\"vit_base_patch16_224\",\n                             pretrained = True,\n                             num_classes = 20)\n    model = model.to(device)\n\n    criterion = nn.CrossEntropyLoss(label_smoothing=0.1)\n    optimizer = optim.AdamW(model.parameters(),\n                           lr = 3e-4,\n                           weight_decay = 1e-4)\n\n    scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=15)\n\n    scaler = GradScaler()\n\n    best_acc = 0\n\n    for epoch in range(15):\n        model.train()\n        for images, labels in tqdm(train_loader):\n            images = images.to(device)\n            labels = labels.to(device)\n\n            optimizer.zero_grad()\n\n            with autocast():\n                outputs = model(images)\n                loss = criterion(outputs, labels)\n\n            scaler.scale(loss).backward()\n            scaler.step(optimizer)\n            scaler.update()\n\n        scheduler.step()\n\n    fold_models.append(model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T15:22:54.665214Z","iopub.execute_input":"2026-02-19T15:22:54.665879Z","iopub.status.idle":"2026-02-19T15:57:46.556937Z","shell.execute_reply.started":"2026-02-19T15:22:54.665851Z","shell.execute_reply":"2026-02-19T15:57:46.555604Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#TTA Boosted Test Predictions\n\ntta_transform = [\n    transforms.Compose([\n        transforms.Resize((224, 224)),\n        transforms.ToTensor(),\n        transforms.Normalize(\n            [0.485, 0.456, 0.406],\n            [0.229, 0.224, 0.225]\n        )\n    ]),\n    transforms.Compose([\n        transforms.Resize((224, 224)),\n        transforms.RandomHorizontalFlip(p=1.0),\n        transforms.ToTensor(),\n        transforms.Normalize(\n            [0.485, 0.456, 0.406],\n            [0.229, 0.224, 0.225]\n        )\n    ])\n]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T15:21:28.716722Z","iopub.status.idle":"2026-02-19T15:21:28.717101Z","shell.execute_reply.started":"2026-02-19T15:21:28.716919Z","shell.execute_reply":"2026-02-19T15:21:28.71694Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Generate Ensemble and TTA Predictions\n\ntest_files = sorted(os.listdir(TEST_DIR))\n\npredictions = []\n\nfor file in tqdm(test_files):\n    img = Image.open(os.path.join(TEST_DIR, file)).convert(\"RGB\")\n\n    logits_sum = 0\n\n    for model in fold_models:\n        model.eval()\n\n        for tform in tta_transform:\n            input_tensor = tform(img).unsqueeze(0).to(device)\n\n            with torch.no_grad():\n                logits_sum += model(input_tensor)\n\n    logits_avg = logits_sum / (len(fold_models) * len(tta_transforms))\n\n    pred = logits_avg.argmax(1).item()\n    img_id = int(file.split(\".\")[0])\n\n    predictions.append([img_id, pred])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T15:21:28.718573Z","iopub.status.idle":"2026-02-19T15:21:28.718861Z","shell.execute_reply.started":"2026-02-19T15:21:28.718708Z","shell.execute_reply":"2026-02-19T15:21:28.718723Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Submission File\n\nsubmission = pd.DataFrame(predictions, columns=[\"ID\", \"label\"])\nsubmission = submission.sort_values(\"ID\")\n\nsubmission.to_csv(\"submission.csv\", index=False)\n\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-19T15:21:28.71999Z","iopub.status.idle":"2026-02-19T15:21:28.720237Z","shell.execute_reply.started":"2026-02-19T15:21:28.720122Z","shell.execute_reply":"2026-02-19T15:21:28.720137Z"}},"outputs":[],"execution_count":null}]}