{"cells":[{"metadata":{"_uuid":"7ab368f83b3e8af52e4291cd3a06bccbf0150064"},"cell_type":"markdown","source":"### **Import libraries**"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom skimage import io \nfrom skimage import transform\nfrom matplotlib import pyplot as plt\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\ndat_path = '../input'\nprint(os.listdir(dat_path))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6132e27c26917d242ea4487395e4ab27f566c9e9"},"cell_type":"code","source":"train_img_path = dat_path + '/train'\ntest_img_path = dat_path + '/test'\nlabel_path = dat_path + '/train.csv' \n\n#Data\nlabDat = pd.read_csv(label_path)\n\nSplitRatio = 0.1 #Ratio to keep as validation and test data\ndatLen = len(labDat)\n\ntrainDat = labDat[ : int(datLen * (1 - 2 * SplitRatio))]\nvalidDat = labDat[int(datLen * (1 - 2 * SplitRatio)) : int(datLen * (1 - SplitRatio))]\ntestDat = labDat[int(datLen * (1 - SplitRatio)) : ]\n\nprint('elements : ' + str(len(labDat)))\nprint('training : ' + str(len(trainDat)))\nprint('validation : ' + str(len(validDat)))\nprint('test : ' + str(len(testDat)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f512468d743eb64c9489a04b2a9da4836664b445"},"cell_type":"code","source":"#number of labels\nnum_labels = 28","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","collapsed":true,"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":false},"cell_type":"markdown","source":"### Loading data\nData is loaded onto the memory in batches to prevent leaks\n#### params:\n###### dat : dataframe consisting of filenames and the corresponding labels.\n###### path : path to folder having the images of the dataset.\n###### batch_size : number of images to load at a time.\n###### ind : (ind * batch_size) to offset by\n###### offset : elements to offset by\n###### n_labels : number of possible labels \n###### aug_chance : probability of data getting augmented\n"},{"metadata":{"trusted":true,"_uuid":"d919f6e58bb6926ee7f650ac97ecb64cbda65b8e"},"cell_type":"code","source":"class datGen():\n    \n    def make_batch(dat, path, batch_size, ind = 0, offset = 0, n_labels = 28, aug_chance = 0.3):\n        I = np.identity(n_labels)\n        imgs = []\n        labels = []\n        rnd_indexes = np.array(range(batch_size)) + ind * batch_size + offset\n        for index in rnd_indexes:\n            imgs.append(datGen.fetch_img('%s/%s' % (path, dat.loc[index][0]), aug_chance))\n            labels.append(\n                np.sum(I[np.array(dat.loc[index][1].split()).astype(np.int)], axis = 0) \n                ) # encodes labels into one-hot vectors and sums all the labels\n        # returns normalized and flattened images along with the labels\n        return np.reshape(np.array(imgs) / 256, [batch_size, 512 * 512 * 4]), np.array(labels)\n\n    def fetch_img(path, aug_chance):\n        img = []\n        colors = ['red', 'green', 'blue', 'yellow']\n        r = np.random.uniform()\n        angle = 0\n        if r < aug_chance:\n            angle = np.random.uniform(90)\n        for color in colors :\n            img.append(datGen.augment(io.imread('%s_%s.png' % (path, color)), angle = angle))\n        return np.stack(img, -1)\n    \n    def augment(img, angle = 0):\n        if angle == 0:\n            return img\n        return transform.rotate(img, angle)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7b54d6a9d2f7ae65c65aaa95643aa3b23cd7a314"},"cell_type":"markdown","source":"Let's look at a few elements from our dataset"},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"9d25d5be839ad1a0446e1b725c82a369f55357fa"},"cell_type":"code","source":"elements = 3\nex_dat = datGen.make_batch(labDat, train_img_path, elements, n_labels = num_labels, ind = 5, aug_chance = 0)\nfig, ax = plt.subplots(elements, 4, sharex = 'col', sharey = 'row', figsize = [15,10], dpi = 150)\nfor ind, i in enumerate(ex_dat[0]):\n    img = np.reshape(i, [512, 512, 4])\n    ax[ind, 0].imshow(img[ : , : , 0], cmap = 'gnuplot')\n    ax[ind, 1].imshow(img[ : , : , 1], cmap = 'hot')\n    ax[ind, 2].imshow(img[ : , : , 2], cmap = 'magma')\n    ax[ind, 3].imshow(img[ : , : , 3], cmap = 'terrain')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"90719d49d17e1bc3b0bed204b8dcf1e79bde8105"},"cell_type":"markdown","source":"## The network \nThe architecture we're using is a modified version of  [ arXiv:1512.03385v1 [cs.CV]](https://arxiv.org/abs/1512.03385) with fewer residual blocks. ![A residual block](https://cdn-images-1.medium.com/max/987/1*pUyst_ciesOz_LUg0HocYg.png) an example residual block\n\n#### Activation : sigmoid (As we have a multi-label classification problem)\n"},{"metadata":{"trusted":true,"_uuid":"638adc9a79cce81c6850bf672684a15190711669"},"cell_type":"code","source":"class ResNet():\n    \n    def resBlock(inp, out_space):\n        rb1 = tf.layers.conv2d(inp, filters = out_space, kernel_size = 3, strides = 1, padding = 'same')\n        rb2 = tf.layers.conv2d(rb1, filters = out_space, kernel_size = 3, strides = 1, padding = 'same')\n        return tf.nn.relu(rb2 + inp)\n    \n    def __init__(self, input_size, out_space, res = 512, l_rate = 0.0001, beta = 0.09):\n        # Placeholders\n        self.inputVec = tf.placeholder(dtype = tf.float32, shape = [None, input_size])\n        self.labels = tf.placeholder(dtype = tf.float32, shape = [None, out_space])\n        \n        # Convolutional layers\n        self.X = tf.reshape(self.inputVec, shape = [-1, res, res, 4])\n        self.cnv1 = tf.layers.conv2d(self.X, filters = 64, kernel_size = 7, strides = 2, padding = 'same')\n        self.pool1 = tf.layers.max_pooling2d(self.cnv1, pool_size = 3, strides = 2, padding = 'same')\n        \n        self.res1 = ResNet.resBlock(self.pool1, 64)\n        self.res2 = ResNet.resBlock(self.res1, 64)\n        self.res3 = ResNet.resBlock(self.res2, 64)\n        \n        self.cnv2 = tf.layers.conv2d(self.res3, filters = 128, kernel_size = 3, strides = 2, padding = 'same')\n        self.cnv2 = tf.layers.batch_normalization(self.cnv2)\n        self.cnv3 = tf.layers.conv2d(self.cnv2, filters = 128, kernel_size = 3, strides = 1, padding = 'same')\n        self.cnv3 = tf.layers.dropout(self.cnv3)\n        \n        self.res4 = ResNet.resBlock(self.cnv3, 128)\n        \n        self.cnv4 = tf.layers.conv2d(self.res4, filters = 256, kernel_size = 3, strides = 2, padding = 'same')\n        self.cnv4 = tf.layers.batch_normalization(self.cnv4)\n        self.cnv5 = tf.layers.conv2d(self.cnv4, filters = 256, kernel_size = 3, strides = 1, padding = 'same')\n        self.cnv5 = tf.layers.dropout(self.cnv5)\n        \n        self.res5 = ResNet.resBlock(self.cnv5, 256)\n        self.res6 = ResNet.resBlock(self.res5, 256)\n        \n        self.cnv6 = tf.layers.conv2d(self.res6, filters = 512, kernel_size = 3, strides = 2, padding = 'same')\n        self.cnv6 = tf.layers.batch_normalization(self.cnv6)\n        self.cnv7 = tf.layers.conv2d(self.cnv6, filters = 512, kernel_size = 3, strides = 2, padding = 'same')\n        self.cnv7 = tf.layers.dropout(self.cnv7)\n        \n        self.res7 = ResNet.resBlock(self.cnv7, 512)\n        self.res8 = ResNet.resBlock(self.res7, 512)\n        \n        self.pool2 = tf.layers.average_pooling2d(self.res8, pool_size = 3, strides = 2, padding = 'same')\n        \n        # Fully connected layer\n        self.fc1 = tf.layers.flatten(self.pool2)\n        xavier_init = tf.contrib.layers.xavier_initializer()\n        self.fc1W = tf.Variable(xavier_init([8192, out_space]))\n        \n        self.logits = tf.matmul(self.fc1, self.fc1W)\n        self.out = tf.sigmoid(self.logits)\n        \n        # Loss\n        reg_losses = tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)\n        self.loss = tf.reduce_mean(tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels = self.labels, logits = self.logits)) + beta * sum(reg_losses))\n        self.optimizer = tf.train.AdamOptimizer(learning_rate = l_rate)\n        self.updateOp = self.optimizer.minimize(self.loss)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"c1d959278dbbbb861880db028daaf711741c6c12"},"cell_type":"markdown","source":"## Training the network"},{"metadata":{"trusted":true,"_uuid":"4d5ff4ba5244fe9b939c28fc6f7cf4b20f89fbe4"},"cell_type":"code","source":"#Hyperparameters \nbatch_size = 40\nlearning_rate  = 0.0001\nepochs = 10\n\n#Create ops\nClassifier = ResNet(512 * 512 * 4, 28, l_rate = learning_rate)\ninit = tf.global_variables_initializer()\nsaver = tf.train.Saver(tf.trainable_variables())\n\n#Session\nsess = tf.InteractiveSession()\ntf.reset_default_graph()\nsess.run(init)\n\nif not os.path.exists('../checkpoints'):\n    os.mkdir('../checkpoints')\ntry:\n    saver.restore(sess, '../checkpoints/test_model.ckpt')\n    print('...model loaded from previous checkpoint')\nexcept:\n    pass","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"314cd71b51706703d98e69b254d220bb5e4ee17b"},"cell_type":"markdown","source":"### Training loop"},{"metadata":{"_kg_hide-output":true,"trusted":true,"_uuid":"91d02f24a6aeff75b9c2ee7d85538c982df4429a"},"cell_type":"code","source":"tr_losses = []\nvl_losses = []\nfor epoch in range(epochs):\n    temp_t_loss = []\n    temp_v_loss = []\n    for i in range(int(datLen * (1 - 2 * SplitRatio)) // batch_size):\n        trDat = datGen.make_batch(trainDat, train_img_path, batch_size = batch_size, ind = i)\n        tr_loss, _ = sess.run([Classifier.loss, Classifier.updateOp], feed_dict = {Classifier.inputVec : trDat[0], Classifier.labels : trDat[1]})\n        saver.save(sess, '../checkpoints/test_model.ckpt')\n        \n        if (i < int(datLen * SplitRatio) // batch_size):\n            valDat = datGen.make_batch(validDat, train_img_path, batch_size = batch_size, ind = i, offset = int(datLen * (1 - 2 * SplitRatio)))\n            vl_loss = sess.run([Classifier.loss], feed_dict = {Classifier.inputVec : valDat[0], Classifier.labels : valDat[1]})\n            temp_v_loss.append(vl_loss)\n        temp_t_loss.append(tr_loss)\n        \n        if (i % ((datLen // batch_size) // 20) == 0):            \n            print('[epoch : %i , iter : %i] tr_loss : %f' % (epoch, i, tr_loss))\n            \n    #print training and validation loss \n    mean_t_loss = np.mean(temp_t_loss)\n    mean_v_loss = np.mean(temp_v_loss)\n    \n    tr_losses.append(mean_t_loss)\n    vl_losses.append(mean_v_loss)\n    \n    print('[epoch : %i] tr_loss : %f, vl_loss : %f' % (epoch, mean_t_loss, mean_v_loss))\n    \nsess.close()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a600d53e248be6330016721cc57ccbd60c98b39c"},"cell_type":"code","source":"plt.plot(tr_losses, label = 'training loss')\nplt.plot(vl_losses, '--', label = 'validation loss')\nplt.legend(loc = 'upper right')\nplt.xlabel('epoch')\nplt.ylabel('loss')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d061830d45215dd86a3e8ba043c444453d6dac0f"},"cell_type":"markdown","source":"## Inference"},{"metadata":{"trusted":true,"_uuid":"84b1bc1b1933061803163a3ee7507ceac6c299d6"},"cell_type":"code","source":"def infer(inp_vector):\n    out = sess.run(Classifier.out, feed_dict = {Classifier.inputVec : inp_vector})\n    labels = []\n    for element in out:\n        label = np.squeeze(np.argwhere(element > 0.2)).astype(np.str)\n        if label.size > 1:\n            label = ' '.join(label)\n        else :\n            label = str(label)\n        labels.append(label)\n    return labels\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ba1110fada52d3ee18e506384319cc294e7f4933"},"cell_type":"code","source":"inDat = datGen.make_batch(trainDat, train_img_path, batch_size = 4)\nx = infer(inDat[0])\ny = ['A', 'B', 'C', 'D']\nlist(zip(y,x))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"416728b74f3a7f4c5b7224c3ac3812677521d5ba"},"cell_type":"code","source":"#write to CSV\nl = list(zip(y, x))\npd.DataFrame(l, columns = list('ky'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"75f67088db0512aa6a27e48b1f87264a1acb03f1"},"cell_type":"code","source":"import copy\ntestDF = copy.deepcopy(labDat[:200])\nlist(testDF.iloc[:,0])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c3233d3cb3fba9b51b15d4295de1d7c056c0768a"},"cell_type":"code","source":"class DFrameOps:\n    \n    def mkFrame():\n        return pd.DataFrame({'Id' : [], 'Target' : []})\n    \n    def append(df, Id, Target):\n        tempDF = pd.DataFrame(list(zip(Id, Target)), columns = ['Id', 'Target'])\n        return df.append(tempDF)\n    \n    def resetIndex(df):\n        return df.set_index(np.array(list(range(len(df)))))\n        ","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-output":false,"trusted":true,"_uuid":"66b1bdd946f0763bde58f366d72885b5f7bc40d8"},"cell_type":"code","source":"tdf = DFrameOps.mkFrame()\ninf_batch_size = 50\nfor i in range(len(testDF) // inf_batch_size):\n    infDat, _ = datGen.make_batch(testDF, train_img_path, inf_batch_size, aug_chance = 0)\n    infTarget = infer(infDat)\n    infIds = testDF.iloc[i * inf_batch_size:(i + 1) * inf_batch_size, 0]\n    tdf = DFrameOps.append(tdf, infIds, infTarget)\n    \ntdf = DFrameOps.resetIndex(tdf)\ntdf[:10]\n    \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1ec1d9b048d03c55cd8fde77fd65f2e3a011ef41"},"cell_type":"code","source":"testDF[:10]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"049bc073296005c8d1ee1d6014202982d7a91cc2"},"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}