{"cells":[{"metadata":{"_uuid":"45d5c69513daf5ed7add9a76697bfc5c26bc38c5"},"cell_type":"markdown","source":"# TFLearn U-Net Starter"},{"metadata":{"_uuid":"8158fca0afef776c222d26849fa87afdb6364fe1"},"cell_type":"markdown","source":"Quick and dirty kernel shows how to get started on segmenting nuclei using a neural network in TFLearn.\n\nKeras version: https://www.kaggle.com/keegil/keras-u-net-starter-lb-0-277/notebook\n\n## Paper\n\nU-Net: Convolutional Networks for Biomedical Image Segmentation https://arxiv.org/abs/1505.04597\n\nThe CNN will be built on the training data and applied to the test data.\n\nU-Net architecture flow:\n![u-net-architecture](https://lmb.informatik.uni-freiburg.de/Publications/2015/RFB15a/u-net-architecture.png)\n\n## Data\n\nusing data from [2018 Data Science Bowl](https://www.kaggle.com/c/data-science-bowl-2018)"},{"metadata":{"trusted":true,"_uuid":"f93b1275f34eaa43ee99cf9327921c0ac11d4564","collapsed":true},"cell_type":"code","source":"from __future__ import absolute_import, division, print_function\n%matplotlib inline\nfrom matplotlib import pyplot as plt\nplt.style.use('fivethirtyeight')\nimport os\nimport sys\nimport random\nimport numpy as np\nimport cv2\nfrom tqdm import tqdm\n\nseed = 42\nrandom.seed = seed\nnp.random.seed = seed\n\n# Set some parameters\nDATA_PATH = '../input'\nTRAIN_PATH = DATA_PATH + '/stage1_train/'\nTEST_PATH  = DATA_PATH + '/stage1_test/'\n\nIMAGE_W = 128\nIMAGE_H = 128\nIMAGE_C = 1","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8045126027625e38a48367a8449428915e2ef962"},"cell_type":"markdown","source":"# Preparing the Data"},{"metadata":{"trusted":true,"_uuid":"53ef3c604d6b2d678b73718112d466ca0a79be4c","collapsed":true},"cell_type":"code","source":"# Get train and test IDs\ntrain_ids = next(os.walk(TRAIN_PATH))[1]\ntest_ids  = next(os.walk(TEST_PATH))[1]\nlen(train_ids), len(test_ids)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5824e15990635abfb2802d6f5463f7ae2574011d","collapsed":true},"cell_type":"code","source":"# Get and resize train images and masks\ndef load_image(filename):\n    img = cv2.imread(filename)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n    img = cv2.resize(img,(IMAGE_W,IMAGE_H))\n    img = img.astype(np.float32)/255.0\n    img = np.expand_dims(img, axis=-1)\n    return img\n\ndef load_data(train_path, test_path, shuffle=False):\n    print('Getting and resizing train images and masks ... ')\n    sys.stdout.flush()\n\n    trainX = np.zeros((len(train_ids), IMAGE_H, IMAGE_W, IMAGE_C), dtype=np.float32)\n    trainY = np.zeros((len(train_ids), IMAGE_H, IMAGE_W, 1), dtype=np.bool)\n    for i, name in tqdm(enumerate(train_ids), total=len(train_ids)):\n        path = train_path + name\n        trainX[i] = load_image(path + '/images/' + name + '.png')\n\n        # 将多个分开的掩码合在一起，边界地方的像素点值为 True\n        mask = np.zeros((IMAGE_H, IMAGE_W, 1), dtype=np.bool)\n        for mask_file in next(os.walk(path + '/masks/'))[2]:\n            img = cv2.imread(path + '/masks/' + mask_file)\n            img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n            img = cv2.resize(img,(IMAGE_W,IMAGE_H))\n            img = np.expand_dims(img, axis=-1)\n            mask = np.maximum(mask, img)\n        trainY[i] = mask\n\n    # Get and resize test images\n    print('Getting and resizing test images ... ')\n    sys.stdout.flush()\n    testX = np.zeros((len(test_ids), IMAGE_H, IMAGE_W, IMAGE_C), dtype=np.float32)\n    sizes_test = []\n    for i, name in tqdm(enumerate(test_ids), total=len(test_ids)):\n        path = test_path + name\n        testX[i] = load_image(path + '/images/' + name + '.png')\n    \n    if shuffle:\n        trainX, trainY = shuffle_data(trainX, trainY)\n\n    return trainX, trainY, testX\n\ntrainX, trainY, testX = load_data(TRAIN_PATH, TEST_PATH)\ntrainX.shape, trainY.shape, testX.shape","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"043d83b06cb2eeb1310cc202c1b1c2101a7fa2cb"},"cell_type":"markdown","source":"## Image Augmentation"},{"metadata":{"trusted":true,"_uuid":"c29b6ae5a562fbb2c62375eb36d61610aa4b97e2","collapsed":true},"cell_type":"code","source":"def image_augmentation(trainX, trainY):\n    n_imgaug = 1+2 # 1 origin + 2 augmentation\n    shape = trainX.shape\n    shape = (trainX.shape[0]*n_imgaug,) + trainX.shape[1:] \n    new_trainX = np.zeros(shape, dtype=np.float32)\n    new_trainY = np.zeros(shape, dtype=np.float32)\n    for i in tqdm(range(len(trainX))):\n        img = trainX[i]\n        new_trainX[i*n_imgaug+0] = img\n        new_trainX[i*n_imgaug+1] = np.fliplr(img)\n        new_trainX[i*n_imgaug+2] = np.flipud(img)\n        \n        img = trainY[i]\n        new_trainY[i*n_imgaug+0] = img\n        new_trainY[i*n_imgaug+1] = np.fliplr(img)\n        new_trainY[i*n_imgaug+2] = np.flipud(img)\n\n    return new_trainX, new_trainY\n\ntrainX, trainY = image_augmentation(trainX, trainY)\ntrainX.shape, trainY.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ad48484b24a0d48ef075f8e3460836405bb13f9d","collapsed":true},"cell_type":"code","source":"# Check if training data looks all right\nix = random.randint(0, len(trainX)-1)\nimage = trainX[ix].reshape(IMAGE_H, IMAGE_W)\n\nplt.figure(figsize=(10, 10))\n\nplt.subplot(121)\nplt.grid(False)\nplt.imshow(image, plt.cm.gray)\nplt.title(\"Image\")\n\nplt.subplot(122)\nplt.grid(False)\nplt.imshow(np.squeeze(trainY[ix]), plt.cm.gray)\nplt.title(\"Mask\");\ndel image","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"275abc45ccb93f169bd6be7d5f6da5c2d6d79cac"},"cell_type":"markdown","source":"# Build and train U-Net network"},{"metadata":{"_uuid":"d76ecf5e46c9acf6a3ddcb014b4b9adaeb73f88d"},"cell_type":"markdown","source":"## Loss: What difference of binary_crossentropy between Keras and TFLearn\n\n> If the last conv_2d's activity function is 'sigmod'\n\nKeras binary_crossentropy: loss = sigmoid(x)\n```python\nx = sigmoid(x)  # the last conv_2d\ndef binary_crossentropy(x):\n    x = ~sigmoid(x) # undo sigmoid(x), transform back to logits\n    return tf.nn.sigmoid_cross_entropy_with_logits(x)\n```\n\nTFLearn binary_crossentropy: loss = sigmoid(sigmoid(x)) = always 0.693. it's wrong!!!\n```python\nx = sigmoid(x)  # the last conv_2d\ndef binary_crossentropy(x):\n    return tf.nn.sigmoid_cross_entropy_with_logits(x)\n```\n\nshould be\n```\nx = linear(x)  # the last conv_2d\ndef binary_crossentropy(x):\n    return tf.nn.sigmoid_cross_entropy_with_logits(x)\n```"},{"metadata":{"_uuid":"052ca99ac55c57bcd9ae95f726429dc01f0cdc08"},"cell_type":"markdown","source":"## Metric\n```python\n# Define IoU metric\ndef mean_iou_accuracy_op(y_pred, y_true, x):\n    with tf.name_scope('Accuracy'):\n        prec = []\n        for t in np.arange(0.5, 1.0, 0.05):\n            y_pred_tmp = tf.to_int32(y_pred > 0.5)\n            score, update_op = tf.metrics.mean_iou(y_true, y_pred_tmp, 2)\n            with tf.Session() as sess:\n                sess.run(tf.local_variables_initializer())\n            with tf.control_dependencies([update_op]):\n                score = tf.identity(score)\n            prec.append(score)\n        acc = tf.reduce_mean(tf.stack(prec), axis=0, name='mean_iou')\n    return acc\n```"},{"metadata":{"scrolled":false,"trusted":true,"_uuid":"371c25c6cde94ee1476bc25fac72d3114f45f895","collapsed":true},"cell_type":"code","source":"import time\nimport tflearn\nimport tensorflow as tf\nfrom tflearn import input_data, dropout, fully_connected\nfrom tflearn import conv_2d, max_pool_2d, conv_2d_transpose, upsample_2d\nfrom tflearn import merge\nfrom tflearn import regression\nfrom tflearn import ImagePreprocessing\nfrom tflearn import ImageAugmentation\nfrom tflearn import Momentum\n\ntf.reset_default_graph()\n\nd0 = input_data(shape=[None, IMAGE_H, IMAGE_W, IMAGE_C], name=\"input\")\n\nc1 = conv_2d(d0,  8, 3, weights_init='variance_scaling', activation='relu', name=\"conv1_1\")\nc1 = conv_2d(c1,  8, 3, weights_init='variance_scaling', activation='relu', name=\"conv1_2\")\np1 = max_pool_2d(c1, 2)\n\nc2 = conv_2d(p1, 16, 3, weights_init='variance_scaling', activation='relu', name=\"conv2_1\")\nc2 = conv_2d(c2, 16, 3, weights_init='variance_scaling', activation='relu', name=\"conv2_2\")\np2 = max_pool_2d(c2, 2)\n\nc3 = conv_2d(p2, 32, 3, weights_init='variance_scaling', activation='relu', name=\"conv3_1\")\nc3 = conv_2d(c3, 32, 3, weights_init='variance_scaling', activation='relu', name=\"conv3_2\")\np3 = max_pool_2d(c3, 2)\n\nc4 = conv_2d(p3, 64, 3, weights_init='variance_scaling', activation='relu', name=\"conv4_1\")\nc4 = conv_2d(c4, 64, 3, weights_init='variance_scaling', activation='relu', name=\"conv4_2\")\np4 = max_pool_2d(c4, 2)\n\nc5 = conv_2d(p4, 128, 3, weights_init='variance_scaling', activation='relu', name=\"conv5_1\")\nc5 = conv_2d(c5, 128, 3, weights_init='variance_scaling', activation='relu', name=\"conv5_2\")\n\nu6 = conv_2d_transpose(c5, 64, 2, [ 16, 16], strides=2)\nu6 = merge([u6, c4], mode='concat', axis=3, name='upsamle-5-merge-4')\nc6 = conv_2d(u6, 64, 3, weights_init='variance_scaling', activation='relu', name=\"conv6_1\")\nc6 = conv_2d(c6, 64, 3, weights_init='variance_scaling', activation='relu', name=\"conv6_2\")\n\nu7 = conv_2d_transpose(c6, 32, 2, [ 32, 32], strides=2)\nu7 = merge([u7, c3], mode='concat', axis=3, name='upsamle-6-merge-3')\nc7 = conv_2d(u7, 32, 3, weights_init='variance_scaling', activation='relu', name=\"conv7_1\")\nc7 = conv_2d(c7, 32, 3, weights_init='variance_scaling', activation='relu', name=\"conv7_2\")\n\nu8 = conv_2d_transpose(c7, 16, 2, [ 64, 64], strides=2)\nu8 = merge([u8, c2], mode='concat', axis=3, name='upsamle-7-merge-2')        \nc8 = conv_2d(u8, 16, 3, weights_init='variance_scaling', activation='relu', name=\"conv8_1\")\nc8 = conv_2d(c8, 16, 3, weights_init='variance_scaling', activation='relu', name=\"conv8_2\")\n\nu9 = conv_2d_transpose(c8,  8, 2, [128,128], strides=2)\nu9 = merge([u9, c1], mode='concat', axis=3, name='upsamle-8-merge-1')\nc9 = conv_2d(u9,  8, 3, weights_init='variance_scaling', activation='relu', name=\"conv9_1\")\nc9 = conv_2d(c9,  8, 3, weights_init='variance_scaling', activation='relu', name=\"conv9_2\")\n\nfc = conv_2d(c9,  1, 1, weights_init='variance_scaling', activation='linear', name=\"target\")\n\n# Define IoU metric\ndef mean_iou_accuracy_op(y_pred, y_true, x):\n    with tf.name_scope('Accuracy'):\n        prec = []\n        for t in np.arange(0.5, 1.0, 0.05):\n            y_pred_tmp = tf.to_int32(y_pred > 0.5)\n            score, update_op = tf.metrics.mean_iou(y_true, y_pred_tmp, 2)\n            with tf.Session() as sess:\n                sess.run(tf.local_variables_initializer())\n            with tf.control_dependencies([update_op]):\n                score = tf.identity(score)\n            prec.append(score)\n        acc = tf.reduce_mean(tf.stack(prec), axis=0, name='mean_iou')\n    return acc\n\nnet = regression(fc,\n                 optimizer='Adam',\n                 loss='binary_crossentropy',\n                 metric=mean_iou_accuracy_op,\n                 learning_rate=0.001\n                )\n\nmodel = tflearn.DNN(net, tensorboard_verbose=3)\n\nstart_time = time.time()\nmodel.fit(trainX, \n          trainY, \n          validation_set=0.1,\n          n_epoch=20,\n          batch_size=16,\n          shuffle=True,\n          show_metric=True,\n          run_id='bowl_unet')\n\nduration = time.time() - start_time\nprint('Training Duration %.3f sec' % (duration))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"67f3429bfb0c741df5205136399a000a9f4cbb34"},"cell_type":"markdown","source":"# Predict"},{"metadata":{"trusted":true,"_uuid":"f80a591829f68a9830c2c9839c7a23dcdf322cb2","collapsed":true},"cell_type":"code","source":"ix = random.randint(0, len(testX)-1)\nimage = testX[ix:ix+1]\ny_pred = model.predict(image)\ny_pred = (y_pred > 0.5).astype(np.uint8).reshape(IMAGE_H, IMAGE_W)\n\nplt.figure(figsize=(10, 10))\n\nplt.subplot(121)\nplt.grid(False)\nplt.imshow(image.reshape(IMAGE_H, IMAGE_W), plt.cm.gray)\nplt.title(\"Image\")\n\nplt.subplot(122)\nplt.grid(False)\nplt.imshow(np.squeeze(y_pred), plt.cm.gray)\nplt.title(\"Predicted Mask\");\ndel image,y_pred","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"},"toc":{"base_numbering":1,"nav_menu":{},"number_sections":false,"sideBar":true,"skip_h1_title":false,"title_cell":"Table of Contents","title_sidebar":"Contents","toc_cell":false,"toc_position":{},"toc_section_display":true,"toc_window_display":true}},"nbformat":4,"nbformat_minor":1}