{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"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","execution":{"iopub.status.busy":"2023-07-30T01:42:43.558805Z","iopub.execute_input":"2023-07-30T01:42:43.559181Z","iopub.status.idle":"2023-07-30T01:42:43.568549Z","shell.execute_reply.started":"2023-07-30T01:42:43.559144Z","shell.execute_reply":"2023-07-30T01:42:43.567501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## データ準備\n・zipファイルの展開\n・使用するディレクトリを作成する\n・作成したディレクトリに画像を移動する","metadata":{}},{"cell_type":"code","source":"import zipfile\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":"2023-07-30T01:42:49.388059Z","iopub.execute_input":"2023-07-30T01:42:49.388742Z","iopub.status.idle":"2023-07-30T01:43:06.690902Z","shell.execute_reply.started":"2023-07-30T01:42:49.388708Z","shell.execute_reply":"2023-07-30T01:43:06.689985Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ライブラリのインポート(globライブラリを用いてファイル検索)\nimport glob\n\n# ファイル一覧を取得\nimages = glob.glob('/kaggle/working/train/train/*.jpg')\n\n# ファイル名を確認(先頭3枚)\nprint(images[:3])","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:43:12.110018Z","iopub.execute_input":"2023-07-30T01:43:12.110435Z","iopub.status.idle":"2023-07-30T01:43:12.219239Z","shell.execute_reply.started":"2023-07-30T01:43:12.110401Z","shell.execute_reply":"2023-07-30T01:43:12.218153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 画像表示に必要なモジュールをインポート\nimport matplotlib.pyplot as plt\nfrom PIL import Image\n\n# 画像の表示\nimage_sample = images[0]\nimg = Image.open(image_sample)\nprint('filename:{}, size:{}'.format(image_sample, img.size))\nplt.imshow(img)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:43:24.514863Z","iopub.execute_input":"2023-07-30T01:43:24.515274Z","iopub.status.idle":"2023-07-30T01:43:24.930944Z","shell.execute_reply.started":"2023-07-30T01:43:24.515241Z","shell.execute_reply":"2023-07-30T01:43:24.930096Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os \n\n# train用フォルダ作成(学習データ)\nos.makedirs('/kaggle/working/images/train/dog', exist_ok=True)\nos.makedirs('/kaggle/working/images/train/cat', exist_ok=True)\n\n# val用フォルダ作成(検証データ)\nos.makedirs('/kaggle/working/images/val/dog', exist_ok=True)\nos.makedirs('/kaggle/working/images/val/cat', exist_ok=True)\n\n# test用フォルダ作成(テストデータ)\nos.makedirs('/kaggle/working/images/test/test', exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:43:30.955877Z","iopub.execute_input":"2023-07-30T01:43:30.956777Z","iopub.status.idle":"2023-07-30T01:43:30.963338Z","shell.execute_reply.started":"2023-07-30T01:43:30.956737Z","shell.execute_reply":"2023-07-30T01:43:30.962441Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 画像のファイルパスを取得\nimages_dog = glob.glob('/kaggle/working/train/train/dog.*.jpg')\nimages_cat = glob.glob('/kaggle/working/train/train/cat.*.jpg')\nimages_test = glob.glob('/kaggle/working/test/test/*.jpg')","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:43:35.986846Z","iopub.execute_input":"2023-07-30T01:43:35.987277Z","iopub.status.idle":"2023-07-30T01:43:36.192196Z","shell.execute_reply.started":"2023-07-30T01:43:35.987242Z","shell.execute_reply":"2023-07-30T01:43:36.190677Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# trainフォルダのファイルを8:2に分割(train, val)\nidx_test_start = int(len(images_cat) * 0.8)\n\nimages_val_dog = images_dog[idx_test_start:]\nimages_val_cat = images_cat[idx_test_start:]\n\nimages_train_dog = images_dog[:idx_test_start]\nimages_train_cat = images_cat[:idx_test_start]","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:43:38.558025Z","iopub.execute_input":"2023-07-30T01:43:38.558465Z","iopub.status.idle":"2023-07-30T01:43:38.564804Z","shell.execute_reply.started":"2023-07-30T01:43:38.558420Z","shell.execute_reply":"2023-07-30T01:43:38.563681Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\n\n# 一括でファイルを移動する関数を作成\ndef move_files(file_list, target_dir):\n    for file in file_list:\n        shutil.move(file, target_dir)\n\n# ファイル移動\nmove_files(images_train_dog, '/kaggle/working/images/train/dog/')\nmove_files(images_train_cat, '/kaggle/working/images/train/cat/')\nmove_files(images_val_dog, '/kaggle/working/images/val/dog/')\nmove_files(images_val_cat, '/kaggle/working/images/val/cat/')\nmove_files(images_test, '/kaggle/working/images/test/test/')","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:43:40.988443Z","iopub.execute_input":"2023-07-30T01:43:40.989449Z","iopub.status.idle":"2023-07-30T01:43:43.007010Z","shell.execute_reply.started":"2023-07-30T01:43:40.989409Z","shell.execute_reply":"2023-07-30T01:43:43.006050Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 学習の準備\nエポック数：全データを学習する回数、\nバッチサイズ：1ステップで学習する画像の枚数\n学習では各データを順番に入力してモデルのパラメータを更新。この学習データを1通り使用した状態が1エポックである。パラメータ更新時に入力するデータ数をバッチサイズという。","metadata":{}},{"cell_type":"code","source":"#分類するクラス\nclasses = ['cat', 'dog']\nnb_classes = len(classes)\n \n# データのディレクトリ\ntrain_data_dir = '/kaggle/working/images/train'\nvalidation_data_dir = '/kaggle/working/images/val'\ntest_data_dir = '/kaggle/working/images/test'\n\n# 学習回数(submissionファイル提出時にスコアが一番優秀だった5を採用)\nepochs = 5\n\n# バッチサイズ\nbatch_size = 1024\n\n# 画像サイズ\nimg_width, img_height = 224, 224","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:43:47.994930Z","iopub.execute_input":"2023-07-30T01:43:47.995337Z","iopub.status.idle":"2023-07-30T01:43:48.002604Z","shell.execute_reply.started":"2023-07-30T01:43:47.995303Z","shell.execute_reply":"2023-07-30T01:43:48.001242Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## ImageDataGenerator作成\nデータの合計サイズが大きいため、メモリにデータが乗り切らない可能性があるため画像読み込みを逐次的に行い、メモリ負荷を軽減するためにKerasライブラリのモジュールであるImageDataGeneratorを使用する。\n作成前にデータの正規化を実施する。","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# 学習データのImageDataGenerator作成\ntrain_datagen = ImageDataGenerator(rescale=1.0 / 255)  # rescaleで各画素のスケールを0～255から0～1に変換して正規化\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=classes,\n    class_mode='categorical',\n    batch_size=batch_size\n)","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:43:52.834894Z","iopub.execute_input":"2023-07-30T01:43:52.835644Z","iopub.status.idle":"2023-07-30T01:44:01.901204Z","shell.execute_reply.started":"2023-07-30T01:43:52.835606Z","shell.execute_reply":"2023-07-30T01:44:01.900189Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 検証データのImageDataGenerator作成\nvalidation_datagen = ImageDataGenerator(rescale=1.0 / 255) # rescaleで各画素のスケールを0～255から0～1に変換して正規化\nvalidation_generator = validation_datagen.flow_from_directory(\n    directory=validation_data_dir,\n    target_size=(img_width, img_height),\n    color_mode='rgb',\n    classes=classes,\n    class_mode='categorical',\n    batch_size=batch_size\n)","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:44:06.575624Z","iopub.execute_input":"2023-07-30T01:44:06.576396Z","iopub.status.idle":"2023-07-30T01:44:06.734690Z","shell.execute_reply.started":"2023-07-30T01:44:06.576360Z","shell.execute_reply":"2023-07-30T01:44:06.733561Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 評価データのImageDataGenerator作成\ntest_datagen = ImageDataGenerator(rescale=1.0 / 255) # rescaleで各画素のスケールを0～255から0～1に変換して正規化\ntest_generator = test_datagen.flow_from_directory(\n    directory=test_data_dir,\n    target_size=(img_width, img_height),\n    class_mode=None,\n    shuffle=False \n)","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:44:11.151268Z","iopub.execute_input":"2023-07-30T01:44:11.152543Z","iopub.status.idle":"2023-07-30T01:44:11.523680Z","shell.execute_reply.started":"2023-07-30T01:44:11.152505Z","shell.execute_reply":"2023-07-30T01:44:11.522498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 学習済みモデルをインポート\n畳み込みニューラルネットワークの学習済みモデルのVGG16を読み込む。最終層は差し替えるため、読み込まない。\ntensorflow及びkerasは機械学習フレームワークのライブラリである。","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.applications.vgg16 import VGG16\nfrom tensorflow.keras.models import Sequential, Model\nfrom tensorflow.keras.layers import Input, Flatten, Dense\n\ninput_tensor = Input(shape=(img_width, img_height, 3))\nVGG16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:44:16.571080Z","iopub.execute_input":"2023-07-30T01:44:16.572079Z","iopub.status.idle":"2023-07-30T01:44:17.674273Z","shell.execute_reply.started":"2023-07-30T01:44:16.572043Z","shell.execute_reply":"2023-07-30T01:44:17.673099Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## モデル作成\n転移学習実施のため、VGG16のパラメータは凍結させ、最終層に全結合層を追加する。","metadata":{}},{"cell_type":"code","source":"# VGG16のパラメータを凍結(すべての層を凍結)\nfor layer in VGG16.layers:\n    layer.trainable = False ","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:44:22.455217Z","iopub.execute_input":"2023-07-30T01:44:22.455607Z","iopub.status.idle":"2023-07-30T01:44:22.460736Z","shell.execute_reply.started":"2023-07-30T01:44:22.455578Z","shell.execute_reply":"2023-07-30T01:44:22.459991Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 差し替え用の新しい層を追加\nmodel = Sequential()\nmodel.add(VGG16)\nmodel.add(Flatten())\nmodel.add(Dense(nb_classes, activation='softmax'))","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:44:24.831107Z","iopub.execute_input":"2023-07-30T01:44:24.832222Z","iopub.status.idle":"2023-07-30T01:44:24.930084Z","shell.execute_reply.started":"2023-07-30T01:44:24.832181Z","shell.execute_reply":"2023-07-30T01:44:24.929264Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary() #構築したモデルの概要を表示","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:44:27.237696Z","iopub.execute_input":"2023-07-30T01:44:27.238526Z","iopub.status.idle":"2023-07-30T01:44:27.259262Z","shell.execute_reply.started":"2023-07-30T01:44:27.238492Z","shell.execute_reply":"2023-07-30T01:44:27.258305Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras import optimizers\n#モデルをコンパイルして学習方法を指定。\n#損失関数にクロスエントロピー・最適化アルゴリズムにAdam・学習中の評価指標にaccuracyを設定\nmodel.compile(loss='categorical_crossentropy',\n              optimizer=optimizers.Adam(learning_rate=1e-3),\n              metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:44:31.593792Z","iopub.execute_input":"2023-07-30T01:44:31.594221Z","iopub.status.idle":"2023-07-30T01:44:31.615979Z","shell.execute_reply.started":"2023-07-30T01:44:31.594186Z","shell.execute_reply":"2023-07-30T01:44:31.614344Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 学習実行\nステップ数とは、1エポック当たり何回パラメータを更新するかを表す数で、全データ数/バッチサイズで与えられる","metadata":{}},{"cell_type":"code","source":"# 学習\nsteps_per_epoch = int(len(train_generator.classes) / batch_size) \nhistory = model.fit(\n    x=train_generator,  # 学習データ\n    steps_per_epoch=steps_per_epoch,  # ステップ数\n    epochs=epochs,  # エポック数\n    validation_data=validation_generator  # 検証データ\n)","metadata":{"execution":{"iopub.status.busy":"2023-07-30T01:44:38.768404Z","iopub.execute_input":"2023-07-30T01:44:38.768797Z","iopub.status.idle":"2023-07-30T11:01:43.600967Z","shell.execute_reply.started":"2023-07-30T01:44:38.768768Z","shell.execute_reply":"2023-07-30T11:01:43.599311Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# グラフ描画(2画面)\nplt.figure(figsize=(8, 4))\n\n# epochごとのlossを表示\nplt.subplot(1, 2, 1)\nplt.plot(range(1, epochs+1), history.history['loss'], '-o')\nplt.plot(range(1, epochs+1), history.history['val_loss'], '-o')\nplt.title('loss_transition')\nplt.ylabel('loss')\nplt.xlabel('epoch')\nplt.grid()\nplt.legend(['loss', 'val_loss'], loc='best')\n\n# epochごとのaccuracyを表示\nplt.subplot(1, 2, 2)\nplt.plot(range(1, epochs+1), history.history['accuracy'], '-o')\nplt.plot(range(1, epochs+1), history.history['val_accuracy'], '-o')\nplt.title('accuracy_transition')\nplt.ylabel('accuracy')\nplt.xlabel('epoch')\nplt.grid()\nplt.legend(['accuracy', 'val_accuracy'], loc='best')\n\n# グラフ表示\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-30T11:02:08.910889Z","iopub.execute_input":"2023-07-30T11:02:08.911475Z","iopub.status.idle":"2023-07-30T11:02:09.528336Z","shell.execute_reply.started":"2023-07-30T11:02:08.911424Z","shell.execute_reply":"2023-07-30T11:02:09.527193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 評価\nvalデータを用いてモデルの精度を評価する","metadata":{}},{"cell_type":"code","source":"model.evaluate(validation_generator)","metadata":{"execution":{"iopub.status.busy":"2023-07-30T11:02:24.273994Z","iopub.execute_input":"2023-07-30T11:02:24.274424Z","iopub.status.idle":"2023-07-30T11:25:36.356929Z","shell.execute_reply.started":"2023-07-30T11:02:24.274391Z","shell.execute_reply":"2023-07-30T11:25:36.355833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 訓練したモデルを用いてテストデータの予測を実施\nimport numpy as np\np = model.predict(test_generator)\npred = np.argmax(p, axis=1)\npred","metadata":{"execution":{"iopub.status.busy":"2023-07-30T11:25:51.249451Z","iopub.execute_input":"2023-07-30T11:25:51.249971Z","iopub.status.idle":"2023-07-30T12:24:13.674430Z","shell.execute_reply.started":"2023-07-30T11:25:51.249925Z","shell.execute_reply":"2023-07-30T12:24:13.672280Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 結果を提出できるように修正","metadata":{}},{"cell_type":"code","source":"pred_pd = pd.DataFrame(p)\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":{"execution":{"iopub.status.busy":"2023-07-30T12:24:22.442787Z","iopub.execute_input":"2023-07-30T12:24:22.443664Z","iopub.status.idle":"2023-07-30T12:24:22.517468Z","shell.execute_reply.started":"2023-07-30T12:24:22.443627Z","shell.execute_reply":"2023-07-30T12:24:22.516377Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 結果の保存\n・notebookから提出を行おうとしても何故かできない（エラーコードが出ているわけでもなく、調べても理由が不明）\n・notebookをRun Allで実行し、生成されたsubmissionファイルを一度ダウンロードして提出することでScore算出が可能になる","metadata":{}},{"cell_type":"code","source":"sub = pd.read_csv('/kaggle/input/dogs-vs-cats-redux-kernels-edition/sample_submission.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":{"execution":{"iopub.status.busy":"2023-07-30T12:24:30.522362Z","iopub.execute_input":"2023-07-30T12:24:30.522789Z","iopub.status.idle":"2023-07-30T12:24:30.607717Z","shell.execute_reply.started":"2023-07-30T12:24:30.522755Z","shell.execute_reply":"2023-07-30T12:24:30.606474Z"},"trusted":true},"execution_count":null,"outputs":[]}]}