{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","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":30528,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"犬と猫の画像がそれぞれ25000枚あり、12500枚のテストデータを犬か猫か見分ける問題。","metadata":{}},{"cell_type":"code","source":"# Kaggle Python環境をセットアップし、/kaggle/input ディレクトリにあるファイルのリストを表示する。\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-02-17T10:34:25.703372Z","iopub.execute_input":"2024-02-17T10:34:25.703696Z","iopub.status.idle":"2024-02-17T10:34:25.716699Z","shell.execute_reply.started":"2024-02-17T10:34:25.703669Z","shell.execute_reply":"2024-02-17T10:34:25.715669Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cv2\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport os\nimport zipfile\nimport shutil\nimport glob\nimport tensorflow as tf\nfrom sklearn.model_selection import train_test_split\nfrom tensorflow.keras import layers, models\nfrom tensorflow.keras.applications import ResNet50  # 転移学習モデル","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:34:25.718525Z","iopub.execute_input":"2024-02-17T10:34:25.718832Z","iopub.status.idle":"2024-02-17T10:34:34.509027Z","shell.execute_reply.started":"2024-02-17T10:34:25.718806Z","shell.execute_reply":"2024-02-17T10:34:34.508040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train.zipの展開。\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip', 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/train')\n\n# test.zipの展開。\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip', 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/test')","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:34:34.510122Z","iopub.execute_input":"2024-02-17T10:34:34.510688Z","iopub.status.idle":"2024-02-17T10:34:53.757214Z","shell.execute_reply.started":"2024-02-17T10:34:34.510660Z","shell.execute_reply":"2024-02-17T10:34:53.756367Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 画像ファイルが展開されたディレクトリ。\ntrain_images_dir = '/kaggle/working/train/train'\n\n# 画像ファイルのリストを取得。\ntrain_image_files = os.listdir(train_images_dir)\n\n# 最初の画像を選ぶ。\nsample_image_path = os.path.join(train_images_dir, train_image_files[0])\n\n# 画像を読み込む。\nimg = cv2.imread(sample_image_path)\n\n# OpenCVのBGR形式をMatplotlibのRGB形式に変換。\nimg_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n# 画像を表示。\nplt.imshow(img_rgb)\nplt.axis('off')  # 軸を表示しない。\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:34:53.759575Z","iopub.execute_input":"2024-02-17T10:34:53.759966Z","iopub.status.idle":"2024-02-17T10:34:54.018813Z","shell.execute_reply.started":"2024-02-17T10:34:53.759912Z","shell.execute_reply":"2024-02-17T10:34:54.017777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 新しいディレクトリのパスを指定。\ndirectory_path = [\n    \"/kaggle/working/data/train/dogs\",\n    \"/kaggle/working/data/train/cats\",\n    \"/kaggle/working/data/valid/dogs\",\n    \"/kaggle/working/data/valid/cats\",\n    \"/kaggle/working/data/test\",\n]\n\n# ディレクトリを作成。\nfor path in directory_path:\n    os.makedirs(path, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:34:54.020106Z","iopub.execute_input":"2024-02-17T10:34:54.020407Z","iopub.status.idle":"2024-02-17T10:34:54.026073Z","shell.execute_reply.started":"2024-02-17T10:34:54.020380Z","shell.execute_reply":"2024-02-17T10:34:54.025033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def move_images(source_directory, destination_directories, file_filter=None):\n    for key, dest_dir in destination_directories.items():\n        files = [file for file in os.listdir(source_directory) if file_filter(file, key)]\n        for file in files:\n            source_path = os.path.join(source_directory, file)\n            destination_path = os.path.join(dest_dir, file)\n            shutil.move(source_path, destination_path)\n\nsource_directory = \"/kaggle/working/train/train\"\ntest_source_directory = \"/kaggle/working/test/test\"\n\ntrain_dest_directories = {\n    \"dog.\": \"/kaggle/working/data/train/dogs\",\n    \"cat.\": \"/kaggle/working/data/train/cats\",\n}\n\ntest_dest_directory = \"/kaggle/working/data/test/\"\n\n# ファイルフィルタ関数。\ndef train_file_filter(file, key):\n    return file.startswith(key)\n\ndef test_file_filter(file, key):\n    return file.endswith(\".jpg\")\n\nmove_images(source_directory, train_dest_directories, file_filter=train_file_filter)\nmove_images(test_source_directory, {None: test_dest_directory}, file_filter=test_file_filter)","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:34:54.027476Z","iopub.execute_input":"2024-02-17T10:34:54.027867Z","iopub.status.idle":"2024-02-17T10:34:55.376855Z","shell.execute_reply.started":"2024-02-17T10:34:54.027834Z","shell.execute_reply":"2024-02-17T10:34:55.376042Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TARGET_SIZE = (128, 128)  ","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:34:55.377963Z","iopub.execute_input":"2024-02-17T10:34:55.378258Z","iopub.status.idle":"2024-02-17T10:34:55.382404Z","shell.execute_reply.started":"2024-02-17T10:34:55.378234Z","shell.execute_reply":"2024-02-17T10:34:55.381417Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## CNN","metadata":{}},{"cell_type":"code","source":"def convert_data(x, y=None):\n    # 画像データの形状を再構築し、指定のターゲットサイズとチャンネル数を設定。\n    x = tf.reshape(x, (-1, *TARGET_SIZE, 1))\n    # データを0から1の範囲に正規化。\n    x = tf.cast(x, tf.float32) / 255.0\n    if y is not None:\n        # ラベルデータを整数型に変換。\n        y = tf.cast(y, tf.int32)\n        return x, y\n    return x\n\n# 特徴データとラベルデータのリストを作成。\nfeature_data, label_data = [], []","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:34:55.383626Z","iopub.execute_input":"2024-02-17T10:34:55.383974Z","iopub.status.idle":"2024-02-17T10:34:55.391443Z","shell.execute_reply.started":"2024-02-17T10:34:55.383949Z","shell.execute_reply":"2024-02-17T10:34:55.390603Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DATADIR = \"/kaggle/working/data/train\"\nTESTDIR = \"/kaggle/working/data/test\"\nCATEGORIES = [\"dogs\", \"cats\"]","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:34:55.395827Z","iopub.execute_input":"2024-02-17T10:34:55.396733Z","iopub.status.idle":"2024-02-17T10:34:55.401013Z","shell.execute_reply.started":"2024-02-17T10:34:55.396699Z","shell.execute_reply":"2024-02-17T10:34:55.400013Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for class_num, category in enumerate(CATEGORIES):\n    path = os.path.join(DATADIR, category)\n    for image_name in os.listdir(path):\n        try:\n            img_file = cv2.imread(os.path.join(path, image_name))\n            \n            # 画像の読み込みが正しくできているか確認。\n            # print(\"Loaded image shape:\", img_file.shape)\n            \n            gray_image = cv2.cvtColor(img_file, cv2.COLOR_BGR2GRAY)\n            \n            # グレースケールへの変換が正しくできているか確認。\n            # print(\"Converted image shape:\", gray_image.shape)\n            \n            resize_file = cv2.resize(gray_image, TARGET_SIZE)\n            \n            feature_data.append(resize_file)\n            label_data.append(class_num)\n        except Exception as e:\n            print(\"Error processing image:\", e)","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:34:55.402046Z","iopub.execute_input":"2024-02-17T10:34:55.402314Z","iopub.status.idle":"2024-02-17T10:35:59.247363Z","shell.execute_reply.started":"2024-02-17T10:34:55.402269Z","shell.execute_reply":"2024-02-17T10:35:59.246297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(len(feature_data))\nprint(len(label_data))","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:35:59.248429Z","iopub.execute_input":"2024-02-17T10:35:59.248694Z","iopub.status.idle":"2024-02-17T10:35:59.253817Z","shell.execute_reply.started":"2024-02-17T10:35:59.248671Z","shell.execute_reply":"2024-02-17T10:35:59.252773Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_x, valid_x, train_y, valid_y = train_test_split(\n    np.array(feature_data), np.array(label_data), test_size=0.1, random_state=50\n)","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:35:59.255011Z","iopub.execute_input":"2024-02-17T10:35:59.255312Z","iopub.status.idle":"2024-02-17T10:35:59.534666Z","shell.execute_reply.started":"2024-02-17T10:35:59.255276Z","shell.execute_reply":"2024-02-17T10:35:59.533573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BATCH_SIZE = 32\nEPOCHS = 25 \nNUM_CLASSES = 2","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:35:59.535968Z","iopub.execute_input":"2024-02-17T10:35:59.536338Z","iopub.status.idle":"2024-02-17T10:35:59.541354Z","shell.execute_reply.started":"2024-02-17T10:35:59.536304Z","shell.execute_reply":"2024-02-17T10:35:59.540345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 訓練データとラベルをTensorSliceDatasetとして読み込む。\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\n# データの読み込みと前処理の効率を向上させるため、AUTOTUNEを使用。\n# AUTOTUNEはGPUの処理とCPUの処理の配分を動的に設定してくれるパラメータである。\nAUTOTUNE = tf.data.experimental.AUTOTUNE\n\n# 訓練データの処理パイプラインを構築。\ntrain_ds = (\n    train_ds.shuffle(len(train_x))  # データをシャッフルしてランダム性を増す。\n    .repeat()                        # データセットを繰り返し利用。（エポックごとに繰り返す。）\n    .batch(BATCH_SIZE)               # バッチサイズに分割。\n    .map(convert_data)               # データ変換関数を適用。\n    .prefetch(buffer_size=AUTOTUNE)  # バッファを使用してデータの取得を最適化。\n)\n\n# 検証データの処理パイプラインを構築。\nvalid_ds = valid_ds.batch(BATCH_SIZE)  # バッチサイズに分割。\nvalid_ds = valid_ds.map(convert_data)  # データ変換関数を適用。","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:35:59.542374Z","iopub.execute_input":"2024-02-17T10:35:59.542688Z","iopub.status.idle":"2024-02-17T10:36:03.810560Z","shell.execute_reply.started":"2024-02-17T10:35:59.542664Z","shell.execute_reply":"2024-02-17T10:36:03.809793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# CNN モデル。\nmodel = models.Sequential([\n    layers.Input(shape=(*TARGET_SIZE, 1)),  \n    layers.Conv2D(32, (9, 9), activation='relu'),\n    layers.MaxPooling2D((2, 2)),\n    layers.Conv2D(64, (5, 5), activation='relu'),  \n    layers.MaxPooling2D((2, 2)),\n    layers.Conv2D(128, (3, 3), activation='relu'),  \n    layers.MaxPooling2D((2, 2)),\n    layers.Flatten(),\n    layers.Dense(256, activation='relu'),\n    layers.Dense(NUM_CLASSES, activation='softmax')  \n])\n\nmodel.compile(\n    optimizer='adam',\n    # 損失関数として交差エントロピー誤差を計算するように設定。\n    loss='sparse_categorical_crossentropy',\n    metrics=['accuracy']\n)\n\nhistory = model.fit(train_ds, epochs=EPOCHS, validation_data=valid_ds, steps_per_epoch=len(train_x) // BATCH_SIZE)","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:36:03.811750Z","iopub.execute_input":"2024-02-17T10:36:03.812072Z","iopub.status.idle":"2024-02-17T10:41:06.152566Z","shell.execute_reply.started":"2024-02-17T10:36:03.812046Z","shell.execute_reply":"2024-02-17T10:41:06.151763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"交差エントロピー誤差は、次のように定義される。\n\n$$-\\sum _{i}y_{i}\\log \\left( p_{i}\\right)$$\nここで、$y_i$は真のクラスに対するOne-Hotエンコーディングされたラベルの要素で、$p_i$はモデルの出力の確率分布の各クラスに対する確率である。\n\n例えば、真のクラスがクラス1である場合のラベルがOne-Hotエンコードされており、モデルの出力が次のような確率分布を持つとする。\n\n真のラベル: $[0,1,0,0]$\n\nモデルの出力: $[0.1,0.6,0.2,0.1]$\n\nこのとき交差エントロピー誤差は$- \\log(0.6)$となる。","metadata":{}},{"cell_type":"code","source":"feature_test_data = []\n\n# テストディレクトリ内の各画像ファイルに対して処理を行う。\nfor image_name in os.listdir(TESTDIR):\n    try:\n        # 画像ファイルを読み込み。\n        img_file = cv2.imread(os.path.join(TESTDIR, image_name))\n        # カラー画像をグレースケールに変換。\n        gray_image = cv2.cvtColor(img_file, cv2.COLOR_BGR2GRAY)\n        # 画像サイズをターゲットサイズにリサイズ。\n        resize_file = cv2.resize(gray_image, TARGET_SIZE)\n        # 処理済みの画像データをリストに追加。\n        feature_test_data.append(resize_file)\n    except Exception as e:\n        # エラーが発生した場合、エラーメッセージを表示。\n        print(f\"画像 {image_name} の処理中にエラーが発生しました: {e}\")","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:41:06.153837Z","iopub.execute_input":"2024-02-17T10:41:06.154150Z","iopub.status.idle":"2024-02-17T10:41:37.621344Z","shell.execute_reply.started":"2024-02-17T10:41:06.154124Z","shell.execute_reply":"2024-02-17T10:41:37.620512Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_ds = tf.data.Dataset.from_tensor_slices(np.array(feature_test_data))\ntest_ds = test_ds.batch(BATCH_SIZE).map(convert_data)\n\ny_pred = model.predict(test_ds)\npredictions = np.argmax(y_pred, axis=1)","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:41:37.622461Z","iopub.execute_input":"2024-02-17T10:41:37.622772Z","iopub.status.idle":"2024-02-17T10:41:40.478442Z","shell.execute_reply.started":"2024-02-17T10:41:37.622739Z","shell.execute_reply":"2024-02-17T10:41:40.477322Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 予測結果の確認","metadata":{}},{"cell_type":"code","source":"# テストデータの読み込みと前処理。\ndef load_and_preprocess_test_image(file_path):\n    img = tf.io.read_file(file_path)\n    img = tf.image.decode_jpeg(img, channels=1)  # グレースケール画像としてデコード。\n    img = tf.image.resize(img, TARGET_SIZE)  # 画像をリサイズ。\n    img = tf.cast(img, tf.float32) / 255.0  # 正規化。\n    return img\n\n# テストデータディレクトリのパス。\ntest_data_dir = \"/kaggle/working/data/test\"\n\n# テストデータのファイルパスリストを取得。\ntest_image_paths = [os.path.join(test_data_dir, fname) for fname in os.listdir(test_data_dir)]\n\n# テストデータを読み込みと前処理を適用。\ntest_ds = tf.data.Dataset.from_tensor_slices(test_image_paths)\ntest_ds = test_ds.map(load_and_preprocess_test_image)\n","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:41:40.479732Z","iopub.execute_input":"2024-02-17T10:41:40.480085Z","iopub.status.idle":"2024-02-17T10:41:40.660447Z","shell.execute_reply.started":"2024-02-17T10:41:40.480059Z","shell.execute_reply":"2024-02-17T10:41:40.659413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# テストデータからサンプルを抽出して可視化。\nsample_test_ds = test_ds.take(10)  # 最初の10個のテストサンプルを抽出。\nsample_labels = predictions[:10]   # 対応する予測ラベルを取得。\n\n# サンプルとラベルを可視化するための関数。\ndef visualize_test_samples_with_labels(dataset, labels, num_samples=10):\n    plt.figure(figsize=(15, 15))\n    for i, (image, label) in enumerate(zip(dataset, labels)):\n        plt.subplot(num_samples, 1, i+1)\n        plt.imshow(image.numpy().squeeze(), cmap='gray')\n        label_text = \"Dog\" if label == 0 else \"Cat\"\n        plt.title(f\"Label: {label_text}\")\n        plt.axis('off')\n    plt.show()\n\nvisualize_test_samples_with_labels(sample_test_ds, sample_labels)\n","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:41:40.661747Z","iopub.execute_input":"2024-02-17T10:41:40.662121Z","iopub.status.idle":"2024-02-17T10:41:41.441458Z","shell.execute_reply.started":"2024-02-17T10:41:40.662093Z","shell.execute_reply":"2024-02-17T10:41:41.440507Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.DataFrame({\"id\": range(1, len(predictions) + 1), \"label\": predictions})\nsubmission.to_csv(\"cnn_submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:41:41.442755Z","iopub.execute_input":"2024-02-17T10:41:41.443165Z","iopub.status.idle":"2024-02-17T10:41:41.477916Z","shell.execute_reply.started":"2024-02-17T10:41:41.443135Z","shell.execute_reply":"2024-02-17T10:41:41.476951Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## ResNet50","metadata":{}},{"cell_type":"code","source":"BATCH_SIZE = 2  # 大きいと学習が途中で止まることがある。\nEPOCHS = 25\nNUM_CLASSES = 2","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:41:41.479058Z","iopub.execute_input":"2024-02-17T10:41:41.479333Z","iopub.status.idle":"2024-02-17T10:41:41.485856Z","shell.execute_reply.started":"2024-02-17T10:41:41.479308Z","shell.execute_reply":"2024-02-17T10:41:41.484772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# モデルを選択。\nbase_model = ResNet50(input_shape=(*TARGET_SIZE, 3), include_top=False, weights='imagenet')\n\n# ベースモデルを凍結。\nfor layer in base_model.layers:\n    layer.trainable = False\n\n# カスタムヘッドを追加。\nmodel = models.Sequential([\n    base_model,\n    layers.Flatten(),\n    layers.Dense(256, activation='relu'),\n    layers.Dense(NUM_CLASSES, activation='softmax')\n])\n\n# モデルをコンパイル。\nmodel.compile(\n    optimizer='adam',\n    loss='sparse_categorical_crossentropy',\n    metrics=['accuracy']\n)","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:41:41.487336Z","iopub.execute_input":"2024-02-17T10:41:41.487857Z","iopub.status.idle":"2024-02-17T10:41:44.533455Z","shell.execute_reply.started":"2024-02-17T10:41:41.487830Z","shell.execute_reply":"2024-02-17T10:41:44.532406Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# データセットの読み込みと前処理。\ndef load_and_preprocess_image(image_path, label):\n    image = tf.io.read_file(image_path)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.resize(image, TARGET_SIZE)\n    image = tf.cast(image, tf.float32) / 255.0\n    return image, label\n\n# 特徴データとラベルデータのリストを作成。\nfeature_data, label_data = [], []\n\nfor class_num, category in enumerate(CATEGORIES):\n    path = os.path.join(DATADIR, category)\n    for image_name in os.listdir(path):\n        try:\n            image_path = os.path.join(path, image_name)\n            feature_data.append(image_path)\n            label_data.append(class_num)\n        except Exception as e:\n            print(\"Error processing image:\", e)\n\n# データの分割。\ntrain_x, valid_x, train_y, valid_y = train_test_split(\n    feature_data, label_data, test_size=0.1, random_state=50\n)\n\n# データセットの作成。\nAUTOTUNE = tf.data.experimental.AUTOTUNE\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\ntrain_ds = (\n    train_ds.shuffle(len(train_x))\n    .repeat()\n    .map(load_and_preprocess_image, num_parallel_calls=AUTOTUNE)\n    .batch(BATCH_SIZE)\n    .prefetch(buffer_size=AUTOTUNE)\n)\n\nvalid_ds = valid_ds.map(load_and_preprocess_image, num_parallel_calls=AUTOTUNE)\nvalid_ds = valid_ds.batch(BATCH_SIZE)\n\n# モデルの学習。\nhistory = model.fit(train_ds, epochs=EPOCHS, validation_data=valid_ds, steps_per_epoch=len(train_x) // BATCH_SIZE)","metadata":{"execution":{"iopub.status.busy":"2024-02-17T10:41:44.534635Z","iopub.execute_input":"2024-02-17T10:41:44.534916Z","iopub.status.idle":"2024-02-17T11:38:10.404359Z","shell.execute_reply.started":"2024-02-17T10:41:44.534892Z","shell.execute_reply":"2024-02-17T11:38:10.403227Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# テストデータの前処理。\nfeature_test_data = []\n\nfor image_path in os.listdir(TESTDIR):\n    try:\n        image_path = os.path.join(TESTDIR, image_path)\n        feature_test_data.append(image_path)\n    except Exception as e:\n        print(f\"Error processing image: {e}\")","metadata":{"execution":{"iopub.status.busy":"2024-02-17T11:38:10.408729Z","iopub.execute_input":"2024-02-17T11:38:10.409084Z","iopub.status.idle":"2024-02-17T11:38:10.459230Z","shell.execute_reply.started":"2024-02-17T11:38:10.409057Z","shell.execute_reply":"2024-02-17T11:38:10.458303Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# テストデータセットの作成。\ntest_ds = tf.data.Dataset.from_tensor_slices((feature_test_data, [0] * len(feature_test_data)))  # ダミーラベル\n\ntest_ds = (\n    test_ds.map(load_and_preprocess_image, num_parallel_calls=AUTOTUNE)\n    .batch(BATCH_SIZE)\n)\n\ny_pred = model.predict(test_ds)\npredictions = np.argmax(y_pred, axis=1)\n\nsubmission = pd.DataFrame({\"id\": range(1, len(predictions) + 1), \"label\": predictions})\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2024-02-17T11:38:10.460406Z","iopub.execute_input":"2024-02-17T11:38:10.460700Z","iopub.status.idle":"2024-02-17T11:39:05.958595Z","shell.execute_reply.started":"2024-02-17T11:38:10.460678Z","shell.execute_reply":"2024-02-17T11:39:05.957806Z"},"trusted":true},"execution_count":null,"outputs":[]}]}