{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os, sys\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport skimage.io\nfrom skimage.transform import resize\nfrom imgaug import augmenters as iaa\nfrom tqdm import tqdm\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"72c425f3aaa2645215a3adc808fc188c5b59106d"},"cell_type":"markdown","source":"### Load dataset info"},{"metadata":{"trusted":true,"_uuid":"42315d01b95b8a901088befa4100b014a1416c7a"},"cell_type":"code","source":"path_to_train = '../input/train/'\ndata = pd.read_csv('../input/train.csv')\n\ntrain_dataset_info = []\nfor name, labels in zip(data['Id'], data['Target'].str.split(' ')):\n    train_dataset_info.append({\n        'path':os.path.join(path_to_train, name),\n        'labels':np.array([int(label) for label in labels])})\ntrain_dataset_info = np.array(train_dataset_info)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ae3dcb3e4a000051fc8947502a28d399d200a924"},"cell_type":"markdown","source":"### Create datagenerator"},{"metadata":{"trusted":true,"_uuid":"c21509d05e2882e6315fc7390d27658c0654fc15"},"cell_type":"code","source":"class data_generator:\n    \n    def create_train(dataset_info, batch_size, shape, augument=True):\n        while True:\n            random_indexes = np.random.choice(len(dataset_info), batch_size)\n            batch_images = np.empty((batch_size, shape[0], shape[1], shape[2]))\n            batch_labels = np.zeros((batch_size, 28))\n            for i, idx in enumerate(random_indexes):\n                image = data_generator.load_image(\n                    dataset_info[idx]['path'], shape)   \n                if augument:\n                    image = data_generator.augment(image)\n                batch_images[i] = image\n                batch_labels[i][dataset_info[idx]['labels']] = 1\n            yield batch_images, batch_labels\n            \n    \n    def load_image(path, shape):\n        image_red_ch = skimage.io.imread(path+'_red.png')/255.0\n        image_yellow_ch = skimage.io.imread(path+'_yellow.png')/255.0\n        image_green_ch = skimage.io.imread(path+'_green.png')/255.0\n        image_blue_ch = skimage.io.imread(path+'_blue.png')/255.0\n\n        image_red_ch += (image_yellow_ch/2).astype(np.uint8) \n        image_blue_ch += (image_yellow_ch/2).astype(np.uint8)\n\n        image = np.stack((\n            image_red_ch, \n            image_green_ch, \n            image_blue_ch\n        ), -1)\n        image = resize(image, (shape[0], shape[1]), mode='reflect')\n        return image\n                \n            \n    def augment(image):\n        augment_img = iaa.Sequential([\n            iaa.OneOf([\n                iaa.Affine(rotate=0),\n                iaa.Affine(rotate=90),\n                iaa.Affine(rotate=180),\n                iaa.Affine(rotate=270),\n                iaa.Fliplr(0.5),\n                iaa.Flipud(0.5),\n            ])], random_order=True)\n        \n        image_aug = augment_img.augment_image(image)\n        return image_aug","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"74687ae11e12c8d0559e5421a356a67e8ab01537"},"cell_type":"markdown","source":"\n### Show data"},{"metadata":{"trusted":true,"_uuid":"3f2ae48955c4b75b13dd9e9ad0d9e1c84214b019"},"cell_type":"code","source":"input_shape = (256,256,3)\n\n# create train datagen\ntrain_datagen = data_generator.create_train(\n    train_dataset_info, 5, input_shape, augument=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5f261d54682cbd326a01e09a0f92598228145d2d"},"cell_type":"code","source":"images, labels = next(train_datagen)\n\nfig, ax = plt.subplots(1,5,figsize=(25,5))\nfor i in range(5):\n    ax[i].imshow(images[i])\nprint('min: {0}, max: {1}'.format(images.min(), images.max()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ddbc11bf72ecab4028380d64a08660a70a2da028"},"cell_type":"markdown","source":"### Create model"},{"metadata":{"trusted":true,"_uuid":"7fdae03e83d304435aca2489edd837e77e9193c1"},"cell_type":"code","source":"from keras import backend as K\nfrom keras.engine.topology import Layer\n\ndef f1(y_true, y_pred):\n    '''\n    metric from here\n    https://stackoverflow.com/questions/43547402/how-to-calculate-f1-macro-in-keras\n    '''\n    def recall(y_true, y_pred):\n        \"\"\"Recall metric.\n\n        Only computes a batch-wise average of recall.\n\n        Computes the recall, a metric for multi-label classification of\n        how many relevant items are selected.\n        \"\"\"\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\n    def precision(y_true, y_pred):\n        \"\"\"Precision metric.\n\n        Only computes a batch-wise average of precision.\n\n        Computes the precision, a metric for multi-label classification of\n        how many selected items are relevant.\n        \"\"\"\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    \n#     y_true = Lambda(K.argmax, arguments={'axis':1})(y_true)\n#     y_true = Lambda(K.cast, arguments={'dtype':'float32'})(y_true)\n    \n#     y_pred = Lambda(K.argmax, arguments={'axis':1})(y_pred)\n#     y_pred = Lambda(K.cast, arguments={'dtype':'float32'})(y_pred)\n    \n    precision = precision(y_true, y_pred)\n    recall = recall(y_true, y_pred)\n    return 2*((precision*recall)/(precision+recall+K.epsilon()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"96acdd124d20976a2dd7782e2c8e2dcd20b02218"},"cell_type":"code","source":"def f1_loss(y_true, y_pred):\n    \n    #y_pred = K.cast(K.greater(K.clip(y_pred, 0, 1), THRESHOLD), K.floatx())\n    tp = K.sum(K.cast(y_true*y_pred, 'float'), axis=0)\n    tn = K.sum(K.cast((1-y_true)*(1-y_pred), 'float'), axis=0)\n    fp = K.sum(K.cast((1-y_true)*y_pred, 'float'), axis=0)\n    fn = K.sum(K.cast(y_true*(1-y_pred), 'float'), axis=0)\n\n    p = tp / (tp + fp + K.epsilon())\n    r = tp / (tp + fn + K.epsilon())\n\n    f1 = 2*p*r / (p+r+K.epsilon())\n    f1 = tf.where(tf.is_nan(f1), tf.zeros_like(f1), f1)\n    return 1-K.mean(f1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"64bba0326be38da7add3594002563bea1c9703db"},"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator\nfrom keras.models import Sequential, load_model, Model\nfrom keras.layers import Activation, Dropout, Flatten, Dense, Input, GlobalAveragePooling2D, Conv2D, BatchNormalization, Reshape, Lambda\nfrom keras.applications.mobilenet_v2 import MobileNetV2\nfrom keras.callbacks import ModelCheckpoint\nfrom keras import metrics\nfrom keras.optimizers import Adam \nfrom keras import backend as K\nimport keras\nimport tensorflow as tf\n\ndef reduce(x):\n    return K.argmax(x, axis=1)\n\ndef cast(x):\n    return K.cast(x, 'float32')\n\ndef create_model(input_shape, n_out):\n    inp = Input(input_shape)\n    pretrain_model = MobileNetV2(include_top=False, weights=None, input_tensor=inp)\n    #x = pretrain_model.get_layer(name=\"block_13_expand_relu\").output\n    x = pretrain_model.output\n    \n    x = GlobalAveragePooling2D()(x)\n    x = Dropout(0.5)(x)\n    x = Dense(n_out, activation=\"relu\")(x)\n    \n    for layer in pretrain_model.layers:\n        layer.trainable = True\n        \n    return Model(inp, x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e7296424196067a0e0a8f2383c99bd2bb76281c4","scrolled":true},"cell_type":"code","source":"keras.backend.clear_session()\n\nmodel = create_model(input_shape=input_shape, n_out=28)\nmodel.compile(loss='binary_crossentropy', optimizer=Adam(), metrics=['acc', f1])\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2fbffd71262d7d7e591ad5955feb6b0c5ee61737"},"cell_type":"markdown","source":"### Train model"},{"metadata":{"trusted":true,"_uuid":"0343374956494b98425448b7aa9092a037aee401","scrolled":true},"cell_type":"code","source":"from keras.callbacks import EarlyStopping\nfrom keras.callbacks import ReduceLROnPlateau\n\nepochs = 5; batch_size = 64\ncheckpointer = ModelCheckpoint('../working/InceptionResNetV2.model', verbose=2, save_best_only=True)\nearly_stopping = EarlyStopping(monitor='val_loss', patience=2)\nreduce_lr = ReduceLROnPlateau(monitor='val_loss', patience=1, factor=0.1)\n\n# split and suffle data \nnp.random.seed(2018)\nindexes = np.arange(train_dataset_info.shape[0])\nnp.random.shuffle(indexes)\ntrain_indexes = indexes[:27500]\nvalid_indexes = indexes[27500:]\n\ntrain_steps = len(train_indexes)//batch_size\nvalid_steps = len(valid_indexes)//batch_size\n\n# create train and valid datagens\ntrain_generator = data_generator.create_train(train_dataset_info[train_indexes], batch_size, input_shape, augument=True)\nvalidation_generator = data_generator.create_train(train_dataset_info[valid_indexes], 100, input_shape, augument=False)\n\n# train model\nhistory = model.fit_generator(\n    train_generator,\n    steps_per_epoch=train_steps,\n    validation_data=next(validation_generator),\n    validation_steps=valid_steps, \n    epochs=epochs, \n    verbose=1,\n    callbacks=[checkpointer, reduce_lr])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"884be9cb5e6c81d0ba382bc436810831b37e3e3f"},"cell_type":"code","source":"fig, ax = plt.subplots(1, 2, figsize=(15,5))\nax[0].set_title('loss')\nax[0].plot(history.epoch, history.history[\"loss\"], label=\"Train loss\")\nax[0].plot(history.epoch, history.history[\"val_loss\"], label=\"Validation loss\")\nax[1].set_title('acc')\nax[1].plot(history.epoch, history.history[\"acc\"], label=\"Train acc\")\nax[1].plot(history.epoch, history.history[\"val_acc\"], label=\"Validation acc\")\nax[0].legend()\nax[1].legend()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2a52b306cd27fc030cfd3f7583009945de7828ac"},"cell_type":"markdown","source":"### Create submit"},{"metadata":{"trusted":true,"_uuid":"9d9ee4a8c2b1fc75b9f8d58855e33b115e92134d"},"cell_type":"code","source":"submit = pd.read_csv('../input/sample_submission.csv')\nmodel = load_model(\"../working/InceptionResNetV2.model\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"782cdb0d614add0f41c11ea180bd45e5600d60fb"},"cell_type":"code","source":"%%time\npredicted = []\nfor name in tqdm(submit['Id']):\n    path = os.path.join('../input/test/', name)\n    image = data_generator.load_image(path, input_shape)\n    score_predict = model.predict(image[np.newaxis])[0]\n    label_predict = np.arange(28)[score_predict>=0.5]\n    str_predict_label = ' '.join(str(l) for l in label_predict)\n    predicted.append(str_predict_label)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"07043ed35ad009ce6edc017e4aa88ac82571a750"},"cell_type":"code","source":"submit['Predicted'] = predicted\nsubmit.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}