{"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-24T09:29:52.252567Z","iopub.execute_input":"2025-07-24T09:29:52.253128Z","iopub.status.idle":"2025-07-24T09:29:52.261386Z","shell.execute_reply.started":"2025-07-24T09:29:52.253089Z","shell.execute_reply":"2025-07-24T09:29:52.260342Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport zipfile\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\n\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms, models\nfrom tqdm import tqdm\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T09:29:52.26313Z","iopub.execute_input":"2025-07-24T09:29:52.263529Z","iopub.status.idle":"2025-07-24T09:29:52.286868Z","shell.execute_reply.started":"2025-07-24T09:29:52.263497Z","shell.execute_reply":"2025-07-24T09:29:52.285921Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== 解凍処理 =====\ndata_dir = \"/kaggle/input/dogs-vs-cats-redux-kernels-edition/\"\nout_dir = \"/kaggle/working/\"\n\nfor archive in [\"train.zip\", \"test.zip\"]:\n    with zipfile.ZipFile(os.path.join(data_dir, archive), \"r\") as zip_ref:\n        zip_ref.extractall(os.path.join(out_dir, archive.split('.')[0]))\n\ntrain_root = os.path.join(out_dir, \"train\")\ntest_root = os.path.join(out_dir, \"test\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T09:29:52.287919Z","iopub.execute_input":"2025-07-24T09:29:52.288271Z","iopub.status.idle":"2025-07-24T09:30:11.35035Z","shell.execute_reply.started":"2025-07-24T09:29:52.288241Z","shell.execute_reply":"2025-07-24T09:30:11.349595Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== パラメータ =====\nBATCH_SIZE = 64\nEPOCHS = 3\nIMG_SIZE = 128\nLR = 0.001\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(\" Device:\", device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T09:30:11.352368Z","iopub.execute_input":"2025-07-24T09:30:11.352648Z","iopub.status.idle":"2025-07-24T09:30:11.359046Z","shell.execute_reply.started":"2025-07-24T09:30:11.352626Z","shell.execute_reply":"2025-07-24T09:30:11.357908Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== Datasetクラス =====\nclass CatsDogsDataset(Dataset):\n    def __init__(self, paths, labels=None, transform=None):\n        self.paths = paths\n        self.labels = labels\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.paths)\n\n    def __getitem__(self, idx):\n        img = Image.open(self.paths[idx]).convert(\"RGB\")\n        if self.transform:\n            img = self.transform(img)\n        if self.labels is not None:\n            return img, self.labels[idx]\n        return img","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T09:30:11.360146Z","iopub.execute_input":"2025-07-24T09:30:11.360421Z","iopub.status.idle":"2025-07-24T09:30:11.379322Z","shell.execute_reply.started":"2025-07-24T09:30:11.360391Z","shell.execute_reply":"2025-07-24T09:30:11.378405Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== データ準備 =====\ntrain_dir = os.path.join(train_root, \"train\")\ntest_dir = os.path.join(test_root, \"test\")\n\nfile_list = os.listdir(train_dir)\npaths = [os.path.join(train_dir, fname) for fname in file_list]\nlabels = [1 if \"dog\" in fname else 0 for fname in file_list]\n\nX_train, X_val, y_train, y_val = train_test_split(paths, labels, test_size=0.1, random_state=42)\n\ntransform = transforms.Compose([\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.ToTensor(),\n])\n\ntrain_loader = DataLoader(CatsDogsDataset(X_train, y_train, transform), batch_size=BATCH_SIZE, shuffle=True)\nval_loader = DataLoader(CatsDogsDataset(X_val, y_val, transform), batch_size=BATCH_SIZE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T09:30:11.380476Z","iopub.execute_input":"2025-07-24T09:30:11.381065Z","iopub.status.idle":"2025-07-24T09:30:11.461169Z","shell.execute_reply.started":"2025-07-24T09:30:11.381015Z","shell.execute_reply":"2025-07-24T09:30:11.460202Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== モデルの構築（MobileNetV2） =====\nmodel = models.mobilenet_v2(pretrained=True)\nmodel.classifier[1] = nn.Linear(model.classifier[1].in_features, 2)\nmodel.to(device)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=LR)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T09:30:11.462268Z","iopub.execute_input":"2025-07-24T09:30:11.463325Z","iopub.status.idle":"2025-07-24T09:30:11.593642Z","shell.execute_reply.started":"2025-07-24T09:30:11.463299Z","shell.execute_reply":"2025-07-24T09:30:11.592598Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== 学習 =====\nfor ep in range(EPOCHS):\n    model.train()\n    total_loss = 0.0\n    loop = tqdm(train_loader, desc=f\"[Epoch {ep+1}/{EPOCHS}]\", leave=False)\n    for imgs, lbls in loop:\n        imgs, lbls = imgs.to(device), lbls.to(device)\n        optimizer.zero_grad()\n        loss = criterion(model(imgs), lbls)\n        loss.backward()\n        optimizer.step()\n        total_loss += loss.item()\n        loop.set_postfix(loss=total_loss / (loop.n + 1e-9))\n    print(f\"[Epoch {ep+1}] Training Loss: {total_loss/len(train_loader):.4f}\")\nprint(\" Training complete!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T09:30:11.595029Z","iopub.execute_input":"2025-07-24T09:30:11.595305Z","iopub.status.idle":"2025-07-24T10:20:20.832265Z","shell.execute_reply.started":"2025-07-24T09:30:11.595283Z","shell.execute_reply":"2025-07-24T10:20:20.831344Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== 推論 =====\ntest_files = sorted([f for f in os.listdir(test_dir) if f.endswith(\".jpg\")], key=lambda x: int(x.split('.')[0]))\ntest_paths = [os.path.join(test_dir, fname) for fname in test_files]\n\ntest_loader = DataLoader(CatsDogsDataset(test_paths, transform=transform), batch_size=BATCH_SIZE)\n\nmodel.eval()\nall_preds = []\nwith torch.no_grad():\n    loop = tqdm(test_loader, desc=\" Predicting\", leave=False)\n    for batch in loop:\n        batch = batch.to(device)\n        probs = torch.softmax(model(batch), dim=1)[:, 1]\n        all_preds.extend(probs.cpu().numpy())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T10:20:20.833522Z","iopub.execute_input":"2025-07-24T10:20:20.834142Z","iopub.status.idle":"2025-07-24T10:22:50.474896Z","shell.execute_reply.started":"2025-07-24T10:20:20.834115Z","shell.execute_reply":"2025-07-24T10:22:50.473962Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== 提出用CSV作成 =====\nsubmission = pd.DataFrame({\n    \"id\": [int(fname.split(\".\")[0]) for fname in test_files],\n    \"label\": all_preds\n})\nsubmission.to_csv(\"submission.csv\", index=False)\nprint(\" submission.csv saved!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T10:22:50.477065Z","iopub.execute_input":"2025-07-24T10:22:50.477354Z","iopub.status.idle":"2025-07-24T10:22:50.527844Z","shell.execute_reply.started":"2025-07-24T10:22:50.477333Z","shell.execute_reply":"2025-07-24T10:22:50.527011Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== 評価 =====\nfrom sklearn.metrics import accuracy_score, f1_score\n\ntrue_vals, pred_vals = [], []\nwith torch.no_grad():\n    for imgs, lbls in val_loader:\n        imgs, lbls = imgs.to(device), lbls.to(device)\n        preds = torch.argmax(model(imgs), dim=1)\n        true_vals.extend(lbls.cpu().numpy())\n        pred_vals.extend(preds.cpu().numpy())\n\nacc = accuracy_score(true_vals, pred_vals)\nf1 = f1_score(true_vals, pred_vals)\nprint(f\" Validation Accuracy: {acc:.4f}, F1 Score: {f1:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T10:22:50.52863Z","iopub.execute_input":"2025-07-24T10:22:50.528883Z","iopub.status.idle":"2025-07-24T10:23:20.233527Z","shell.execute_reply.started":"2025-07-24T10:22:50.528865Z","shell.execute_reply":"2025-07-24T10:23:20.232663Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== モデル保存とファイル確認 =====\ntorch.save(model.state_dict(), \"model.pth\")\nprint(\" model.pth saved\")\n\nprint(\" Working Directory Files:\")\nfor f in os.listdir(out_dir):\n    print(\"-\", f)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-24T10:23:20.234626Z","iopub.execute_input":"2025-07-24T10:23:20.234976Z","iopub.status.idle":"2025-07-24T10:23:20.283708Z","shell.execute_reply.started":"2025-07-24T10:23:20.234945Z","shell.execute_reply":"2025-07-24T10:23:20.28264Z"}},"outputs":[],"execution_count":null}]}