{"cells":[{"metadata":{"_uuid":"a70dc481a90df220ae74ac6b745cceee81f69abc"},"cell_type":"markdown","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."},{"metadata":{"_uuid":"be2cb7f23a7a3a420b2d50169e6f30741fe8ccbd","_cell_guid":"b9427e93-b792-4303-9546-2c48ab8d1ed4","trusted":true},"cell_type":"code","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\nimport numpy as np # linear algebra\nimport 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\nfrom subprocess import check_output\nprint(check_output([\"ls\", \"../input\"]).decode(\"utf8\"))\n\n# Any results you write to the current directory are saved as output.\nimport gzip\nimport os\nfrom os.path import basename\nimport glob\nimport cv2\nimport random\nfrom PIL import Image\n#import scipy.ndimage\nfrom scipy import ndimage\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nfrom scipy.misc import imresize\nfrom skimage.transform import resize\n\nfrom sklearn.model_selection import train_test_split\n\nfrom keras import models\n\nfrom keras.models import Model\nfrom keras.layers.core import Activation, Reshape, Permute\nfrom keras.layers.convolutional import Convolution2D, MaxPooling2D, UpSampling2D\nfrom keras.layers.normalization import BatchNormalization\nfrom keras.layers import Input, merge, Conv2D, MaxPooling2D, UpSampling2D, Concatenate\n#from keras.layers import Dense, Conv2D, Input, MaxPool2D, UpSampling2D, Concatenate, Conv2DTranspose\nfrom keras.optimizers import Adam\nfrom keras.optimizers import SGD\nfrom keras.optimizers import RMSprop\nfrom keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping\nfrom keras.callbacks import ReduceLROnPlateau, TensorBoard, Callback\nfrom keras.preprocessing.image import array_to_img, img_to_array, load_img, ImageDataGenerator\nfrom keras.losses import binary_crossentropy\n\nfrom keras import backend as K\n\nK.set_image_dim_ordering('tf') # Theano dimension ordering in this code\n\nfrom keras import __version__ as keras_version\nimport sys\nprint(sys.version)\nprint(sys.path)\nprint('Keras version: {}'.format(keras_version))\nprint('openCV version: ', cv2.__version__)\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"134b9bbe9002a8d3ab7ab994f05dd384fa1edafc","trusted":true,"collapsed":true},"cell_type":"code","source":"INPUT_PATH = '../input/'\ninput_size = 256\ndims = [input_size, input_size]    #height X width\nimg_rows = dims[0]\nimg_cols = dims[1]\nn_labels = 2","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a26ad0babcbf17e45061a1cc19741a0f2640c64e","trusted":true},"cell_type":"code","source":"train = sorted(glob.glob(INPUT_PATH + 'train/*.jpg'))\nmasks = sorted(glob.glob(INPUT_PATH + 'train_masks/*.gif'))\ntest  = sorted(glob.glob(INPUT_PATH + 'test/*.jpg'))\nprint('Number of training images: ', len(train), ' Number of corresponding masks: ', len(masks), ' Number of test images: ', len(test))\n\nmeta = pd.read_csv(INPUT_PATH + 'metadata.csv')\nmask_df = pd.read_csv(INPUT_PATH + 'train_masks.csv')\nids_train = mask_df['img'].map(lambda s: s.split('_')[0]).unique()\nprint('Length of ids_train ', len(ids_train))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9e56a929d258370b12414bc3e1a9bbd9d1e61f9f","trusted":true,"collapsed":true},"cell_type":"code","source":"smooth = 1.\n\ndef 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\ndef 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\ndef dice_coef_loss(y_true, y_pred):\n    return -dice_coef(y_true, y_pred)\n\ndef 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\ndef bce_dice_loss(y_true, y_pred):\n    return binary_crossentropy(y_true, y_pred) + (1 - dice_loss(y_true, y_pred))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4fe2a2f3c92224f7498a02ba7e763dcbc13a55d7"},"cell_type":"markdown","source":"The SegNet model and some of its utilities can be found here: https://github.com/imlab-uiip/keras-segnet"},{"metadata":{"_uuid":"c8a9a9402c96c926829f846179409e0c88e8d0b5","trusted":true,"collapsed":true},"cell_type":"code","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","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"39ae0d8f51664c52728f52bd4f85403baf4c9d41","trusted":true,"collapsed":true},"cell_type":"code","source":"\ndef 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","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"544619a759a92728102af8899422ab004445e285","trusted":true},"cell_type":"code","source":"# split the train set into train and validation sets:\ntrain_images, validation_images = train_test_split(train, train_size=0.8, test_size=0.2)\nprint('Split into training set with ', len(train_images), ' images and validation set with  ', len(validation_images), ' images')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fe408323facc179d404efa404505c2caf74bded6"},"cell_type":"code","source":"len(train_images)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"4828309630b1b388e45d399bee99701a181b0b1a","trusted":true},"cell_type":"code","source":"# batch generator for training\ndef 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:\nbatch_size=16\ntrain_gen = data_gen_small( train_images, 1) \nimg, msk = next(train_gen) \nprint('shape of image batch: ', img.shape, ' shape of mask batch: ', msk.shape)\n# create an instance of a validation generator:\nvalidation_gen = data_gen_small( validation_images, 1) \nimgv, mskv = next(validation_gen)\nprint('shape of validation batch: ', imgv.shape, ' shape of validation mask batch: ', mskv.shape)\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c701d468430604d78d6c96882e70bbed3ea87e09","trusted":true},"cell_type":"code","source":"model = build_model(input_size, input_size, 10)\n\n#optimizer = SGD(lr=0.001, momentum=0.9, decay=0.0005, nesterov=False)\noptimizer=Adam(0.0005)\nmodel.compile(loss=bce_dice_loss, optimizer=optimizer, metrics=['accuracy',dice_coef,'binary_crossentropy'])\nprint( 'Compilation: OK')\n#model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"19acafd211e6e15cca91fe626efd82a99673488c"},"cell_type":"code","source":"callbacks = [EarlyStopping(monitor='val_loss',\n                           patience=20,\n                           verbose=2,\n                           min_delta=1e-4),\n             ReduceLROnPlateau(monitor='val_loss',\n                               factor=np.sqrt(0.1),\n                               patience=10,\n                               cooldown=2,\n                               verbose=1,\n                               epsilon=1e-4),\n             ModelCheckpoint(monitor='val_loss',\n                             filepath='./segnet_{epoch:02d}-{val_loss:.5f}-{val_acc:.5f}.hdf5',\n                             save_best_only=True,\n                             save_weights_only=True,\n                             period = 1),\n             TensorBoard(log_dir=\"logs/\")]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"228a0a118bad799e27367aa6924f67679be2583a"},"cell_type":"code","source":"a=train_gen","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"25268f60f43a524350217c45d25b262574667ba5"},"cell_type":"code","source":"for i in a:\n    print (i[0].shape,i[1].shape)\n    break","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9f4d1bad630a5b974cf7681cab4f284affb5935f","trusted":true},"cell_type":"code","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#\nmodel.fit_generator(train_gen,steps_per_epoch=np.ceil(float(len(train_images)) / float(batch_size)),callbacks=callbacks, epochs=100, validation_data=validation_gen,validation_steps=np.ceil(float(len(validation_images)) / float(batch_size)),verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d95b85531228f136f033331099255b7af6a95f62","trusted":true,"collapsed":true},"cell_type":"code","source":"predicted_mask = model.predict(img)\nprint('shape of prediction: ', predicted_mask.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"daa484a4daa1b6418fffdb52b598fed87dab43b1","collapsed":true},"cell_type":"code","source":"img.shape","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"bf1aae3bbc7fa93a3890cae170d3997513b0dfbb","trusted":true,"collapsed":true},"cell_type":"code","source":"predicted_mask = predicted_mask.reshape((1, input_size, input_size, 2))\nplt.imshow(predicted_mask[0][:, :, 0])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3b61378e69c93796a6f9c580d316d739b54ab3fa","trusted":true,"collapsed":true},"cell_type":"code","source":"labeled = np.argmax(predicted_mask[0], axis=-1)\nplt.imshow(labeled)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"dfa8de6a8e0377a08dd15ced74702fa5e1ff1e08","trusted":true,"collapsed":true},"cell_type":"code","source":"plt.imshow(img[0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8d6d9e15e2aab29862ecf73553a4a5c42a89618f","trusted":true,"collapsed":true},"cell_type":"code","source":"img[0].shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"34391cfc84cf8cc67b7c4e3ae23ba4d40a292f6c","collapsed":true},"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.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}