{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"},{"sourceId":218421606,"sourceType":"kernelVersion"}],"dockerImageVersionId":30840,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"%%bash\nif [ ! -d \"/kaggle/working/train\" ]; then\n    unzip -q /kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip -d /kaggle/working\nfi\n\nif [ ! -d \"/kaggle/working/test\" ]; then\n    unzip -q /kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip -d /kaggle/working\nfi","metadata":{"_uuid":"b77013f1-b708-4276-a9dc-32dd1953ed8f","_cell_guid":"b8948a67-0968-45db-85e9-6d3858bd1933","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2025-01-22T14:23:47.999527Z","iopub.execute_input":"2025-01-22T14:23:47.999850Z","iopub.status.idle":"2025-01-22T14:24:02.143422Z","shell.execute_reply.started":"2025-01-22T14:23:47.999826Z","shell.execute_reply":"2025-01-22T14:24:02.142515Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport glob\nimport numpy as np\nimport random\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport pytorch_lightning as pl\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import models\nimport cv2\nimport timm\nfrom torch.optim.lr_scheduler import _LRScheduler\nimport math\nimport gc\nfrom pytorch_lightning.callbacks import EarlyStopping, ModelCheckpoint, TQDMProgressBar\nimport time\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2   \nfrom sklearn.model_selection import KFold\nimport tqdm","metadata":{"_uuid":"4062e288-a565-4b69-bc98-3ec3fed33629","_cell_guid":"0e63b5e8-8b64-46b3-a6d9-02b8b0412393","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2025-01-22T14:24:02.144372Z","iopub.execute_input":"2025-01-22T14:24:02.144689Z","iopub.status.idle":"2025-01-22T14:24:16.865406Z","shell.execute_reply.started":"2025-01-22T14:24:02.144659Z","shell.execute_reply":"2025-01-22T14:24:16.864335Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Config:\n    dog = 0.999\n    cat = 0.001\n    train_dir = '/kaggle/working/train'\n    test_dir = '/kaggle/working/test'\n    pretrain_dir = \"/kaggle/input/cat-dog-images-for-classification/cat_dog\"\n    n_fold = 5\n    num_workers = 4\n    pin_memory = True\n    batch_size = 64\n    seed = 2025\n    drop_last = True\n    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n    epochs = 2\n    early_stopping = 20\n    lr = 1e-5\n    optimizer = torch.optim.AdamW\n    warmup_epochs = 0\n    criterion = nn.BCEWithLogitsLoss()\n    size = (224, 224)\n\ncfg = Config()","metadata":{"_uuid":"a32ef7f7-936f-4d4b-be37-28baac75ef54","_cell_guid":"43f4afd6-e495-4371-a3d9-89b34974d603","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2025-01-22T14:24:16.866332Z","iopub.execute_input":"2025-01-22T14:24:16.866624Z","iopub.status.idle":"2025-01-22T14:24:16.899182Z","shell.execute_reply.started":"2025-01-22T14:24:16.866601Z","shell.execute_reply":"2025-01-22T14:24:16.898531Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def seed_everything(seed=cfg.seed):\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":{"_uuid":"9528d221-a2eb-4622-88e3-e584d88e2564","_cell_guid":"b70dbbca-5b94-4cc3-a69b-85b37a3f37b9","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2025-01-22T14:24:16.901395Z","iopub.execute_input":"2025-01-22T14:24:16.901621Z","iopub.status.idle":"2025-01-22T14:24:16.912350Z","shell.execute_reply.started":"2025-01-22T14:24:16.901603Z","shell.execute_reply":"2025-01-22T14:24:16.911670Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class WarmupCosineAnnealingLR(_LRScheduler):\n    def __init__(self, optimizer, warmup_epochs, total_epochs, eta_min=0, last_epoch=-1):\n        self.warmup_epochs = warmup_epochs\n        self.total_epochs = total_epochs\n        self.eta_min = eta_min\n        super(WarmupCosineAnnealingLR, self).__init__(optimizer, last_epoch)\n\n    def get_lr(self):\n        if self.last_epoch < self.warmup_epochs:\n            # Warmup phase\n            warmup_lr = [\n                base_lr * (self.last_epoch + 1) / self.warmup_epochs\n                for base_lr in self.base_lrs\n            ]\n            return warmup_lr\n        else:\n            # Cosine Annealing phase\n            cos_anneal_lr = [\n                self.eta_min + (base_lr - self.eta_min) * \n                (1 + math.cos(math.pi * (self.last_epoch - self.warmup_epochs) / \n                              (self.total_epochs - self.warmup_epochs))) / 2\n                for base_lr in self.base_lrs\n            ]\n            return cos_anneal_lr\n\ndef square_pad_and_resize(image, size):\n    h, w, _ = image.shape\n    \n    max_dim = max(h, w)\n    \n    top = (max_dim - h) // 2\n    bottom = max_dim - h - top\n    left = (max_dim - w) // 2\n    right = max_dim - w - left\n    \n    padded_image = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT, value=(0, 0, 0))\n    \n    resized_image = cv2.resize(padded_image, (size))\n    return resized_image\n\nclass DC_Dataset(Dataset):\n    def __init__(self, paths, valid=False):\n        super().__init__()\n        self.labels = []\n        self.paths = paths\n        self.valid = valid\n        for path in self.paths:\n            if 'dog' in os.path.basename(path):\n                self.labels.append(1 if self.valid else cfg.dog)\n            elif 'cat' in os.path.basename(path):\n                self.labels.append(0 if self.valid else cfg.cat)\n\n        if not self.valid:\n            self.transform = transform = A.Compose([\n                A.ShiftScaleRotate(shift_limit=0.2, scale_limit=0.2, rotate_limit=180, p=0.5),\n                A.HorizontalFlip(p=0.5),\n                A.VerticalFlip(p=0.5),\n                A.RandomBrightnessContrast(p=0.5),\n                A.RGBShift(p=0.5),\n                A.RandomSizedCrop(min_max_height=(cfg.size[0], cfg.size[0]//2), height=cfg.size[0], width=cfg.size[1]),\n                A.Normalize(),\n                ToTensorV2(),\n            ])\n        else:\n            self.transform = transform = A.Compose([\n                A.Normalize(),\n                ToTensorV2(),\n            ])\n\n    def __len__(self):\n        return len(self.paths)\n\n    def __getitem__(self, index):\n        img = cv2.resize(cv2.imread(self.paths[index]), cfg.size)\n        img = self.transform(image=img)['image']\n        label = torch.tensor(self.labels[index],dtype=torch.float32)\n        return img, label\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        return torch.mean(x.clamp(min=self.eps).pow(self.p), dim=(-1,-2)).pow(1.0 / self.p)\n\n    def __repr__(self):\n        return f\"{self.__class__.__name__}(p={self.p.data.tolist()[0]:.4f}, eps={self.eps})\"\n\nclass DC_Model(pl.LightningModule):\n    def __init__(self, model_name='convnext_small', pretrained=True, num_batch=0, fold=0):\n        super().__init__()\n        self.model = timm.create_model(\n            model_name,\n            pretrained=pretrained,\n            num_classes=1,  # ヘッドを後で定義\n        )\n        if not 'vit' in model_name:\n            num_features = self.model.head.in_features\n            self.model.head = nn.Sequential(\n                GeM(),\n                nn.Linear(self.model.head.in_features, 1)\n            )\n\n        self.fold = fold\n        self.num_batch = num_batch\n        self.criterion = cfg.criterion\n        self.model_name = model_name\n        self.pretrained = pretrained\n\n        self.save_hyperparameters()\n\n    def forward(self, x):\n        return self.model(x).squeeze()\n\n    def training_step(self, batch, batch_idx):\n        img, label = batch\n        output = self(img)\n        loss = self.criterion(output, label)\n        self.log('train_loss', loss, prog_bar=True)\n        return loss\n\n    def validation_step(self, batch, batch_idx):\n        img, label = batch\n        output = self(img)\n        loss = self.criterion(output, label)\n        pred = torch.sigmoid(output) > 0.5\n        acc = (pred == label).float().mean()\n        if torch.isnan(loss):\n            return None\n\n        self.log('val_loss', loss, prog_bar=True)\n        self.log('val_acc', acc, prog_bar=True)\n        return loss\n\n    def test_step(self, batch, batch_idx):\n        img, label = batch\n        output = self(img)\n        loss = self.criterion(output, label)\n        pred = torch.sigmoid(output) > 0.5\n        acc = (pred == label).float().mean()\n        self.log('test_loss', loss, prog_bar=True)\n        self.log('test_acc', acc, prog_bar=True)\n\n    def configure_optimizers(self):\n        optimizer = cfg.optimizer(self.parameters(), lr=cfg.lr)\n        scheduler = WarmupCosineAnnealingLR(optimizer, warmup_epochs=cfg.warmup_epochs*self.num_batch, total_epochs=cfg.epochs*self.num_batch+1)\n        return {\n            \"optimizer\": optimizer,\n            \"lr_scheduler\": {\n                \"scheduler\": scheduler,\n                \"interval\": \"step\",\n                \"frequency\": 1,\n            }\n        }\n\ndef collate(x):\n    return","metadata":{"_uuid":"c561eb12-fa52-4f46-bb04-e5f7f37d18af","_cell_guid":"b47c2cb8-1393-49be-92ee-bc0c06e0f8ed","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2025-01-22T14:24:16.913509Z","iopub.execute_input":"2025-01-22T14:24:16.913808Z","iopub.status.idle":"2025-01-22T14:24:16.932909Z","shell.execute_reply.started":"2025-01-22T14:24:16.913780Z","shell.execute_reply":"2025-01-22T14:24:16.932171Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_paths = glob.glob(cfg.train_dir + '/*')\nkf = KFold(n_splits=cfg.n_fold, shuffle=True, random_state=cfg.seed)","metadata":{"_uuid":"3e0f6333-676e-4e0f-9836-cf85525abfe3","_cell_guid":"5a60b231-2354-4673-99e9-18b286cba87b","trusted":true,"collapsed":false,"execution":{"iopub.status.busy":"2025-01-22T14:24:16.933733Z","iopub.execute_input":"2025-01-22T14:24:16.934000Z","iopub.status.idle":"2025-01-22T14:24:17.000191Z","shell.execute_reply.started":"2025-01-22T14:24:16.933979Z","shell.execute_reply":"2025-01-22T14:24:16.999517Z"},"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def train():\n    for fold, (train_index, valid_index) in enumerate(kf.split(image_paths)):\n        train_paths = [image_paths[i] for i in train_index]\n        valid_paths = [image_paths[i] for i in valid_index]\n\n        train_dataset = DC_Dataset(\n            paths=train_paths,\n            valid=False\n        )\n        valid_dataset = DC_Dataset(\n            paths=valid_paths,\n            valid=True\n        )\n\n        train_loader = DataLoader(\n            train_dataset, batch_size=cfg.batch_size, shuffle=True,\n            num_workers=cfg.num_workers, pin_memory=cfg.pin_memory, drop_last=cfg.drop_last,\n        )\n        valid_loader = DataLoader(\n            valid_dataset, batch_size=cfg.batch_size, shuffle=False,\n            num_workers=cfg.num_workers, pin_memory=cfg.pin_memory,\n        )\n\n        trainer = pl.Trainer(\n            max_epochs=cfg.epochs,\n            accelerator='gpu',\n            devices=2,\n            strategy='ddp_notebook',\n            precision='16-mixed',\n            log_every_n_steps=1,\n            enable_checkpointing=False,\n            gradient_clip_val=1.0,\n        )\n\n        model = DC_Model(num_batch=len(train_loader), fold=fold)\n\n        early_stopping = EarlyStopping(\n            monitor='val_loss',\n            patience=cfg.early_stopping,\n            mode='min',\n            verbose=True\n        )\n        checkpoint_callback = ModelCheckpoint(\n            monitor='val_loss',\n            dirpath=f'/kaggle/working/lightning_logs/version_{trainer.logger.version}/checkpoints',\n            filename=f'{model.model_name}-fold{fold}-{cfg.seed}-{{epoch:02d}}-{{val_loss:.4f}}',\n            save_top_k=1,\n            mode='min',\n            verbose=True,\n            save_last=True\n        )\n\n        trainer.callbacks += [checkpoint_callback, early_stopping]\n        trainer.fit(model, train_loader, valid_loader)\n\ntrain()","metadata":{"_uuid":"f0d2a882-c09e-41f3-bdcd-d00c6756b51c","_cell_guid":"046e0011-925b-44c8-97ee-d9bd08beb7d5","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2025-01-22T14:24:17.000914Z","iopub.execute_input":"2025-01-22T14:24:17.001161Z","execution_failed":"2025-01-22T14:27:04.051Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!rm -r /kaggle/working/train\n!rm -r /kaggle/working/test","metadata":{"_uuid":"ffedb839-7fed-413d-a6f6-a98c2ab86047","_cell_guid":"f3004fd4-8a7f-4cb8-b7fa-30bfe3ca4862","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"execution_failed":"2025-01-22T14:27:04.052Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!zip -r /kaggle/working/lightning_logs.zip /kaggle/working/lightning_logs","metadata":{"_uuid":"c2fce801-df0d-4f48-b031-8cf9ceb37bf2","_cell_guid":"a6dac802-b636-4953-9288-0baa0180cfb2","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"execution_failed":"2025-01-22T14:27:04.052Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"_uuid":"248dcf17-5f7e-430e-a760-13417f387e2f","_cell_guid":"7167e6e1-ccc5-4257-850e-a73b8bc3cc58","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null}]}