{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","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":30733,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# データのロードや処理の準備を行うための基本的なセットアップ\n\n- ライブラリのインポート\n- 入力データファイルをリストする\n- ファイルのフルパスを出力する","metadata":{}},{"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) ・データ処理や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# os.walkを使用して、/kaggle/inputディレクトリ内のすべてのファイルをリストする\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":{"execution":{"iopub.status.busy":"2024-07-24T14:51:40.180575Z","iopub.execute_input":"2024-07-24T14:51:40.181246Z","iopub.status.idle":"2024-07-24T14:51:40.198402Z","shell.execute_reply.started":"2024-07-24T14:51:40.181213Z","shell.execute_reply":"2024-07-24T14:51:40.197352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# データを準備する\n# ・zipファイルの展開","metadata":{}},{"cell_type":"code","source":"import zipfile # ZIPアーカイブを作成するためのクラス\n\n#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-07-24T14:51:40.200552Z","iopub.execute_input":"2024-07-24T14:51:40.201202Z","iopub.status.idle":"2024-07-24T14:51:52.084480Z","shell.execute_reply.started":"2024-07-24T14:51:40.201166Z","shell.execute_reply":"2024-07-24T14:51:52.083339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ライブラリをインストール","metadata":{}},{"cell_type":"code","source":"import numpy as np #numpy（Pythonでの機械学習の計算をより速くかつ効率的に行えるようにする拡張モジュール）\nimport pandas as pd\nimport os\nimport shutil\nimport cv2\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport tensorflow.keras as keras\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.models import load_model\nimport csv","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:52.085735Z","iopub.execute_input":"2024-07-24T14:51:52.086023Z","iopub.status.idle":"2024-07-24T14:51:52.091838Z","shell.execute_reply.started":"2024-07-24T14:51:52.085998Z","shell.execute_reply":"2024-07-24T14:51:52.090789Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# パスを設定（ファイルの場所を決める）","metadata":{}},{"cell_type":"code","source":"# trainデータのディレクトリのパスを設定する\ntrain_dir = '/kaggle/working/train/train'","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:52.095242Z","iopub.execute_input":"2024-07-24T14:51:52.095762Z","iopub.status.idle":"2024-07-24T14:51:52.104303Z","shell.execute_reply.started":"2024-07-24T14:51:52.095734Z","shell.execute_reply":"2024-07-24T14:51:52.103325Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# testデータのディレクトリのパスを設定する\ntest_dir = '/kaggle/working/test/test'","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:52.105299Z","iopub.execute_input":"2024-07-24T14:51:52.105608Z","iopub.status.idle":"2024-07-24T14:51:52.113260Z","shell.execute_reply.started":"2024-07-24T14:51:52.105584Z","shell.execute_reply":"2024-07-24T14:51:52.112311Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 画像の大きさを統一する","metadata":{}},{"cell_type":"code","source":"# 画像のサイズを64で統一する\nIMG_SIZE = 64","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:52.114764Z","iopub.execute_input":"2024-07-24T14:51:52.115454Z","iopub.status.idle":"2024-07-24T14:51:52.121944Z","shell.execute_reply.started":"2024-07-24T14:51:52.115420Z","shell.execute_reply":"2024-07-24T14:51:52.121021Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# データ読み込み関数を作成する\n理由：関数にすることで同じコードを打たなくても済むようにしたい","metadata":{}},{"cell_type":"code","source":"# データを読み込むための関数\ndef load_data(data_dir, sample_size=1000):\n    images = [] # 写真を入れるためのリスト\n    labels = [] # 写真が犬か猫かを判別するラベルを保存するためのリスト\n    files = os.listdir(data_dir)[:sample_size] # ファイルの一覧を獲得できるコード + サイズを指定\n#     print(f'（発見） {len(files)} files in {data_dir}')  # デバッグ（ソースコードのエラーやバグを見つけて修正する）文。（ここでは、見つけたディレクトリの表示）\n    for file in files: # for文で全体的に網羅する\n        img_path = os.path.join(data_dir, file) # ディレクトリのパスとファイル名（写真名）を結合して(join)、ファイル（写真）のパスを作り、img_pathに入れる\n#         print(f'（ファイル読み込み） {img_path}')  # デバッグ文（ここでは、読み込んだファイルを表示する）\n        img = cv2.imread(img_path) # 写真を得る\n        if img is not None: # もし、写真がNoneではないなら（写真があれば）\n            img = cv2.resize(img, (IMG_SIZE, IMG_SIZE)) # 写真の大きさを調整\n            images.append(img) # 一枚ずつリストに収納\n            label = 1 if 'dog' in file else 0 # 写真が犬 = 1, 猫 = 0としてラベルする\n            labels.append(label) # リストにラベルを収納\n        else: #　それ以外、例えば、写真がきちんと読み込めていない場合\n            print(f'（エラー）ファイル読み込み不可 {img_path}')  # デバッグ文（読み込めてない場合、エラーを示す）\n    return np.array(images) / 255.0, np.array(labels) #  値を返す（写真、ラベルのリスト）","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:52.123008Z","iopub.execute_input":"2024-07-24T14:51:52.123296Z","iopub.status.idle":"2024-07-24T14:51:52.131262Z","shell.execute_reply.started":"2024-07-24T14:51:52.123273Z","shell.execute_reply":"2024-07-24T14:51:52.130427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# trainデータ、testデータの読み込み","metadata":{}},{"cell_type":"code","source":"X_train, y_train = load_data(train_dir, sample_size=1000)\nX_test, y_test = load_data(test_dir, sample_size=500)","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:52.132061Z","iopub.execute_input":"2024-07-24T14:51:52.132303Z","iopub.status.idle":"2024-07-24T14:51:53.438362Z","shell.execute_reply.started":"2024-07-24T14:51:52.132281Z","shell.execute_reply":"2024-07-24T14:51:53.437319Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 読み込まれているか確認（データの形状を確認）","metadata":{}},{"cell_type":"code","source":"# print(f'X_train shape: {X_train.shape}')\n# print(f'y_train shape: {y_train.shape}')\n# print(f'X_test shape: {X_test.shape}')\n# print(f'y_test shape: {y_test.shape}')","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:53.440142Z","iopub.execute_input":"2024-07-24T14:51:53.440534Z","iopub.status.idle":"2024-07-24T14:51:53.444493Z","shell.execute_reply.started":"2024-07-24T14:51:53.440490Z","shell.execute_reply":"2024-07-24T14:51:53.443557Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 性能を上げるためにデータを拡張する","metadata":{}},{"cell_type":"code","source":"# 全てのコードをランダムに試行\ndatagen = ImageDataGenerator(\n    rotation_range=20, # 最大20度まで画像の回転\n    width_shift_range=0.2, # 水平方向に最大20%移動\n    height_shift_range=0.2, # 垂直方向に最大20%移動\n    shear_range=0.2, # 画像を斜め方向に最大20%拡張\n    zoom_range=0.2, # 最大20%ズーム\n    horizontal_flip=True, # 水平方向に反転\n    fill_mode='nearest' # 変換後の空白を処理\n)","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:53.447807Z","iopub.execute_input":"2024-07-24T14:51:53.448105Z","iopub.status.idle":"2024-07-24T14:51:53.459332Z","shell.execute_reply.started":"2024-07-24T14:51:53.448080Z","shell.execute_reply":"2024-07-24T14:51:53.458272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# モデルを作成する","metadata":{}},{"cell_type":"markdown","source":"# モデルの関数を作成する（畳み込みニューラルネットワークを用いる）","metadata":{}},{"cell_type":"code","source":"# モデルの作成\ndef create_model(neuron):\n    # 必要なライブラリ、関数をインポート\n    Dense = keras.layers.Dense\n    Conv2D = keras.layers.Conv2D\n    MaxPooling2D = keras.layers.MaxPooling2D\n    Flatten = keras.layers.Flatten\n    Dropout = keras.layers.Dropout\n    \n    # モデルを定義する\n    model = keras.models.Sequential()\n    \n    # 畳み込みニューラルネットワークのレイヤー追加\n    \n    # 32個のフィルターと3x3のカーネルサイズを持つ畳み込み層を作成する。活性化関数はreluを使用する。入力画像の形状はカラー画像（赤、青、緑）なので、チャンネル数は3である。\n    model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(IMG_SIZE, IMG_SIZE, 3)))\n    # 2x2のプーリング層を使用して、空間サイズを半分にする。\n    model.add(MaxPooling2D((2, 2)))\n    \n    # 64個のフィルターと3x3のカーネルサイズを持つ畳み込み層を作成する。活性化関数はreluを使用する。\n    model.add(Conv2D(64, (3, 3), activation='relu'))\n    # 2x2のプーリング層を使用して、空間サイズを半分にする。\n    model.add(MaxPooling2D((2, 2)))\n    \n    # 128個のフィルターと3x3のカーネルサイズを持つ畳み込み層を作成する。活性化関数はreluを使用する。\n    model.add(Conv2D(128, (3, 3), activation='relu'))\n    # 2x2のプーリング層を使用して、空間サイズを半分にする。\n    model.add(MaxPooling2D((2, 2)))\n    \n    # 全結合層を追加します　　　　　　　　\n    # Flatten(): 3次元の特徴マップを1次元のベクトルに変換する\n    model.add(Flatten())\n    # neuron:指定した数のユニットを持つ全結合層。\n    model.add(Dense(neuron, activation='relu'))\n    # ドロップアウト正則化を適用し、半分のニューロンをランダムに無効化する。\n    model.add(Dropout(0.5))\n    # 出力層にはシグモイド活性化関数を使用する。\n    model.add(Dense(1, activation='sigmoid'))\n\n    # モデルをコンパイルする。\n    # 損失関数はバイナリクロスエントロピーを使用し、最適化アルゴリズムはAdamを選択する。モデルの評価指標はaccuracy（精度）とする。\n    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])\n    \n    # モデルの返還\n    return model","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:53.460906Z","iopub.execute_input":"2024-07-24T14:51:53.461215Z","iopub.status.idle":"2024-07-24T14:51:53.472399Z","shell.execute_reply.started":"2024-07-24T14:51:53.461190Z","shell.execute_reply":"2024-07-24T14:51:53.471454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# モデルを保存する","metadata":{}},{"cell_type":"code","source":"def save_model(model, filename):\n    model.save(filename)","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:53.473609Z","iopub.execute_input":"2024-07-24T14:51:53.474020Z","iopub.status.idle":"2024-07-24T14:51:53.482360Z","shell.execute_reply.started":"2024-07-24T14:51:53.473989Z","shell.execute_reply":"2024-07-24T14:51:53.481296Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# モデルを読み込む","metadata":{}},{"cell_type":"code","source":"def load_existing_model(filename):\n    return load_model(filename)","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:53.483841Z","iopub.execute_input":"2024-07-24T14:51:53.484130Z","iopub.status.idle":"2024-07-24T14:51:53.490169Z","shell.execute_reply.started":"2024-07-24T14:51:53.484105Z","shell.execute_reply":"2024-07-24T14:51:53.489210Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# モデルの学習開始\n学習→評価→評価値を表示","metadata":{}},{"cell_type":"code","source":"# 学習を行い、テストデータで評価してスコアを表示する関数\ndef fit_epoch(neuron, batch, epochs, initial_epoch=0, model_filename='model.h5'):\n    if initial_epoch == 0: # モデルを作成するのが初めての場合\n        # さっき作成したモデル作成関数を実行し、ニューロン数を指定して渡す。\n        model = create_model(neuron)\n    else: # すでにモデルを作成している場合\n        model = load_existing_model(model_filename) #モデルを読み込む\n        \n    model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])\n    \n    # モデルを学習\n    hist = model.fit(datagen.flow(X_train, y_train, batch_size=batch),\n                     steps_per_epoch=len(X_train) // batch,\n                     validation_data=(X_test, y_test),\n                     epochs=epochs,\n                     initial_epoch=initial_epoch,\n                     verbose=1)\n    \n    # モデルを訓練する\n    score = model.evaluate(X_test, y_test, verbose=1)\n    print('正解率=', score[1], 'loss=', score[0])\n    \n    #モデルを保存する\n    save_model(model, model_filename)\n    \n    \n    # 学習結果を可視化して、グラフ化する\n    \n    # trainデータの精度を示すグラフ\n    plt.plot(hist.history['accuracy'])\n    # testデータの精度を示すグラフ\n    plt.plot(hist.history['val_accuracy'])\n    # グラフタイトル\n    plt.title('Accuracy')\n    # 凡例\n    plt.legend(['train', 'test'], loc='upper left')\n    # グラフを表示する\n    plt.show()\n\n    # trainデータの損失値を示すグラフ\n    plt.plot(hist.history['loss'])\n    # testデータの損失値を示すグラフ\n    plt.plot(hist.history['val_loss'])\n    # グラフタイトル\n    plt.title('Loss')\n    # 凡例\n    plt.legend(['train', 'test'], loc='upper left')\n    # グラフを表示する\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:53.491525Z","iopub.execute_input":"2024-07-24T14:51:53.491814Z","iopub.status.idle":"2024-07-24T14:51:53.502572Z","shell.execute_reply.started":"2024-07-24T14:51:53.491791Z","shell.execute_reply":"2024-07-24T14:51:53.501545Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# モデルを作成する","metadata":{}},{"cell_type":"code","source":"### total_epochs = 30  # 総エポック数\nneuron = 512  # 総ニューロン数\nbatch = 8  # バッチの大きさ\nmodel_filename = 'model.h5'  # 保存しているモデルのファイル名","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:53.503664Z","iopub.execute_input":"2024-07-24T14:51:53.503906Z","iopub.status.idle":"2024-07-24T14:51:53.513453Z","shell.execute_reply.started":"2024-07-24T14:51:53.503884Z","shell.execute_reply":"2024-07-24T14:51:53.512607Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 学習（1回目）\nfit_epoch(neuron=neuron, batch=batch, epochs=10, initial_epoch=0, model_filename=model_filename)","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:51:53.514806Z","iopub.execute_input":"2024-07-24T14:51:53.515199Z","iopub.status.idle":"2024-07-24T14:52:06.956659Z","shell.execute_reply.started":"2024-07-24T14:51:53.515167Z","shell.execute_reply":"2024-07-24T14:52:06.955679Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 学習（2回目）\nfit_epoch(neuron=neuron, batch=batch, epochs=20, initial_epoch=10, model_filename=model_filename)","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:52:06.957895Z","iopub.execute_input":"2024-07-24T14:52:06.958189Z","iopub.status.idle":"2024-07-24T14:52:20.462857Z","shell.execute_reply.started":"2024-07-24T14:52:06.958162Z","shell.execute_reply":"2024-07-24T14:52:20.461859Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 学習（3回目）\nfit_epoch(neuron=neuron, batch=batch, epochs=30, initial_epoch=20, model_filename=model_filename)","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:52:20.464257Z","iopub.execute_input":"2024-07-24T14:52:20.464701Z","iopub.status.idle":"2024-07-24T14:52:33.888183Z","shell.execute_reply.started":"2024-07-24T14:52:20.464666Z","shell.execute_reply":"2024-07-24T14:52:33.887266Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 予測結果をCSVファイルとして保存","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport cv2\nimport tensorflow.keras as keras\nfrom tensorflow.keras.models import load_model\n\n# 定数設定\nIMG_SIZE = 64  # 画像の大きさ\ntest_dir = '/kaggle/working/test/test'  # テストデータが格納されているディレクトリ\nmodel_filename = 'model.h5'  # 学習済みモデルのファイル名\noutput_csv = '/kaggle/working/submission.csv'  # 提出用CSVファイルのパス\n\n# 画像データの読み込むための関数\ndef load_test_data(data_dir):\n    images = []\n    filenames = os.listdir(data_dir)\n    for file in filenames:\n        img_path = os.path.join(data_dir, file)\n        img = cv2.imread(img_path)\n        if img is not None:\n            img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))\n            images.append(img)\n        else:\n            print(f'Error reading {img_path}')\n    return np.array(images) / 255.0, filenames\n\n# テストデータを読み込む\nX_test, test_filenames = load_test_data(test_dir)\n\n# モデルを読み込む\nmodel = load_model(model_filename)\n\n# 予測を実行する\npredictions = model.predict(X_test)\n\n# 予測結果を0か1に変換\npredictions = (predictions > 0.5).astype(int).flatten()\n\n# CSVファイルを作成する\noutput_df = pd.DataFrame({\n    'id': [os.path.splitext(f)[0] for f in test_filenames],  # ファイル名から拡張子を取り除いてIDとして使用する\n    'label': predictions\n})\noutput_df.to_csv(output_csv, index=False)\n\nprint(f'CSVファイル {output_csv} の作成完了')","metadata":{"execution":{"iopub.status.busy":"2024-07-24T14:52:33.889393Z","iopub.execute_input":"2024-07-24T14:52:33.889697Z","iopub.status.idle":"2024-07-24T14:52:47.712816Z","shell.execute_reply.started":"2024-07-24T14:52:33.889672Z","shell.execute_reply":"2024-07-24T14:52:47.711788Z"},"trusted":true},"execution_count":null,"outputs":[]}]}