{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"%%capture\n!unzip '/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip'\n!unzip '/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-12T04:12:36.833728Z","iopub.execute_input":"2025-09-12T04:12:36.834004Z","iopub.status.idle":"2025-09-12T04:12:58.522796Z","shell.execute_reply.started":"2025-09-12T04:12:36.833982Z","shell.execute_reply":"2025-09-12T04:12:58.521782Z"},"_kg_hide-input":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# First look at few images","metadata":{}},{"cell_type":"code","source":"import os\nfrom glob import glob\nimport cv2\nimport matplotlib.pyplot as plt","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-12T04:12:58.524269Z","iopub.execute_input":"2025-09-12T04:12:58.524567Z","iopub.status.idle":"2025-09-12T04:12:58.728358Z","shell.execute_reply.started":"2025-09-12T04:12:58.524542Z","shell.execute_reply":"2025-09-12T04:12:58.727577Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMG_SIZE = (224, 224)\n\ntrain_path = glob('/kaggle/working/train/*')\ntrain_path[:3]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-12T04:12:58.729339Z","iopub.execute_input":"2025-09-12T04:12:58.729583Z","iopub.status.idle":"2025-09-12T04:12:58.778828Z","shell.execute_reply.started":"2025-09-12T04:12:58.729559Z","shell.execute_reply":"2025-09-12T04:12:58.778087Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Show few images\nfig, axs = plt.subplots(nrows = 2, ncols = 5, figsize = (15,6))\n\n\nfor idx, ax in enumerate(axs.flat):\n    path = train_path[idx]\n    img = cv2.imread(path)\n    img = cv2.resize(img, IMG_SIZE)\n    label =path.split('/')[-1].split('.')[0]\n    ax.set_title(label)\n    ax.imshow(img)\n    ax.axis('off')\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-12T04:12:58.780296Z","iopub.execute_input":"2025-09-12T04:12:58.780513Z","iopub.status.idle":"2025-09-12T04:12:59.977376Z","shell.execute_reply.started":"2025-09-12T04:12:58.780495Z","shell.execute_reply":"2025-09-12T04:12:59.976387Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader, random_split\nfrom torchvision import models, transforms\nfrom PIL import Image\nimport pytorch_lightning as pl\nfrom pytorch_lightning import Trainer\nfrom tqdm import tqdm\n\n# ===============================\n# 1. Кастомный Dataset\n# ===============================\nclass CatDogDataset(Dataset):\n    def __init__(self, folder_path, transform=None):\n        self.folder_path = folder_path\n        self.transform = transform\n        self.image_files = [f for f in os.listdir(folder_path) if f.endswith('.jpg')]\n\n    def __len__(self):\n        return len(self.image_files)\n\n    def __getitem__(self, idx):\n        img_name = self.image_files[idx]\n        img_path = os.path.join(self.folder_path, img_name)\n        image = Image.open(img_path).convert('RGB')\n        label = 0 if img_name.startswith('cat') else 1  # 0 - cat, 1 - dog\n\n        if self.transform:\n            image = self.transform(image)\n        return image, label\n\n# ===============================\n# 2. Трансформации и DataLoader\n# ===============================\ntransform = transforms.Compose([\n    transforms.Resize((224,224)),\n    transforms.ToTensor(),\n    transforms.Normalize([0.485,0.456,0.406],[0.229,0.224,0.225])\n])\n\ndataset = CatDogDataset('/kaggle/working/train', transform=transform)\n\n# Разделение train/val\ntrain_size = int(0.8 * len(dataset))\nval_size = len(dataset) - train_size\ntrain_dataset, val_dataset = random_split(dataset, [train_size, val_size])\n\ntrain_loader = DataLoader(train_dataset, batch_size=16, shuffle=True, num_workers=2)\nval_loader = DataLoader(val_dataset, batch_size=16, shuffle=False, num_workers=2)\n\n# ===============================\n# 3. LightningModule\n# ===============================\nclass CatDogClassifier(pl.LightningModule):\n    def __init__(self, learning_rate=1e-4):\n        super().__init__()\n        self.learning_rate = learning_rate\n        self.num_classes = 2\n\n        # VGG16 с предобученными весами\n        self.model = models.vgg16(pretrained=True)\n\n        # Замораживаем сверточные слои\n        for param in self.model.features.parameters():\n            param.requires_grad = False\n\n        # Новый классификатор\n        self.model.classifier = nn.Sequential(\n            nn.Linear(512*7*7, 256),\n            nn.ReLU(),\n            nn.Dropout(0.5),\n            nn.Linear(256, self.num_classes)\n        )\n\n        self.criterion = nn.CrossEntropyLoss()\n\n    def forward(self, x):\n        return self.model(x)\n\n    def training_step(self, batch, batch_idx):\n        inputs, labels = batch\n        outputs = self(inputs)\n        loss = self.criterion(outputs, labels)\n        preds = torch.argmax(outputs, dim=1)\n        acc = (preds == labels).float().mean()\n        self.log('train_loss', loss, on_step=False, on_epoch=True, prog_bar=True)\n        self.log('train_acc', acc, on_step=False, on_epoch=True, prog_bar=True)\n        return loss\n\n    def validation_step(self, batch, batch_idx):\n        inputs, labels = batch\n        outputs = self(inputs)\n        loss = self.criterion(outputs, labels)\n        preds = torch.argmax(outputs, dim=1)\n        acc = (preds == labels).float().mean()\n        self.log('val_loss', loss, on_step=False, on_epoch=True, prog_bar=True)\n        self.log('val_acc', acc, on_step=False, on_epoch=True, prog_bar=True)\n        return loss\n\n    def configure_optimizers(self):\n        return optim.Adam(self.model.classifier.parameters(), lr=self.learning_rate)\n\n    def predict_step(self, batch, batch_idx):\n        imgs, names = batch  # если твой TestDataset возвращает (image, path)\n        outputs = self(imgs)\n        probs = torch.softmax(outputs, dim=1)\n        preds = torch.argmax(probs, dim=1)\n        return [(int(name.split('.')[0]), prob[1].item()) for (name, prob) in zip(names, probs)]\n        # [{\"path\": p, \"pred\": pred.item(), \"conf\": float(probs[i][pred]), 'prob' : probs[i][1].item() }\n        #         for i, (p, pred) in enumerate(zip(paths, preds))]\n\n   \n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-12T04:17:15.287188Z","iopub.execute_input":"2025-09-12T04:17:15.287769Z","iopub.status.idle":"2025-09-12T04:17:15.320244Z","shell.execute_reply.started":"2025-09-12T04:17:15.287746Z","shell.execute_reply":"2025-09-12T04:17:15.319739Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===============================\n# 4. Обучение с Trainer\n# ===============================\nmodel = CatDogClassifier(learning_rate=1e-4)\ntrainer = Trainer(max_epochs=1, accelerator='auto', log_every_n_steps=10,\n                 # fast_dev_run=3\n                 )\ntrainer.fit(model, train_loader, val_loader)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-12T04:26:59.809443Z","iopub.execute_input":"2025-09-12T04:26:59.809712Z","iopub.status.idle":"2025-09-12T04:28:23.363004Z","shell.execute_reply.started":"2025-09-12T04:26:59.809692Z","shell.execute_reply":"2025-09-12T04:28:23.362388Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import Dataset, DataLoader\nfrom PIL import Image\n\nclass TestDataset(Dataset):\n    def __init__(self, image_dir, transform=None):\n        self.image_dir = image_dir\n        self.transform = transform\n        self.image_files = sorted(os.listdir(image_dir), key=lambda x: int(x.split('.')[0]))\n\n    def __len__(self):\n        return len(self.image_files)\n\n    def __getitem__(self, idx):\n        image_name = self.image_files[idx]\n        image_path = os.path.join(self.image_dir, image_name)\n        image = Image.open(image_path).convert(\"RGB\")\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, image_name\n\ntest_dataset = TestDataset('/kaggle/working/test', transform=transform)\ntest_loader = DataLoader(test_dataset, batch_size=16, shuffle=False)\n\npredictions = trainer.predict(model, test_loader)\n# predictions","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-12T04:28:32.211074Z","iopub.execute_input":"2025-09-12T04:28:32.212136Z","iopub.status.idle":"2025-09-12T04:29:40.525892Z","shell.execute_reply.started":"2025-09-12T04:28:32.212091Z","shell.execute_reply":"2025-09-12T04:29:40.525185Z"},"collapsed":true,"jupyter":{"outputs_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\npredictions = np.vstack(predictions)\ndf = pd.DataFrame(predictions, columns = ['id', 'label'])\ndf['id'] = df['id'].astype('int32')\nprint(df.head(3))\nprint(df.shape)\n\ndf.to_csv('submission.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-12T04:29:49.930481Z","iopub.execute_input":"2025-09-12T04:29:49.930974Z","iopub.status.idle":"2025-09-12T04:29:49.969638Z","shell.execute_reply.started":"2025-09-12T04:29:49.930953Z","shell.execute_reply":"2025-09-12T04:29:49.969028Z"}},"outputs":[],"execution_count":null}]}