{"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        assert shape[2] == 3\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')\n        image_yellow_ch = skimage.io.imread(path+'_yellow.png')\n        image_green_ch = skimage.io.imread(path+'_green.png')\n        image_blue_ch = skimage.io.imread(path+'_blue.png')\n\n        image_red_ch += (image_yellow_ch/2).astype(np.uint8) \n        image_green_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), -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":"# create train datagen\ntrain_datagen = data_generator.create_train(\n    train_dataset_info, 5, (299,299,3), 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":"64bba0326be38da7add3594002563bea1c9703db"},"cell_type":"code","source":"# -*- coding: utf-8 -*-\n\"\"\"SE-ResNet-50 model for Keras.\nBased on https://github.com/fchollet/keras/blob/master/keras/applications/resnet50.py\n\"\"\"\nfrom __future__ import print_function\nfrom __future__ import absolute_import\n\nimport warnings\n\nfrom keras.layers import Input\nfrom keras import layers\nfrom keras.layers import Dense\nfrom keras.layers import Activation\nfrom keras.layers import Flatten\nfrom keras.layers import Conv2D\nfrom keras.layers import MaxPooling2D\nfrom keras.layers import AveragePooling2D\nfrom keras.layers import GlobalAveragePooling2D\nfrom keras.layers import GlobalMaxPooling2D\nfrom keras.layers import BatchNormalization\nfrom keras.layers import Reshape\nfrom keras.layers import Multiply\nfrom keras.models import Model\nfrom keras import backend as K\nfrom keras.engine.topology import get_source_inputs\nfrom keras.utils import layer_utils\nfrom keras.utils.data_utils import get_file\n#from keras.applications.imagenet_utils import _obtain_input_shape\nfrom keras_applications.imagenet_utils import _obtain_input_shape\nimport keras\nfrom keras.optimizers import Adam \n\n  \ndef identity_block(input_tensor, kernel_size, filters, stage, block):\n    filters1, filters2, filters3 = filters\n    if K.image_data_format() == 'channels_last':\n        bn_axis = 3\n    else:\n        bn_axis = 1\n    bn_eps = 0.0001\n        \n    block_name = str(stage) + \"_\" + str(block)\n    conv_name_base = \"conv\" + block_name\n    relu_name_base = \"relu\" + block_name\n\n    x = Conv2D(filters1, (1, 1), use_bias=False, name=conv_name_base + '_x1')(input_tensor)\n    x = BatchNormalization(axis=bn_axis, epsilon=bn_eps, name=conv_name_base + '_x1_bn')(x)\n    x = Activation('relu', name=relu_name_base + '_x1')(x)\n\n    x = Conv2D(filters2, kernel_size, padding='same', use_bias=False, name=conv_name_base + '_x2')(x)\n    x = BatchNormalization(axis=bn_axis, epsilon=bn_eps, name=conv_name_base + '_x2_bn')(x)\n    x = Activation('relu', name=relu_name_base + '_x2')(x)\n\n    x = Conv2D(filters3, (1, 1), use_bias=False, name=conv_name_base + '_x3')(x)\n    x = BatchNormalization(axis=bn_axis, epsilon=bn_eps, name=conv_name_base + '_x3_bn')(x)\n\n    se = GlobalAveragePooling2D(name='pool' + block_name + '_gap')(x)\n    se = Dense(filters3 // 16, activation='relu', name = 'fc' + block_name + '_sqz')(se)\n    se = Dense(filters3, activation='sigmoid', name = 'fc' + block_name + '_exc')(se)\n    se = Reshape([1, 1, filters3])(se)\n    x = Multiply(name='scale' + block_name)([x, se])\n\n    x = layers.add([x, input_tensor], name='block_' + block_name)\n    x = Activation('relu', name=relu_name_base)(x)\n    return x\n\n\ndef conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2)):\n    filters1, filters2, filters3 = filters\n    if K.image_data_format() == 'channels_last':\n        bn_axis = 3\n    else:\n        bn_axis = 1\n    bn_eps = 0.0001\n    \n    block_name = str(stage) + \"_\" + str(block)\n    conv_name_base = \"conv\" + block_name\n    relu_name_base = \"relu\" + block_name\n\n    x = Conv2D(filters1, (1, 1), use_bias=False, name=conv_name_base + '_x1')(input_tensor)\n    x = BatchNormalization(axis=bn_axis, epsilon=bn_eps, name=conv_name_base + '_x1_bn')(x)\n    x = Activation('relu', name=relu_name_base + '_x1')(x)\n\n    x = Conv2D(filters2, kernel_size, strides=strides, padding='same', use_bias=False, name=conv_name_base + '_x2')(x)\n    x = BatchNormalization(axis=bn_axis, epsilon=bn_eps, name=conv_name_base + '_x2_bn')(x)\n    x = Activation('relu', name=relu_name_base + '_x2')(x)\n\n    x = Conv2D(filters3, (1, 1), use_bias=False, name=conv_name_base + '_x3')(x)\n    x = BatchNormalization(axis=bn_axis, epsilon=bn_eps, name=conv_name_base + '_x3_bn')(x)\n    \n    se = GlobalAveragePooling2D(name='pool' + block_name + '_gap')(x)\n    se = Dense(filters3 // 16, activation='relu', name = 'fc' + block_name + '_sqz')(se)\n    se = Dense(filters3, activation='sigmoid', name = 'fc' + block_name + '_exc')(se)\n    se = Reshape([1, 1, filters3])(se)\n    x = Multiply(name='scale' + block_name)([x, se])\n    \n    shortcut = Conv2D(filters3, (1, 1), strides=strides, use_bias=False, name=conv_name_base + '_prj')(input_tensor)\n    shortcut = BatchNormalization(axis=bn_axis, epsilon=bn_eps, name=conv_name_base + '_prj_bn')(shortcut)\n\n    x = layers.add([x, shortcut], name='block_' + block_name)\n    x = Activation('relu', name=relu_name_base)(x)\n    return x\n\n\ndef SEResNet50(include_top=True, weights='imagenet',\n               input_tensor=None, input_shape=None,\n               pooling=None,\n               classes=1000):\n\n    # Determine proper input shape\n    input_shape = _obtain_input_shape(input_shape,\n                                      default_size=299,\n                                      min_size=32,\n                                      data_format=K.image_data_format(),\n                                      require_flatten=include_top,\n                                      weights=weights)\n\n    if input_tensor is None:\n        img_input = Input(shape=input_shape)\n    else:\n        if not K.is_keras_tensor(input_tensor):\n            img_input = Input(tensor=input_tensor, shape=input_shape)\n        else:\n            img_input = input_tensor\n    if K.image_data_format() == 'channels_last':\n        bn_axis = 3\n    else:\n        bn_axis = 1\n    bn_eps = 0.0001\n\n    x = Conv2D(64, (7, 7), strides=(2, 2), padding='same', use_bias=False, name='conv1')(img_input)\n    x = BatchNormalization(axis=bn_axis, epsilon=bn_eps, name='conv1_bn')(x)\n    x = Activation('relu', name='relu1')(x)\n    x = MaxPooling2D((3, 3), strides=(2, 2), name='pool1')(x)\n\n    x = conv_block(x, 3, [64, 64, 256], stage=2, block=1, strides=(1, 1))\n    x = identity_block(x, 3, [64, 64, 256], stage=2, block=2)\n    x = identity_block(x, 3, [64, 64, 256], stage=2, block=3)\n\n    x = conv_block(x, 3, [128, 128, 512], stage=3, block=1)\n    x = identity_block(x, 3, [128, 128, 512], stage=3, block=2)\n    x = identity_block(x, 3, [128, 128, 512], stage=3, block=3)\n    x = identity_block(x, 3, [128, 128, 512], stage=3, block=4)\n\n    x = conv_block(x, 3, [256, 256, 1024], stage=4, block=1)\n    x = identity_block(x, 3, [256, 256, 1024], stage=4, block=2)\n    x = identity_block(x, 3, [256, 256, 1024], stage=4, block=3)\n    x = identity_block(x, 3, [256, 256, 1024], stage=4, block=4)\n    x = identity_block(x, 3, [256, 256, 1024], stage=4, block=5)\n    x = identity_block(x, 3, [256, 256, 1024], stage=4, block=6)\n\n    x = conv_block(x, 3, [512, 512, 2048], stage=5, block=1)\n    x = identity_block(x, 3, [512, 512, 2048], stage=5, block=2)\n    x = identity_block(x, 3, [512, 512, 2048], stage=5, block=3)\n\n    x = Flatten()(x)\n    x = Dense(classes, activation='softmax', name='fc6')(x)\n\n    # Ensure that the model takes into account\n    # any potential predecessors of `input_tensor`.\n    if input_tensor is not None:\n        inputs = get_source_inputs(input_tensor)\n    else:\n        inputs = img_input\n    # Create model.\n    model = Model(inputs, x, name='se-resnet50')\n    return model  \nkeras.backend.clear_session()\nmodel = SEResNet50(weights=None, input_shape=(299, 299, 3), classes=28)\nmodel.summary()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"11cbaca708e550260a900fcbcd3f3136a2e0e1bb"},"cell_type":"code","source":"from IPython.display import SVG\nfrom keras.utils.vis_utils import model_to_dot\n\nSVG(model_to_dot(model).create(prog='dot', format='svg'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b58e23d8f31f6117f5e7d57ef236336ee252377b"},"cell_type":"code","source":"def f1(y_true, y_pred):\n    tp = K.sum(K.cast(y_true*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 K.mean(f1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e7296424196067a0e0a8f2383c99bd2bb76281c4"},"cell_type":"code","source":"from keras.optimizers import SGD\n\nimport tensorflow as tf\nmodel.compile(\n    loss='binary_crossentropy',  \n    optimizer=SGD(1e-4),\n    metrics=['acc', f1])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"2fbffd71262d7d7e591ad5955feb6b0c5ee61737"},"cell_type":"markdown","source":"### Train model"},{"metadata":{"trusted":true,"_uuid":"0343374956494b98425448b7aa9092a037aee401"},"cell_type":"code","source":"# define the checkpoint\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.models import Sequential, load_model\nfrom keras.layers import Input\nfrom keras.layers import BatchNormalization\nfrom keras.models import Model\nfrom keras.applications import InceptionResNetV2\nfrom keras.callbacks import ModelCheckpoint\nfrom keras.callbacks import LambdaCallback\nfrom keras.callbacks import Callback\nfrom keras import metrics\nfrom keras.optimizers import Adam \nfrom keras import backend as K\nimport tensorflow as tf\nimport keras\n\nepochs = 100; batch_size = 16\ncheckpointer = ModelCheckpoint(\n    '../working/se-resnet50.h5', \n    verbose=2, \n    save_best_only=True)\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\n# create train and valid datagens\ntrain_generator = data_generator.create_train(\n    train_dataset_info[train_indexes], batch_size, (299,299,3), augument=True)\nvalidation_generator = data_generator.create_train(\n    train_dataset_info[valid_indexes], 100, (299,299,3), augument=False)\n\n# train model\nhistory = model.fit_generator(\n    train_generator,\n    steps_per_epoch=100,\n    validation_data=next(validation_generator),\n    epochs=epochs, \n    verbose=1,\n    callbacks=[checkpointer])","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')","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, (299,299,3))\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":{"trusted":true,"_uuid":"21012bfa39d48eb7e1468827c2fb6e5cd70fd0dc"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1e4cb871a61616326f2cbadb30cb64e42d9018b4"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6b4a2ff9349e3edfab5946dcc8f4f02cd34cba86"},"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.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}