{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"import gc\nimport os\nimport warnings\nimport numpy as np \nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nimport PIL\nfrom PIL import ImageDraw\n\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import f1_score\nfrom keras.optimizers import Adadelta\nfrom keras.optimizers import RMSprop\nfrom keras.optimizers import Adam, SGD\n\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.applications import Xception\nfrom keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint\nfrom keras import layers, models, optimizers\n\nfrom keras import backend as K\nwarnings.filterwarnings(action='ignore')\n\nK.image_data_format()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA_PATH = '../input/'\nos.listdir(DATA_PATH)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 이미지 폴더 경로\nTRAIN_IMG_PATH = os.path.join(DATA_PATH, 'train')\nTEST_IMG_PATH = os.path.join(DATA_PATH, 'test')\n\n# CSV 파일 경로\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":"# Data 누락 체크\nif set(list(df_train.img_file)) == set(os.listdir(TRAIN_IMG_PATH)) :\n    print(\"Train file 누락 없음!\")\nelse : \n    print(\"Train file 누락\")\n\nif set(list(df_test.img_file)) == set(os.listdir(TEST_IMG_PATH)) :\n    print(\"Test file 누락 없음!\")\nelse : \n    print(\"Test file 누락\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Data 갯수\nprint(\"Number of Train Data : {}\".format(df_train.shape[0]))\nprint(\"Number of Test Data : {}\".format(df_test.shape[0]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_class.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"타겟 클래스 총 갯수 : {}\".format(df_class.shape[0]))\nprint(\"Train Data의 타겟 종류 갯수 : {}\".format(df_train['class'].nunique()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(12, 6))\nsns.countplot(df_train[\"class\"], order=df_train[\"class\"].value_counts(ascending=True).index)\nplt.title(\"Number of data per each class\")\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cntEachClass = df_train[\"class\"].value_counts(ascending=False)\nprint(\"Class with most count  : {}\".format(cntEachClass.index[0]))\nprint(\"Most Count : {}\".format(cntEachClass.max()))\n\nprint(\"Class with fewest count  : {}\".format(cntEachClass.index[-1]))\nprint(\"Fewest Count : {}\".format(cntEachClass.min()))\n\nprint(\"Mean  : {}\".format(cntEachClass.mean()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import PIL\nfrom PIL import ImageDraw\n\ntmp_imgs = df_train['img_file'][100:110]\nplt.figure(figsize=(12,20))\n\nfor num, f_name in enumerate(tmp_imgs):\n    img = PIL.Image.open(os.path.join(TRAIN_IMG_PATH, f_name))\n    plt.subplot(5, 2, num + 1)\n    plt.title(f_name)\n    plt.imshow(img)\n    plt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def draw_rect(drawcontext, pos, outline=None, width=0):\n    (x1, y1) = (pos[0], pos[1])\n    (x2, y2) = (pos[2], pos[3])\n    points = (x1, y1), (x2, y1), (x2, y2), (x1, y2), (x1, y1)\n    drawcontext.line(points, fill=outline, width=width)\n\ndef make_boxing_img(img_name) :\n    if img_name.split('_')[0] == \"train\" :\n        PATH = TRAIN_IMG_PATH\n        data = df_train\n    elif img_name.split('_')[0] == \"test\" :\n        PATH = TEST_IMG_PATH\n        data = df_test\n        \n    img = PIL.Image.open(os.path.join(PATH, img_name))\n    pos = data.loc[data[\"img_file\"] == img_name, \\\n                   ['bbox_x1','bbox_y1', 'bbox_x2', 'bbox_y2']].values.reshape(-1)\n    draw = ImageDraw.Draw(img)\n    draw_rect(draw, pos, outline='red', width=10)\n    \n    return img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"f_name = \"train_00102.jpg\"\n\nplt.figure(figsize=(20,10))\nplt.subplot(1, 2, 1)\n# Original Image\norigin_img = PIL.Image.open(os.path.join(TRAIN_IMG_PATH, f_name))\nplt.title(\"Original Image - {}\".format(f_name))\nplt.imshow(origin_img)\nplt.axis('off')\n\n# Image included bounding box\nplt.subplot(1, 2, 2)\nboxing = make_boxing_img(f_name)\nplt.title(\"Boxing Image - {}\".format(f_name))\nplt.imshow(boxing)\nplt.axis('off')\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# ResNet50 -> 224\n# Xception,InceptionResNetV2 -> 299\n# NASNetLarge -> 331\n\nIMAGE_SIZE = 299\nBATCH_SIZE = 32\nEPOCHS = 50\nk_folds=5\n\nimage_size = 299\n\ndef crop_boxing_img(img_name, margin=0, size=(IMAGE_SIZE,IMAGE_SIZE)):\n    if img_name.split('_')[0] == 'train':\n        PATH = TRAIN_IMG_PATH\n        data = df_train\n    else:\n        PATH = TEST_IMG_PATH\n        data = df_test\n\n    img = PIL.Image.open(os.path.join(PATH, img_name))\n    pos = data.loc[data[\"img_file\"] == img_name, ['bbox_x1', 'bbox_y1', 'bbox_x2', 'bbox_y2']].values.reshape(-1)\n\n    width, height = img.size\n    x1 = max(0, pos[0] - margin)\n    y1 = max(0, pos[1] - margin)\n    x2 = min(pos[2] + margin, width)\n    y2 = min(pos[3] + margin, height)\n\n    return img.crop((x1, y1, x2, y2)).resize(size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"TRAIN_CROPPED_PATH = '../cropped_train'\nTEST_CROPPED_PATH = '../cropped_test'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"if (os.path.isdir(TRAIN_CROPPED_PATH) == False):\n    os.mkdir(TRAIN_CROPPED_PATH)\n\nif (os.path.isdir(TEST_CROPPED_PATH) == False):\n    os.mkdir(TEST_CROPPED_PATH)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i, row in df_train.iterrows():\n    cropped = crop_boxing_img(row['img_file'])\n    cropped.save(os.path.join(TRAIN_CROPPED_PATH, row['img_file']))\n\nfor i, row in df_test.iterrows():\n    cropped = crop_boxing_img(row['img_file'])\n    cropped.save(os.path.join(TEST_CROPPED_PATH, row['img_file']))","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":{"trusted":true},"cell_type":"code","source":"model_path = '../working/'\nif not os.path.exists(model_path):\n    os.mkdir(model_path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_callback(model_name, patient):\n    ES = EarlyStopping(\n        monitor='val_f1score', \n        patience=3, \n        mode='max', \n        min_delta=0,\n        verbose=1)\n    RR = ReduceLROnPlateau(\n        monitor = 'val_f1score', \n        factor = 0.5, \n        patience = 2,\n        min_lr=0.00001, \n        verbose=1, \n        mode='max')\n    MC = ModelCheckpoint(\n        filepath=model_name, \n        monitor='val_f1score', \n        verbose=1, \n        save_best_only=True, \n        mode='max')\n\n    return [ES, RR, MC]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def recall(y_target, y_pred):\n    # clip(t, clip_value_min, clip_value_max) : clip_value_min~clip_value_max 이외 가장자리를 깎아 낸다\n    # round : 반올림한다\n    y_target_yn = K.round(K.clip(y_target, 0, 1)) # 실제값을 0(Negative) 또는 1(Positive)로 설정한다\n    y_pred_yn = K.round(K.clip(y_pred, 0, 1)) # 예측값을 0(Negative) 또는 1(Positive)로 설정한다\n\n    # True Positive는 실제 값과 예측 값이 모두 1(Positive)인 경우이다\n    count_true_positive = K.sum(y_target_yn * y_pred_yn) \n\n    # (True Positive + False Negative) = 실제 값이 1(Positive) 전체\n    count_true_positive_false_negative = K.sum(y_target_yn)\n\n    # Recall =  (True Positive) / (True Positive + False Negative)\n    # K.epsilon()는 'divide by zero error' 예방차원에서 작은 수를 더한다\n    recall = count_true_positive / (count_true_positive_false_negative + K.epsilon())\n\n    # return a single tensor value\n    return recall\n\n\ndef precision(y_target, y_pred):\n    # clip(t, clip_value_min, clip_value_max) : clip_value_min~clip_value_max 이외 가장자리를 깎아 낸다\n    # round : 반올림한다\n    y_pred_yn = K.round(K.clip(y_pred, 0, 1)) # 예측값을 0(Negative) 또는 1(Positive)로 설정한다\n    y_target_yn = K.round(K.clip(y_target, 0, 1)) # 실제값을 0(Negative) 또는 1(Positive)로 설정한다\n\n    # True Positive는 실제 값과 예측 값이 모두 1(Positive)인 경우이다\n    count_true_positive = K.sum(y_target_yn * y_pred_yn) \n\n    # (True Positive + False Positive) = 예측 값이 1(Positive) 전체\n    count_true_positive_false_positive = K.sum(y_pred_yn)\n\n    # Precision = (True Positive) / (True Positive + False Positive)\n    # K.epsilon()는 'divide by zero error' 예방차원에서 작은 수를 더한다\n    precision = count_true_positive / (count_true_positive_false_positive + K.epsilon())\n\n    # return a single tensor value\n    return precision\n\ndef f1score(y_target, y_pred):\n    _recall = recall(y_target, y_pred)\n    _precision = precision(y_target, y_pred)\n    # K.epsilon()는 'divide by zero error' 예방차원에서 작은 수를 더한다\n    _f1score = ( 2 * _recall * _precision) / (_recall + _precision+ K.epsilon())\n    \n    # return a single tensor value\n    return _f1score","execution_count":null,"outputs":[]},{"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(1024, activation='selu'))\n    model.add(layers.Dropout(0.4))\n \n    model.add(layers.Dense(196, activation='softmax', kernel_initializer='he_normal'))\n    model.summary()\n\n    # optimizer=Adam(lr=0.001, beta_1=0.9, beta_2=0.999)\n    # optimizer='adam'\n    # optimizer=RMSprop(lr=0.0001)\n    # optimizer=SGD(lr=0.001, momentum=0.9, nesterov=True)\n    # optimizer=Adadelta(rho=0.95)\n    \n    optimizer = optimizers.Adadelta(rho=0.95)\n    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['acc', f1score])\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#https://github.com/yu4u/mixup-generator\n#https://github.com/Tony607/keras_mixup_generator/blob/master/test_mixup_files.ipynb","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.applications.resnet50 import ResNet50, preprocess_input\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.applications import Xception, NASNetLarge, InceptionResNetV2\n\n# Parameter\n# ResNet50, ResNeXt101 -> 224\n# Xception,InceptionResNetV2 -> 299\n# NASNetLarge -> 331\n\nimg_size = (299, 299)\n\ntrain_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=10,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    shear_range=0.2,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    vertical_flip=False,\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":{"trusted":true},"cell_type":"code","source":"skf = StratifiedKFold(n_splits=k_folds, random_state=2019)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"j = 1\nmodel_xception_names = []\nfor (train_index, valid_index) in skf.split(\n    df_train['img_file'], \n    df_train['class']):\n\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_CROPPED_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=2019,\n        shuffle=True\n        )\n\n    valid_generator = valid_datagen.flow_from_dataframe(\n        dataframe=validdf,\n        directory=TRAIN_CROPPED_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=2019,\n        shuffle=True\n        )\n\n    model_name = model_path + str(j) + '_xception.hdf5'\n    model_xception_names.append(model_name)\n    \n    model_xception = get_model(Xception, IMAGE_SIZE)\n    \n    try:\n        model_xception.load_weights(model_name)\n    except:\n        pass\n        \n    history = model_xception.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, 4)\n        )\n        \n    j+=1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_generator = test_datagen.flow_from_dataframe(\n    dataframe=df_test,\n    directory=TEST_CROPPED_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":"xception_prediction = []\nfor i, name in enumerate(model_xception_names):\n    model_xception = get_model(Xception, IMAGE_SIZE)\n    model_xception.load_weights(name)\n    model_xception.save_weights(name)\n    test_generator.reset()\n    pred = model_xception.predict_generator(\n        generator=test_generator,\n        steps = len(df_test)/BATCH_SIZE,\n        verbose=1\n    )\n    xception_prediction.append(pred)\n\ny_pred_xception = np.mean(xception_prediction, axis=0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds_class_indices=np.argmax(y_pred_xception, axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels = (train_generator.class_indices)\nlabels = dict((v,k) for k,v in labels.items())\nfinal_pred = [labels[k] for k in preds_class_indices]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission = pd.read_csv(os.path.join(DATA_PATH, 'sample_submission.csv'))\nsubmission[\"class\"] = final_pred\nsubmission.to_csv(\"submission.csv\", index=False)\nsubmission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"os.listdir(model_path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}