{"cells":[{"metadata":{},"cell_type":"markdown","source":"# <center>3rd ML Month - Car Model Classification </center>\n![Main Image](https://t1.daumcdn.net/cfile/tistory/2738983451EB766507)"},{"metadata":{},"cell_type":"markdown","source":"### 다음 및의 커널들을 참조하여 작성하였습니다. 커널 공유해주셔서 정말 감사합니다!\n - 김태진님의 \"[3rd ML Month] Car Model Classification Baseline\"\n - 허태명님의 \"[3rd ML Month] Car Image Cropping - updated 7.10\"\n - Jang님의 \"[3rd ML Month] Xception, StratifiedKFold, Ensemble\""},{"metadata":{},"cell_type":"markdown","source":" - 밑의 코드는 Inference 커널 코드입니다.\n - 앙상블에 사용한 Weight를 만든 커널은 Version2를 보시면 알 수 있습니다."},{"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/2019-3rd-ml-month-with-kakr/'\n#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":"# ResNet50 -> 224\n# Xception,InceptionResNetV2 -> 299\n# NASNetLarge -> 331\n\nIMAGE_SIZE = 299\nBATCH_SIZE = 32\nEPOCHS = 50\nk_folds=5","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Image Cropped"},{"metadata":{"trusted":true},"cell_type":"code","source":"def 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":{},"cell_type":"markdown","source":"## Callback 함수 정의"},{"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":{},"cell_type":"markdown","source":"## F1score(평가 지표) 정의"},{"metadata":{"trusted":true},"cell_type":"code","source":"def recall(y_target, y_pred):\n    y_target_yn = K.round(K.clip(y_target, 0, 1))\n    y_pred_yn = K.round(K.clip(y_pred, 0, 1))\n    count_true_positive = K.sum(y_target_yn * y_pred_yn) \n    count_true_positive_false_negative = K.sum(y_target_yn)\n    recall = count_true_positive / (count_true_positive_false_negative + K.epsilon())\n\n    return recall\n\ndef precision(y_target, y_pred):\n    y_pred_yn = K.round(K.clip(y_pred, 0, 1)) \n    y_target_yn = K.round(K.clip(y_target, 0, 1)) \n    count_true_positive = K.sum(y_target_yn * y_pred_yn) \n    count_true_positive_false_positive = K.sum(y_pred_yn)\n    precision = count_true_positive / (count_true_positive_false_positive + K.epsilon())\n\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    _f1score = ( 2 * _recall * _precision) / (_recall + _precision+ K.epsilon())\n    \n    return _f1score","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model 정의"},{"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":{},"cell_type":"markdown","source":"## Generator"},{"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\ntrain_datagen = ImageDataGenerator(\n    rescale=1./255,\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    )\ntest_datagen = ImageDataGenerator(\n    rescale=1./255\n    )","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## K-Fold Cross Validation(With StratifiedKFold)"},{"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\n#model_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":{},"cell_type":"markdown","source":"## Ensemble Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"model_xception_names = ['../input/3rd-ml-month-xception-weight/1_xception.hdf5','../input/3rd-ml-month-xception-weight/2_xception.hdf5','../input/3rd-ml-month-xception-weight/3_xception.hdf5','../input/3rd-ml-month-xception-weight/4_xception.hdf5','../input/3rd-ml-month-xception-weight/5_xception.hdf5']\n\nxception_prediction = []\nfor i, name in enumerate(model_xception_names):\n    model_xception = get_model(Xception, IMAGE_SIZE)\n    model_xception.load_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":{},"cell_type":"markdown","source":"## 결과 저장"},{"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":{"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}