{"cells":[{"metadata":{},"cell_type":"markdown","source":"[Tony Lee](https://www.kaggle.com/easter3163)님의 [3rd ML Month - Keras EfficientNet](https://www.kaggle.com/easter3163/3rd-ml-month-keras-efficientnet) kernel을 참고하였습니다.\n\nTony Lee님은 허태명님, 김태진님, Daehun Gwak님의 커널을 참고하였다고 합니다.\n\n다른 것은 바꾸지 않고, ImageDataGenerator에서 cutout augmentation만 추가적으로 수행하였습니다.\n\n이 augmentation이 이 dataset에 적합한지 테스트하기 위한 kernel입니다. LB 성능의 차이로 확인해보려합니다.\n\n제가 Base로 잡은 Kernel의 Public Score는 0.88841 였습니다."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"collapsed":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport os\nprint(os.listdir(\"../input\"))\n\nimport warnings\nwarnings.filterwarnings('ignore')\n\nimport seaborn as sns\nimport matplotlib.pylab as plt\nimport PIL\nfrom keras import backend as K\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\n!pip install git+https://github.com/qubvel/efficientnet\nfrom efficientnet import EfficientNetB3","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image_size = 299\napplication = Xception\nbatch_size = 32","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA_PATH = '../input'\nTRAIN_IMG_PATH = os.path.join(DATA_PATH, 'train')\nTEST_IMG_PATH = os.path.join(DATA_PATH, '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'))\n\ndf_train['class'] = df_train['class'].astype('str')\n\nnb_train_sample = df_train.shape[0] * 0.7\nnb_validation_sample = df_train.shape[0] - nb_train_sample\nnb_test_sample = df_test.shape[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def crop_boxing_img(img_name, margin=16, 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'\nVALID_CROPPED_PATH = '../cropped_valid'\nTEST_CROPPED_PATH = '../cropped_test'\n\nif (os.path.isdir(TRAIN_CROPPED_PATH) == False):\n    os.mkdir(TRAIN_CROPPED_PATH)\n\nif (os.path.isdir(VALID_CROPPED_PATH) == False):\n    os.mkdir(VALID_CROPPED_PATH)\n\nif (os.path.isdir(TEST_CROPPED_PATH) == False):\n    os.mkdir(TEST_CROPPED_PATH)\n\nfor i, row in df_train.iterrows():\n    cropped = crop_boxing_img(row['img_file'])\n    \n    if ( i < nb_train_sample):\n        class_path = os.path.join(TRAIN_CROPPED_PATH, df_train['class'][i])\n        if(os.path.isdir(class_path) == False):\n            os.mkdir(class_path)\n\n        cropped.save(os.path.join(class_path, row['img_file']))\n    else:\n        class_path = os.path.join(VALID_CROPPED_PATH, df_train['class'][i])\n        if(os.path.isdir(class_path) == False):\n            os.mkdir(class_path)\n\n        cropped.save(os.path.join(class_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":"#ref: https://github.com/yu4u/cutout-random-erasing/blob/master/cifar10_resnet.py\ndef get_random_eraser(p=0.5, s_l=0.02, s_h=0.4, r_1=0.3, r_2=1/0.3, v_l=0, v_h=255, pixel_level=False):\n    def eraser(input_img):\n        img_h, img_w, img_c = input_img.shape\n        p_1 = np.random.rand()\n\n        if p_1 > p:\n            return input_img\n\n        while True:\n            s = np.random.uniform(s_l, s_h) * img_h * img_w\n            r = np.random.uniform(r_1, r_2)\n            w = int(np.sqrt(s / r))\n            h = int(np.sqrt(s * r))\n            left = np.random.randint(0, img_w)\n            top = np.random.randint(0, img_h)\n\n            if left + w <= img_w and top + h <= img_h:\n                break\n\n        if pixel_level:\n            c = np.random.uniform(v_l, v_h, (h, w, img_c))\n        else:\n            c = np.random.uniform(v_l, v_h)\n\n        input_img[top:top + h, left:left + w, :] = c\n\n        return input_img\n\n    return eraser","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_datagen = ImageDataGenerator(\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.1,\n    fill_mode='nearest',\n    preprocessing_function = get_random_eraser(v_l=0, v_h=255),\n    )\n\nvalid_datagen = ImageDataGenerator()\ntest_datagen = ImageDataGenerator()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def generate_plot_pics(datagen,orig_img):\n    dir_augmented_data = \"preview\"\n    try:\n        ## if the preview folder does not exist, create\n        os.mkdir(dir_augmented_data)\n    except:\n        ## if the preview folder exists, then remove\n        ## the contents (pictures) in the folder\n        for item in os.listdir(dir_augmented_data):\n            os.remove(dir_augmented_data + \"/\" + item)\n\n    ## convert the original image to array\n    x = img_to_array(orig_img)\n    ## reshape (Sampke, Nrow, Ncol, 3) 3 = R, G or B\n    x = x.reshape((1,) + x.shape)\n    ## -------------------------- ##\n    ## randomly generate pictures\n    ## -------------------------- ##\n    i = 0\n    Nplot = 8\n    for batch in datagen.flow(x,batch_size=1,\n                          save_to_dir=dir_augmented_data,\n                          save_prefix=\"pic\",\n                          save_format='jpeg'):\n        i += 1\n        if i > Nplot - 1: ## generate 8 pictures \n            break\n\n    ## -------------------------- ##\n    ##   plot the generated data\n    ## -------------------------- ##\n    fig = plt.figure(figsize=(8, 6))\n    fig.subplots_adjust(hspace=0.02,wspace=0.01,\n                    left=0,right=1,bottom=0, top=1)\n\n    ## original picture\n    ax = fig.add_subplot(3, 3, 1,xticks=[],yticks=[])        \n    ax.imshow(orig_img)\n    ax.set_title(\"original\")\n\n    i = 2\n    for imgnm in os.listdir(dir_augmented_data):\n        ax = fig.add_subplot(3, 3, i,xticks=[],yticks=[]) \n        img = cv2.imread(dir_augmented_data + \"/\" + imgnm)\n        ax.imshow(img)\n        i += 1\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import cv2\nfrom keras.preprocessing.image import img_to_array\norig_img = cv2.imread(\"../cropped_train/27/train_05701.jpg\")\ngenerate_plot_pics(train_datagen, orig_img)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_generator = train_datagen.flow_from_directory(\n    TRAIN_CROPPED_PATH,\n    target_size=(image_size, image_size),\n    batch_size=batch_size,\n    class_mode='categorical',\n    seed=2019,\n    color_mode='rgb'\n)\n\nvalidation_generator = valid_datagen.flow_from_directory(\n    VALID_CROPPED_PATH,\n    target_size=(image_size,image_size),\n    batch_size=batch_size,\n    class_mode='categorical',\n    seed=2019,\n    color_mode='rgb'\n)\n\ntest_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":"def get_model():\n    # base_model = application(weights='imagenet', input_shape=(image_size,image_size,3), include_top=False)\n    base_model = EfficientNetB3(weights='imagenet', include_top=False, input_shape=(image_size, image_size, 3))\n    # base_model.trainable = False\n\n    model = models.Sequential()\n    model.add(base_model)\n    model.add(layers.GlobalAveragePooling2D())\n    model.add(layers.Dense(1024, activation='relu'))\n    model.add(layers.Dropout(0.5))\n    model.add(layers.Dense(196, activation='softmax'))\n    model.summary()\n\n    #optimizer = optimizers.SGD(lr=1e-4, decay=1e-6, momentum=0.9, nesterov=True)\n    optimizer = optimizers.RMSprop(lr=0.0001)\n    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['acc'])\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = get_model()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_path = '../model/'\nif not os.path.exists(model_path):\n    os.mkdir(model_path)\n    \nmodel_path = model_path + 'best_model.hdf5'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"patient = 2\ncallbacks1 = [\n    EarlyStopping(monitor='val_loss', patience=patient, mode='min', verbose=1),\n    ReduceLROnPlateau(monitor = 'val_loss', factor = 0.5, patience = patient / 2, min_lr=0.00001, verbose=1, mode='min'),\n    ModelCheckpoint(filepath=model_path, monitor='val_loss', verbose=1, save_best_only=True, mode='min'),\n    ]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_steps(num_samples, batch_size):\n    if (num_samples % batch_size) > 0:\n        return (num_samples // batch_size) + 1\n    else:\n        return num_samples // batch_size","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit_generator(\n    train_generator,\n    steps_per_epoch=get_steps(nb_train_sample, batch_size),\n    epochs=100,\n    validation_data=validation_generator,\n    validation_steps=get_steps(nb_validation_sample, batch_size),\n    verbose=1,\n    callbacks = callbacks1\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"acc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs = range(1, len(acc) + 1)\n\nplt.plot(epochs, acc, 'bo', label='Training Acc')\nplt.plot(epochs, val_acc, 'b', label='Validation Acc')\nplt.title('Training and validation accuracy')\nplt.legend()\nplt.show()\n\nplt.plot(epochs, loss, 'bo', label='Traing loss')\nplt.plot(epochs, val_loss, 'b', label='Validation loss')\nplt.title('Trainging and validation loss')\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.load_weights(model_path)\ntest_generator.reset()\n\nprediction = model.predict_generator(\n    generator=test_generator,\n    steps = get_steps(nb_test_sample, batch_size),\n    verbose=1\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predicted_class_indices=np.argmax(prediction, axis=1)\n\n# Generator class dictionary mapping\nlabels = (train_generator.class_indices)\nlabels = dict((v,k) for k,v in labels.items())\npredictions = [labels[k] for k in predicted_class_indices]\n\nsubmission = pd.read_csv(os.path.join(DATA_PATH, 'sample_submission.csv'))\nsubmission[\"class\"] = predictions\nsubmission.to_csv(\"submission.csv\", index=False)\nsubmission.head()","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}