{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import warnings\nimport seaborn as sns\nimport matplotlib.pylab as plt\nimport PIL\nfrom sklearn.model_selection import StratifiedKFold\nfrom keras import Input\nfrom keras import backend as K\nfrom keras import optimizers\nfrom keras.models import *\nfrom keras.layers import *\nfrom keras.applications import *\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint\n\nwarnings.filterwarnings('ignore')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 이미지 처리함수"},{"metadata":{"trusted":true},"cell_type":"code","source":"def crop_boxing_img(img_name, margin=16, size=(299, 299)):\n    '''\n    이미지 잘라내기 함수 : 추후 내용 보완\n    \n    Keyword arguments:\n    img_name  -- 이미지 파일명\n    margin    -- 간격\n    size      -- 최종 이미지 사이즈\n    '''\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)\n\n\ndef get_train_image_generator(dataframe, datagen, image_size, batch_size, path, seed_num=2019, shuffle_yn=False):\n    '''\n    훈련용 이미지 생성기\n    \n    Keyword arguments:\n    dataframe  -- 이미지 생성을 위한 DataFrame\n    datagen    -- 데이터 증식용 ImageGenerator \n    image_size -- 이미지 가로/세로 크기\n    batch_size -- Batch 크기\n    path       -- 이미지 파일의 시작 경로\n    seed_num   -- Random Seed 값\n    shuffle_yn -- Shuffle 여부 : True / False\n    '''\n    image_generator = datagen.flow_from_dataframe(\n        dataframe=dataframe,\n        directory=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_num,\n        shuffle=shuffle_yn\n    )\n    \n    return image_generator\n\ndef get_test_image_generator(dataframe, datagen, image_size, batch_size, path, seed_num=2019, shuffle_yn=False):\n    '''\n    테스트용 이미지 생성기\n    \n    Keyword arguments:\n    dataframe  -- 이미지 생성을 위한 DataFrame\n    datagen    -- 데이터 증식용 ImageGenerator \n    image_size -- 이미지 가로/세로 크기\n    batch_size -- Batch 크기\n    path       -- 이미지 파일의 시작 경로\n    seed_num   -- Random Seed 값\n    shuffle_yn -- Shuffle 여부 : True / False\n    '''\n    image_generator = datagen.flow_from_dataframe(\n        dataframe=dataframe,\n        directory=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        seed=seed_num,\n        shuffle=shuffle_yn\n    )\n    \n    return image_generator","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 훈련 처리함수"},{"metadata":{"trusted":true},"cell_type":"code","source":"def build_model(application, image_size=299):\n    '''\n    사전훈련 모델 생성\n    \n    Keyword arguments:\n    application  -- 사전 훈련 모델(ex:ResNet50, Xception, ...)\n    image_size   -- 이미지 가로/세로 크기\n    '''\n    input_layer = Input(shape=(image_size, image_size, 3))\n    base_model = application(weights='imagenet', include_top=False)(input_layer)\n    \n    x = GlobalAveragePooling2D()(base_model)\n    x = Dense(1024, activation='relu',\n                     bias_initializer='zeros',\n                     kernel_initializer='glorot_normal',\n                     kernel_regularizer=regularizers.L1L2(l1=0.001, l2=0.001))(x)\n    \n    x = Dropout(0.5)(x)\n    x = BatchNormalization()(x)\n    \n    output_layer = Dense(196, activation='softmax')(x)    \n    model = Model(input_layer, output_layer)\n    model.summary()\n    \n    optimizer = optimizers.nadam(lr=0.00001)\n        \n    model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['acc'])\n\n    return model\n\n\ndef get_callback(model_path, patient=4):\n    '''\n    callback 정의값 반환\n    \n    Keyword arguments:\n    model_path  -- Best weights 저장 경로\n    patient     -- Early Stop 수, Learning Rate 개선 수(patient / 2)\n    '''\n    \n    patient_count = patient / 2\n    patient_count = 1 if patient_count < 1 else patient_count\n    \n    callbacks = [\n        EarlyStopping(monitor='val_loss', patience=patient, mode='min', verbose=1),\n        ReduceLROnPlateau(monitor = 'val_loss', factor = 0.5, patience = int(patient_count), 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    ]\n    \n    return callbacks\n\ndef get_steps(num_samples, batch_size):\n    '''\n    step당 샘플링개수 반환\n    \n    Keyword arguments:\n    num_samples  -- 전체 샘플개수\n    batch_size   -- Batch 크기\n    '''\n    if (num_samples % batch_size) > 0:\n        return (num_samples // batch_size) + 1\n    else:\n        return num_samples // batch_size\n  \n\ndef create_k_fold_model_path(model_name, num):\n    '''\n    K Fold 훈련별 Best weights 저장경로 반환\n    \n    Keyword arguments:\n    model_name  -- 훈련중인 모델이름\n    num         -- 진행중 Fold 수\n    '''\n    model_path ='./'\n    final_model_path = model_path + str(num) + '_' + model_name + '.hdf5'\n    return final_model_path\n\n\ndef print_header(file_num, k_folds):\n    '''\n    K Fold별 머릿말 출력\n    \n    Keyword arguments:\n    file_num  -- 진행중인 Fold 수\n    k_folds   -- 전체 Fold 수\n    '''\n    print(\"=\" * 44)\n    print(\"====== K Fold Validation step => %d/%d =======\" % (file_num, k_folds))\n    print(\"=\" * 44)\n    \n\ndef train_with_StratifiedKFold(model, model_name, image_size=299, k_folds=5, epoch_num=20, batch_size=16,\n                               train_augmentaion_size=1, seed=2019, saved_model_path=None):\n    '''\n    Stratified K Fold 훈련 진행\n    훈련된 모델과 Fold별 Best Weight 경로 리스트 반환\n    \n    Keyword arguments:\n    model                   -- 사전훈련 모델\n    model_name              -- 훈련모델 이름\n    image_size              -- 이미지 가로/세로 크기\n    k_folds                 -- 전체 Fold 수\n    epoch_num               -- 훈련 횟수 \n    batch_size              -- Batch 크기\n    train_augmentaion_size  -- 데이터 증식 배수\n    seed                    -- Random Seed 수\n    saved_model_path        -- 중복(연장) 훈련시 참고할 기존 weights 파일 경로\n    '''\n    \n    skf = StratifiedKFold(n_splits=k_folds, shuffle=False, random_state=seed)\n    \n    file_num = 1\n    save_model_names = []\n    \n    # 모델 생성\n    target_model = build_model(model, image_size)\n    \n    # 저장된 모델 불러오기\n    if saved_model_path is not None:\n        target_model.load_weights(saved_model_path)\n    \n    # K-Fold 검증 시작\n    for (train_index, valid_index) in skf.split(\n        df_train['img_file'], \n        df_train['class']):\n\n        # 훈련 대상 데이터 수집\n        traindf = df_train.iloc[train_index, :].reset_index()\n        train_generator = get_train_image_generator(traindf, train_datagen, image_size, batch_size, TRAIN_CROPPED_PATH)\n        \n        # 검증 대상 데이터 수집\n        validdf = df_train.iloc[valid_index, :].reset_index()\n        valid_generator = get_train_image_generator(validdf, train_datagen, image_size, batch_size, TRAIN_CROPPED_PATH)\n\n        # 머릿말 출력\n        print_header(file_num, k_folds)\n\n        # 저장할 모델 weight 경로 생성하기\n        model_path = create_k_fold_model_path(model_name, file_num)\n        save_model_names.append(model_path)\n\n        # 훈련 시작\n        history = target_model.fit_generator(\n            train_generator,\n            steps_per_epoch=get_steps(len(traindf.index), batch_size) * train_augmentaion_size,\n            epochs=epoch_num,\n            validation_data=valid_generator,\n            validation_steps=get_steps(len(validdf.index), batch_size),\n            verbose=1,\n            shuffle=False,\n            callbacks = get_callback(model_path, patient=4)\n            )\n        \n        # 시각화\n        show_history(history)\n        \n        # Fold 수 증가\n        file_num += 1\n    \n    return (model, save_model_names)\n\n\ndef show_history(history):\n    '''\n    훈련결과 시각화\n    \n    Keyword arguments:\n    history  -- 훈련결과 history \n    '''\n    acc = history.history['acc']\n    val_acc = history.history['val_acc']\n    loss = history.history['loss']\n    val_loss = history.history['val_loss']\n    epochs = range(1, len(acc) + 1)\n\n    plt.plot(epochs, acc, 'bo', label='Training Acc')\n    plt.plot(epochs, val_acc, 'b', label='Validation Acc')\n    plt.title('Training and validation accuracy')\n    plt.legend()\n    plt.show()\n\n    plt.plot(epochs, loss, 'bo', label='Traing loss')\n    plt.plot(epochs, val_loss, 'b', label='Validation loss')\n    plt.title('Trainging and validation loss')\n    plt.legend()\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 예측 처리함수"},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_prediction(model, image_generator, batch_size=16, tta_size=1):\n    '''\n    모델 예측 tta 적용하여 실행\n    예측값을 합산하여 반환\n    \n    Keyword arguments:\n    model            -- 예측 대상 모델 \n    image_generator  -- 테스트 이미지 생성기\n    batch_size       -- Batch 크기 \n    tta_size         -- TTA 횟수 \n    '''\n    predictions = None\n    \n    for i in range(tta_size):\n        image_generator.reset()\n        prediction = model.predict_generator(\n            generator = image_generator,\n            steps = get_steps(len(df_test.index), batch_size),\n            verbose=1) \n        \n        if predictions is None:\n            predictions = prediction\n        else :\n            predictions += prediction\n    \n    return predictions\n\ndef get_total_prediction_scores(model, model_paths, image_generator, batch_size=16, tta_size=1):\n    '''\n    모델 예측 실행\n    \n    Keyword arguments:\n    model            -- 예측 대상 모델 \n    model_paths      -- weight 파일 경로 List\n    image_generator  -- 테스트 이미지 생성기\n    batch_size       -- Batch 크기 \n    tta_size         -- TTA 횟수 \n    '''\n    predictions = None\n    target_model = build_model(model)\n\n    for path in model_paths:\n        target_model.load_weights(path)\n        prediction = get_prediction(target_model, image_generator, batch_size, tta_size)\n\n        if predictions is None:\n            predictions = prediction\n        else :\n            predictions += prediction\n\n    predictions /= (len(model_paths) * tta_size)\n    \n    return predictions","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 전역 변수선언"},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA_PATH = '../input/2019-3rd-ml-month-with-kakr'\nTRAIN_IMG_PATH = os.path.join(DATA_PATH, 'train')\nTEST_IMG_PATH = os.path.join(DATA_PATH, 'test')\n\nTRAIN_CROPPED_PATH = '../cropped_train'\nTEST_CROPPED_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'))\n\ndf_train['class'] = df_train['class'].astype('str')\n\nIMAGE_SIZE = 299\nBATCH_SIZE = 16","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 이미지 잘라내기"},{"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)\n\nfor i, row in df_train.iterrows():\n    cropped = crop_boxing_img(row['img_file'], size=(IMAGE_SIZE, IMAGE_SIZE))\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'], size=(IMAGE_SIZE, IMAGE_SIZE))\n    cropped.save(os.path.join(TEST_CROPPED_PATH, row['img_file']))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 이미지 생성기 준비"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_datagen = ImageDataGenerator(\n    rescale=1./255,\n    rotation_range=20,\n    width_shift_range=0.5,\n    height_shift_range=0.5,\n    shear_range = 0.1,\n    horizontal_flip=True,\n    vertical_flip=False,\n    zoom_range=0.3,\n    #fill_mode='reflect'\n    )\n\ntest_datagen = ImageDataGenerator(rescale=1./255)\n\ntta_datagen = ImageDataGenerator(\n    rescale=1./255,\n    horizontal_flip=True,\n    vertical_flip=False\n    )","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 이미지 생성기(TRAIN, TEST, TTA)"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_generator = get_train_image_generator(df_train, train_datagen, IMAGE_SIZE, BATCH_SIZE, TRAIN_CROPPED_PATH)\ntest_generator = get_test_image_generator(df_test, test_datagen, IMAGE_SIZE, BATCH_SIZE * 4, TEST_CROPPED_PATH)\ntta_generator = get_test_image_generator(df_test, tta_datagen, IMAGE_SIZE, BATCH_SIZE * 4, TEST_CROPPED_PATH)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 예측실행 및 결과생성"},{"metadata":{"trusted":true},"cell_type":"code","source":"model_paths = []\nmodel_paths.append('../input/3rd-ml-month-xception/1_Xception.hdf5')\nmodel_paths.append('../input/3rd-ml-month-xception/2_Xception.hdf5')\nmodel_paths.append('../input/3rd-ml-month-xception/3_Xception.hdf5')\nmodel_paths.append('../input/3rd-ml-month-xception/4_Xception.hdf5')\nmodel_paths.append('../input/3rd-ml-month-xception/5_Xception.hdf5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions = get_total_prediction_scores(\n    model = Xception,\n    model_paths = model_paths,\n    image_generator = tta_generator,\n    batch_size = BATCH_SIZE * 4,\n    tta_size = 10\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model_paths = []\nmodel_paths.append('../input/3rd-ml-month-densenet201/1_DenseNet201.hdf5')\nmodel_paths.append('../input/3rd-ml-month-densenet201/2_DenseNet201.hdf5')\nmodel_paths.append('../input/3rd-ml-month-densenet201/3_DenseNet201.hdf5')\nmodel_paths.append('../input/3rd-ml-month-densenet201/4_DenseNet201.hdf5')\nmodel_paths.append('../input/3rd-ml-month-densenet201/5_DenseNet201.hdf5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions += get_total_prediction_scores(\n    model = DenseNet201,\n    model_paths = model_paths,\n    image_generator = tta_generator,\n    batch_size = BATCH_SIZE * 4,\n    tta_size = 10\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predicted_class_indices=np.argmax(predictions, 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":{},"cell_type":"markdown","source":"# 결과파일을 로컬로 다운로드하기"},{"metadata":{},"cell_type":"markdown","source":"<a href='./submission.csv'>Download submission csv File</a>"},{"metadata":{},"cell_type":"markdown","source":"# 모델 파일을 로컬로 다운로드하기"},{"metadata":{},"cell_type":"markdown","source":"<a href='./1_DenseNet201.hdf5'>Download Model File</a>"},{"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}