{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.18","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":31090,"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},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## ライブラリのインポート","metadata":{}},{"cell_type":"code","source":"import zipfile # zipファイルの解凍に必要\nimport tensorflow as tf # 機械学習に必要\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator # データの正規化に必要\nfrom tensorflow.keras import layers, models, regularizers # レイヤークラス, 学習モデル\nfrom tensorflow.keras.preprocessing import image # 画像の前処理に必要\n#from tensorflow.keras.applications import InceptionV3\n#from tensorflow.keras.layers import Dense, GlobalAveragePooling2D, Input\n#from tensorflow.keras.models import Model\nimport shutil # クラス分けに必要\nimport random\nimport glob # ファイルのソートに必要\nimport re","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## ハイパーパラメータの定義","metadata":{}},{"cell_type":"code","source":"hyper_epochs = 10\nhyper_split_rate = 0.8","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## CNNモデルの構築\n学習モデルを構築する。Seqential()は順番に積み重ねるタイプのニューラルネットワークである。\n\n- Conv2D（畳み込み層）\n  - 第一引数：フィルター数\n  - 第二引数：フィルターサイズ\n  - 第三引数：活性化関数\n  - 第四引数：入力サイズ\n- MaxPooling2D（プーリング層）\n  - n*nの領域ごとに最大値を取って縮小する。\n- Flatten\n  - 出力を1次元のベクトルに変換\n- Dense（全結合層）\n  - 第一引数：ノード数\n  - 第二引数：活性化関数","metadata":{}},{"cell_type":"code","source":"model = models.Sequential([\n    layers.Conv2D(32, (3, 3), activation='relu', input_shape=(150, 150, 3)), # 画像化から特徴を抽出する\n    layers.MaxPooling2D(2, 2), # 重要な情報を残しつつ、画像サイズを圧縮\n    layers.Conv2D(64, (3, 3), activation='relu'),\n    layers.MaxPooling2D(2, 2),\n    layers.Conv2D(128, (3, 3), activation='relu'),\n    layers.MaxPooling2D(2, 2),\n    layers.Flatten(), # 畳み込み層の出力を、1次元のベクトルに変換\n    layers.Dense(512, activation='relu'), # 中間特徴を学習し、分析精度を向上させる\n    layers.Dense(1, activation='sigmoid') # sigmoidにより0-1の確率を算出\n])","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\"\"\"base_model = InceptionV3(\n    weights='imagenet',\n    include_top=False,\n    input_shape=(299, 299, 3)\n)\n\nbase_model.trainable = False\n\nx = base_model.output\nx = GlobalAveragePooling2D()(x)\nx = Dense(1024, activation='relu')(x)\noutput = Dense(2, activation='softmax')(x)\n\nmodel = Model(inputs=base_model.input, outputs=output)\"\"\"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## モデルのコンパイル","metadata":{}},{"cell_type":"code","source":"model.compile(\n    loss='binary_crossentropy', # 損失関数\n    optimizer='adam', # 最適化アルゴリズム\n    metrics=['accuracy'] # 評価指標 accuracy：予測が正解だった割合\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\"\"\"model.compile(\n    loss='categorical_crossentropy',\n    optimizer='adam',\n    metrics=['accuracy']\n)\"\"\"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 学習データファイルを解凍する","metadata":{}},{"cell_type":"code","source":"zip_file = '/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip'\nout_dir = '/kaggle/working'\n\nwith zipfile.ZipFile(zip_file, 'r') as file:\n    file.extractall(out_dir)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 学習データをトレーニング用と検証用で分ける","metadata":{}},{"cell_type":"code","source":"# 画像ファイル一覧を取得し、ランダム化\nlearn_dir = '/kaggle/working/train'\nlearn_file_names = [file for file in os.listdir(learn_dir) if os.path.isfile(os.path.join(learn_dir, file))]\nrandom.shuffle(learn_file_names)\n\n# 分岐点を計算\nsplit_point = int(len(learn_file_names) * hyper_split_rate)\ntrain_file_names = learn_file_names[:split_point]\nval_file_names = learn_file_names[split_point:]\n\n# フォルダ作成\ntrain_dir = '/kaggle/working/train/train'\nval_dir = '/kaggle/working/train/val'\nos.makedirs(train_dir, exist_ok=True)\nos.makedirs(val_dir, exist_ok=True)\n\n# ファイルの移動\nfor file_name in train_file_names:\n    shutil.move(os.path.join(learn_dir, file_name), os.path.join(train_dir, file_name))\n\nfor file_name in val_file_names:\n    shutil.move(os.path.join(learn_dir, file_name), os.path.join(val_dir, file_name))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 画像ファイルをクラスで分別する\n犬の画像を\"/kaggle/working/train/\\*/dogs\"に、猫の画像を\"/kaggle/working/train/\\*/cats\"に分ける。\n\n- cat:0\n- dog:1","metadata":{}},{"cell_type":"code","source":"# クラスを分別する関数\ndef devide_class(any_dir):\n    cat_dir = os.path.join(any_dir, 'cats')\n    dog_dir = os.path.join(any_dir, 'dogs')\n\n    os.makedirs(cat_dir, exist_ok=True)\n    os.makedirs(dog_dir, exist_ok=True)\n\n    for file_name in os.listdir(any_dir):\n        file = os.path.join(any_dir, file_name)\n        if not os.path.isfile(file):\n            continue\n\n        if file_name.lower().startswith('cat'):\n            shutil.move(os.path.join(any_dir, file_name), os.path.join(cat_dir, file_name))\n        elif file_name.lower().startswith('dog'):\n            shutil.move(os.path.join(any_dir, file_name), os.path.join(dog_dir, file_name))\n\ndevide_class('/kaggle/working/train/train')\ndevide_class('/kaggle/working/train/val')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## データの正規化を行う\nImageDataGeneratorは画像の前処理やデータ拡張を行うためのクラスである。\"rescale=1./255\"は画像のピクセル値（0-255）を0-1に正規化する。","metadata":{}},{"cell_type":"code","source":"train_datagen = ImageDataGenerator(rescale=1./255,\n    rotation_range=20,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    zoom_range=0.2,\n    horizontal_flip=True)\nval_datagen = ImageDataGenerator(rescale=1./255)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## ジェネレーターを作成する\nflow_datagen.flow_from_directory()は、指定したディレクトリ構造に基づいて、自動的に画像とラベルを生成するジェネレーターを作成する。\n- '/kaggle/working/train/train' ：トレーニング画像が保存されている親ディレクトリ\n- target_size=(150, 150) ：すべての画像を150*150にリサイズする\n- batch_size=32 ：1回の学習ステップで32枚の画像を処理する\n- class_mode='binary' ：クラスが2つ（犬、猫）のため、出力は0か1の2値","metadata":{}},{"cell_type":"code","source":"train_generator = train_datagen.flow_from_directory(\n    '/kaggle/working/train/train',\n    target_size=(150, 150),\n    batch_size=32,\n    class_mode='binary'\n)\n\nval_generator = train_datagen.flow_from_directory(\n    '/kaggle/working/train/val',\n    target_size=(150, 150),\n    batch_size=32,\n    class_mode='binary'\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## モデルの学習","metadata":{}},{"cell_type":"code","source":"history = model.fit(\n    train_generator,\n    epochs=hyper_epochs, # 訓練データをn回学習する\n    validation_data=val_generator\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\"\"\"base_model.trainable = True\n\nfor layer in base_model.layers[:-30]:\n    layer.trainable = False\n\nmodel.compile(\n    loss='categorical_crossentropy',\n    optimizer='adam',\n    metrics=['accuracy']\n)\n\nmodel.fit(train_generator, epochs=10, validation_data=val_generator)\"\"\"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## モデルのセーブとロード","metadata":{}},{"cell_type":"code","source":"model_file = '/kaggle/working/cnn.h5'\n\nmodel.save(model_file)\n# model = load_model(model_file)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## テストデータファイルを解凍する","metadata":{}},{"cell_type":"code","source":"zip_file = '/kaggle/input/dogs-vs-cats-redux-kernels-edition/test1.zip'\nout_dir = '/kaggle/working'\n\nwith zipfile.ZipFile(zip_file, 'r') as file:\n    file.extractall(out_dir)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## テストデータのソート","metadata":{}},{"cell_type":"code","source":"# ファイル一覧を所得\ntest_dir = '/kaggle/working/test1'\ntest_files = os.listdir(test_dir)\n\n# 数値順にソートする関数\ndef extract_number(filename):\n    match = re.search(r'\\d+', filename)\n    return int(match.group()) if match else -1\n\n# 数値順にソート\nsorted_files = sorted(test_files, key=extract_number)\n\n# 画像ファイルのフルパスリスト\nimage_path_list = [os.path.join(test_dir, image) for image in sorted_files]","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## テストデータの推論\n画像の読み込んだあと、numpy配列に変換する。その後、推論を行う。","metadata":{}},{"cell_type":"code","source":"# 前処理\nimages = [image.img_to_array(image.load_img(path, target_size=(150, 150))) / 255.0 for path in image_path_list]\nbatch = np.array(images)\n\n# 推論\npreds = model.predict(batch)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 結果の出力\nCSVで結果を保存","metadata":{}},{"cell_type":"code","source":"# IDの取得\nids = [os.path.splitext(os.path.basename(path))[0] for path in image_path_list]\n\n# ラベルの取得\nlabels = [1 if p[0] > 0.5 else 0 for p in preds]\n\n# CSVで保存\ndf = pd.DataFrame({'id': ids, 'label': labels})\ndf.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}