{"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":"from google.colab import drive\ndrive.mount('/content/drive')","metadata":{"id":"5mggF81HTTQN","executionInfo":{"status":"ok","timestamp":1621851229167,"user_tz":-480,"elapsed":17307,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}},"outputId":"c9bd7ad2-e411-4982-cb8d-c7f01c077c28"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!unzip \"/content/drive/MyDrive/Colab Notebooks/Dog_Cat/train.zip\" -d \"/content/drive/MyDrive/Colab Notebooks/Dog_Cat/\"","metadata":{"id":"aisVEjgBU9aY"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install tensorflow-addons\nimport tensorflow_addons as tfa\nimport tensorflow as tf\nfrom tensorflow import keras\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom tensorflow.keras.applications.vgg16 import VGG16, preprocess_input\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator","metadata":{"id":"5f14519b","executionInfo":{"status":"ok","timestamp":1621854959033,"user_tz":-480,"elapsed":2442,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}},"outputId":"003099be-9b82-4dcf-a19c-d82be118e284"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 設定資料、顯示圖片","metadata":{"id":"ce746251"}},{"cell_type":"code","source":"import glob\nbase_path = \"/content/drive/MyDrive/Colab Notebooks/Dog_Cat/\"\ntrain_path = f\"{base_path}/train\"\ntest_path = f\"{base_path}/test\"\ndog_train_set = (glob.glob(f\"{train_path}/dog.*.jpg\"))\ncat_train_set = (glob.glob(f\"{train_path}/cat.*.jpg\"))\nprint(f\"{len(dog_train_set)}, {len(cat_train_set)}\")","metadata":{"id":"888b85fa","executionInfo":{"status":"ok","timestamp":1621851554262,"user_tz":-480,"elapsed":443,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}},"outputId":"837579b4-42bf-408d-fee6-624876fe9e3c"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_name = {0:\"cat\", 1:\"dog\"}\nX_df = pd.DataFrame(columns=[\"path\", \"target\"])\nfor path in dog_train_set:\n    s = pd.Series([path, 1], index=[\"path\", \"target\"])\n    X_df = X_df.append(s, ignore_index=True)\nfor path in cat_train_set:\n    s = pd.Series([path, 0], index=[\"path\", \"target\"])\n    X_df = X_df.append(s, ignore_index=True)\nX_df","metadata":{"id":"6184effc","executionInfo":{"status":"ok","timestamp":1621851620351,"user_tz":-480,"elapsed":66097,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}},"outputId":"b50fda36-6227-4317-aefa-988bc7635f8f"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.preprocessing.image import load_img\nimport random\nnum = random.randint(0, len(X_df.index))\nimg = load_img(X_df[\"path\"][num], target_size=(224,224))\nplt.axis(\"off\")\nplt.title(class_name[X_df[\"target\"][num]])\nplt.imshow(img)","metadata":{"id":"baff0ecc","executionInfo":{"status":"ok","timestamp":1621851620354,"user_tz":-480,"elapsed":21,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}},"outputId":"4c1a48c6-11cd-4ce1-aa0b-98fb31e48155"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 切分資料","metadata":{"id":"a6302a4f"}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nX_train, X_test, y_train, y_test = train_test_split(X_df[\"path\"],\n                              X_df[\"target\"],\n                              test_size=0.1,\n                              random_state=1031)\nX_train.shape, X_test.shape, y_train.value_counts(), y_test.value_counts()","metadata":{"id":"c90b69d0","executionInfo":{"status":"ok","timestamp":1621853089713,"user_tz":-480,"elapsed":278,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}},"outputId":"eb096109-d1dd-43c3-faf2-f73ef0147002"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 使用ImageDataGenerator準備資料的方法","metadata":{"id":"ecf185c3"}},{"cell_type":"code","source":"train_df = pd.concat([X_train, y_train], axis=1)\nvalid_df = pd.concat([X_test, y_test], axis=1)\ntrain_df[\"target\"] = [str(val) for val in train_df[\"target\"]]\nvalid_df[\"target\"] = [str(val) for val in valid_df[\"target\"]]\ntrain_df.shape, valid_df.shape","metadata":{"id":"2914a566","executionInfo":{"status":"ok","timestamp":1621853524419,"user_tz":-480,"elapsed":325,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}},"outputId":"558a5823-94ca-402a-bbb5-a78fda9ab3a9"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size, target_size = 32, (224,224)\ntrain_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)\nvalid_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)\ntrain_generator = train_datagen.flow_from_dataframe(dataframe=train_df,x_col=\"path\",y_col=\"target\",target_size=target_size,batch_size=batch_size,class_mode='categorical')\nvalid_generator = valid_datagen.flow_from_dataframe(dataframe=valid_df,x_col=\"path\",y_col=\"target\",target_size=target_size,batch_size=batch_size,class_mode='categorical',shuffle=False)","metadata":{"id":"43675ec8","executionInfo":{"status":"ok","timestamp":1621853876610,"user_tz":-480,"elapsed":4726,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}},"outputId":"8a1dd664-014d-4021-902e-fdea2d3ef580"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 導入VGG16模型","metadata":{"id":"857a1020"}},{"cell_type":"code","source":"vgg = VGG16(include_top=False, input_shape=(224,224,3))\nvgg.trainable = False\n#vgg.summary(), vgg.layers","metadata":{"id":"643cfff9","executionInfo":{"status":"ok","timestamp":1621856314382,"user_tz":-480,"elapsed":1481,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}}},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 保留VGG16_Flatten前所有結構，自行修改輸出層。","metadata":{"id":"66eb692a"}},{"cell_type":"code","source":"from keras.models import Model\nfrom keras.layers import Flatten, Dense, BatchNormalization, GlobalAveragePooling2D\nfor l in vgg.layers:\n    l.trainable = False\n#x = BatchNormalization()(vgg.output)\nx = GlobalAveragePooling2D()(vgg.output)\nx = Flatten()(x)\nx = Dense(units=2048, activation=\"relu\")(x) #前一層參數量7*7*512=25088，每一層降低1/10 = 25088/2508，找2508最接近的2平方倍數\nx = Dense(units=256, activation=\"relu\")(x)\nx = Dense(units=2, activation=\"softmax\")(x)\ncnn = Model(inputs=vgg.input, outputs=x)\ncnn.compile(optimizer=tfa.optimizers.RectifiedAdam(), loss='categorical_crossentropy', metrics=['accuracy'])\ncnn.summary()","metadata":{"id":"e8af6872","executionInfo":{"status":"ok","timestamp":1621856327985,"user_tz":-480,"elapsed":1040,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}},"outputId":"904251e7-2216-4c36-9f22-fc310e36716e"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 設定儲存最佳模型參數、提早停止模型訓練、儲存History","metadata":{"id":"e0e9ec3e"}},{"cell_type":"code","source":"import os\nmodel_dir = base_path\nfile_name = \"dog_cat_vgg16-best-model\"\nmodelfile = f\"{model_dir}/{file_name}.h5\"\nlogfile = f\"{model_dir}/{file_name}_training.log\"\nif not os.path.exists(model_dir):\n  os.makedirs(model_dir)\nmodel_chpo = keras.callbacks.ModelCheckpoint(modelfile, monitor='val_accuracy', save_best_only=True)\nearlystop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=3, verbose=1)\ncsv_logger = keras.callbacks.CSVLogger(logfile)\ncallbacks_list = [model_chpo, earlystop, csv_logger]","metadata":{"id":"f5f74e19","executionInfo":{"status":"ok","timestamp":1621856345858,"user_tz":-480,"elapsed":543,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}}},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 訓練模型","metadata":{"id":"74e74b01"}},{"cell_type":"code","source":"epochs = 50\ncnn.fit(train_generator,\n    epochs=epochs,\n    validation_data=valid_generator,\n    # class_weight=class_weights,\n    batch_size=batch_size,\n    callbacks=callbacks_list)","metadata":{"id":"1ebab4e6","executionInfo":{"status":"ok","timestamp":1621857012803,"user_tz":-480,"elapsed":664689,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}},"outputId":"45181e03-efe8-4498-ad24-9a0276f54f3f"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_dir = base_path\nfile_name = \"dog_cat_vgg16-best-model\"\nlogfile = f\"{model_dir}/{file_name}_training.log\"\n\ndef plot_accuracy_loss(file_name):\n    import pandas as pd\n    log_data = pd.read_csv(file_name)\n    acc = log_data['accuracy']\n    val_acc = log_data['val_accuracy']\n    loss = log_data['loss']\n    val_loss = log_data['val_loss']\n    import matplotlib.pyplot as plt\n    plt.style.use('ggplot')\n    plt.figure(figsize=(16, 8))\n    plt.subplot(1, 2, 1)\n    plt.plot(log_data['epoch'], acc, label='Training Accuracy')\n    plt.plot(log_data['epoch'], val_acc, label='Validation Accuracy')\n    plt.legend(loc='lower right')\n    plt.title('Training and Validation Accuracy')\n    plt.subplot(1, 2, 2)\n    plt.plot(log_data['epoch'], loss, label='Training Loss')\n    plt.plot(log_data['epoch'], val_loss, label='Validation Loss')\n    plt.legend(loc='upper right')\n    plt.title('Training and Validation Loss')\n    return plt.show()\nplot_accuracy_loss(logfile)","metadata":{"id":"ZO9y9ZCuNwEh","executionInfo":{"status":"ok","timestamp":1621857332878,"user_tz":-480,"elapsed":954,"user":{"displayName":"ChienMing LIN","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GgprRXa30aFW-3xT50h6I9RdqSwGlfm9m7_uboeAw=s64","userId":"04273980221177808121"}},"outputId":"5dcf8e75-8517-4636-d104-fae4faaabd8d"},"execution_count":null,"outputs":[]}]}