{"cells":[{"metadata":{"_uuid":"b7da188542295605973b40ac1b1ce0cfc4ce7773"},"cell_type":"markdown","source":"In the original competition,  the pneumonia locations of  chest x-ray images need to be detected. Images which have pneumonia locations are labeled of \"1\". Others which have not pneumonia locations are marked of \"0\".  \n\nTask #1:  It has been asked to classify images by the category of the target (\"1\" or \"0\")\n\n\nThere has been an attempt to solve this task by designing a light-weight model where it is an efficient architecture in the computation and performance as well.  "},{"metadata":{"trusted":true,"_uuid":"f2e5e5157318e7dbde5e9280015583a851b5915b"},"cell_type":"code","source":"from __future__ import print_function\nimport numpy as np\nimport cv2\nimport pandas as pd\nimport pydicom\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nfrom matplotlib.patches import Polygon\nfrom sklearn.model_selection import train_test_split\n\nimport os,time,cv2, sys, math\nimport tensorflow as tf\nimport tensorflow.contrib.slim as slim\nimport numpy as np\nimport time, datetime\nimport argparse\nimport random\nimport os, sys\nimport subprocess","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"587457c23462591dfddb80156e6e5d02a4d06d52","scrolled":true},"cell_type":"code","source":"def data_loader_csv(path,columns=None):\n    data = pd.read_csv(path)\n    if not columns==None:\n        data = data.filter(columns)\n    return data\n    \n\n\ndata = data_loader_csv('../input/rsna-pneumonia-detection-challenge/stage_2_train_labels.csv')\ndata.head(10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"69586e56dbab6710929b5cf34b7db2fd10295180"},"cell_type":"code","source":"def image_reader(image_path, show='False'):\n    image_arr = pydicom.read_file(image_path)\n    image_arr = image_arr.pixel_array\n    if show:\n        plt.imshow(image_arr,cmap='gray')\n        plt.show()\n    return image_arr","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6e6fa488fd1bf7f638357104faf62e02ecab344c"},"cell_type":"code","source":"\narr = image_reader('../input/rsna-pneumonia-detection-challenge/stage_2_train_images/0004cfab-14fd-4e49-80ba-63a80b6bddd6.dcm', show=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4900ac214a9166488fee84cf97c38285c952bcd4","scrolled":true},"cell_type":"code","source":"data_rsna = data_loader_csv('../input/rsna-pneumonia-detection-challenge/stage_2_train_labels.csv', ['patientId','Target'])\ndata_rsna.head(10)\n\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0609e88d26bbdf8dcf9f79eb5eede434f3d391fa"},"cell_type":"markdown","source":"[Here](http://www.kaggle.com/nikhilikhar/classification-with-83-accuracy ) reported that Loading all train images in memory causes memory overflow by that implementation, However my data loader implementation as below will not have any problem and it can use all training images by randomly selection over batch size.  \n"},{"metadata":{"trusted":true,"_uuid":"e236577e7dac4e8ae1cd25e978b359cc0ca03944"},"cell_type":"code","source":"def one_hot_encoder(class_data, n_labels):\n    label = np.array(class_data).reshape(-1)\n    return np.eye(n_labels)[label]\n\n\ndef next_batch_generator(path,data, batch_size, resize_size, n_labels):\n    ix = np.random.choice(np.arange(len(data)), batch_size)\n    imgs =[]\n    labels =[]\n    for i in ix:\n        array_img = image_reader(path+data[i][0]+'.dcm', show=False)\n        img = Image.fromarray(array_img)\n        img = img.resize(resize_size)\n        array_img =np.array(img) / 255\n        imgs.append(array_img)\n        label = one_hot_encoder(data[i][1],n_labels)\n        labels.append(label)\n    imgs = np.array(imgs)\n    imgs = imgs.reshape((batch_size,imgs.shape[1],imgs.shape[2],1))\n    labels = np.array(labels)\n    labels = labels.reshape((batch_size,n_labels))\n\n    return imgs, labels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"de05963a0e0db232e959a1bf266d14350089e9f3"},"cell_type":"code","source":"data = data_rsna.values\ntrain_data, val_data = train_test_split(data, test_size=0.1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"30b084f9c9c64670ea7f7b834c272f95b09bcc15"},"cell_type":"code","source":"train_x, train_y = next_batch_generator('../input/rsna-pneumonia-detection-challenge/stage_2_train_images/',train_data,128,(224,224), 2)\nval_x, val_y = next_batch_generator('../input/rsna-pneumonia-detection-challenge/stage_2_train_images/',val_data,64,(224,224), 2)\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6704164d185f9fb2e7731ab014cc619eb52ef3fa"},"cell_type":"markdown","source":"**Below,  a custom architecture is designed in order to make model a light weight. The bottleneck blocks of Resnet v2 are used**"},{"metadata":{"trusted":true,"_uuid":"b58de74a2ff033654cc8321f1afe07b9da526581"},"cell_type":"code","source":"def subsample(inputs, factor, scope=None):\n    if factor == 1:\n        return inputs\n    else:\n        return slim.max_pool2d(inputs, [1, 1], stride=factor)\n\n\n    \ndef global_pooll(input_tensor, pool_op=tf.nn.avg_pool):\n    shape = input_tensor.get_shape().as_list()\n    if shape[1] is None or shape[2] is None:\n        kernel_size = tf.convert_to_tensor([1, tf.shape(input_tensor)[1],tf.shape(input_tensor)[2], 1])\n    else:\n        kernel_size = [1, shape[1], shape[2], 1]\n    output = pool_op(\n      input_tensor, ksize=kernel_size, strides=[1, 1, 1, 1], padding='VALID')\n    # Recover output shape, for unknown shape.\n    output.set_shape([None, 1, 1, None])\n    return output\n    \ndef conv2d_same(inputs, num_outputs, kernel_size, stride, rate=1, scope=None):\n\n    if stride == 1:\n        return slim.conv2d(inputs, num_outputs, kernel_size, stride=1, rate=rate,\n                           padding='SAME')\n    else:\n        kernel_size_effective = kernel_size + (kernel_size - 1) * (rate - 1)\n        pad_total = kernel_size_effective - 1\n        pad_beg = pad_total // 2\n        pad_end = pad_total - pad_beg\n        inputs = tf.pad(inputs,\n                        [[0, 0], [pad_beg, pad_end], [pad_beg, pad_end], [0, 0]])\n        return slim.conv2d(inputs, num_outputs, kernel_size, stride=stride,\n                           rate=rate, padding='VALID', weights_regularizer=slim.l2_regularizer(0.0001),weights_initializer=slim.variance_scaling_initializer())\n\n\ndef resBlock(x, Depth,depth_bottleneck, kernel_size=[3, 3], stride=1, skipCon=False, rate=2):\n    depth_in = slim.utils.last_dimension(x.get_shape(), min_rank=4)\n    peatct = slim.batch_norm(x, activation_fn=tf.nn.relu)\n    if Depth == depth_in:\n        shortcut = subsample(x, stride)\n    else:\n        shortcut = slim.conv2d(peatct, Depth, [1, 1], stride=stride,\n                               activation_fn=None)\n    residual = slim.conv2d(peatct, depth_bottleneck, [1, 1], stride=1, weights_regularizer=slim.l2_regularizer(0.0001),weights_initializer=slim.variance_scaling_initializer())\n    residual = tf.nn.relu(slim.batch_norm(residual, fused=True, scale=True))\n    residual = conv2d_same(residual, depth_bottleneck, 3, stride,rate=rate)\n    residual = tf.nn.relu(slim.batch_norm(residual, fused=True, scale=True))\n    residual = slim.conv2d(residual, Depth, [1, 1], stride=1,activation_fn=None)\n\n    output = shortcut + residual\n    return output\n\n\ndef UnitBlockA(x, base_depth, stride=1, rate=1):\n    \n    \"\"\"\n    A custom Block: Bekmirzaev shohrukh\n    \"\"\"\n    \n    depth =base_depth * 4\n    depth_bottleneck =base_depth\n    res = resBlock(x, depth, depth_bottleneck, stride=1, skipCon=True, rate=rate)\n    res = resBlock(res, depth,depth_bottleneck, stride=1, skipCon=False, rate=rate)\n    res = resBlock(res, depth,depth_bottleneck, stride=stride, skipCon=True, rate=rate)\n    return res\n\ndef UnitBlockB(x, base_depth, stride=1, rate=1):\n    \n    \"\"\"\n    B custom Block: Bekmirzaev shohrukh\n    \n    \"\"\"\n    depth =base_depth * 4\n    depth_bottleneck =base_depth\n    res = resBlock(x, depth, depth_bottleneck, stride=1, skipCon=True, rate=rate)\n    res = resBlock(res, depth,depth_bottleneck, stride=1, skipCon=False, rate=rate)\n    res = resBlock(res, depth, depth_bottleneck, stride=1, skipCon=False, rate=rate)\n    res = resBlock(res, depth,depth_bottleneck, stride=stride, skipCon=True, rate=rate)\n    res = tf.nn.relu(res)\n    return res\n\n\n\n\ndef conv_block(inputs, n_filters, kernel_size=[3, 3], dropout_p=0.0, stride=1):\n    out = slim.conv2d(inputs, n_filters, kernel_size, stride=stride, activation_fn=None, normalizer_fn=None)\n    return out\n\ndef ourCustomNetwork(inputs,is_training=True,scope='OurCustomNetwork',num_classes=2):\n\n    net = conv_block(inputs, 32, stride=2)\n    net = UnitBlockA(net, 64, stride=2)\n    net = UnitBlockB(net, 64, stride=2)\n    net = UnitBlockA(net, 128, stride=2)\n    net = UnitBlockB(net, 256, stride=2)\n        \n    with tf.variable_scope(scope):\n        net = global_pooll(net)\n        # 1 x 1 x num_classes\n        # Note: legacy scope name.\n        logits = slim.conv2d(\n            net,\n            num_classes, [1, 1],\n            activation_fn=None,\n            normalizer_fn=None,\n            biases_initializer=tf.zeros_initializer(),\n            scope='Conv2d_1c_1x1')\n        logits = tf.squeeze(logits, [1, 2])\n        logits = tf.identity(logits, name='output')\n    return logits","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e6462061932ad5813115079174877d7c229a8e68"},"cell_type":"code","source":"\n\nnet_input = tf.placeholder(tf.float32,shape=[None,224,224,1])\nnet_output = tf.placeholder(tf.float32,shape=[None,2])\n\ndef LOG(X, f=None):\n    time_stamp = datetime.datetime.now().strftime(\"[%Y-%m-%d %H:%M:%S]\")\n    if not f:\n        print(time_stamp + \" \" + X)\n    else:\n        f.write(time_stamp + \" \" + X)\n\ndef count_params():\n    total_parameters = 0\n    for variable in tf.trainable_variables():\n        shape = variable.get_shape()\n        variable_parameters = 1\n        for dim in shape:\n            variable_parameters *= dim.value\n        total_parameters += variable_parameters\n    print(\"This model has %d trainable parameters\"% (total_parameters))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"db7361e32bf78cd1349a55ad8a8af57ab4fbe1ab"},"cell_type":"code","source":"logits = ourCustomNetwork(net_input,scope='OurCustomNetwork', num_classes=2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9642fd9db61666d32c5d3c03bf3cc15304db7849"},"cell_type":"code","source":"prediction = tf.nn.softmax(logits)\n\nloss_op = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=net_output))\noptimizer = tf.train.AdamOptimizer(learning_rate=0.0001)\ntrain_op = optimizer.minimize(loss_op)\n\ncorrect_pred = tf.equal(tf.argmax(prediction, 1), tf.argmax(net_output, 1))\naccuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))\n\ninit = tf.global_variables_initializer()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"50c7ca7e170b0f3c8a0426387690e99c88ca5b50"},"cell_type":"code","source":"epochs = 5\nbatch_size =64\ndisplay_step = 100","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b7a593b133d80199abe70ff93c02fb2d06ae140b","_kg_hide-output":true,"_kg_hide-input":true,"scrolled":false},"cell_type":"code","source":"config = tf.ConfigProto()\nconfig.gpu_options.allow_growth = True\navg_loss_per_epoch  = []\nwith tf.Session() as sess:\n    saver=tf.train.Saver(max_to_keep=1000)\n    sess.run(init)\n    \n    for epoch in range(epochs):\n        num_steps = int(len(data) / batch_size)\n        current_losses = []\n        cnt=0\n        st = time.time()\n        epoch_st=time.time()\n\n        for step in range(1, num_steps+1):\n            train_x, train_y = next_batch_generator('../input/rsna-pneumonia-detection-challenge/stage_2_train_images/',train_data,batch_size,(224,224), 2)\n            _, loss, acc = sess.run([train_op,loss_op, accuracy], feed_dict={net_input: train_x, net_output:train_y})\n            current_losses.append(loss)\n            cnt = cnt + batch_size\n            if cnt % 20 == 0:\n                string_print = \"Epoch = %d Count = %d Current_Loss = %.4f Current_Accuracy = %.2f Time = %.1f\"%(epoch,cnt,loss,acc,time.time()-st)\n                LOG(string_print)\n                st = time.time()\n                \n        mean_loss = np.mean(current_losses)\n        avg_loss_per_epoch.append(mean_loss)\n        print(\"Saving latest checkpoint\")\n        model_checkpoint_name = \"latest_model_\" + str(epoch) + \".ckpt\"\n        #saver.save(sess,model_checkpoint_name)\n        \n        print(\"Validation Accuracy:\")\n        val_x, val_y = next_batch_generator('../input/rsna-pneumonia-detection-challenge/stage_2_train_images/',val_data,64,(224,224), 2)\n        accVal = sess.run(accuracy, feed_dict={net_input: val_x, net_output:val_y}) \n        print(\"Epoch \" + str(epoch) +  \", Val Accuracy= \" + \"{:.3f}\".format(accVal))\n        \n#         fig2, ax2 = plt.subplots(figsize=(11, 8))\n\n#         ax2.plot(range(epoch+1), avg_loss_per_epoch)\n#         ax2.set_title(\"Average loss vs epochs\")\n#         ax2.set_xlabel(\"Epoch\")\n#         ax2.set_ylabel(\"Current loss\")\n\n#         #plt.savefig('loss_vs_epochs.png')\n\n#         plt.clf()\n        \n            ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4150da5c3f1912810df12f5a99141ee2267403e7"},"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.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}