{"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":"none","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"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-18T08:39:13.861195Z","iopub.execute_input":"2025-07-18T08:39:13.861404Z","iopub.status.idle":"2025-07-18T08:39:16.008087Z","shell.execute_reply.started":"2025-07-18T08:39:13.861385Z","shell.execute_reply":"2025-07-18T08:39:16.007249Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import zipfile\n# ===== 1. zipファイルの解凍 =====\ninput_dir = \"/kaggle/input/dogs-vs-cats-redux-kernels-edition/\"\nwork_dir = \"/kaggle/working/\"\n\nwith zipfile.ZipFile(input_dir + \"train.zip\", \"r\") as zip_ref:\n    zip_ref.extractall(work_dir + \"train/\")\n\nwith zipfile.ZipFile(input_dir + \"test.zip\", \"r\") as zip_ref:\n    zip_ref.extractall(work_dir + \"test/\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T08:39:16.010258Z","iopub.execute_input":"2025-07-18T08:39:16.010632Z","iopub.status.idle":"2025-07-18T08:39:30.786672Z","shell.execute_reply.started":"2025-07-18T08:39:16.010608Z","shell.execute_reply":"2025-07-18T08:39:30.785758Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 必要なライブラリのインポート\nimport os\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import models, transforms\nfrom torch.utils.data import DataLoader, Dataset\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T08:39:30.787513Z","iopub.execute_input":"2025-07-18T08:39:30.787747Z","iopub.status.idle":"2025-07-18T08:39:44.391618Z","shell.execute_reply.started":"2025-07-18T08:39:30.787727Z","shell.execute_reply":"2025-07-18T08:39:44.390864Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ハイパーパラメータの設定\nBATCH_SIZE = 64\nEPOCHS = 3\nIMG_SIZE = 128\nLR = 0.001\n\n# GPUが使えるか確認\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(\"✅ 使用デバイス:\", device)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T08:39:44.392289Z","iopub.execute_input":"2025-07-18T08:39:44.392632Z","iopub.status.idle":"2025-07-18T08:39:44.402290Z","shell.execute_reply.started":"2025-07-18T08:39:44.392612Z","shell.execute_reply":"2025-07-18T08:39:44.401287Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# カスタム Dataset クラス\nclass CatsDogsDataset(Dataset):\n    def __init__(self, filepaths, labels=None, transform=None):\n        self.filepaths = filepaths\n        self.labels = labels\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.filepaths)\n\n    def __getitem__(self, idx):\n        image = Image.open(self.filepaths[idx]).convert('RGB')\n        if self.transform:\n            image = self.transform(image)\n        if self.labels is not None:\n            label = self.labels[idx]\n            return image, label\n        else:\n            return image\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T08:39:44.403241Z","iopub.execute_input":"2025-07-18T08:39:44.403565Z","iopub.status.idle":"2025-07-18T08:39:44.474805Z","shell.execute_reply.started":"2025-07-18T08:39:44.403536Z","shell.execute_reply":"2025-07-18T08:39:44.473726Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Kaggle の入力パスに応じて変更してください\n# 例: /kaggle/input/dogs-vs-cats/train/\ntrain_dir = \"/kaggle/working/train/train\"\n\nall_imgs = [os.path.join(train_dir, fname) for fname in os.listdir(train_dir) if fname.endswith('.jpg')]\nlabels = [1 if 'dog' in fname else 0 for fname in os.listdir(train_dir) if fname.endswith('.jpg')]\n\ntrain_paths, val_paths, train_labels, val_labels = train_test_split(\n    all_imgs, labels, test_size=0.2, stratify=labels, random_state=42\n)\n\ntransform = transforms.Compose([\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.ToTensor(),\n])\n\ntrain_dataset = CatsDogsDataset(train_paths, train_labels, transform)\nval_dataset = CatsDogsDataset(val_paths, val_labels, transform)\n\ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T08:39:44.476085Z","iopub.execute_input":"2025-07-18T08:39:44.476393Z","iopub.status.idle":"2025-07-18T08:39:44.581572Z","shell.execute_reply.started":"2025-07-18T08:39:44.476361Z","shell.execute_reply":"2025-07-18T08:39:44.580482Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# EfficientNet (転移学習) モデルの構築\nmodel = models.efficientnet_b0(pretrained=True)\nmodel.classifier[1] = nn.Linear(model.classifier[1].in_features, 2)\nmodel = model.to(device)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T08:39:44.583781Z","iopub.execute_input":"2025-07-18T08:39:44.584194Z","iopub.status.idle":"2025-07-18T08:39:44.974281Z","shell.execute_reply.started":"2025-07-18T08:39:44.584164Z","shell.execute_reply":"2025-07-18T08:39:44.973374Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 損失関数と最適化手法の定義\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr=LR)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T08:39:44.975458Z","iopub.execute_input":"2025-07-18T08:39:44.975860Z","iopub.status.idle":"2025-07-18T08:39:46.521871Z","shell.execute_reply.started":"2025-07-18T08:39:44.975826Z","shell.execute_reply":"2025-07-18T08:39:46.520834Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 学習ループ\nfor epoch in range(EPOCHS):\n    model.train()\n    total_loss = 0\n    correct = 0\n    total = 0\n\n    for inputs, targets in train_loader:\n        inputs, targets = inputs.to(device), targets.to(device)\n\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, targets)\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item()\n        _, predicted = torch.max(outputs, 1)\n        correct += (predicted == targets).sum().item()\n        total += targets.size(0)\n\n    train_acc = correct / total\n    print(f\"📘 Epoch {epoch+1}: Loss={total_loss:.4f}, Accuracy={train_acc:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T08:39:46.522964Z","iopub.execute_input":"2025-07-18T08:39:46.523280Z","iopub.status.idle":"2025-07-18T09:34:28.920970Z","shell.execute_reply.started":"2025-07-18T08:39:46.523256Z","shell.execute_reply":"2025-07-18T09:34:28.919715Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# モデルの評価\nmodel.eval()\ncorrect = 0\ntotal = 0\n\nwith torch.no_grad():\n    for inputs, targets in val_loader:\n        inputs, targets = inputs.to(device), targets.to(device)\n        outputs = model(inputs)\n        _, predicted = torch.max(outputs, 1)\n        correct += (predicted == targets).sum().item()\n        total += targets.size(0)\n\nval_acc = correct / total\nprint(f\"✅ 検証精度 (Validation Accuracy): {val_acc:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T09:34:28.923153Z","iopub.execute_input":"2025-07-18T09:34:28.923534Z","iopub.status.idle":"2025-07-18T09:35:22.012492Z","shell.execute_reply.started":"2025-07-18T09:34:28.923502Z","shell.execute_reply":"2025-07-18T09:35:22.011660Z"}},"outputs":[],"execution_count":null}]}