{"metadata": {"kernelspec": {"language": "python", "display_name": "Python 3", "name": "python3"}, "language_info": {"mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "file_extension": ".py", "version": "3.6.1", "codemirror_mode": {"name": "ipython", "version": 3}}}, "nbformat": 4, "nbformat_minor": 1, "cells": [{"cell_type": "markdown", "metadata": {}, "source": ["It may be too late to get useful results from this kernel but I decided to make it public anyway. When I run it on my MacBook I get decent results but the validation accuracy improves vey slowly. Using all images from the train set produces Ok maks but nothing comparable to what one can do with U-Net."]}, {"cell_type": "code", "metadata": {"_uuid": "be2cb7f23a7a3a420b2d50169e6f30741fe8ccbd", "_cell_guid": "b9427e93-b792-4303-9546-2c48ab8d1ed4"}, "execution_count": null, "outputs": [], "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", "\n", "import numpy as np # linear algebra\n", "import 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", "\n", "from subprocess import check_output\n", "print(check_output([\"ls\", \"../input\"]).decode(\"utf8\"))\n", "\n", "# Any results you write to the current directory are saved as output.\n", "import gzip\n", "import os\n", "from os.path import basename\n", "import glob\n", "import cv2\n", "import random\n", "from PIL import Image\n", "#import scipy.ndimage\n", "from scipy import ndimage\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline\n", "\n", "from scipy.misc import imresize\n", "from skimage.transform import resize\n", "\n", "from sklearn.model_selection import train_test_split\n", "\n", "from keras import models\n", "\n", "from keras.models import Model\n", "from keras.layers.core import Activation, Reshape, Permute\n", "from keras.layers.convolutional import Convolution2D, MaxPooling2D, UpSampling2D\n", "from keras.layers.normalization import BatchNormalization\n", "from keras.layers import Input, merge, Conv2D, MaxPooling2D, UpSampling2D, Concatenate\n", "#from keras.layers import Dense, Conv2D, Input, MaxPool2D, UpSampling2D, Concatenate, Conv2DTranspose\n", "from keras.optimizers import Adam\n", "from keras.optimizers import SGD\n", "from keras.optimizers import RMSprop\n", "from keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping\n", "from keras.callbacks import ReduceLROnPlateau, TensorBoard, Callback\n", "from keras.preprocessing.image import array_to_img, img_to_array, load_img, ImageDataGenerator\n", "from keras.losses import binary_crossentropy\n", "\n", "from keras import backend as K\n", "\n", "K.set_image_dim_ordering('tf') # Theano dimension ordering in this code\n", "\n", "from keras import __version__ as keras_version\n", "import sys\n", "print(sys.version)\n", "print(sys.path)\n", "print('Keras version: {}'.format(keras_version))\n", "print('openCV version: ', cv2.__version__)\n"]}, {"cell_type": "code", "metadata": {"collapsed": true}, "execution_count": null, "outputs": [], "source": ["INPUT_PATH = '../input/'\n", "input_size = 256\n", "dims = [input_size, input_size]    #height X width\n", "img_rows = dims[0]\n", "img_cols = dims[1]\n", "n_labels = 2"]}, {"cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": ["train = sorted(glob.glob(INPUT_PATH + 'train/*.jpg'))\n", "masks = sorted(glob.glob(INPUT_PATH + 'train_masks/*.gif'))\n", "test  = sorted(glob.glob(INPUT_PATH + 'test/*.jpg'))\n", "print('Number of training images: ', len(train), ' Number of corresponding masks: ', len(masks), ' Number of test images: ', len(test))\n", "\n", "meta = pd.read_csv(INPUT_PATH + 'metadata.csv')\n", "mask_df = pd.read_csv(INPUT_PATH + 'train_masks.csv')\n", "ids_train = mask_df['img'].map(lambda s: s.split('_')[0]).unique()\n", "print('Length of ids_train ', len(ids_train))"]}, {"cell_type": "code", "metadata": {"collapsed": true}, "execution_count": null, "outputs": [], "source": ["smooth = 1.\n", "\n", "def dice_coef(y_true, y_pred):\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 dice_coef_np(y_true,y_pred):\n", "    y_true_f = y_true.flatten()\n", "    y_pred_f = y_pred.flatten()\n", "    intersection = np.sum(y_true_f * y_pred_f)\n", "    return (2. * intersection + smooth) / (np.sum(y_true_f) + np.sum(y_pred_f) + smooth)\n", "\n", "def dice_coef_loss(y_true, y_pred):\n", "    return -dice_coef(y_true, y_pred)\n", "\n", "def dice_loss(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", "\n", "def bce_dice_loss(y_true, y_pred):\n", "    return binary_crossentropy(y_true, y_pred) + (1 - dice_loss(y_true, y_pred))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The SegNet model and some of its utilities can be found here: https://github.com/imlab-uiip/keras-segnet"]}, {"cell_type": "code", "metadata": {"collapsed": true}, "execution_count": null, "outputs": [], "source": ["def label_map(labels):\n", "    label_map = np.zeros([img_rows, img_cols, n_labels])    \n", "    #print('label_map shape ', label_map.shape)\n", "    for r in range(img_rows):\n", "        for c in range(img_cols):\n", "            #label_map[r, c, labels[r][c]] = 1\n", "            label_map[r, c, labels[r, c]] = 1\n", "    return label_map\n"]}, {"cell_type": "code", "metadata": {"collapsed": true}, "execution_count": null, "outputs": [], "source": ["\n", "def build_model(img_w, img_h, filters):\n", "    n_labels = 2\n", "\n", "    kernel = 3\n", "\n", "    encoding_layers = [\n", "        Conv2D(64, (kernel, kernel), input_shape=(img_h, img_w, 3), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(64, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        MaxPooling2D(),\n", "\n", "        Convolution2D(128, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(128, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        MaxPooling2D(),\n", "\n", "        Convolution2D(256, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(256, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(256, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        MaxPooling2D(),\n", "\n", "        Convolution2D(512, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(512, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(512, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        MaxPooling2D(),\n", "\n", "        Convolution2D(512, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(512, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(512, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        MaxPooling2D(),\n", "    ]\n", "\n", "    autoencoder = models.Sequential()\n", "    autoencoder.encoding_layers = encoding_layers\n", "\n", "    for l in autoencoder.encoding_layers:\n", "        autoencoder.add(l)\n", "\n", "    decoding_layers = [\n", "        UpSampling2D(),\n", "        Convolution2D(512, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(512, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(512, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "\n", "        UpSampling2D(),\n", "        Convolution2D(512, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(512, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(256, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "\n", "        UpSampling2D(),\n", "        Convolution2D(256, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(256, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(128, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "\n", "        UpSampling2D(),\n", "        Convolution2D(128, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(64, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "\n", "        UpSampling2D(),\n", "        Convolution2D(64, (kernel, kernel), padding='same'),\n", "        BatchNormalization(),\n", "        Activation('relu'),\n", "        Convolution2D(n_labels, (1, 1), padding='valid', activation=\"sigmoid\"),\n", "        BatchNormalization(),\n", "    ]\n", "    autoencoder.decoding_layers = decoding_layers\n", "    for l in autoencoder.decoding_layers:\n", "        autoencoder.add(l)\n", "\n", "    autoencoder.add(Reshape((n_labels, img_h * img_w)))\n", "    autoencoder.add(Permute((2, 1)))\n", "    autoencoder.add(Activation('softmax'))\n", "\n", "    #with open('model_5l.json', 'w') as outfile:\n", "    #    outfile.write(json.dumps(json.loads(autoencoder.to_json()), indent=2))\n", "    \n", "    return autoencoder"]}, {"cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": ["# split the train set into train and validation sets:\n", "train_images, validation_images = train_test_split(train, train_size=0.8, test_size=0.2)\n", "print('Split into training set with ', len(train_images), ' images and validation set with  ', len(validation_images), ' images')"]}, {"cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": ["# batch generator for training\n", "def data_gen_small( images, batch_size):\n", "        print('entered data_gen_small batch size: ', batch_size, 'size of input: ', len(images))\n", "    \n", "        while True:\n", "            #\n", "            # use all data sequentially\n", "            #\n", "            for start in range(0, len(images), batch_size):\n", "                x_batch = []\n", "                y_batch = []\n", "                end = min(start + batch_size, len(images))\n", "                ix = images[start:end] \n", "                imgs = []\n", "                labels = []\n", "                for i in ix:\n", "                    img = cv2.imread(i)\n", "                    img = cv2.resize(img, (input_size, input_size))\n", "                    mask_filename = basename(i)\n", "                    no_extension = os.path.splitext(mask_filename)[0]\n", "                    correct_mask = INPUT_PATH + 'train_masks/' + no_extension + '_mask.gif' \n", "                    original_mask = Image.open(correct_mask).convert('L')\n", "                    resized_mask = imresize(original_mask, dims+[3])\n", "                    array_mask = resized_mask / 255\n", "                    gt = np.clip(array_mask, 0, 1)\n", "                    gt = np.array(gt, np.int)\n", "                    x_batch.append(img)\n", "                    y_batch.append(label_map(gt))\n", "                x_batch = np.array(x_batch, np.float32) / 255\n", "                y_batch = np.array(y_batch, np.float32) \n", "                y_batch = np.array(y_batch).reshape((batch_size, img_rows * img_cols, n_labels))\n", "                yield x_batch, y_batch\n", "\n", "            \n", "# create an instance of a training generator:\n", "train_gen = data_gen_small( train_images, 1) \n", "img, msk = next(train_gen) \n", "print('shape of image batch: ', img.shape, ' shape of mask batch: ', msk.shape)\n", "# create an instance of a validation generator:\n", "validation_gen = data_gen_small( validation_images, 2) \n", "imgv, mskv = next(validation_gen)\n", "print('shape of validation batch: ', imgv.shape, ' shape of validation mask batch: ', mskv.shape)\n"]}, {"cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": ["model = build_model(input_size, input_size, 10)\n", "\n", "optimizer = SGD(lr=0.001, momentum=0.9, decay=0.0005, nesterov=False)\n", "model.compile(loss=\"categorical_crossentropy\", optimizer=optimizer, metrics=['accuracy'])\n", "print( 'Compilation: OK')\n", "#model.summary()"]}, {"cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": ["# to read the complete train and validation sets with batches of size 5 one would use:\n", "# steps_per_epoch = 814\n", "# validation_steps = 204\n", "# I run for 50 epochs\n", "# here I am limited by kaggle's limit of 1200 sec of cpu.\n", "#\n", "model.fit_generator(train_gen, steps_per_epoch=14, epochs=7, validation_data=validation_gen, validation_steps=20)"]}, {"cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": ["predicted_mask = model.predict(img)\n", "print('shape of prediction: ', predicted_mask.shape)"]}, {"cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": ["predicted_mask = predicted_mask.reshape((1, input_size, input_size, 2))\n", "plt.imshow(predicted_mask[0][:, :, 0])\n", "plt.show()"]}, {"cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": ["labeled = np.argmax(predicted_mask[0], axis=-1)\n", "plt.imshow(labeled)"]}, {"cell_type": "code", "metadata": {}, "execution_count": null, "outputs": [], "source": ["plt.imshow(img[0])"]}, {"cell_type": "code", "metadata": {"collapsed": true}, "execution_count": null, "outputs": [], "source": []}]}