{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"collapsed":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\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"collapsed":true},"cell_type":"code","source":"from keras.models import Model,Sequential\nfrom keras.layers import Input, concatenate, Conv2D, MaxPooling2D,Reshape, BatchNormalization, Activation, UpSampling2D, Average, Add, SeparableConv2D, Conv2DTranspose,Permute,Convolution2D,ZeroPadding2D\nfrom keras.optimizers import SGD, Adam\nfrom keras.losses import binary_crossentropy\nimport keras.backend as K\nfrom keras import regularizers\nfrom keras.layers.core import Activation, Layer, SpatialDropout2D\nfrom keras.utils.vis_utils import plot_model\nfrom keras.layers.advanced_activations import PReLU, ELU\n\n#from custom_layers import MaxPoolingWithArgmax2D,MaxUnpooling2D\n\n###################################################################################################\n\ndef dice_coeff(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    score = (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth)\n    return score\n\n\ndef dice_loss(y_true, y_pred):\n    loss = 1 - dice_coeff(y_true, y_pred)\n    return loss\n\n\ndef bce_dice_loss(y_true, y_pred):\n    loss = binary_crossentropy(y_true, y_pred) + dice_loss(y_true, y_pred)\n    return loss\n\n\ndef weighted_dice_coeff(y_true, y_pred, weight):\n    smooth = 1.\n    w, m1, m2 = weight * weight, y_true, y_pred\n    intersection = (m1 * m2)\n    score = (2. * K.sum(w * intersection) + smooth) / (K.sum(w * m1) + K.sum(w * m2) + smooth)\n    return score\n\n\ndef weighted_dice_loss(y_true, y_pred):\n    y_true = K.cast(y_true, 'float32')\n    y_pred = K.cast(y_pred, 'float32')\n    # if we want to get same size of output, kernel size must be odd number\n    if K.int_shape(y_pred)[1] == 128:\n        kernel_size = 11\n    elif K.int_shape(y_pred)[1] == 256:\n        kernel_size = 21\n    elif K.int_shape(y_pred)[1] == 512:\n        kernel_size = 21\n    elif K.int_shape(y_pred)[1] == 1024:\n        kernel_size = 41\n    else:\n        raise ValueError('Unexpected image size')\n    averaged_mask = K.pool2d(\n        y_true, pool_size=(kernel_size, kernel_size), strides=(1, 1), padding='same', pool_mode='avg')\n    border = K.cast(K.greater(averaged_mask, 0.005), 'float32') * K.cast(K.less(averaged_mask, 0.995), 'float32')\n    weight = K.ones_like(averaged_mask)\n    w0 = K.sum(weight)\n    weight += border * 2\n    w1 = K.sum(weight)\n    weight *= (w0 / w1)\n    loss = 1 - weighted_dice_coeff(y_true, y_pred, weight)\n    return loss\n\n\ndef weighted_bce_loss(y_true, y_pred, weight):\n    # avoiding overflow\n    epsilon = 1e-7\n    y_pred = K.clip(y_pred, epsilon, 1. - epsilon)\n    logit_y_pred = K.log(y_pred / (1. - y_pred))\n\n    # https://www.tensorflow.org/api_docs/python/tf/nn/weighted_cross_entropy_with_logits\n    loss = (1. - y_true) * logit_y_pred + (1. + (weight - 1.) * y_true) * \\\n                                          (K.log(1. + K.exp(-K.abs(logit_y_pred))) + K.maximum(-logit_y_pred, 0.))\n    return K.sum(loss) / K.sum(weight)\n\n\ndef weighted_bce_dice_loss(y_true, y_pred):\n    y_true = K.cast(y_true, 'float32')\n    y_pred = K.cast(y_pred, 'float32')\n    # if we want to get same size of output, kernel size must be odd number\n    if K.int_shape(y_pred)[1] == 128:\n        kernel_size = 11\n    elif K.int_shape(y_pred)[1] == 256:\n        kernel_size = 21\n    elif K.int_shape(y_pred)[1] == 512:\n        kernel_size = 21\n    elif K.int_shape(y_pred)[1] == 1024:\n        kernel_size = 41\n    else:\n        raise ValueError('Unexpected image size')\n    averaged_mask = K.pool2d(\n        y_true, pool_size=(kernel_size, kernel_size), strides=(1, 1), padding='same', pool_mode='avg')\n    border = K.cast(K.greater(averaged_mask, 0.005), 'float32') * K.cast(K.less(averaged_mask, 0.995), 'float32')\n    weight = K.ones_like(averaged_mask)\n    w0 = K.sum(weight)\n    weight += border * 2\n    w1 = K.sum(weight)\n    weight *= (w0 / w1)\n    loss = weighted_bce_loss(y_true, y_pred, weight) + (1 - weighted_dice_coeff(y_true, y_pred, weight))\n    return loss\n    \n##############################################################################################################\ndef SegNet(input_shape=(1024, 1024, 3), classes=1, kernel=3):\n\n    encoding_layers = [\n        Conv2D(64, (kernel, kernel), input_shape=input_shape, 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 = 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(classes, (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((classes,input_shape[0],input_shape[1])))\n    #autoencoder.add(Permute((2, 1)))\n    autoencoder.add(Activation('softmax'))\n    \n    autoencoder.compile(optimizer=Adam(lr=0.0005),\n                  loss=bce_dice_loss,\n                  metrics=[dice_coeff])\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\n################################################################################################\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ada445ec3badd2e9ae42fbf7b6af45c006c0556f","collapsed":true},"cell_type":"code","source":"INPUT_PATH = '../input/'\ninput_size = 1024\ndims = [input_size, input_size]    #height X width\nimg_rows = dims[0]\nimg_cols = dims[1]\nn_labels = 2\nfrom keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint, TensorBoard","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2c2d216c461e5ebb3e735ae062c0ff2183e6674e","collapsed":true},"cell_type":"code","source":"import glob\ntrain = 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":{"trusted":true,"_uuid":"e5ab2a0bccbef5adb6d9cf498d42e6226fb21e6b","collapsed":true},"cell_type":"code","source":"from sklearn.model_selection import  train_test_split\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')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"42f5e4fd2b2286f6b7ed82b6b56f13a559ef6974"},"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","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"05e834b0f924136a7a0c380bd17283c36b375479"},"cell_type":"code","source":"batch_size=32","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"4f5a23b02e046b34a7ec61d88a8ea9867d4334c3"},"cell_type":"code","source":"input_w,input_h=1024,1024","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ffb343b92b014f290f673e73890acc8b0c5f73fc","collapsed":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"796661345a723fbed34a849cc06cb4a495c438fd","collapsed":true},"cell_type":"code","source":"\ndef train_generator():\n    while True:\n        for start in range(0, len(train_images), batch_size):\n            x_batch = []\n            y_batch = []\n            end = min(start + batch_size, len(train_images))\n            ids_train_batch = train_images[start:end]\n            for id in ids_train_batch:\n                img = cv2.imread(id)\n                img = cv2.resize(img, (input_w, input_h))\n\n                # Augmentation Testing ==================================================\n                #img = gamma_correction(img, u=0.5)\n                #img = equalize_hist(img)\n                #img = cv2.blur(img, (3, 3))\n                #img = cv2.bilateralFilter(img, 3, 40, 40)\n                #img = img[160:1120, 0:960]  # NOTE: its img[y: y + h, x: x + w]\n                #img = random_saturation(img, u=0.25)\n                #img = random_brightness(img, u=0.25)\n                #img = random_contrast(img, u=0.25)\n                #img = random_gray(img, u=0.25)\n                #===============================================================\n                mask_filename = basename(id)\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                \n                \n                #mask = np.expand_dims(mask, axis=2)\n                x_batch.append(img)\n                y_batch.append(gt)\n            x_batch = np.array(x_batch, np.float32) / 255\n            y_batch = np.array(y_batch, np.float32) / 255\n            yield x_batch, y_batch\n\n\ndef valid_generator():\n    while True:\n        for start in range(0, len(validation_images), batch_size):\n            x_batch = []\n            y_batch = []\n            end = min(start + batch_size, len(validation_images))\n            ids_valid_batch = validation_images[start:end]\n            for id in ids_valid_batch:\n                img = cv2.imread(id)\n                img = cv2.resize(img, (input_w, input_h))\n                mask = cv2.imread(id)\n                mask = cv2.resize(mask, (input_w, input_h))\n                mask = np.expand_dims(mask, axis=2)\n                x_batch.append(img)\n                y_batch.append(mask)\n            x_batch = np.array(x_batch, np.float32) / 255\n            y_batch = np.array(y_batch, np.float32) / 255\n            yield x_batch, y_batch\n\ncallbacks = [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='weights/segnet_{epoch:02d}-{dice_coeff:.5f}-{val_dice_coeff:.5f}.hdf5',\n                             save_best_only=True,\n                             save_weights_only=True,\n                             period = 1),\n             TensorBoard(log_dir=\"logs/\")]\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a08628b06fdadf4b40ee0d0e70eaecc0590c7b37","collapsed":true},"cell_type":"code","source":"model = SegNet()\n\noptimizer = SGD(lr=0.001, momentum=0.9, decay=0.0005, nesterov=False)\n#model.compile(loss=\"categorical_crossentropy\", optimizer=optimizer, metrics=['accuracy'])\nprint( 'Compilation: OK')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"2e263563a08671680535371ebb7981f0e0084960"},"cell_type":"code","source":"epochs=10","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"db6d8742a324c48320ad7bd8db8ca6d0a690ac9a","collapsed":true},"cell_type":"code","source":"mask_df.iloc[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c3b8aef0addb910493b6d490fc89eaa60cc58878","collapsed":true},"cell_type":"code","source":"train_images[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"bb84c4748ad8a62b72eb5d75113c76e37bdfb114","collapsed":true},"cell_type":"code","source":"model.fit_generator(generator=train_generator(),\n                    steps_per_epoch=np.ceil(float(len(train_images)) / float(batch_size)),\n                    epochs=epochs,\n                    verbose=1,\n                    callbacks=callbacks,\n                    validation_data=valid_generator(),\n                    validation_steps=np.ceil(float(len(validation_images)) / float(batch_size)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"0336b8a7aa575da7b8a7f04f15d21c101d606570"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"c3a5fc2829886bd8c455fb51b22f8f0370fbea5a"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"16eeb3d2a1e092a366603d4b990a4998800b7856"},"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}