{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","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"}],"dockerImageVersionId":31041,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-07-06T00:19:17.686578Z","iopub.execute_input":"2025-07-06T00:19:17.686771Z","iopub.status.idle":"2025-07-06T00:19:18.562245Z","shell.execute_reply.started":"2025-07-06T00:19:17.686754Z","shell.execute_reply":"2025-07-06T00:19:18.561631Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ====================================================\n# 0. 依存ライブラリ\n# ====================================================\n!pip install -q timm torchmetrics --upgrade\n\nimport os, zipfile, random, pandas as pd, numpy as np, time, torch, timm\nfrom torch import nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\nfrom torch.amp import autocast, GradScaler\n\n# ====================================================\n# 1. デバイス設定 & 基本ハイパーパラメータ\n# ====================================================\nassert torch.cuda.is_available(), \"Settings → Accelerator を GPU にして再起動してください\"\nn_gpus   = torch.cuda.device_count()\ndevice   = torch.device(\"cuda\")\nprint(f\"💻  Using {n_gpus}×{torch.cuda.get_device_name(0)}\")\n\nIMG_SIZE = 160\nBATCH    = 32 * n_gpus          # GPU 枚数に応じて自動で拡大\nEPOCHS   = 5\nLR       = 3e-4\n\n# 高速化フラグ\ntorch.backends.cudnn.benchmark = True\n\n# ====================================================\n# 2. データ解凍\n# ====================================================\nDATA_DIR = \"/kaggle/input/dogs-vs-cats-redux-kernels-edition\"\nfor zipf in [\"train.zip\", \"test.zip\"]:\n    with zipfile.ZipFile(f\"{DATA_DIR}/{zipf}\") as z:\n        z.extractall(\"/kaggle/working\")\nTRAIN_DIR, TEST_DIR = \"/kaggle/working/train\", \"/kaggle/working/test\"\n\n# ====================================================\n# 3. DataFrame & Dataset\n# ====================================================\ntrain_files = os.listdir(TRAIN_DIR)\nlabels = [1 if f.startswith(\"dog\") else 0 for f in train_files]\ndf = pd.DataFrame({\"filepath\": [f\"{TRAIN_DIR}/{f}\" for f in train_files],\n                   \"label\": labels})\ntrain_df, val_df = train_test_split(df, test_size=0.1,\n                                    stratify=df.label, random_state=42)\n\nmean, std = [0.485,0.456,0.406], [0.229,0.224,0.225]\ntrain_tfms = transforms.Compose([\n    transforms.RandomResizedCrop(IMG_SIZE),\n    transforms.RandomHorizontalFlip(),\n    transforms.ColorJitter(0.2,0.2,0.2,0.1),\n    transforms.ToTensor(),\n    transforms.Normalize(mean, std),\n])\nval_tfms = transforms.Compose([\n    transforms.Resize(IMG_SIZE+32),\n    transforms.CenterCrop(IMG_SIZE),\n    transforms.ToTensor(),\n    transforms.Normalize(mean, std),\n])\n\nclass CatDogDS(Dataset):\n    def __init__(self, df, tfms, infer=False):\n        self.df, self.tfms, self.infer = df.reset_index(drop=True), tfms, infer\n    def __len__(self): return len(self.df)\n    def __getitem__(self, idx):\n        p = self.df.filepath[idx]\n        img = Image.open(p).convert(\"RGB\"); img = self.tfms(img)\n        if self.infer: return img, os.path.basename(p).split(\".\")[0]\n        return img, torch.tensor(self.df.label[idx], dtype=torch.float32)\n\ntrain_dl = DataLoader(CatDogDS(train_df, train_tfms), batch_size=BATCH,\n                      shuffle=True, num_workers=2, pin_memory=True)\nval_dl   = DataLoader(CatDogDS(val_df,   val_tfms),   batch_size=BATCH*2,\n                      shuffle=False, num_workers=2, pin_memory=True)\n\n# ====================================================\n# 4. モデル・損失・OPT\n# ====================================================\nmodel = timm.create_model(\"efficientnet_b0\", pretrained=True, num_classes=1)\nif n_gpus > 1:\n    model = torch.nn.DataParallel(model)   # 自動で複数 GPU へ\nmodel = model.to(device)\n\ncriterion = nn.BCEWithLogitsLoss()\noptimizer = torch.optim.AdamW(model.parameters(), lr=LR, weight_decay=1e-2)\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=EPOCHS)\nscaler    = GradScaler(device='cuda')\n\n# ====================================================\n# 5. 学習ループ\n# ====================================================\nbest_loss = 1e9\nfor epoch in range(1, EPOCHS+1):\n    # ----- train -----\n    model.train(); t0 = time.time()\n    for xb, yb in train_dl:\n        xb = xb.to(device, non_blocking=True)\n        yb = yb.to(device, non_blocking=True).unsqueeze(1)\n        optimizer.zero_grad()\n        with autocast(device_type='cuda'):\n            loss = criterion(model(xb), yb)\n        scaler.scale(loss).backward()\n        scaler.step(optimizer); scaler.update()\n    scheduler.step()\n\n    # ----- val -----\n    model.eval(); val_loss, n = 0, 0\n    with torch.no_grad(), autocast(device_type='cuda'):\n        for xb, yb in val_dl:\n            xb = xb.to(device, non_blocking=True)\n            yb = yb.to(device, non_blocking=True).unsqueeze(1)\n            loss = criterion(model(xb), yb)\n            val_loss += loss.item() * xb.size(0); n += xb.size(0)\n    val_loss /= n\n    print(f\"[{epoch}/{EPOCHS}]  val_loss={val_loss:.4f}  ({time.time()-t0:.1f}s)\")\n\n    if val_loss < best_loss:\n        best_loss = val_loss\n        torch.save(model.state_dict(), \"best.pt\")\n\n# ====================================================\n# 6. 推論 & 提出\n# ====================================================\ntest_files = sorted(os.listdir(TEST_DIR), key=lambda x:int(x.split('.')[0]))\ntest_df = pd.DataFrame({\"filepath\":[f\"{TEST_DIR}/{f}\" for f in test_files]})\ntest_dl = DataLoader(CatDogDS(test_df, val_tfms, infer=True),\n                     batch_size=BATCH*2, shuffle=False,\n                     num_workers=4, pin_memory=True)\n\nmodel.load_state_dict(torch.load(\"best.pt\")); model.eval()\nids, probs = [], []\nwith torch.no_grad(), autocast(device_type='cuda'):\n    for xb, img_ids in test_dl:\n        xb = xb.to(device, non_blocking=True)\n        preds = torch.sigmoid(model(xb)).squeeze().cpu().numpy()\n        ids.extend(img_ids); probs.extend(preds)\n\nsub = pd.DataFrame({\"id\": ids, \"label\": probs})\nsub.to_csv(\"submission.csv\", index=False)\nprint(\"✅  submission.csv saved — ready to upload!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-06T00:19:18.563747Z","iopub.execute_input":"2025-07-06T00:19:18.564063Z","iopub.status.idle":"2025-07-06T00:49:20.023614Z","shell.execute_reply.started":"2025-07-06T00:19:18.564044Z","shell.execute_reply":"2025-07-06T00:49:20.022657Z"}},"outputs":[],"execution_count":null}]}