{"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":"none","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":31040,"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-18T11:26:53.820404Z","iopub.execute_input":"2025-07-18T11:26:53.821447Z","iopub.status.idle":"2025-07-18T11:26:54.176400Z","shell.execute_reply.started":"2025-07-18T11:26:53.821414Z","shell.execute_reply":"2025-07-18T11:26:54.175396Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Zipファイルの展開","metadata":{}},{"cell_type":"code","source":"import zipfile\n\n# zipファイルのパス\nzip_train_path = '/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip'\nzip_test_path = '/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip'\n# 展開先のパス\nextract_train_path = '/kaggle/working'\nextract_test_path = '/kaggle/working'\n# 展開処理\nwith zipfile.ZipFile(zip_train_path, 'r') as zip_ref:\n    zip_ref.extractall(extract_train_path)\nwith zipfile.ZipFile(zip_test_path, 'r') as zip_ref:\n    zip_ref.extractall(extract_test_path)\nprint(\"ファイル展開完了\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T11:26:54.178407Z","iopub.execute_input":"2025-07-18T11:26:54.178858Z","iopub.status.idle":"2025-07-18T11:27:10.739286Z","shell.execute_reply.started":"2025-07-18T11:26:54.178834Z","shell.execute_reply":"2025-07-18T11:27:10.738319Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# trainデータのラベル付け","metadata":{}},{"cell_type":"code","source":"train_dir = '/kaggle/working/train'  # 展開された画像の場所\n\nfilenames = os.listdir(train_dir)\nlabels = ['dog' if 'dog' in fname else 'cat' for fname in filenames]\nprint(\"ラベル付け完了\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T11:27:10.740259Z","iopub.execute_input":"2025-07-18T11:27:10.740573Z","iopub.status.idle":"2025-07-18T11:27:10.764499Z","shell.execute_reply.started":"2025-07-18T11:27:10.740545Z","shell.execute_reply":"2025-07-18T11:27:10.763528Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# データセットのデータフレーム化","metadata":{}},{"cell_type":"code","source":"# trainファイルのフルパス\ntrain_filepaths = [os.path.join(train_dir, fname) for fname in filenames]\n\n# train DataFrame作成\ntrain_df = pd.DataFrame({\n    'filename': filenames,\n    'filepath': train_filepaths,\n    'label': labels\n})\nprint(\"trainDF作成完了\")\n\n# testファイルのパス\ntest_dir = '/kaggle/working/test'\ntest_filenames = os.listdir(test_dir)\ntest_filepaths = [os.path.join(test_dir, fname) for fname in test_filenames]\n\n# test DataFrame作成\ntest_df = pd.DataFrame({\n    'filename': test_filenames,\n    'filepath': test_filepaths\n})\nprint(\"testDF作成完了\")\n\n# 確認（ラベルはtrainのみ）\nprint(train_df.head())\nprint(test_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T11:27:10.765527Z","iopub.execute_input":"2025-07-18T11:27:10.765851Z","iopub.status.idle":"2025-07-18T11:27:10.837676Z","shell.execute_reply.started":"2025-07-18T11:27:10.765825Z","shell.execute_reply":"2025-07-18T11:27:10.836649Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# データセットを128×128にリサイズ","metadata":{}},{"cell_type":"code","source":"from PIL import Image\n\n# 保存先ディレクトリ作成\ntrain_resized_dir = '/kaggle/working/train_128'\ntest_resized_dir = '/kaggle/working/test_128'\nos.makedirs(train_resized_dir, exist_ok=True)\nos.makedirs(test_resized_dir, exist_ok=True)\n\n# ----------- train画像のリサイズ -----------\nfor fname in train_df['filename']:\n    src_path = os.path.join(train_dir, fname)\n    dst_path = os.path.join(train_resized_dir, fname)\n    with Image.open(src_path) as img:\n        img_resized = img.resize((128, 128))\n        img_resized.save(dst_path)\n\n# filepathを更新\ntrain_df['filepath'] = train_df['filename'].apply(lambda x: os.path.join(train_resized_dir, x))\nprint(\"trainのリサイズ完了\")\n\n# ----------- test画像のリサイズ -----------\nfor fname in test_df['filename']:\n    src_path = os.path.join(test_dir, fname)\n    dst_path = os.path.join(test_resized_dir, fname)\n    with Image.open(src_path) as img:\n        img_resized = img.resize((128, 128))\n        img_resized.save(dst_path)\n\n# filepathを更新\ntest_df['filepath'] = test_df['filename'].apply(lambda x: os.path.join(test_resized_dir, x))\nprint(\"testのリサイズ完了\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T11:27:10.840292Z","iopub.execute_input":"2025-07-18T11:27:10.840567Z","iopub.status.idle":"2025-07-18T11:29:28.705266Z","shell.execute_reply.started":"2025-07-18T11:27:10.840546Z","shell.execute_reply":"2025-07-18T11:29:28.704351Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# データセットのサイズ確認","metadata":{}},{"cell_type":"code","source":"# ----------- train_128のサイズ確認 -----------\ncorrect_train_size = 0\nfor path in train_df['filepath']:\n    with Image.open(path) as img:\n        if img.size == (128, 128):\n            correct_train_size += 1\n\nprint(f\"128x128に正しくリサイズされたtrain画像：{correct_train_size} / {len(train_df)}\")\n\n# ----------- test_128のサイズ確認 -----------\ncorrect_test_size = 0\nfor path in test_df['filepath']:\n    with Image.open(path) as img:\n        if img.size == (128, 128):\n            correct_test_size += 1\n\nprint(f\"128x128に正しくリサイズされたtest画像：{correct_test_size} / {len(test_df)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T11:29:28.706232Z","iopub.execute_input":"2025-07-18T11:29:28.706545Z","iopub.status.idle":"2025-07-18T11:29:31.636310Z","shell.execute_reply.started":"2025-07-18T11:29:28.706521Z","shell.execute_reply":"2025-07-18T11:29:31.635278Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# グレースケール化","metadata":{}},{"cell_type":"code","source":"from PIL import Image\nfrom sklearn.model_selection import train_test_split\n\n# データとラベルの準備\nX = []\ny = []\n\nfor _, row in train_df.iterrows():\n    img = Image.open(row['filepath']).convert('L')  # グレースケール\n    img_array = np.array(img) / 255.0               # 正規化（0〜1）\n    X.append(img_array)\n    y.append(0 if row['label'] == 'cat' else 1)\n\nX = np.array(X).reshape(-1, 128, 128, 1).astype(np.float32)  # チャンネル追加＆型変換\ny = np.array(y).astype(np.int32)\nprint(\"X shape:\", X.shape, \"| y shape:\", y.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T11:29:31.637435Z","iopub.execute_input":"2025-07-18T11:29:31.637807Z","iopub.status.idle":"2025-07-18T11:29:51.163873Z","shell.execute_reply.started":"2025-07-18T11:29:31.637778Z","shell.execute_reply":"2025-07-18T11:29:51.162853Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 訓練データと検証データに分割","metadata":{}},{"cell_type":"code","source":"train_x, valid_x, train_y, valid_y = train_test_split(X, y, test_size=0.1, random_state=42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T11:29:51.164876Z","iopub.execute_input":"2025-07-18T11:29:51.165529Z","iopub.status.idle":"2025-07-18T11:29:51.439793Z","shell.execute_reply.started":"2025-07-18T11:29:51.165494Z","shell.execute_reply":"2025-07-18T11:29:51.439039Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# TensorFlow Datasetに変換","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\n\ntrain_ds = tf.data.Dataset.from_tensor_slices((train_x, train_y))\nvalid_ds = tf.data.Dataset.from_tensor_slices((valid_x, valid_y))\n\nBATCH_SIZE = 32\n\ntrain_ds = train_ds.shuffle(1000).batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)\nvalid_ds = valid_ds.batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T11:29:51.440711Z","iopub.execute_input":"2025-07-18T11:29:51.441025Z","iopub.status.idle":"2025-07-18T11:30:14.740634Z","shell.execute_reply.started":"2025-07-18T11:29:51.440999Z","shell.execute_reply":"2025-07-18T11:30:14.739480Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# CNNモデル構築","metadata":{}},{"cell_type":"code","source":"model = tf.keras.Sequential([\n    tf.keras.layers.Input(shape=(128, 128, 1)),\n    tf.keras.layers.Conv2D(32, 3, activation='relu'),\n    tf.keras.layers.MaxPooling2D(),\n    tf.keras.layers.Conv2D(64, 3, activation='relu'),\n    tf.keras.layers.MaxPooling2D(),\n    tf.keras.layers.Conv2D(128, 3, activation='relu'),\n    tf.keras.layers.MaxPooling2D(),\n    tf.keras.layers.Flatten(),\n    tf.keras.layers.Dense(128, activation='relu'),\n    tf.keras.layers.Dense(1, activation='sigmoid')  # 2値分類\n])\n\nmodel.compile(optimizer='adam',\n              loss='binary_crossentropy',\n              metrics=['accuracy'])\n\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T11:30:14.741891Z","iopub.execute_input":"2025-07-18T11:30:14.742536Z","iopub.status.idle":"2025-07-18T11:30:14.961339Z","shell.execute_reply.started":"2025-07-18T11:30:14.742509Z","shell.execute_reply":"2025-07-18T11:30:14.960405Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 学習","metadata":{}},{"cell_type":"code","source":"#history = model.fit(train_ds, validation_data=valid_ds, epochs=10)\n#model.save('/kaggle/working/my_model.h5')  # 保存パスとファイル名は自由\n#print(\"✅ モデルを保存しました\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T11:30:14.962349Z","iopub.execute_input":"2025-07-18T11:30:14.962731Z","iopub.status.idle":"2025-07-18T12:31:26.256883Z","shell.execute_reply.started":"2025-07-18T11:30:14.962705Z","shell.execute_reply":"2025-07-18T12:31:26.255837Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# テスト画像を読み込み（グレースケール＋リサイズ＋正規化）","metadata":{}},{"cell_type":"code","source":"test_images = []\nimage_ids = []\n\nfor _, row in test_df.iterrows():\n    img = Image.open(row['filepath']).convert('L')  # グレースケール\n    img_array = np.array(img) / 255.0               # 正規化\n    img_array = img_array.reshape(128, 128, 1)\n    test_images.append(img_array)\n\n    # id（ファイル名の「.jpg」を取り除いた整数）を保存\n    image_ids.append(int(row['filename'].split('.')[0]))\n\n# numpy配列に変換\ntest_images = np.array(test_images).astype(np.float32)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T12:31:26.258187Z","iopub.execute_input":"2025-07-18T12:31:26.258564Z","iopub.status.idle":"2025-07-18T12:31:35.599070Z","shell.execute_reply.started":"2025-07-18T12:31:26.258531Z","shell.execute_reply":"2025-07-18T12:31:35.598008Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# モデルで予測","metadata":{}},{"cell_type":"code","source":"# 予測（出力は0.0〜1.0）\npreds = model.predict(test_images)\npreds = preds.flatten()  # 1次元に","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T12:31:35.601828Z","iopub.execute_input":"2025-07-18T12:31:35.602165Z","iopub.status.idle":"2025-07-18T12:32:55.612315Z","shell.execute_reply.started":"2025-07-18T12:31:35.602139Z","shell.execute_reply":"2025-07-18T12:32:55.611095Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 提出用CSVの作成","metadata":{}},{"cell_type":"code","source":"import pandas as pd\n\nsubmission = pd.DataFrame({\n    'id': image_ids,\n    'label': preds  # 確率のままでもOK（Kaggleで受け入れられる）\n})\n\nsubmission = submission.sort_values('id')  # id順にソート（Kaggle提出形式）\nsubmission.to_csv('submission.csv', index=False)\nprint(\"✅ submission.csv を保存しました\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T12:32:55.616476Z","iopub.execute_input":"2025-07-18T12:32:55.616791Z","iopub.status.idle":"2025-07-18T12:32:55.666827Z","shell.execute_reply.started":"2025-07-18T12:32:55.616768Z","shell.execute_reply":"2025-07-18T12:32:55.665170Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nprint(os.listdir('/kaggle/working'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-18T12:37:13.944150Z","iopub.execute_input":"2025-07-18T12:37:13.944530Z","iopub.status.idle":"2025-07-18T12:37:13.950907Z","shell.execute_reply.started":"2025-07-18T12:37:13.944504Z","shell.execute_reply":"2025-07-18T12:37:13.949876Z"}},"outputs":[],"execution_count":null}]}