{"cells":[{"metadata":{},"cell_type":"markdown","source":"    고수분들의 커널 공유 감사합니다.\n    3차 대회를 통해 딥러닝을 활용한 이미지 분류와 관련한 많은 배움을 얻어갑니다.\n    1. 케라스 프레임워크에 대한 이해\n    2. 이미지 제너레이터\n    3. 기 모델을 활용한 전이학습\n    4. 콜백함수를 활용한 학습\n    5. 정확도를 올리기 위한 방법\n        5-1. 층화 폴드\n        5-2. 폴드 모델을 통한 앙상블\n        5-2. TTA"},{"metadata":{},"cell_type":"markdown","source":"## 라이브러리 불러오기"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport warnings\nimport gc\n\nimport numpy as np\nimport pandas as pd\n\nfrom sklearn.model_selection import StratifiedKFold, KFold\nfrom sklearn.metrics import f1_score\nfrom keras import backend as K\nfrom keras import layers, models, optimizers\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.applications import *\nfrom keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint\n\nwarnings.filterwarnings('ignore')\nK.image_data_format()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 분석 파라미터 설정"},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 22\nEPOCHS = 100\nk_folds = 5\nTTA_STEPS = 5\nPATIENCE = 10\nSEED = 523\nBASE_MODEL = Xception\nIMAGE_SIZE = 299","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA_PATH = '../input/3rd-comp-car-img/'\n\nTRAIN_IMG_PATH = os.path.join(DATA_PATH, 'cropped_train')\nTEST_IMG_PATH = os.path.join(DATA_PATH, 'cropped_test')\n\ndf_train = pd.read_csv(os.path.join(DATA_PATH, 'train.csv'))\ndf_test = pd.read_csv(os.path.join(DATA_PATH, 'test.csv'))\ndf_class = pd.read_csv(os.path.join(DATA_PATH, 'class.csv'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train['class'] = df_train['class'].astype('str')\ndf_train = df_train[['img_file', 'class']]\ndf_test = df_test[['img_file']]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Metric 함수 정의"},{"metadata":{"trusted":true},"cell_type":"code","source":"def recall_m(y_true, y_pred):\n        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))\n        possible_positives = K.sum(K.round(K.clip(y_true, 0, 1)))\n        recall = true_positives / (possible_positives + K.epsilon())\n        return recall\n\ndef precision_m(y_true, y_pred):\n        true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))\n        predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1)))\n        precision = true_positives / (predicted_positives + K.epsilon())\n        return precision\n\ndef f1_m(y_true, y_pred):\n    precision = precision_m(y_true, y_pred)\n    recall = recall_m(y_true, y_pred)\n    return 2*((precision*recall)/(precision+recall+K.epsilon()))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 콜백 함수 정의"},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_callback(model_name, patient):\n    ES = EarlyStopping(\n        monitor='val_f1_m', \n        patience=patient, \n        mode='max', \n        verbose=1)\n    RR = ReduceLROnPlateau(\n        monitor = 'val_f1_m', \n        factor = 0.5, \n        patience = patient / 3, \n        min_lr=0.000001, \n        verbose=1, \n        mode='max')\n    MC = ModelCheckpoint(\n        filepath=model_name, \n        monitor='val_f1_m', \n        verbose=1, \n        save_best_only=True, \n        mode='max')\n\n    return [ES, RR, MC]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 전이학습을 위한 모델 생성 함수"},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_model(model_name, iamge_size):\n    base_model = model_name(weights='imagenet', input_shape=(iamge_size,iamge_size,3), include_top=False)\n    #base_model.trainable = False\n    model = models.Sequential()\n    model.add(base_model)\n    model.add(layers.GlobalAveragePooling2D())\n    model.add(layers.Dense(2048, activation='relu', kernel_initializer='he_normal'))\n    model.add(layers.Dropout(0.5))\n \n    model.add(layers.Dense(196, activation='softmax', kernel_initializer='lecun_normal'))\n    #model.summary()\n\n    optimizer = optimizers.Nadam(lr=0.0001)\n    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['acc', f1_m, precision_m, recall_m])\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 이미지 제너레이터 설정(data augmentation)"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_datagen = ImageDataGenerator(\n    rescale=1./255,\n    #featurewise_center= True,  # set input mean to 0 over the dataset\n    #samplewise_center=True,  # set each sample mean to 0\n    #featurewise_std_normalization= True,  # divide inputs by std of the dataset\n    #samplewise_std_normalization=True,  # divide each input by its std\n    rotation_range=20,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    horizontal_flip=True,\n    vertical_flip=False,\n    zoom_range=0.2,\n    shear_range=0.2,\n    brightness_range=[0.5, 1.5],\n    fill_mode='nearest'\n    )\n\nvalid_datagen = ImageDataGenerator(\n    rescale=1./255,\n    #featurewise_center= True,  # set input mean to 0 over the dataset\n    #samplewise_center=True,  # set each sample mean to 0\n    #featurewise_std_normalization= True,  # divide inputs by std of the dataset\n    #samplewise_std_normalization=True  # divide each input by its std\n    )\ntest_datagen = ImageDataGenerator(\n    rescale=1./255,\n    #featurewise_center= True,  # set input mean to 0 over the dataset\n    #samplewise_center=True,  # set each sample mean to 0\n    #featurewise_std_normalization= True,  # divide inputs by std of the dataset\n    #samplewise_std_normalization=True,  # divide each input by its std\n    )","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 층화 폴드 설정"},{"metadata":{"trusted":true},"cell_type":"code","source":"skf = StratifiedKFold(n_splits=k_folds, random_state=SEED)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 모델 훈련 시작\n    1~5번 폴드로 나누어 훈련을 진행하는 부분입니ㅣ다.\n    캐글이나 로컬에서 실행해도 3번째 폴드까지만 한 번에 돌아가서\n    1~3번/4~5번으로 나누어 훈련시킨 흔적이 남아있습니다.\n    해당 코드는 4~5번 코드"},{"metadata":{"trusted":true},"cell_type":"code","source":"# %%time\n# j = 1\n# model_names = []\n# for (train_index, valid_index) in skf.split(df_train['img_file'], df_train['class']):\n#     if j<=3:\n#         print(\"skip %d fold\" %(j))\n#         j+=1\n#         gc.collect()\n#         continue\n#     else:\n#         traindf = df_train.iloc[train_index, :].reset_index()\n#         validdf = df_train.iloc[valid_index, :].reset_index()\n# \n#         print(\"==============================================\")\n#         print(\"====== K Fold Validation step => %d/%d =======\" % (j,k_folds))\n#         print(\"==============================================\")\n# \n#         train_generator = train_datagen.flow_from_dataframe(\n#             dataframe=traindf,\n#             directory=TRAIN_IMG_PATH,\n#             x_col='img_file',\n#             y_col='class',\n#             target_size= (IMAGE_SIZE, IMAGE_SIZE),\n#             color_mode='rgb',\n#             class_mode='categorical',\n#             batch_size=BATCH_SIZE,\n#             seed=SEED,\n#             shuffle=True\n#             )\n# \n#         valid_generator = valid_datagen.flow_from_dataframe(\n#             dataframe=validdf,\n#             directory=TRAIN_IMG_PATH,\n#             x_col='img_file',\n#             y_col='class',\n#             target_size= (IMAGE_SIZE, IMAGE_SIZE),\n#             color_mode='rgb',\n#             class_mode='categorical',\n#             batch_size=BATCH_SIZE,\n#             seed=SEED,\n#             shuffle=True\n#             )\n# \n#         model_name = model_path + str(j) + '_' + 'Xception' + '.hdf5'\n#         model_names.append(model_name)\n# \n#         model = get_model(BASE_MODEL, IMAGE_SIZE)\n# \n#         try:\n#             model.load_weights(model_name)\n#         except:\n#             pass\n# \n#         history = model.fit_generator(\n#             train_generator,\n#             steps_per_epoch=len(traindf.index) / BATCH_SIZE,\n#             epochs=EPOCHS,\n#             validation_data=valid_generator,\n#             validation_steps=len(validdf.index) / BATCH_SIZE,\n#             verbose=1,\n#             shuffle=False,\n#             callbacks = get_callback(model_name, PATIENCE)\n#             )\n#         j+=1\n#         gc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 이미지 제너레이터 생성"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_generator = train_datagen.flow_from_dataframe(\n            dataframe=df_train,\n            directory=TRAIN_IMG_PATH,\n            x_col='img_file',\n            y_col='class',\n            target_size= (IMAGE_SIZE, IMAGE_SIZE),\n            color_mode='rgb',\n            class_mode='categorical',\n            batch_size=BATCH_SIZE,\n            seed=SEED,\n            shuffle=True\n            )\n\ntest_generator = test_datagen.flow_from_dataframe(\n    dataframe=df_test,\n    directory=TEST_IMG_PATH,\n    x_col='img_file',\n    y_col=None,\n    target_size= (IMAGE_SIZE, IMAGE_SIZE),\n    color_mode='rgb',\n    class_mode=None,\n    batch_size=BATCH_SIZE,\n    shuffle=False\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"tmp_list = os.listdir(\"../input/3rd-comp-car-img\")\ntmp_list.sort()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_names = tmp_list[:5]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## TTA"},{"metadata":{"trusted":true},"cell_type":"code","source":"prediction = []\nfor i, name in enumerate(model_names):\n    model = get_model(BASE_MODEL, IMAGE_SIZE)\n    model.load_weights(\"../input/3rd-comp-car-img/\"+name)\n    \n    preds = []\n    for j in range(TTA_STEPS):\n        test_generator.reset()\n        pred = model.predict_generator(\n            generator=test_generator,\n            steps = len(df_test)/BATCH_SIZE,\n            verbose=1\n        )\n        preds.append(pred)\n    pred_tta = np.mean(preds, axis=0)\n    prediction.append(pred_tta)\n\ny_pred = np.mean(prediction, axis=0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 예측 결과 확인 및 제출 파일 생성"},{"metadata":{"trusted":true},"cell_type":"code","source":"y_pred","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds_class_indices=np.argmax(y_pred, axis=1)\nlabels = (train_generator.class_indices)\nlabels = dict((v,k) for k,v in labels.items())\nfinal_pred = [labels[k] for k in preds_class_indices]\nsubmission = pd.read_csv(os.path.join(DATA_PATH, 'sample_submission.csv'))\nsubmission[\"class\"] = final_pred\nsubmission.to_csv(\"xception_folds_avg.csv\", index=False)\nsubmission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":1}