{"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":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":31041,"isInternetEnabled":false,"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-04T08:26:37.203815Z","iopub.execute_input":"2025-07-04T08:26:37.204614Z","iopub.status.idle":"2025-07-04T08:26:37.463226Z","shell.execute_reply.started":"2025-07-04T08:26:37.204587Z","shell.execute_reply":"2025-07-04T08:26:37.462454Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Cat と Dog の画像の分類をCNNを使用して行う","metadata":{}},{"cell_type":"markdown","source":"## 学習用データとテストデータを読み込む\nデータの解凍，中身の確認，学習に使える形に前処理&データセットの作成","metadata":{}},{"cell_type":"code","source":"# 使用する外部ライブラリーのインポート\nimport zipfile\nimport os\nimport tensorflow as tf\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport glob\nfrom sklearn.model_selection import train_test_split\nimport shutil\nfrom tensorflow.keras import layers, models\nfrom tensorflow.keras.applications import EfficientNetB3\nfrom tensorflow.keras.callbacks import EarlyStopping","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T08:26:37.464450Z","iopub.execute_input":"2025-07-04T08:26:37.464712Z","iopub.status.idle":"2025-07-04T08:26:51.354033Z","shell.execute_reply.started":"2025-07-04T08:26:37.464696Z","shell.execute_reply":"2025-07-04T08:26:51.353475Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 訓練データ（train.zip）とテストデータ(test.zip)をそれぞれ，/kaggle/working/train,/kaggle/working/testに解凍\n\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip', 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/')\n\n\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip', 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T08:26:51.354693Z","iopub.execute_input":"2025-07-04T08:26:51.355053Z","iopub.status.idle":"2025-07-04T08:27:03.609568Z","shell.execute_reply.started":"2025-07-04T08:26:51.355036Z","shell.execute_reply":"2025-07-04T08:27:03.609001Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 本当にファイルが生成されているのかの確認\nfile_list = os.listdir('/kaggle/working')\nprint(file_list)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T08:27:03.611020Z","iopub.execute_input":"2025-07-04T08:27:03.611270Z","iopub.status.idle":"2025-07-04T08:27:03.615781Z","shell.execute_reply.started":"2025-07-04T08:27:03.611252Z","shell.execute_reply":"2025-07-04T08:27:03.615007Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# データの中身の確認\n# 解凍先のパス\ntrain_dir = '/kaggle/working/train'\n\n# ファイル一覧取得（catとdog両方含む）\nfile_list = os.listdir(train_dir)\nfile_list.sort()  # 確認しやすくするためソート\nprint(file_list[0:10])\n\ncat_count = sum(s.startswith(\"cat\") for s in file_list)\ndog_count = sum(s.startswith(\"dog\") for s in file_list)\nprint(f'The number of Train data : {len(file_list)}')\nprint(f'Cats : {cat_count} ,Dog : {dog_count}')\n\n# 最初の画像ファイル\nimg_path = os.path.join(train_dir, file_list[0])\n\n# 画像読み込み\nimg = Image.open(img_path)\nprint(\"Image size:\", img.size)\n\n# 表示\nfig = plt.figure(figsize=(5, 5))\nax = fig.add_subplot(1, 1, 1)\nax.imshow(img)\nax.set_title(f\"Filename: {os.path.basename(img_path)}\")\nax.axis('off')  # 軸を非表示\nplt.show()\n\n\n# 特定の10枚\ndog_list = [f for f in file_list if f.startswith(\"dog.\")]  # dogで始まるやつのみ\nselected_files = dog_list[0:10]\n\n# プロット準備\nfig, axes = plt.subplots(2, 5, figsize=(15, 6))\nfig.tight_layout(pad=2.0)\n\n# 各画像を表示\nfor i, ax in enumerate(axes.flat):\n    img_path = os.path.join(train_dir, selected_files[i])\n    img = Image.open(img_path)\n    ax.imshow(img)\n    ax.set_title(os.path.basename(img_path), fontsize=8)\n    ax.axis('off')\nfig.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T08:27:03.616736Z","iopub.execute_input":"2025-07-04T08:27:03.616998Z","iopub.status.idle":"2025-07-04T08:27:05.078205Z","shell.execute_reply.started":"2025-07-04T08:27:03.616974Z","shell.execute_reply":"2025-07-04T08:27:05.077469Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#データのサイズの確認\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\n\nimg = load_img(img_path, target_size=(224, 224))  # 高さ224 × 幅224 に統一\nimg_array = img_to_array(img) / 255.0  # 正規化\n\nprint(img_array.shape)\nprint(np.max(img_to_array(img)))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T08:27:05.079040Z","iopub.execute_input":"2025-07-04T08:27:05.079291Z","iopub.status.idle":"2025-07-04T08:27:05.087661Z","shell.execute_reply.started":"2025-07-04T08:27:05.079273Z","shell.execute_reply":"2025-07-04T08:27:05.086785Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 動かしたいけど動かすとメモリ制限を超える\n# import os\n# import numpy as np\n# from tqdm import tqdm\n# from tensorflow.keras.preprocessing.image import load_img, img_to_array\n# from sklearn.model_selection import train_test_split\n\n\n# train_dir = '/kaggle/working/train'\n# file_list = sorted([f for f in os.listdir(train_dir) if f.endswith('.jpg')])\n\n# target_size = (244, 244)\n# images = []\n# labels = []\n\n# for file_name in tqdm(file_list, desc=\"Loading images\"):\n#     img_path = os.path.join(train_dir, file_name)\n#     img = load_img(img_path, target_size=target_size)\n#     img_array = img_to_array(img) / 255.0\n#     images.append(img_array)\n#     labels.append(0 if file_name.startswith('cat') else 1)\n\n# X = np.array(images)\n# y = np.array(labels)\n\n\n# X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T08:27:05.088519Z","iopub.execute_input":"2025-07-04T08:27:05.088740Z","iopub.status.idle":"2025-07-04T08:27:05.097639Z","shell.execute_reply.started":"2025-07-04T08:27:05.088724Z","shell.execute_reply":"2025-07-04T08:27:05.096816Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 前処理＆データセット作成\nsrc_dir = '/kaggle/working/train'\ncat_dir = os.path.join(src_dir, 'cat')\ndog_dir = os.path.join(src_dir, 'dog')\n\nos.makedirs(cat_dir, exist_ok=True)\nos.makedirs(dog_dir, exist_ok=True)\n\nfor filename in os.listdir(src_dir):\n    if filename.endswith('.jpg'):\n        if filename.startswith('cat'):\n            shutil.move(os.path.join(src_dir, filename), os.path.join(cat_dir, filename))\n        elif filename.startswith('dog'):\n            shutil.move(os.path.join(src_dir, filename), os.path.join(dog_dir, filename))\n\n# ファイルパスとラベルを取得（cat=0, dog=1）\ncat_images = glob.glob(os.path.join('/kaggle/working/train', 'cat', '*.jpg'))\ndog_images = glob.glob(os.path.join('/kaggle/working/train', 'dog', '*.jpg'))\nprint(\"🐱 cat images:\", len(cat_images))\nprint(\"🐶 dog images:\", len(dog_images))\n\nall_images = cat_images + dog_images\nlabels = [0]*len(cat_images) + [1]*len(dog_images)\n\n# 学習・検証データに分割\ntrain_paths, val_paths, train_labels, val_labels = train_test_split(\n    all_images, labels, test_size=0.2, stratify=labels, random_state=42\n)\n\n\n# 画像を読み込み、リサイズ・正規化＋学習時のみデータ拡張を行う関数\ndef decode_img(path, label, is_train):\n    img = tf.io.read_file(path)  # 画像ファイルを読み込む\n    img = tf.image.decode_jpeg(img, channels=3)  # JPEG形式をRGB画像に変換\n    img = tf.image.resize(img, (224, 224))  # サイズを224×224に調整\n\n    if is_train:\n        img = tf.image.random_flip_left_right(img)  # 左右反転\n        img = tf.image.random_brightness(img, max_delta=0.2)  # 明るさ変更\n        img = tf.image.random_contrast(img, lower=0.8, upper=1.2)  # コントラスト変更\n        img = tf.image.random_saturation(img, lower=0.8, upper=1.2)  # 彩度変更\n        img = tf.image.random_hue(img, max_delta=0.05)  # 色相変更\n\n    img = img / 255.0  # 正規化（0〜1の範囲）\n    return img, label\n\n# 学習・検証用の tf.data.Dataset を構築する関数\ndef build_dataset(paths, labels, is_train=True):\n    def _decode_img(path, label):\n        return decode_img(path, label, is_train)  # ← ここで is_train を渡す！\n\n    ds = tf.data.Dataset.from_tensor_slices((paths, labels))\n    ds = ds.map(_decode_img, num_parallel_calls=tf.data.AUTOTUNE)\n\n    if is_train:\n        ds = ds.shuffle(buffer_size=1024, seed=42)\n\n    ds = ds.batch(32)\n    ds = ds.prefetch(tf.data.AUTOTUNE)\n    return ds\n\n\n\n# データセット作成\nDs_train = build_dataset(train_paths, train_labels, is_train=True)\nDs_val = build_dataset(val_paths, val_labels, is_train=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T08:27:05.098597Z","iopub.execute_input":"2025-07-04T08:27:05.098865Z","iopub.status.idle":"2025-07-04T08:27:08.809908Z","shell.execute_reply.started":"2025-07-04T08:27:05.098839Z","shell.execute_reply":"2025-07-04T08:27:08.809373Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 使用するモデルを定義＆作成する","metadata":{}},{"cell_type":"code","source":"# def build_efficientnet_b3_model(input_shape=(300, 300, 3)):\n#     # 入力\n#     inputs = tf.keras.Input(shape=input_shape)\n    \n#     # EfficientNetB3のバックボーン（出力層なし, ImageNetの重み）\n#     base_model = EfficientNetB3(include_top=False, weights='imagenet', input_tensor=inputs)\n#     base_model.trainable = False  # 転移学習：特徴抽出フェーズでは凍結\n\n#     # グローバル平均プーリング + 出力層（シグモイド）\n#     x = base_model.output\n#     x = layers.GlobalAveragePooling2D()(x)\n#     x = layers.Dense(128, activation='relu')(x)\n#     # x = layers.Dropout(0.3)(x)\n#     outputs = layers.Dense(1, activation='sigmoid')(x)  # 2値分類用\n\n#     model = models.Model(inputs, outputs)\n#     return model\n\ndef residual_block_2d(x, filters, downsample=False):\n    shortcut = x\n    \n    if downsample:\n        shortcut = layers.Conv2D(filters, kernel_size=1, strides=2, padding='same', use_bias=False)(shortcut)\n        shortcut = layers.BatchNormalization()(shortcut)\n\n    x = layers.Conv2D(filters, kernel_size=3, strides=1 if not downsample else 2, padding='same', use_bias=False)(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.ReLU()(x)\n\n    x = layers.Conv2D(filters, kernel_size=3, strides=1, padding='same', use_bias=False)(x)\n    x = layers.BatchNormalization()(x)\n\n    x = layers.add([x, shortcut])\n    x = layers.ReLU()(x)\n    \n    return x\n\ndef build_model(input_shape=(224, 224, 3)):\n    inputs = tf.keras.Input(shape=input_shape)\n    \n    x = layers.Conv2D(64, kernel_size=7, strides=2, padding='same', use_bias=False)(inputs)\n    x = layers.BatchNormalization()(x)\n    x = layers.ReLU()(x)\n\n    x = layers.MaxPooling2D(pool_size=3, strides=2, padding='same')(x)\n\n    x = residual_block_2d(x, 64)\n    x = residual_block_2d(x, 64)\n\n    x = residual_block_2d(x, 128, downsample=True)\n    x = residual_block_2d(x, 128)\n\n    x = residual_block_2d(x, 256, downsample=True)\n    x = residual_block_2d(x, 256)\n\n    x = residual_block_2d(x, 512, downsample=True)\n    x = residual_block_2d(x, 512)\n\n    x = layers.GlobalAveragePooling2D()(x)\n\n    outputs = layers.Dense(1, activation='sigmoid')(x) \n\n    model = models.Model(inputs, outputs)\n    return model\n\n# モデル作成\n# input_shape = (300, 300, 3)\n# model = build_efficientnet_b3_model(input_shape)\ninput_shape = (224, 224, 3)\nmodel = build_model(input_shape)\n\n# 最適化とコンパイル\noptimizer = tf.keras.optimizers.Adam(learning_rate=1e-4)\nmodel.compile(\n    optimizer=optimizer,\n    loss='binary_crossentropy',\n    metrics=['accuracy']\n)\n\n# モデルの構造を表示\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T08:27:08.810753Z","iopub.execute_input":"2025-07-04T08:27:08.811020Z","iopub.status.idle":"2025-07-04T08:27:09.835363Z","shell.execute_reply.started":"2025-07-04T08:27:08.810996Z","shell.execute_reply":"2025-07-04T08:27:09.834647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# EarlyStopping\n# early_stopping = EarlyStopping(\n#     monitor='val_loss',\n#     patience=10,  # 20エポック改善がなければ止める\n#     restore_best_weights=True  # 最も良かった時の重みを復元\n# )\n\nhistory = model.fit(\n    Ds_train,\n    validation_data=Ds_val,\n    epochs=10,\n    # callbacks=[early_stopping],\n    verbose=1\n)\n\nmodel.save('/kaggle/working/ResNet2D.keras')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T08:27:09.837254Z","iopub.execute_input":"2025-07-04T08:27:09.837476Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def plot_training_history(history):\n    fig, axes = plt.subplots(1, 2, figsize=(14, 5))  # 横長のグラフにする\n\n    # Loss Curve\n    axes[0].plot(history.history['loss'], label='Train Loss', linewidth=2)\n    axes[0].plot(history.history['val_loss'], label='Validation Loss', linewidth=2)\n    axes[0].set_xlabel('Epochs',loc='right')\n    axes[0].set_ylabel('Loss',loc='top')\n    axes[0].set_title('Loss Curve')\n    axes[0].legend(loc='upper right', fontsize=16)\n    axes[0].grid(True)\n\n    # Accuracy Curve\n    axes[1].plot(history.history['accuracy'], label='Train Accuracy', linewidth=2)\n    axes[1].plot(history.history['val_accuracy'], label='Validation Accuracy', linewidth=2)\n    axes[1].set_xlabel('Epochs',loc='right')\n    axes[1].set_ylabel('Accuracy',loc='top')\n    axes[1].set_title('Accuracy Curve')\n    # axes[1].set_ylim(0.9, 1.0)  # Y軸の範囲を制限（0〜1の範囲で見やすく）\n    axes[1].legend(loc='lower right', fontsize=16)\n    axes[1].grid(True)\n\n    plt.tight_layout()  # レイアウト調整\n    plt.show()\n\nplot_training_history(history)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## テストデータを予測する","metadata":{}},{"cell_type":"code","source":"# クラッシュするパート２\n# import os\n# import numpy as np\n# import pandas as pd\n# from tensorflow.keras.preprocessing.image import load_img, img_to_array\n\n# test_dir = '/kaggle/working/test'\n# test_files = sorted([f for f in os.listdir(test_dir) if f.endswith('.jpg')])\n# target_size = (224, 224)  # モデルと同じサイズ\n\n# # 画像読み込み＆前処理\n# test_images = []\n# ids = []\n\n# for fname in test_files:\n#     img_path = os.path.join(test_dir, fname)\n#     img = load_img(img_path, target_size=target_size)\n#     img_array = img_to_array(img) / 255.0\n#     test_images.append(img_array)\n#     ids.append(int(fname.split('.')[0]))  # '123.jpg' → 123\n\n# X_test = np.array(test_images)\n\n# # 予測\n# pred_probs = model.predict(X_test, batch_size=32)\n\n# # 提出用CSV作成\n# submission = pd.DataFrame({\n#     'id': ids,\n#     'label': pred_labels\n# })\n# submission = submission.sort_values('id')  # id順にソート（Kaggle仕様）\n# submission.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# テスト画像の準備\ntest_dir = '/kaggle/working/test'\ntest_files = sorted([f for f in os.listdir(test_dir) if f.endswith('.jpg')])\ntest_paths = [os.path.join(test_dir, f) for f in test_files]\nids = [int(f.split('.')[0]) for f in test_files]\n\n# 前処理関数（ラベル不要なので）\ndef decode_test_img(path):\n    img = tf.io.read_file(path)\n    img = tf.image.decode_jpeg(img, channels=3)\n    img = tf.image.resize(img, (224, 224))\n    img = img / 255.0\n    return img\n\n# tf.data.Dataset 作成\ntest_ds = tf.data.Dataset.from_tensor_slices(test_paths)\ntest_ds = test_ds.map(decode_test_img, num_parallel_calls=tf.data.AUTOTUNE)\ntest_ds = test_ds.batch(32).prefetch(tf.data.AUTOTUNE)\n\n# 予測実行（確率出力）\npred_probs = model.predict(test_ds).flatten()\n\n# 提出用CSV\nsubmission = pd.DataFrame({'id': ids, 'label': pred_probs})\nsubmission = submission.sort_values('id')\nsubmission.to_csv('submission.csv', index=False)\nprint('Done!')","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}