{"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":"markdown","source":"**실습 목표**\n\n💡 딥러닝 모델 (MLP, CNN, VGG19)을 이용한 개 vs.고양이 이미지 분류\n\n💡 모델이 이미지의 어떤 특징을 추출하였는지 시각화 ","metadata":{}},{"cell_type":"markdown","source":"**필요 라이브러리 import 및 추가된 데이터 path 확인**","metadata":{}},{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport os\nimport shutil\n\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-01-20T09:22:50.547854Z","iopub.execute_input":"2022-01-20T09:22:50.548201Z","iopub.status.idle":"2022-01-20T09:22:50.576937Z","shell.execute_reply.started":"2022-01-20T09:22:50.548123Z","shell.execute_reply":"2022-01-20T09:22:50.576272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**zip파일 압축 해제**","metadata":{}},{"cell_type":"code","source":"from zipfile import ZipFile\n\nbase_path = '/kaggle/input/dogs-vs-cats/'\nunzip_path = '/kaggle/working/' # 현재 디렉토리\n\n# 반복문 이용\nfor folder in os.listdir(path = base_path):\n    if folder.split(\".\")[1] == 'zip':\n        with ZipFile(base_path + folder, 'r') as zipfile:\n            zipfile.extractall(unzip_path)\n            print(f'{folder} 압축해제 완료!')","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:22:50.57866Z","iopub.execute_input":"2022-01-20T09:22:50.579239Z","iopub.status.idle":"2022-01-20T09:23:08.961696Z","shell.execute_reply.started":"2022-01-20T09:22:50.579203Z","shell.execute_reply":"2022-01-20T09:23:08.960949Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 데이터분석 및 전처리","metadata":{}},{"cell_type":"markdown","source":"모델에 입력하여 컴퓨터가 학습 할 수 있도록 전처리 해준다. ","metadata":{}},{"cell_type":"code","source":"train_dir = os.path.join(unzip_path, 'train')\ntest_dir = os.path.join(unzip_path, 'test1')\n\n# 파일리스트 가져오기\ntrain_img_names = os.listdir(train_dir)\ntest_img_names = os.listdir(test_dir)\n\nprint('total training images : ', len(train_img_names))\nprint('total test images : ', len(test_img_names))","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:08.962929Z","iopub.execute_input":"2022-01-20T09:23:08.963188Z","iopub.status.idle":"2022-01-20T09:23:08.991225Z","shell.execute_reply.started":"2022-01-20T09:23:08.963149Z","shell.execute_reply":"2022-01-20T09:23:08.990195Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_img_names[:5]","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:08.993202Z","iopub.execute_input":"2022-01-20T09:23:08.993457Z","iopub.status.idle":"2022-01-20T09:23:09.000515Z","shell.execute_reply.started":"2022-01-20T09:23:08.993423Z","shell.execute_reply":"2022-01-20T09:23:08.999675Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**이미지 이름과 분류 카테고리 정보를 갖는 dataframe 생성**","metadata":{}},{"cell_type":"code","source":"categories = list()\n\n# 반복문 이용\nfor image in train_img_names:\n    category = image.split('.')[0]\n    if category == 'dog':\n        categories.append('dog')\n    else:\n        categories.append('cat')\n        \ndf = pd.DataFrame({'Image':train_img_names, 'Category':categories})[:2000]","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:09.002077Z","iopub.execute_input":"2022-01-20T09:23:09.002352Z","iopub.status.idle":"2022-01-20T09:23:09.028621Z","shell.execute_reply.started":"2022-01-20T09:23:09.002318Z","shell.execute_reply":"2022-01-20T09:23:09.027949Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**📌Try it!!**","metadata":{}},{"cell_type":"code","source":"# 만들어진 데이터프레임 df를 출력해보자.\n","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:09.029813Z","iopub.execute_input":"2022-01-20T09:23:09.030188Z","iopub.status.idle":"2022-01-20T09:23:09.036549Z","shell.execute_reply.started":"2022-01-20T09:23:09.030153Z","shell.execute_reply":"2022-01-20T09:23:09.035785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**데이터 시각화**","metadata":{}},{"cell_type":"code","source":"# 필요 라이브러리 import\nimport matplotlib.pyplot as plt\nimport seaborn as sns","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:09.039593Z","iopub.execute_input":"2022-01-20T09:23:09.039999Z","iopub.status.idle":"2022-01-20T09:23:09.730856Z","shell.execute_reply.started":"2022-01-20T09:23:09.039965Z","shell.execute_reply":"2022-01-20T09:23:09.730099Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"f = plt.figure(figsize=(5, 5))\nax = f.add_subplot()\nsns.countplot(data=df[:2000], x='Category', ax=ax)\n\nfor patch in ax.patches:\n    label_x = patch.get_x() + patch.get_width()/2\n    label_y = patch.get_y() + patch.get_height()/2\n    text_msg = str(int(patch.get_height())) \n    ax.text(label_x, label_y, text_msg, horizontalalignment='center', verticalalignment='center')\n    \nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:09.732276Z","iopub.execute_input":"2022-01-20T09:23:09.732532Z","iopub.status.idle":"2022-01-20T09:23:09.922934Z","shell.execute_reply.started":"2022-01-20T09:23:09.732497Z","shell.execute_reply":"2022-01-20T09:23:09.922198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"random 함수를 이용하여 이미지 확인하기","metadata":{}},{"cell_type":"code","source":"import random\n\nsample = random.choice(train_img_names)\nsample_path = '/kaggle/working/train/' + sample\nplt.imshow(plt.imread(sample_path))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:09.92435Z","iopub.execute_input":"2022-01-20T09:23:09.924643Z","iopub.status.idle":"2022-01-20T09:23:10.446056Z","shell.execute_reply.started":"2022-01-20T09:23:09.924596Z","shell.execute_reply":"2022-01-20T09:23:10.445223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path = '/kaggle/working/train/'\nplt.figure(figsize=(10,10))\nfor i in range(25):\n    img_path = path + df.Image[i]\n    \n    plt.subplot(5,5,i+1)\n    plt.xticks([])\n    plt.yticks([])\n    plt.grid(False)\n    plt.imshow(plt.imread(img_path))\n    plt.xlabel(df.Category[i])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:10.449372Z","iopub.execute_input":"2022-01-20T09:23:10.449652Z","iopub.status.idle":"2022-01-20T09:23:12.044959Z","shell.execute_reply.started":"2022-01-20T09:23:10.449616Z","shell.execute_reply":"2022-01-20T09:23:12.042623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**📌 Try it!!**\n\n실행할때마다 정말로 random하게 이미지가 출력되는지 확인해보자.","metadata":{}},{"cell_type":"markdown","source":"### 훈련데이터, 테스트데이터 나누기","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\ntrain, test = train_test_split(df, test_size=0.25)\n# dataframe의 기존 인덱스 제거\ntrain = train.reset_index(drop=True)\n# test = test.reset_index(drop=False)","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:12.04645Z","iopub.execute_input":"2022-01-20T09:23:12.0469Z","iopub.status.idle":"2022-01-20T09:23:12.20465Z","shell.execute_reply.started":"2022-01-20T09:23:12.046862Z","shell.execute_reply":"2022-01-20T09:23:12.203931Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"🎁 **Try it !!!**\n\ntrain, test 데이터를 각각 reset_index(drop=True) 처리를 했을 때와\n\n하지 않았을 때 데이터프레임 인덱스 차이를 확인하여 보세요.","metadata":{}},{"cell_type":"markdown","source":"**훈련데이터와 테스트데이터 갯수 시각화**","metadata":{}},{"cell_type":"code","source":"f, ax = plt.subplots(1, 2, figsize=(13,5))\nsns.countplot(data=train, x='Category', palette='magma', ax=ax[0])\nsns.countplot(data=test, x='Category', palette='magma', ax=ax[1])\n\nfor patch in ax[0].patches:\n    label_x = patch.get_x() + patch.get_width()/2\n    label_y = patch.get_y() + patch.get_height()/2\n    text_msg = str(int(patch.get_height())) \n    ax[0].text(label_x, label_y, text_msg, horizontalalignment='center', verticalalignment='center')\n\nfor patch in ax[1].patches:\n    label_x = patch.get_x() + patch.get_width()/2\n    label_y = patch.get_y() + patch.get_height()/2\n    text_msg = str(int(patch.get_height())) \n    ax[1].text(label_x, label_y, text_msg, horizontalalignment='center', verticalalignment='center')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:12.206207Z","iopub.execute_input":"2022-01-20T09:23:12.206486Z","iopub.status.idle":"2022-01-20T09:23:12.781033Z","shell.execute_reply.started":"2022-01-20T09:23:12.206447Z","shell.execute_reply":"2022-01-20T09:23:12.780339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"개 이미지와 고양이 이미지가 일대일로 딱맞게 떨어지지는 않지만, 크게 차이나는 정도는 아니기 때문에 이대로 학습시켜도 무관하다.","metadata":{}},{"cell_type":"code","source":"# keras의 ImageDataGenerator 라이브러리를 이용하여 이미지 전처리 진행\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\nheight, width, channel = (150, 150, 3)\n\ntrain_datagen = ImageDataGenerator(rescale=1. / 255.)\n\ntrain_generator = train_datagen.flow_from_dataframe(train,\n                                                   directory = './train',\n                                                   x_col='Image',\n                                                   y_col='Category',\n                                                   batch_size=32,\n                                                   class_mode='categorical',\n                                                   color_mode= 'rgb',\n                                                   target_size=(height, width))\n\ntest_datagen = ImageDataGenerator(rescale=1. / 255.)\ntest_generator = test_datagen.flow_from_dataframe(test,\n                                                   directory = './train',\n                                                   x_col='Image',\n                                                   y_col='Category',\n                                                   batch_size=32,\n                                                   class_mode='categorical',\n                                                   color_mode= 'rgb',\n                                                   target_size=(height, width))","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:12.782235Z","iopub.execute_input":"2022-01-20T09:23:12.783712Z","iopub.status.idle":"2022-01-20T09:23:17.320777Z","shell.execute_reply.started":"2022-01-20T09:23:12.78367Z","shell.execute_reply":"2022-01-20T09:23:17.320004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_generator.class_indices","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:18.345774Z","iopub.execute_input":"2022-01-20T09:23:18.346707Z","iopub.status.idle":"2022-01-20T09:23:18.352536Z","shell.execute_reply.started":"2022-01-20T09:23:18.346664Z","shell.execute_reply":"2022-01-20T09:23:18.3519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x, y = train_generator.next()\nclass_ = list(train_generator.class_indices.keys())\n\nplt.figure(figsize=(10,10))\nfor i in range(25):\n    plt.subplot(5,5,i+1)\n    plt.xticks([])\n    plt.yticks([])\n    plt.grid(False)\n    plt.imshow(x[i])\n    plt.xlabel(class_[np.argmax(y[i])])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:18.354009Z","iopub.execute_input":"2022-01-20T09:23:18.354476Z","iopub.status.idle":"2022-01-20T09:23:19.660787Z","shell.execute_reply.started":"2022-01-20T09:23:18.354433Z","shell.execute_reply":"2022-01-20T09:23:19.657961Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 모델 훈련","metadata":{}},{"cell_type":"code","source":"# 필요 라이브러리 import\nimport tensorflow\n\nfrom tensorflow.keras.models import Sequential, Model\nfrom tensorflow.keras.layers import Input, InputLayer, Resizing\nfrom tensorflow.keras.layers import Conv2D, BatchNormalization\nfrom tensorflow.keras.layers import MaxPool2D, GlobalMaxPooling2D\nfrom tensorflow.keras.layers import Flatten\nfrom tensorflow.keras.layers import Dense, Dropout\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras.optimizers import SGD","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:19.662256Z","iopub.execute_input":"2022-01-20T09:23:19.662701Z","iopub.status.idle":"2022-01-20T09:23:19.671266Z","shell.execute_reply.started":"2022-01-20T09:23:19.662665Z","shell.execute_reply":"2022-01-20T09:23:19.670523Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### MLP","metadata":{}},{"cell_type":"code","source":"# MLP 모델 정의\nmlp_model = Sequential()\n\nmlp_model.add(InputLayer((height, width, channel)))\nmlp_model.add(Resizing(48, 48, interpolation='bilinear'))\nmlp_model.add(Flatten()) \nmlp_model.add(Dense(2048, activation='relu'))\nmlp_model.add(Dense(1024, activation='relu'))\nmlp_model.add(Dense(512, activation='relu'))\nmlp_model.add(Dense(128, activation='relu'))\nmlp_model.add(Dense(2, activation='softmax'))","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:19.672611Z","iopub.execute_input":"2022-01-20T09:23:19.673032Z","iopub.status.idle":"2022-01-20T09:23:22.092895Z","shell.execute_reply.started":"2022-01-20T09:23:19.672999Z","shell.execute_reply":"2022-01-20T09:23:22.091393Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 모델 확인\nmlp_model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:22.0941Z","iopub.execute_input":"2022-01-20T09:23:22.094328Z","iopub.status.idle":"2022-01-20T09:23:22.104203Z","shell.execute_reply.started":"2022-01-20T09:23:22.094296Z","shell.execute_reply":"2022-01-20T09:23:22.103373Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 모델 컴파일\nmlp_model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=[\"accuracy\"])\n\n# 모델 훈련\ncallback=EarlyStopping(monitor=\"val_loss\", patience=4)\nmlp_history = mlp_model.fit(train_generator,\n                            validation_data=test_generator,\n                            epochs=20,\n                            callbacks=[callback])","metadata":{"execution":{"iopub.status.busy":"2022-01-20T09:23:22.105204Z","iopub.execute_input":"2022-01-20T09:23:22.105691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 정확도와 손실값 확인\n\nmlp_acc = mlp_history.history['accuracy']\nmlp_val_acc = mlp_history.history['val_accuracy']\nmlp_loss = mlp_history.history['loss']\nmlp_val_loss = mlp_history.history['val_loss']\n\nmlp_epochs = range(len(mlp_acc))\n\nplt.plot(mlp_epochs, mlp_acc, 'r', label='Training accuracy')\nplt.plot(mlp_epochs, mlp_val_acc, 'b', label='Validation accuracy')\nplt.title('Training and validation accuracy')\nplt.legend()\n\nplt.figure()\n\nplt.plot(mlp_epochs, mlp_loss, 'r', label='Training Loss')\nplt.plot(mlp_epochs, mlp_val_loss, 'b', label='Validation Loss')\nplt.title('Training and validation loss')\nplt.legend()\n\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_names = ['cat','dogs']\ndef plot_image(i, predictions_array, true_label, img):\n    predictions_array, true_label, img = predictions_array[i], true_label[i], img[i]\n    plt.grid(False)\n    plt.xticks([])\n    plt.yticks([])\n\n    plt.imshow(img)\n\n    predicted_label = np.argmax(predictions_array)\n    true_label = np.argmax(true_label)\n    if predicted_label == true_label:\n        color = 'blue'\n    else:\n        color = 'red'\n\n    plt.xlabel(\"{} {:2.0f}% ({})\".format(class_names[predicted_label],\n                                100*np.max(predictions_array),\n                                class_names[true_label]),\n                                color=color)\n\ndef plot_value_array(i, predictions_array, true_label):\n    predictions_array, true_label = predictions_array[i], true_label[i]\n    plt.grid(False)\n    plt.xticks([])\n    plt.yticks([])\n    thisplot = plt.bar(range(2), predictions_array, color=\"#777777\")\n    plt.ylim([0, 1])\n    predicted_label = np.argmax(predictions_array)\n    true_label = np.argmax(true_label)\n\n    thisplot[predicted_label].set_color('red')\n    thisplot[true_label].set_color('blue')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x, y = test_generator.next()\npredictions = mlp_model.predict(x)\n\nnum_rows = 5\nnum_cols = 3\nnum_images = num_rows*num_cols\nplt.figure(figsize=(4*num_cols, 2*num_rows))\nfor i in range(num_images):\n    plt.subplot(num_rows, 2*num_cols, 2*i+1)\n    plot_image(i, predictions, y, x)\n    plt.subplot(num_rows, 2*num_cols, 2*i+2)\n    plot_value_array(i, predictions, y)\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### CNN","metadata":{}},{"cell_type":"code","source":"# CNN 모델 정의\n\ncnn_model = Sequential()\n\ncnn_model.add(Conv2D(filters=32, kernel_size=3,activation=\"relu\", input_shape=(height, width, channel)))\ncnn_model.add(MaxPool2D(pool_size=2, strides=2))\ncnn_model.add(Conv2D(filters=64, kernel_size=3,activation=\"relu\"))\ncnn_model.add(MaxPool2D(pool_size=2, strides=2))\ncnn_model.add(Conv2D(filters=128, kernel_size=3, activation=\"relu\"))\ncnn_model.add(MaxPool2D(pool_size=2, strides=2))\ncnn_model.add(Flatten())\ncnn_model.add(Dense(units=512, activation=\"relu\"))\ncnn_model.add(Dropout(0.15))\ncnn_model.add(Dense(units=2, activation=\"softmax\"))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 모델 확인\ncnn_model.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 모델 컴파일\ncnn_model.compile(optimizer=\"adam\", loss=\"categorical_crossentropy\", metrics=[\"accuracy\"])\n\n# 모델 훈련\ncnn_history = cnn_model.fit(train_generator,\n                            validation_data=test_generator,\n                            epochs=20,\n                            callbacks=[callback])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 모델 저장\ncnn_model.save('cnn_model.h5')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 정확도와 손실값 확인\n\ncnn_acc = cnn_history.history['accuracy']\ncnn_val_acc = cnn_history.history['val_accuracy']\ncnn_loss = cnn_history.history['loss']\ncnn_val_loss = cnn_history.history['val_loss']\n\ncnn_epochs = range(len(cnn_acc))\n\nplt.plot(cnn_epochs, cnn_acc, 'r', label='Training accuracy')\nplt.plot(cnn_epochs, cnn_val_acc, 'b', label='Validation accuracy')\nplt.title('Training and validation accuracy')\nplt.legend()\n\nplt.figure()\n\nplt.plot(cnn_epochs, cnn_loss, 'r', label='Training Loss')\nplt.plot(cnn_epochs, cnn_val_loss, 'b', label='Validation Loss')\nplt.title('Training and validation loss')\nplt.legend()\n\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions = cnn_model.predict(x)\n\nnum_rows = 5\nnum_cols = 3\nnum_images = num_rows*num_cols\nplt.figure(figsize=(4*num_cols, 2*num_rows))\nfor i in range(num_images):\n    plt.subplot(num_rows, 2*num_cols, 2*i+1)\n    plot_image(i, predictions, y, x)\n    plt.subplot(num_rows, 2*num_cols, 2*i+2)\n    plot_value_array(i, predictions, y)\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### VGG19","metadata":{}},{"cell_type":"code","source":"# VGG 모델 정의\n\nfrom tensorflow.keras.applications import VGG19\ncallback=EarlyStopping(monitor=\"val_loss\", patience=4)\n\nvgg19_model = VGG19(weights='imagenet', include_top=False, input_shape=(height,width,channel))\n\nfor layer in vgg19_model.layers[:15]:\n    layer.trainable = False\n\nfor layer in vgg19_model.layers[15:]:\n    layer.trainable = True\n    \nlast_layer = vgg19_model.get_layer('block5_pool')\nlast_output = last_layer.output\n    \nx = GlobalMaxPooling2D()(last_output)\nx = Dense(512, activation='relu')(x)\nx = Dropout(0.5)(x)\nx = Dense(2, activation='softmax')(x)\n\nvgg_model = Model(vgg19_model.input, x)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_input = Input(shape = (height,width,channel))\n\n# Block 1\nx = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv1')(img_input)\nx = Conv2D(64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)\nx = MaxPool2D((2, 2), strides=(2, 2), name='block1_pool')(x)\nx = BatchNormalization()(x)\n\n# Block 2\nx = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)\nx = Conv2D(128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)\nx = MaxPool2D((2, 2), strides=(2, 2), name='block2_pool')(x)\nx = BatchNormalization()(x)\n\n# Block 3\nx = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)\nx = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)\nx = Conv2D(256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)\nx = MaxPool2D((2, 2), strides=(2, 2), name='block3_pool')(x)\nx = BatchNormalization()(x)\n\n# Block 4\nx = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)\nx = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)\nx = Conv2D(512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)\nx = MaxPool2D((2, 2), strides=(2, 2), name='block4_pool')(x)\nx = BatchNormalization()(x)\n\n# Block 5\nx = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)\nx = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)\nx = Conv2D(512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)\nx = MaxPool2D((2, 2), strides=(2, 2), name='block5_pool')(x)\nx = BatchNormalization()(x)\n\nx = Flatten(name='flatten')(x)\nx = Dense(4096, activation='relu', name='fc1')(x)\nx = Dense(4096, activation='relu', name='fc2')(x)\nx = Dense(2, activation='softmax', name='predictions')(x)\n\nvgg_model = Model(img_input, x, name='vgg16')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 모델 확인\nvgg_model.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 모델 컴파일\nvgg_model.compile(loss='categorical_crossentropy',\n                  optimizer='adam',\n                  metrics=['accuracy'])\n\n# 모델 학습\nvgg_history = vgg_model.fit(train_generator,\n                            validation_data=test_generator,\n                            epochs=20)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 정확도 및 손실값 확인\n\nvgg_acc = vgg_history.history['accuracy']\nvgg_val_acc = vgg_history.history['val_accuracy']\nvgg_loss = vgg_history.history['loss']\nvgg_val_loss = vgg_history.history['val_loss']\n\nvgg_epochs = range(len(vgg_acc))\n\nplt.plot(vgg_epochs, vgg_acc, 'r', label='Training accuracy')\nplt.plot(vgg_epochs, vgg_val_acc, 'b', label='Validation accuracy')\nplt.title('Training and validation accuracy')\nplt.legend()\n\nplt.figure()\n\nplt.plot(vgg_epochs, vgg_loss, 'r', label='Training Loss')\nplt.plot(vgg_epochs, vgg_val_loss, 'b', label='Validation Loss')\nplt.title('Training and validation loss')\nplt.legend()\n\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x, y = test_generator.next()\npredictions = vgg_model.predict(x)\n\nnum_rows = 5\nnum_cols = 3\nnum_images = num_rows*num_cols\nplt.figure(figsize=(4*num_cols, 2*num_rows))\nfor i in range(num_images):\n    plt.subplot(num_rows, 2*num_cols, 2*i+1)\n    plot_image(i, predictions, y, x)\n    plt.subplot(num_rows, 2*num_cols, 2*i+2)\n    plot_value_array(i, predictions, y)\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 모델이 어떠한 특징으로 이미지를 분류 한 걸까!?\n\n👀시각화 해보자! ","metadata":{}},{"cell_type":"code","source":"# 저장한 cnn 모델 불러오기\nfrom tensorflow.keras.models import load_model\nsaved_model = load_model('cnn_model.h5')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**🎁Try it!!**\n\n불러온 모델 정보를 표시해보자.","metadata":{}},{"cell_type":"code","source":"# 불러온 모델 정보 확인\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**훈련에 포함되지 않은 이미지 하나 가져오기**","metadata":{}},{"cell_type":"code","source":"# 리스트 형태이기 때문에 head()사용할 수 없으므로 [:5]로 확인\ntest_img_names[:5]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from  tensorflow.keras.preprocessing import image\n\nimg_path = './test1/8961.jpg'\n# 모델이 훈련될 때 입력에 적용한 전처리 방식을 동일하게 사용해줘야합니다. (color정보, 이미지 크기 등)\n\nimg = image.load_img(img_path, target_size=(150, 150), color_mode='rgb')\nimg_tensor = image.img_to_array(img)\nimg_tensor = np.expand_dims(img_tensor, axis=0)\nimg_tensor /= 255.\n\n# 이미지 크기 (1, 150, 150, 3)\nprint(img_tensor.shape)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 불러온 이미지 확인\nplt.imshow(img_tensor[0])\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"모델이 사진을보고 각 층별로 어떤 특징을 추출했는지 살펴보자.","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras import models\n\n\n# 상위 8개 층의 출력을 추출합\nlayer_outputs = [layer.output for layer in saved_model.layers[:8]]\n# 입력에 대해 8개 층의 출력을 반환하는 모델을 생성\nactivation_model = models.Model(inputs=saved_model.input, outputs=layer_outputs)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 층의 활성화마다 하나씩 8개의 넘파이 배열로 이루어진 리스트를 반환합니다:\nactivations = activation_model.predict(img_tensor)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"first_layer_activation = activations[0]\nprint(first_layer_activation.shape)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.matshow(first_layer_activation[0, :, :, 19], cmap='viridis')\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"강아지의 가장자리가 주로 감지된 것 같다.\n\n다른 채널도 그려보자.","metadata":{}},{"cell_type":"code","source":"plt.matshow(first_layer_activation[0, :, :, 8], cmap='viridis')\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"세로 선상이 주로 추출된 것 같다. \n\n강아지 얼굴 무늬 중 색이 구분되는 선이 뚜렷히 관찰된다.\n\n이제 네트워크의 모든 활성화층을 시각화 해봅시다.\n\n**특성맵 그리기**","metadata":{}},{"cell_type":"code","source":"# 층의 이름을 그래프 제목으로 사용\nlayer_names = []\nfor layer in saved_model.layers[:8]:\n    layer_names.append(layer.name)\n\nimages_per_row = 16\n\n# 특성 맵을 그ㅣ기\nfor layer_name, layer_activation in zip(layer_names, activations):\n    # 특성 맵에 있는 특성의 수\n    n_features = layer_activation.shape[-1]\n\n    # 특성 맵의 크기 : (1, size, size, n_features)\n    size = layer_activation.shape[1]\n\n    # 활성화 채널을 위한 그리드 크기\n    n_cols = n_features // images_per_row\n    display_grid = np.zeros((size * n_cols, images_per_row * size))\n\n    # 각 활성화를 하나의 큰 그리드에 채웁니다\n    for col in range(n_cols):\n        for row in range(images_per_row):\n            channel_image = layer_activation[0,\n                                             :, :,\n                                             col * images_per_row + row]\n            # 그래프로 나타내기 좋게 특성을 처리합니다\n            channel_image -= channel_image.mean()\n            channel_image /= channel_image.std()\n            channel_image *= 64\n            channel_image += 128\n            channel_image = np.clip(channel_image, 0, 255).astype('uint8')\n            display_grid[col * size : (col + 1) * size,\n                         row * size : (row + 1) * size] = channel_image\n\n    # 그리드 출력\n    scale = 1. / size\n    plt.figure(figsize=(scale * display_grid.shape[1],\n                        scale * display_grid.shape[0]))\n    plt.title(layer_name)\n    plt.grid(False)\n    plt.imshow(display_grid, aspect='auto', cmap='viridis')\n\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}