{"cells": [{"cell_type": "markdown", "metadata": {"_cell_guid": "01e3b8c5-7e10-450b-a663-08c829eb793e", "_uuid": "9ae1e73615b56d28a06645128661dfa9e817f9c7"}, "source": ["This code is inspirated by https://www.kaggle.com/keegil/keras-u-net-starter-lb-0-277"]}, {"cell_type": "code", "metadata": {"_cell_guid": "a3a5212a-bc80-485a-9109-e5be9b05f546", "collapsed": true, "_uuid": "bcb8165daaa0a560b300be8bcf4e4f9b31bfa472"}, "outputs": [], "execution_count": null, "source": ["import cv2\n", "import os\n", "import numpy as np\n", "\n", "\n", "def make_df(train_path, test_path, img_size):\n", "    train_ids = next(os.walk(train_path))[1]\n", "    test_ids = next(os.walk(test_path))[1]\n", "    X_train = np.zeros((len(train_ids), img_size, img_size, 3), dtype=np.uint8)\n", "    Y_train = np.zeros((len(train_ids), img_size, img_size, 1), dtype=np.bool)\n", "    for i, id_ in enumerate(train_ids):\n", "        path = train_path + id_\n", "        img = cv2.imread(path + '/images/' + id_ + '.png')\n", "        img = cv2.resize(img, (img_size, img_size))\n", "        X_train[i] = img\n", "        mask = np.zeros((img_size, img_size, 1), dtype=np.bool)\n", "        for mask_file in next(os.walk(path + '/masks/'))[2]:\n", "            mask_ = cv2.imread(path + '/masks/' + mask_file, 0)\n", "            mask_ = cv2.resize(mask_, (img_size, img_size))\n", "            mask_ = mask_[:, :, np.newaxis]\n", "            mask = np.maximum(mask, mask_)\n", "        Y_train[i] = mask\n", "    X_test = np.zeros((len(test_ids), img_size, img_size, 3), dtype=np.uint8)\n", "    sizes_test = []\n", "    for i, id_ in enumerate(test_ids):\n", "        path = test_path + id_\n", "        img = cv2.imread(path + '/images/' + id_ + '.png')\n", "        sizes_test.append([img.shape[0], img.shape[1]])\n", "        img = cv2.resize(img, (img_size, img_size))\n", "        X_test[i] = img\n", "\n", "    return X_train, Y_train, X_test, sizes_test"]}, {"cell_type": "markdown", "metadata": {"_cell_guid": "27f0fe04-cd5b-4042-a2e0-eb9e301933f0", "_uuid": "bf6df4dfbbaddbd3d40293f3b05bf68ee51d4475"}, "source": ["Define Unet model."]}, {"cell_type": "code", "metadata": {"_cell_guid": "1960ba32-cdec-4aec-b39b-86e832940976", "collapsed": true, "_uuid": "8318ccbe407bf32eeba9723a597556cc634465ff"}, "outputs": [], "execution_count": null, "source": ["from keras.layers.convolutional import Conv2D, Conv2DTranspose\n", "from keras.layers.pooling import MaxPooling2D\n", "from keras.layers.merge import concatenate\n", "from keras.models import Model\n", "from keras.layers import Input\n", "from keras.layers.core import Dropout, Lambda\n", "\n", "\n", "def Unet(img_size):\n", "    inputs = Input((img_size, img_size, 3))\n", "    s = Lambda(lambda x: x / 255)(inputs)\n", "\n", "    c1 = Conv2D(16, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(s)\n", "    c1 = Dropout(0.1)(c1)\n", "    c1 = Conv2D(16, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(c1)\n", "    p1 = MaxPooling2D((2, 2))(c1)\n", "\n", "    c2 = Conv2D(32, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(p1)\n", "    c2 = Dropout(0.1)(c2)\n", "    c2 = Conv2D(32, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(c2)\n", "    p2 = MaxPooling2D((2, 2))(c2)\n", "\n", "    c3 = Conv2D(64, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(p2)\n", "    c3 = Dropout(0.2)(c3)\n", "    c3 = Conv2D(64, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(c3)\n", "    p3 = MaxPooling2D((2, 2))(c3)\n", "\n", "    c4 = Conv2D(128, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(p3)\n", "    c4 = Dropout(0.2)(c4)\n", "    c4 = Conv2D(128, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(c4)\n", "    p4 = MaxPooling2D(pool_size=(2, 2))(c4)\n", "\n", "    c5 = Conv2D(256, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(p4)\n", "    c5 = Dropout(0.3)(c5)\n", "    c5 = Conv2D(256, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(c5)\n", "\n", "    u6 = Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(c5)\n", "    u6 = concatenate([u6, c4])\n", "    c6 = Conv2D(128, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(u6)\n", "    c6 = Dropout(0.2)(c6)\n", "    c6 = Conv2D(128, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(c6)\n", "\n", "    u7 = Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(c6)\n", "    u7 = concatenate([u7, c3])\n", "    c7 = Conv2D(64, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(u7)\n", "    c7 = Dropout(0.2)(c7)\n", "    c7 = Conv2D(64, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(c7)\n", "\n", "    u8 = Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same')(c7)\n", "    u8 = concatenate([u8, c2])\n", "    c8 = Conv2D(32, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(u8)\n", "    c8 = Dropout(0.1)(c8)\n", "    c8 = Conv2D(32, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(c8)\n", "\n", "    u9 = Conv2DTranspose(16, (2, 2), strides=(2, 2), padding='same')(c8)\n", "    u9 = concatenate([u9, c1], axis=3)\n", "    c9 = Conv2D(16, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(u9)\n", "    c9 = Dropout(0.1)(c9)\n", "    c9 = Conv2D(16, (3, 3), activation='elu', kernel_initializer='he_normal', padding='same')(c9)\n", "\n", "    outputs = Conv2D(1, (1, 1), activation='sigmoid')(c9)\n", "\n", "    model = Model(inputs=[inputs], outputs=[outputs])\n", "\n", "    return model"]}, {"cell_type": "markdown", "metadata": {"_cell_guid": "475c0fc2-ca32-4db9-9008-05f675696a0e", "_uuid": "bebc9fc8e555aaba633741c0452fcfa0925664b4"}, "source": ["Define generator. Using keras ImageDataGenerator.\n", "You can change the method of data augmentation by changing data_gen_args."]}, {"cell_type": "code", "metadata": {"_cell_guid": "b2a782ca-1656-4c4b-b320-4212989c530d", "collapsed": true, "_uuid": "487865a51b4d4c28bb69b88d4e5e20bc6b7bba80"}, "outputs": [], "execution_count": null, "source": ["from keras.preprocessing.image import ImageDataGenerator\n", "\n", "\n", "def generator(xtr, xval, ytr, yval, batch_size):\n", "    data_gen_args = dict(horizontal_flip=True,\n", "                         vertical_flip=True,\n", "                         rotation_range=90.,\n", "                         width_shift_range=0.1,\n", "                         height_shift_range=0.1,\n", "                         zoom_range=0.1)\n", "    image_datagen = ImageDataGenerator(**data_gen_args)\n", "    mask_datagen = ImageDataGenerator(**data_gen_args)\n", "    image_datagen.fit(xtr, seed=7)\n", "    mask_datagen.fit(ytr, seed=7)\n", "    image_generator = image_datagen.flow(xtr, batch_size=batch_size, seed=7)\n", "    mask_generator = mask_datagen.flow(ytr, batch_size=batch_size, seed=7)\n", "    train_generator = zip(image_generator, mask_generator)\n", "\n", "    val_gen_args = dict()\n", "    image_datagen_val = ImageDataGenerator(**val_gen_args)\n", "    mask_datagen_val = ImageDataGenerator(**val_gen_args)\n", "    image_datagen_val.fit(xval, seed=7)\n", "    mask_datagen_val.fit(yval, seed=7)\n", "    image_generator_val = image_datagen_val.flow(xval, batch_size=batch_size, seed=7)\n", "    mask_generator_val = mask_datagen_val.flow(yval, batch_size=batch_size, seed=7)\n", "    val_generator = zip(image_generator_val, mask_generator_val)\n", "\n", "    return train_generator, val_generator"]}, {"cell_type": "markdown", "metadata": {"_cell_guid": "c9d9d672-adfc-4e79-a3fa-26d206e5e6d2", "_uuid": "fa55995ed9b64862fd28a6454172ad7ed74bae49"}, "source": ["Define metrics and loss function."]}, {"cell_type": "code", "metadata": {"_cell_guid": "23672e7c-a61a-40cb-9221-5d52a3893cb1", "collapsed": true, "_uuid": "bfaf03f19a053db96548e4973a26060072c3ccce"}, "outputs": [], "execution_count": null, "source": ["import tensorflow as tf\n", "import numpy as np\n", "from keras import backend as K\n", "from keras.losses import binary_crossentropy\n", "\n", "\n", "def mean_iou(y_true, y_pred):\n", "    prec = []\n", "    for t in np.arange(0.5, 1.0, 0.05):\n", "        y_pred_ = tf.to_int32(y_pred > t)\n", "        score, up_opt = tf.metrics.mean_iou(y_true, y_pred_, 2)\n", "        K.get_session().run(tf.local_variables_initializer())\n", "        with tf.control_dependencies([up_opt]):\n", "            score = tf.identity(score)\n", "        prec.append(score)\n", "    return K.mean(K.stack(prec))\n", "\n", "def dice_coef(y_true, y_pred):\n", "    smooth = 1.\n", "    y_true_f = K.flatten(y_true)\n", "    y_pred_f = K.flatten(y_pred)\n", "    intersection = K.sum(y_true_f * y_pred_f)\n", "    return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)\n", "\n", "def bce_dice_loss(y_true, y_pred):\n", "    return 0.5 * binary_crossentropy(y_true, y_pred) - dice_coef(y_true, y_pred)"]}, {"cell_type": "code", "metadata": {"_cell_guid": "af47f36d-64d0-4f71-a012-8761055e0ea2", "collapsed": true, "_uuid": "fa38f24d8a66d3017332927be0f350a00b389558"}, "outputs": [], "execution_count": null, "source": ["from skimage.morphology import label\n", "\n", "def rle_encoding(x):\n", "    dots = np.where(x.T.flatten() == 1)[0]\n", "    run_lengths = []\n", "    prev = -2\n", "    for b in dots:\n", "        if (b>prev+1): run_lengths.extend((b + 1, 0))\n", "        run_lengths[-1] += 1\n", "        prev = b\n", "    return run_lengths\n", "\n", "def prob_to_rles(x, cutoff=0.5):\n", "    lab_img = label(x > cutoff)\n", "    for i in range(1, lab_img.max() + 1):\n", "        yield rle_encoding(lab_img == i)"]}, {"cell_type": "code", "metadata": {"_cell_guid": "9b52df95-5431-4765-a304-fb3192fb25ac", "collapsed": true, "_uuid": "1b752a957409a3242f07436af05572f8bfe5ad2d"}, "outputs": [], "execution_count": null, "source": ["import cv2\n", "import os\n", "import pandas as pd\n", "from sklearn.model_selection import train_test_split\n", "\n", "\n", "if __name__ == \"__main__\":\n", "    img_size = 256\n", "    batch_size = 32\n", "    train_path = '../input/stage1_train/'\n", "    test_path = '../input/stage1_test/'\n", "    \n", "    X_train, Y_train, X_test, sizes_test = make_df(train_path, test_path, img_size)\n", "    xtr, xval, ytr, yval = train_test_split(X_train, Y_train, test_size=0.1, random_state=7)\n", "    train_generator, val_generator = generator(xtr, xval, ytr, yval, batch_size)\n", "    \n", "    model = Unet(img_size)\n", "    model.compile(optimizer='adam', loss=bce_dice_loss, metrics=[mean_iou])\n", "    \n", "    model.fit_generator(train_generator, steps_per_epoch=len(xtr)/6, epochs=50,\n", "                        validation_data=val_generator, validation_steps=len(xval)/batch_size)\n", "    \n", "    preds_test = model.predict(X_test, verbose=1)\n", "\n", "    preds_test_upsampled = []\n", "    for i in range(len(preds_test)):\n", "        preds_test_upsampled.append(cv2.resize(preds_test[i], \n", "                                           (sizes_test[i][1], sizes_test[i][0])))\n", "        \n", "    test_ids = next(os.walk(test_path))[1]\n", "    new_test_ids = []\n", "    rles = []\n", "    for n, id_ in enumerate(test_ids):\n", "        rle = list(prob_to_rles(preds_test_upsampled[n]))\n", "        rles.extend(rle)\n", "        new_test_ids.extend([id_] * len(rle))\n", "    sub = pd.DataFrame()\n", "    sub['ImageId'] = new_test_ids\n", "    sub['EncodedPixels'] = pd.Series(rles).apply(lambda x: ' '.join(str(y) for y in x))\n", "    sub.to_csv('sub.csv', index=False)"]}, {"cell_type": "code", "metadata": {"_cell_guid": "eb2418cf-bfd1-4679-b133-a8bc0cb8b31e", "collapsed": true, "_uuid": "e9cb41031c9abf8bde6c4819c22cdc0ac10d323d"}, "outputs": [], "execution_count": null, "source": []}], "metadata": {"kernelspec": {"name": "python3", "display_name": "Python 3", "language": "python"}, "language_info": {"name": "python", "mimetype": "text/x-python", "codemirror_mode": {"name": "ipython", "version": 3}, "version": "3.6.4", "file_extension": ".py", "nbconvert_exporter": "python", "pygments_lexer": "ipython3"}}, "nbformat": 4, "nbformat_minor": 1}