{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Introduction\nThis model is a fine-tuned model of VGG16 by Keras.\n\nAlso, this Kernel has written a detailed explanation for beginners.\n\nPlease set in advance that Internet can be used from Kernel."},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport os\nimport random\nimport time\nfrom keras import layers\nfrom keras.layers import Dense, Dropout, GlobalMaxPooling2D, Flatten\nfrom keras.preprocessing.image import load_img\nfrom keras.applications import VGG16\nfrom keras.models import Model, Sequential\nfrom keras.optimizers import SGD\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import ModelCheckpoint, EarlyStopping\nfrom sklearn.model_selection import train_test_split\n%matplotlib inline","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data preparation"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Data preparation.\n# データの確認をします。\nprint(os.listdir(\"../input\"))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Check the data.\n# トレーニングデータ10件をリストします。\nprint(os.listdir(\"../input/train/train\")[:10])\n# テストデータ10件をリストします。\nprint(os.listdir(\"../input/test1/test1\")[:10])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Get category from file name.Because there is no correct \n# answer label, get the label from the file name and make \n# it a classification class.\n# First, get a list of file names.\n# トレーニングデータのファイル名からdog, catを取得し分類するカテゴリとします。\n# トレーニングデータのファイル名一覧を取得。\nfilenames = os.listdir(\"../input/train/train\")\n# Variable to store categories.\n# クラスを格納する変数。\ncategories = []\n# Perform processing for the number of acquired files.\n# 取得したファイル数分処理を繰り返します。\nfor filename in filenames:\n    # Cut out label from file name.\n    # ファイル名から正解ラベルを切り取る。\n    category = filename.split('.')[0]\n    # If the file name contains Dog, set the class to 1, \n    # otherwise set it to 0.\n    # ファイル名にDogが含まれていれば、クラスに1を設定し、\n    # そうでない場合は0を設定する。\n    whichCategorys = '1' if category == 'dog' else '0'\n    # Add label.\n    # ラベルを変数に格納します。\n    categories.append(whichCategorys)\n\n# Create a data frame with file name and class, \n# and use it as supervised learning data.\n# ファイル名とクラスを持つデータフレームを作成し、教師ありの学習データとします。\ndf = pd.DataFrame({\n    'filename': filenames,\n    'category': categories\n})\n\n# display the beginning.\n# 先頭を表示してみます。\ndf.head()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# We have the same amount of images of dogs and cats.\n# 犬猫は同数あることが確認できます。\n#df['class'].value_counts()\ndf['category'].value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# See sample image.\n# 画像を表示してみます。\nplt.figure(figsize=(12, 12))\nfor i in range(0, 9):\n    plt.subplot(3, 3, i+1)\n    image = load_img('../input/train/train/'+df.filename[i])\n    plt.imshow(image)\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Fine-tuned model of VGG16"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Input data is a color image (3 channels) with an image size of 224x224.(Same as VGG 16 input layer)\n# 入力データは、画像サイズを224x224のカラー画像(3チャンネル)とする。(VGG16の入力層に合わせた)\nimage_size = 224\ninput_shape = (image_size, image_size, 3)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# エポック数7、バッチサイズを16に設定。\nepochs = 7\nbatch_size = 16","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# VGG16 model download(Set up Internet connection from Kernel beforehand)\n# The output layer of the VGG 16 is 1,000 classes, and this time the output \n# layer is replaced for 2-class classification. \n# VGG16モデルのダウンロード(事前にKernelからInternet接続ができるよう設定しておきます)\n# VGG16は1,000クラスの出力層となっており、今回は犬、猫の２クラス分類となるため出力層の取り替えを行います。\n# このためinclude_top=Falseとし、出力層の前の層を利用します。\nVGG16model = VGG16(input_shape=input_shape, include_top=False, weights=\"imagenet\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Display model summary.\n# モデルのサマリを表示します。\n# 入力層と畳み込み層、プーリング層からなるブロックが５つある事がわかります。\nVGG16model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 最後の畳み込み層の直前までの層は、学習されたパラメータをそのまま利用するため\n# 今後のトレーニングによって変更されないようにします。今回最後の層だけ学習させます。\n# Freeze the layer just before the last convolutional layer.\nfor layer in VGG16model.layers[:15]:\n    layer.trainable = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# ５ブロック目の畳み込み層だけ学習できる状態になっている事を確認します。\n# Only the 5th block can learn.\nfor layer in VGG16model.layers[:-1]:\n    print(layer.trainable)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Set the 5th block of the VGG16 model as the last output layer.\n# VGG16モデルの5ブロック目を最後の出力層とする。\nlast_layer = VGG16model.get_layer('block5_pool')\nlast_output = last_layer.output","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create a new output layer for 2 class classification.\n# 分類は犬猫の２クラスの分類を出力する層を新規に作成する。\n# プーリング層を置き、入力はVGG16の出力を受け取るようにする。\nnew_last_layers = GlobalMaxPooling2D()(last_output)\n# Add a fully connected layer with 512 hidden units and ReLU activation\n# 512ノードの全結合層を追加、活性化関数はReLU\nnew_last_layers = Dense(512, activation='relu')(new_last_layers)\n# Add a dropout rate of 0.5\n# ドロップアウトを追加、レートは0.5\nnew_last_layers = Dropout(0.5)(new_last_layers)\n# Add a final sigmoid layer for classification\n# 最後に犬猫のクラスを示すノード２つの出力層を作り、シグモイド関数を適用する\nnew_last_layers = layers.Dense(2, activation='sigmoid')(new_last_layers)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Combine the VGG 16 with the output layer.\n# VGG16と出力層を結合する。\nmodel = Model(VGG16model.input, new_last_layers)\n# complile.\n# モデルのコンパイル。\nmodel.compile(loss = \"categorical_crossentropy\",\n              optimizer=SGD(lr=1e-4, momentum=0.9),\n              metrics=['accuracy'])\n# Display model summary.\n# サマリ表示\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Prepare training data and validation data.\n# トレーニングデータ(train_df)と検証データ(validate_df)を準備する。\ntrain_df, validate_df = train_test_split(df, test_size=0.1)\n# indexのリセット\ntrain_df = train_df.reset_index()\nvalidate_df = validate_df.reset_index()\n# データ数の取得\ntotal_train = train_df.shape[0]\ntotal_validate = validate_df.shape[0]\nprint('Total amount of data={}, Total train={}, Total validate={}'.format(len(df), total_train, total_validate))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"validate_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Traning Generator\n# トレーニングデータの拡張を行う\ntrain_datagen = ImageDataGenerator(\n    # 画像をランダムに回転範囲\n    rotation_range=15,\n    # 画素値のリスケーリング係数\n    rescale=1./255,\n    # シアー強度（反時計回りのシアー角度）\n    shear_range=0.2,\n    # ランダムにズームする範囲\n    zoom_range=0.2,\n    # 水平方向に画像反転\n    horizontal_flip=True,\n    # 入力画像の境界周りを埋める指定\n    fill_mode='nearest',\n    # 水平シフトする範囲\n    width_shift_range=0.1,\n    # 垂直シフトする範囲\n    height_shift_range=0.1\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Generate a batch of expanded data from data frames and directory.\n# トレーニングデータのジェネレータ\n# データフレームとパスからデータを拡張したバッチを生成する\ntrain_generator = train_datagen.flow_from_dataframe(\n    # トレーニングデータのデータフレーム\n    train_df, \n    # トレーニングデータのパス\n    \"../input/train/train/\",\n    # ファイル名\n    x_col='filename',\n    # 正解ラベル(カテゴリ)\n    y_col='category',\n    # '犬(1)'、'猫(0)'のカテゴリ分類として扱う\n    class_mode='categorical',\n    # 対象のデータサイズ\n    target_size=(image_size, image_size),\n    # バッチサイズ\n    batch_size=batch_size\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Validation Generator\n# 検証データのジェネレータ\nvalidation_datagen = ImageDataGenerator(rescale=1./255)\nvalidation_generator = validation_datagen.flow_from_dataframe(\n    validate_df, \n    \"../input/train/train/\", \n    x_col='filename',\n    y_col='category',\n    class_mode='categorical',\n    target_size=(image_size, image_size),\n    batch_size=batch_size\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Prepare a generator for sample display of extended image\n# 拡張画像のサンプル表示を行うジェネレータを準備\nexample_df = train_df.sample(n=1).reset_index(drop=True)\nexample_generator = train_datagen.flow_from_dataframe(\n    example_df, \n    \"../input/train/train/\", \n    x_col='filename',\n    y_col='category',\n    class_mode='categorical'\n)\n# Display a sample of expanded image data\n# 拡張した画像データのサンプルを表示する\nplt.figure(figsize=(12, 12))\nfor i in range(0, 9):\n    plt.subplot(3, 3, i+1)\n    for X_batch, Y_batch in example_generator:\n        image = X_batch[0]\n        plt.imshow(image)\n        break\nplt.tight_layout()\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# トレーニング時間測定のためタイムスタンプを取得\nstart = time.time()\n\n# Fit Model\n# fine-tune the model\n# トレーニングの実施\nhistory = model.fit_generator(\n    train_generator,\n    epochs=epochs,\n    validation_data=validation_generator,\n    validation_steps=total_validate//batch_size,\n    steps_per_epoch=total_train//batch_size)\n\n# Display of learning time\n# トレーニング時間の表示\nelapsed_time = time.time() - start\nprint (\"elapsed_time:{0}\".format(elapsed_time) + \"[sec]\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Evaluate the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# evaluation\n# モデルの評価\nloss, accuracy = model.evaluate_generator(validation_generator, total_validate//batch_size, workers=12)\nprint(\"Test: accuracy = %f  ;  loss = %f \" % (accuracy, loss))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# loss and accuracy graph\n# 損失関数の値と分類精度のグラフ\ndef plot_model_history(model_history, acc='acc', val_acc='val_acc'):\n    fig, axs = plt.subplots(1,2,figsize=(15,5))\n    axs[0].plot(range(1,len(model_history.history[acc])+1),model_history.history[acc])\n    axs[0].plot(range(1,len(model_history.history[val_acc])+1),model_history.history[val_acc])\n    axs[0].set_title('Model Accuracy')\n    axs[0].set_ylabel('Accuracy')\n    axs[0].set_xlabel('Epoch')\n    axs[0].set_xticks(np.arange(1,len(model_history.history[acc])+1),len(model_history.history[acc])/10)\n    axs[0].legend(['train', 'val'], loc='best')\n    axs[1].plot(range(1,len(model_history.history['loss'])+1),model_history.history['loss'])\n    axs[1].plot(range(1,len(model_history.history['val_loss'])+1),model_history.history['val_loss'])\n    axs[1].set_title('Model Loss')\n    axs[1].set_ylabel('Loss')\n    axs[1].set_xlabel('Epoch')\n    axs[1].set_xticks(np.arange(1,len(model_history.history['loss'])+1),len(model_history.history['loss'])/10)\n    axs[1].legend(['train', 'val'], loc='best')\n    plt.show()\n    \nplot_model_history(history)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Try image recognition.\n# Run this cell several times and try out various images.\n# 試しに、ランダムに１枚画像を選んで表示してみましょう。\n# このセルは何度か実行し、色々な画像で試してみましょう。\nfilenames = os.listdir(\"../input/test1/test1\")\nsample = random.choice(filenames)\nimg = load_img(\"../input/test1/test1/\"+sample,target_size=(224,224))\nplt.imshow(img)\nimg = np.asarray(img)\nimg = np.expand_dims(img, axis=0)\n\npredict =  model.predict(img)\ndog_vs_cat= np.argmax(predict,axis=1)\nprint('The animals in the picture are \"', end='')\nif dog_vs_cat == 1:\n    print('dog\".')\nelse:\n    print('cat\".')\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prediction and submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Preparation of test data.\n# テスト用データの準備。\ntest_filenames = os.listdir(\"../input/test1/test1\")\ntest_df = pd.DataFrame({\n    'filename': test_filenames\n})\nnb_samples = test_df.shape[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create Testing Generator.\n# テストジェネレータを作成。\ntest_gen = ImageDataGenerator(rescale=1./255)\ntest_generator = test_gen.flow_from_dataframe(\n    test_df, \n    \"../input/test1/test1/\", \n    x_col='filename',\n    y_col=None,\n    class_mode=None,\n    batch_size=batch_size,\n    target_size=(image_size, image_size),\n    shuffle=False\n)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Predict\n# 予測する\npredict = model.predict_generator(test_generator, steps=np.ceil(nb_samples/batch_size))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Display some of the prediction results.\n# 予測結果の一部を表示。\ndog_vs_cat= np.argmax(predict,axis=1)\nplt.figure(figsize=(12, 12))\nfor i in range(0, 9):\n    ax= plt.subplot(3, 3, i+1, xticks=[], yticks=[])\n    image = load_img('../input/test1/test1/'+test_df.filename[i])\n    plt.imshow(image)\n    ax.set_title(\"predict={}\".format(('dog' if dog_vs_cat[i]==1 else 'cat')))\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Submission file output\n# サブミッション用のDFを準備\nsubmission_df = test_df.copy()\n#idを設定\nsubmission_df['id'] = submission_df['filename'].str.split('.').str[0]\n#labelを設定\nsubmission_df['label'] = dog_vs_cat\n#filenameは不要なので削除\nsubmission_df.drop(['filename'], axis=1, inplace=True)\n# サブミッションファイルの出力\nsubmission_df.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}