{"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-25T13:31:27.817063Z","iopub.execute_input":"2025-07-25T13:31:27.817373Z","iopub.status.idle":"2025-07-25T13:31:30.534178Z","shell.execute_reply.started":"2025-07-25T13:31:27.817344Z","shell.execute_reply":"2025-07-25T13:31:30.532202Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import zipfile\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\nimport torchvision.transforms as transforms\nimport torchvision.models as models\nfrom tqdm import tqdm","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-25T13:31:30.539922Z","iopub.execute_input":"2025-07-25T13:31:30.541102Z","iopub.status.idle":"2025-07-25T13:31:42.473921Z","shell.execute_reply.started":"2025-07-25T13:31:30.541045Z","shell.execute_reply":"2025-07-25T13:31:42.473167Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== zipファイルの解凍 =====\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]))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-25T13:31:42.474763Z","iopub.execute_input":"2025-07-25T13:31:42.475127Z","iopub.status.idle":"2025-07-25T13:31:57.720911Z","shell.execute_reply.started":"2025-07-25T13:31:42.475104Z","shell.execute_reply":"2025-07-25T13:31:57.719938Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_root = os.path.join(out_dir, \"train\")\ntest_root = os.path.join(out_dir, \"test\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-25T13:31:57.721835Z","iopub.execute_input":"2025-07-25T13:31:57.722072Z","iopub.status.idle":"2025-07-25T13:31:57.727428Z","shell.execute_reply.started":"2025-07-25T13:31:57.722052Z","shell.execute_reply":"2025-07-25T13:31:57.726128Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== パラメータ =====\nBATCH_SIZE = 64\nEPOCHS = 3\nIMG_SIZE = 128\nLR = 0.001\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(\" Device:\", device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-25T13:31:57.729639Z","iopub.execute_input":"2025-07-25T13:31:57.729925Z","iopub.status.idle":"2025-07-25T13:31:57.802432Z","shell.execute_reply.started":"2025-07-25T13:31:57.729906Z","shell.execute_reply":"2025-07-25T13:31:57.801461Z"}},"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-25T13:31:57.803212Z","iopub.execute_input":"2025-07-25T13:31:57.803440Z","iopub.status.idle":"2025-07-25T13:31:57.822719Z","shell.execute_reply.started":"2025-07-25T13:31:57.803422Z","shell.execute_reply":"2025-07-25T13:31:57.821718Z"}},"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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-25T13:31:57.823608Z","iopub.execute_input":"2025-07-25T13:31:57.823896Z","iopub.status.idle":"2025-07-25T13:31:57.890606Z","shell.execute_reply.started":"2025-07-25T13:31:57.823871Z","shell.execute_reply":"2025-07-25T13:31:57.889782Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===== データ変換とDataLoader =====\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-25T13:31:57.891580Z","iopub.execute_input":"2025-07-25T13:31:57.891890Z","iopub.status.idle":"2025-07-25T13:31:57.897655Z","shell.execute_reply.started":"2025-07-25T13:31:57.891860Z","shell.execute_reply":"2025-07-25T13:31:57.896694Z"}},"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-25T13:31:57.898543Z","iopub.execute_input":"2025-07-25T13:31:57.898798Z","iopub.status.idle":"2025-07-25T13:31:58.193208Z","shell.execute_reply.started":"2025-07-25T13:31:57.898776Z","shell.execute_reply":"2025-07-25T13:31:58.192215Z"}},"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-25T13:31:58.194211Z","iopub.execute_input":"2025-07-25T13:31:58.194545Z","iopub.status.idle":"2025-07-25T14:13:22.040359Z","shell.execute_reply.started":"2025-07-25T13:31:58.194518Z","shell.execute_reply":"2025-07-25T14:13:22.038738Z"}},"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-25T14:13:22.042731Z","iopub.execute_input":"2025-07-25T14:13:22.043281Z","iopub.status.idle":"2025-07-25T14:16:03.996910Z","shell.execute_reply.started":"2025-07-25T14:13:22.043238Z","shell.execute_reply":"2025-07-25T14:16:03.995989Z"}},"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-25T14:16:03.997912Z","iopub.execute_input":"2025-07-25T14:16:03.998258Z","iopub.status.idle":"2025-07-25T14:16:04.082026Z","shell.execute_reply.started":"2025-07-25T14:16:03.998225Z","shell.execute_reply":"2025-07-25T14:16:04.081098Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from 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-25T14:16:04.083308Z","iopub.execute_input":"2025-07-25T14:16:04.083592Z","iopub.status.idle":"2025-07-25T14:16:32.880690Z","shell.execute_reply.started":"2025-07-25T14:16:04.083569Z","shell.execute_reply":"2025-07-25T14:16:32.879642Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# PyTorchモデルの保存\ntorch.save(model.state_dict(), \"model.pth\")\nprint(\" model.pth saved\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-25T14:16:32.886165Z","iopub.execute_input":"2025-07-25T14:16:32.886466Z","iopub.status.idle":"2025-07-25T14:16:32.928603Z","shell.execute_reply.started":"2025-07-25T14:16:32.886446Z","shell.execute_reply":"2025-07-25T14:16:32.927754Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ファイル確認\nprint(\" Working Directory Files:\")\nfor f in os.listdir(out_dir):\n    print(\"-\", f)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-25T14:16:32.929326Z","iopub.execute_input":"2025-07-25T14:16:32.929554Z","iopub.status.idle":"2025-07-25T14:16:32.934929Z","shell.execute_reply.started":"2025-07-25T14:16:32.929537Z","shell.execute_reply":"2025-07-25T14:16:32.934131Z"}},"outputs":[],"execution_count":null}]}