{"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":3362,"databundleVersionId":31148,"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-03T22:23:30.995891Z","iopub.execute_input":"2025-07-03T22:23:30.996560Z","iopub.status.idle":"2025-07-03T22:23:31.018561Z","shell.execute_reply.started":"2025-07-03T22:23:30.996521Z","shell.execute_reply":"2025-07-03T22:23:31.017384Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# データの準備\nモデルを作成するための画像データを準備していく","metadata":{}},{"cell_type":"markdown","source":"## zipファイルの展開\n訓練用・テスト用のzipファイルを展開していく","metadata":{}},{"cell_type":"code","source":"import zipfile\n\n# train.zipの展開\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats/train.zip', 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working')\n\n# test1.zipの展開\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats/test1.zip', 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T22:23:31.020357Z","iopub.execute_input":"2025-07-03T22:23:31.020704Z","iopub.status.idle":"2025-07-03T22:23:48.158504Z","shell.execute_reply.started":"2025-07-03T22:23:31.020681Z","shell.execute_reply":"2025-07-03T22:23:48.157518Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 学習用の画像振り分け\n学習用として犬・猫の画像を振り分けていく","metadata":{}},{"cell_type":"code","source":"import shutil\nfrom pathlib import Path\n\n# pathの定義\ntrain_dir = \"/kaggle/working/train\"\ndog_dir = os.path.join(train_dir, \"dog\")\ncat_dir = os.path.join(train_dir, \"cat\")\n\n# 学習データのフォルダを作成（犬・猫）\nos.makedirs(dog_dir, exist_ok=True)\nos.makedirs(cat_dir, exist_ok=True)\n\n# 最初にすべてのファイル名を取得（固定リスト）\nfile_list = os.listdir(train_dir)\n\n# 移動処理\nfor fname in file_list:\n    src = os.path.join(train_dir, fname)\n\n    # ファイルかつ存在しているかを確認\n    if os.path.isfile(src):\n        if fname.startswith(\"dog\"):\n            shutil.move(src, os.path.join(dog_dir, fname))\n        elif fname.startswith(\"cat\"):\n            shutil.move(src, os.path.join(cat_dir, fname))\n\n# ファイル数の確認\ndog_count = len(list(Path(dog_dir).glob(\"*.jpg\")))\ncat_count = len(list(Path(cat_dir).glob(\"*.jpg\")))\n\nprint(\"dog:\", dog_count)\nprint(\"cat:\", cat_count)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T22:23:48.159634Z","iopub.execute_input":"2025-07-03T22:23:48.160038Z","iopub.status.idle":"2025-07-03T22:23:50.101050Z","shell.execute_reply.started":"2025-07-03T22:23:48.160008Z","shell.execute_reply":"2025-07-03T22:23:50.100103Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## ファイルの確認\nちゃんと犬と猫の画像データを仕分けられているか確認する。\n\n乱数を用いて確認できるようにしている","metadata":{}},{"cell_type":"code","source":"# 画像表示に必要なモジュールをインポート\nimport glob\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport random\n\ndog_images = glob.glob('/kaggle/working/train/dog/*.jpg')\ncat_images = glob.glob('/kaggle/working/train/cat/*.jpg')\n\n# 画像の表示（犬）\nindex = random.randint(0, dog_count)\nimage_sample = dog_images[index]\nimg = Image.open(image_sample)\nprint('filename:{}, size:{}'.format(image_sample, img.size))\nplt.imshow(img)\nplt.show()\n\n# 画像の表示（猫）\nindex = random.randint(0, cat_count)\nimage_sample = cat_images[index]\nimg = Image.open(image_sample)\nprint('filename:{}, size:{}'.format(image_sample, img.size))\nplt.imshow(img)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T22:23:50.102043Z","iopub.execute_input":"2025-07-03T22:23:50.102284Z","iopub.status.idle":"2025-07-03T22:23:50.682212Z","shell.execute_reply.started":"2025-07-03T22:23:50.102264Z","shell.execute_reply":"2025-07-03T22:23:50.681266Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 訓練用と検証用に画像を振り分け\n先程仕分けた画像データをそれぞれ訓練用,検証用に分ける(訓練用：テスト用 = 0.8: 0.2)","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\n# クラス作成\nanimal_class = ['cat', 'dog'] # overviewによるとcat=0,dog=1\n\n# 検証用データを格納するフォルダを作成\nos.makedirs(\"/kaggle/working/val/dog\", exist_ok=True)\nos.makedirs(\"/kaggle/working/val/cat\", exist_ok=True)\n\n# 実際に仕分けていく\nfor cls in animal_class:\n    files = list(Path(\"/kaggle/working/train\", cls).glob(\"*.jpg\"))\n    train_f, val_f = train_test_split(files, test_size=0.2, random_state=42)\n    for f in val_f:\n        dest = Path(\"/kaggle/working/val\", cls)\n        shutil.move(f, os.path.join(dest,f.name))\n\n#ファイル数の確認\n# 元がそれぞれ12500なので訓練用 = 10000,検証用 = 2500になっているはず\nprint(\"dog(train):\", len(list(Path(\"/kaggle/working/train/dog\").glob(\"*.jpg\"))))\nprint(\"dog(val):\", len(list(Path(\"/kaggle/working/val/dog\").glob(\"*.jpg\"))))\nprint(\"cat(train):\", len(list(Path(\"/kaggle/working/train/cat\").glob(\"*.jpg\"))))\nprint(\"cat(val):\", len(list(Path(\"/kaggle/working/val/cat\").glob(\"*.jpg\"))))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T22:23:50.684209Z","iopub.execute_input":"2025-07-03T22:23:50.684512Z","iopub.status.idle":"2025-07-03T22:23:52.845978Z","shell.execute_reply.started":"2025-07-03T22:23:50.684489Z","shell.execute_reply":"2025-07-03T22:23:52.845128Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 学習前の準備\n画像データが少ないと機械学習モデルが過学習しやすく、汎化性能が落ちるためデータ数を増やす","metadata":{}},{"cell_type":"markdown","source":"## 前準備\nテストデータの構造をflow_from_directoryに対応させる","metadata":{}},{"cell_type":"code","source":"#testフォルダの中にサブフォルダを作成（flow_from_directory使うにはサブフォルダじゃなきゃだめらしい）\nos.makedirs(\"/kaggle/working/test1/unknows\", exist_ok=True)\n\n# 最初にすべてのファイル名を取得（固定リスト）\nfile_list = os.listdir(\"/kaggle/working/test1\")\n\n#test1フォルダ内の画像データをサブフォルダに移動\nfor fname in file_list:\n    src = os.path.join(\"/kaggle/working/test1\", fname)\n\n    # ファイルかつ存在しているかを確認\n    if os.path.isfile(src):\n        shutil.move(src, os.path.join(\"/kaggle/working/test1/unknows\", fname))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T22:23:52.847135Z","iopub.execute_input":"2025-07-03T22:23:52.847873Z","iopub.status.idle":"2025-07-03T22:23:54.155652Z","shell.execute_reply.started":"2025-07-03T22:23:52.847841Z","shell.execute_reply":"2025-07-03T22:23:54.154502Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## ImageDataGeneratorを用いたデータ数増加\n訓練用データのみに実施","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n\n# 各データのディレクトリのpathを定義\ntrain_data_dir = '/kaggle/working/train'\nvalidation_data_dir = '/kaggle/working/val'\ntest_data_dir = '/kaggle/working/test1'\n\n#flow_from_directory用の変数を定義\nimg_width, img_height = 224, 224  # 画像サイズ\nbatch_size = 1024                 # バッチサイズ\n\n# 学習データのImageDataGenerator作成\ntrain_datagen = ImageDataGenerator(\n    rescale=1.0 / 255,          # 各画素のスケールを0～255から0～1に変換して正規化\n    rotation_range=20,          # 画像をランダムに ±20度まで回転（被写体の位置ズレに強くなる）\n    width_shift_range=0.1,      # 横方向にランダムで最大10%（被写体の位置ズレに強くなる）\n    height_shift_range=0.1,     # 縦方向にランダムで最大10%（被写体の位置ズレに強くなる）\n    zoom_range=0.1,             # ランダム(±10%)にズームイン or ズームアウト （被写体のサイズ変化に強くなる）\n    horizontal_flip=True        # ランダムで画像を左右反転させる (右向き・左向き両方学習できる)\n)\n\n# データ数増加\ntrain_generator = train_datagen.flow_from_directory(\n    directory=train_data_dir,\n    target_size=(img_width, img_height),\n    color_mode='rgb',\n    classes=animal_class,\n    class_mode='categorical',\n    batch_size=batch_size\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T22:23:54.156685Z","iopub.execute_input":"2025-07-03T22:23:54.156965Z","iopub.status.idle":"2025-07-03T22:23:54.355567Z","shell.execute_reply.started":"2025-07-03T22:23:54.156939Z","shell.execute_reply":"2025-07-03T22:23:54.354427Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 検証,テスト用のデータは正規化のみ実施\n正規化を行うと処理が高速になる","metadata":{}},{"cell_type":"code","source":"# 検証,テスト用のデータのImageDataGenerator作成\nval_datagen = ImageDataGenerator(rescale=1.0 / 255)\ntest_datagen = ImageDataGenerator(rescale=1.0 / 255)\n\n#検証データの正規化\nval_generator = val_datagen.flow_from_directory(\n    directory=validation_data_dir,\n    target_size=(img_width, img_height),\n    color_mode='rgb',\n    classes=animal_class,\n    class_mode='categorical',\n    batch_size=batch_size,\n    shuffle=False\n)\n\n#テストデータの正規化（こっちは犬と猫でclass分けしていないのでclasses指定なし）\ntest_generator = test_datagen.flow_from_directory(\n    directory=test_data_dir,\n    target_size=(img_width, img_height),\n    color_mode='rgb',\n    class_mode=None,\n    batch_size=batch_size,\n    shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T22:23:54.356571Z","iopub.execute_input":"2025-07-03T22:23:54.356837Z","iopub.status.idle":"2025-07-03T22:23:54.527233Z","shell.execute_reply.started":"2025-07-03T22:23:54.356818Z","shell.execute_reply":"2025-07-03T22:23:54.526291Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 学習モデル(CNN)の作成","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Conv2D, Input, MaxPooling2D, Flatten, Dense, Dropout\nfrom tensorflow.keras.optimizers import Adam\n\n\n# モデル構築\nmodel = Sequential([\n    Input(shape=(img_width, img_height, 3)),\n    Conv2D(32, (3, 3), activation='relu'),\n    MaxPooling2D(2, 2),\n    \n    Conv2D(64, (3, 3), activation='relu'),\n    MaxPooling2D(2, 2),\n    \n    Conv2D(128, (3, 3), activation='relu'),\n    MaxPooling2D(2, 2),\n    \n    Flatten(),\n    Dense(512, activation='relu'),\n    Dropout(0.5),\n    Dense(2, activation='softmax')\n])\n\n# コンパイル\nmodel.compile(\n    optimizer=Adam(learning_rate=0.0001),\n    loss='categorical_crossentropy',\n    metrics=['accuracy']\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T22:23:54.528221Z","iopub.execute_input":"2025-07-03T22:23:54.528522Z","iopub.status.idle":"2025-07-03T22:23:55.334029Z","shell.execute_reply.started":"2025-07-03T22:23:54.528493Z","shell.execute_reply":"2025-07-03T22:23:55.333045Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 学習を実行","metadata":{}},{"cell_type":"code","source":"# 学習回数を設定\nepochs = 10\n\nhistory = model.fit(\n    train_generator,\n    epochs = epochs,\n    validation_data = val_generator\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-03T22:23:55.334991Z","iopub.execute_input":"2025-07-03T22:23:55.335313Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 評価\n検証用データ（val）を用いて評価を実施","metadata":{}},{"cell_type":"code","source":"loss, accuracy = model.evaluate(val_generator)\nprint(f\"Validation Loss: {loss}\")\nprint(f\"Validation Accuracy: {accuracy}\")\n\n# 推論結果の取得\npred_probs = model.predict(test_generator)\n\n# クラスのインデックスに変換（0 or 1）\npred_classes = np.argmax(pred_probs, axis=1)\npred_classes","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-04T01:22:54.774189Z","iopub.execute_input":"2025-07-04T01:22:54.774383Z","iopub.status.idle":"2025-07-04T01:22:54.846625Z","shell.execute_reply.started":"2025-07-04T01:22:54.774366Z","shell.execute_reply":"2025-07-04T01:22:54.845176Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 結果の表示","metadata":{}},{"cell_type":"code","source":"## 結果を表に作成\npred_pd = pd.DataFrame(pred_probs)\n# id列を作成\npred_pd.insert(0, 'id', range(1, len(pred_pd) + 1))\npred_pd.columns\npred_pd = pred_pd.drop([0], axis=1)\npred_pd = pred_pd.rename(columns={1: 'label'})\npred_pd","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 結果の保存.csvファイル化","metadata":{}},{"cell_type":"code","source":"sub = pd.read_csv('/kaggle/input/dogs-vs-cats/sampleSubmission.csv') # ひな形ファイルを読み込む\nprint(sub.shape)\n# subのlabel列をtest_predictedのlabel列で上書きする\nsub['label'] = pred_pd['label']\n# 結果を表示\nsub\nsub.to_csv('submission.csv', index=False) # 変換したファイルを保存","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}