{"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":3362,"databundleVersionId":31148,"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-04T09:18:41.130151Z","iopub.execute_input":"2025-07-04T09:18:41.130369Z","iopub.status.idle":"2025-07-04T09:18:42.927645Z","shell.execute_reply.started":"2025-07-04T09:18:41.130347Z","shell.execute_reply":"2025-07-04T09:18:42.926991Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport zipfile\n\ntrain_zip_path = '/kaggle/input/dogs-vs-cats/train.zip'\nextract_path_train = '/kaggle/working/train/'\n\nwith zipfile.ZipFile(train_zip_path, 'r') as zip_ref:\n    zip_ref.extractall(extract_path_train)\n\ntest_zip_path = '/kaggle/input/dogs-vs-cats/test1.zip'\nextract_path_test = '/kaggle/working/test/'\n\nwith zipfile.ZipFile(test_zip_path, 'r') as zip_ref:\n    zip_ref.extractall(extract_path_test)\n\nprint(\"解凍が完了しました。\")\nprint(os.listdir('/kaggle/working/train/train')[:5]) # 中身を一部確認\nprint(os.listdir('/kaggle/working/test/test1')[:5])  # 中身を一部確認","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T09:29:29.429496Z","iopub.execute_input":"2025-07-04T09:29:29.430184Z","iopub.status.idle":"2025-07-04T09:29:41.962850Z","shell.execute_reply.started":"2025-07-04T09:29:29.430160Z","shell.execute_reply":"2025-07-04T09:29:41.962226Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"train_loaderとval_loaderの作成","metadata":{}},{"cell_type":"code","source":"import os\nimport pandas as pd\nfrom sklearn.model_selection import train_test_split\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom PIL import Image\n\nTRAIN_DIR = '/kaggle/working/train/train/'\n\nall_filenames = os.listdir(TRAIN_DIR)\n\ndf_data = []\nfor filename in all_filenames:\n    filepath = os.path.join(TRAIN_DIR, filename)\n    label = 1 if 'dog' in filename else 0  # dogなら1, catなら0\n    df_data.append({'filepath': filepath, 'label': label})\n\ndf = pd.DataFrame(df_data)\n\nprint(f\"総画像数: {len(df)}\")\nprint(df.head())\n\ntrain_df, val_df = train_test_split(\n    df,\n    test_size=0.2,       # 20%を検証用にする\n    random_state=42,     # 再現性のための乱数シード\n    stratify=df['label'] # ラベルの比率を保つ\n)\n\nprint(f\"訓練データ数: {len(train_df)}\")\nprint(f\"検証データ数: {len(val_df)}\")\n\n\nIMG_SIZE = 224\n\nMEAN = [0.485, 0.456, 0.406]\nSTD = [0.229, 0.224, 0.225]\n\ntrain_transforms = transforms.Compose([\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(10),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=MEAN, std=STD)\n])\n\nval_transforms = transforms.Compose([\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=MEAN, std=STD)\n])\n\n\nclass CatsDogsDataset(Dataset):\n    def __init__(self, df, transform=None):\n        self.df = df\n        self.transform = transform\n        self.filepaths = df['filepath'].values\n        self.labels = df['label'].values\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        img_path = self.filepaths[idx]\n        image = Image.open(img_path).convert('RGB')\n        label = self.labels[idx]\n\n        if self.transform:\n            image = self.transform(image)\n        \n        return image, torch.tensor(label, dtype=torch.long)\n\nBATCH_SIZE = 32\n\ntrain_dataset = CatsDogsDataset(train_df, transform=train_transforms)\nval_dataset = CatsDogsDataset(val_df, transform=val_transforms)\n\ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False)\n\n\nimages, labels = next(iter(train_loader))\nprint(\"\\n--- 動作確認 ---\")\nprint(f\"1バッチの画像テンソルの形状: {images.shape}\") # [バッチサイズ, 色チャネル, 高さ, 幅]\nprint(f\"1バッチのラベルテンソルの形状: {labels.shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T09:34:08.359424Z","iopub.execute_input":"2025-07-04T09:34:08.359699Z","iopub.status.idle":"2025-07-04T09:34:16.777627Z","shell.execute_reply.started":"2025-07-04T09:34:08.359678Z","shell.execute_reply":"2025-07-04T09:34:16.776998Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Vision Transformerの学習","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport timm\nfrom tqdm import tqdm\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Using device: {device}\")\n\nmodel = timm.create_model('vit_base_patch16_224', pretrained=True)\n\nnum_classes = 2\nmodel.head = nn.Linear(model.head.in_features, num_classes)\n\nmodel = model.to(device)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.AdamW(model.parameters(), lr=1e-5)\n\nnum_epochs = 3 # エポック数（全訓練データを何周学習するか）\n\nfor epoch in range(num_epochs):\n    model.train()\n    running_loss = 0.0\n    correct_train = 0\n    total_train = 0\n    \n    train_bar = tqdm(train_loader, desc=f\"Epoch {epoch+1}/{num_epochs} [Training]\")\n    for images, labels in train_bar:\n        images, labels = images.to(device), labels.to(device)\n\n        optimizer.zero_grad()\n\n        outputs = model(images)\n        \n        loss = criterion(outputs, labels)\n\n        loss.backward()\n        \n        optimizer.step()\n\n        running_loss += loss.item()\n        _, predicted = torch.max(outputs.data, 1)\n        total_train += labels.size(0)\n        correct_train += (predicted == labels).sum().item()\n        \n        train_bar.set_postfix(loss=(running_loss / (train_bar.n + 1)))\n\n    train_accuracy = 100 * correct_train / total_train\n    train_loss = running_loss / len(train_loader)\n\n    model.eval() # モデルを評価モードに設定\n    val_loss = 0.0\n    correct_val = 0\n    total_val = 0\n    \n    with torch.no_grad():\n        val_bar = tqdm(val_loader, desc=f\"Epoch {epoch+1}/{num_epochs} [Validation]\")\n        for images, labels in val_bar:\n            images, labels = images.to(device), labels.to(device)\n            outputs = model(images)\n            loss = criterion(outputs, labels)\n            \n            val_loss += loss.item()\n            _, predicted = torch.max(outputs.data, 1)\n            total_val += labels.size(0)\n            correct_val += (predicted == labels).sum().item()\n\n    val_accuracy = 100 * correct_val / total_val\n    val_loss /= len(val_loader)\n\n    print(f\"\\nEpoch {epoch+1}/{num_epochs}:\")\n    print(f\"  Training Loss: {train_loss:.4f}, Training Accuracy: {train_accuracy:.2f}%\")\n    print(f\"  Validation Loss: {val_loss:.4f}, Validation Accuracy: {val_accuracy:.2f}%\\n\")\n\nprint(\"学習が完了しました。\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T09:39:49.164865Z","iopub.execute_input":"2025-07-04T09:39:49.165682Z","iopub.status.idle":"2025-07-04T10:24:46.114457Z","shell.execute_reply.started":"2025-07-04T09:39:49.165655Z","shell.execute_reply":"2025-07-04T10:24:46.113780Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"推論とファイル作成","metadata":{}},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms\nfrom PIL import Image\nfrom tqdm import tqdm\nimport torch.nn.functional as F\nimport numpy as np\n\nTEST_DIR = '/kaggle/working/test/test1/'\n\ntest_filenames = os.listdir(TEST_DIR)\ntest_filenames.sort(key=lambda x: int(x.split('.')[0]))\ntest_filepaths = [os.path.join(TEST_DIR, f) for f in test_filenames]\n\nclass TestDataset(Dataset):\n    def __init__(self, filepaths, transform=None):\n        self.filepaths = filepaths\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.filepaths)\n\n    def __getitem__(self, idx):\n        img_path = self.filepaths[idx]\n        image = Image.open(img_path).convert('RGB')\n        if self.transform:\n            image = self.transform(image)\n        return image\n\nval_transforms = transforms.Compose([\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=MEAN, std=STD)\n])\n\ntest_dataset = TestDataset(test_filepaths, transform=val_transforms)\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False)\n\nmodel.eval() # モデルを評価モードに\npredictions = []\n\nwith torch.no_grad():\n    test_bar = tqdm(test_loader, desc=\"Predicting\")\n    for images in test_bar:\n        images = images.to(device)\n        outputs = model(images)\n        \n        probs = F.softmax(outputs.data, dim=1)[:, 1].cpu().numpy()\n        predictions.extend(probs)\n\nids = [int(f.split('.')[0]) for f in test_filenames]\n\nsubmission_df = pd.DataFrame({\n    'id': ids,\n    'label': predictions\n})\n\nsubmission_df.to_csv('submission.csv', index=False)\n\nprint(\"\\nsubmission.csvの作成が完了しました。\")\nprint(\"ファイルの中身:\")\nprint(submission_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T10:27:25.954599Z","iopub.execute_input":"2025-07-04T10:27:25.955111Z","iopub.status.idle":"2025-07-04T10:30:40.137845Z","shell.execute_reply.started":"2025-07-04T10:27:25.955086Z","shell.execute_reply":"2025-07-04T10:30:40.137002Z"}},"outputs":[],"execution_count":null}]}