├── ConvNets ├── ImageNet-InceptionV4.ipynb ├── ImageNet-VGG.ipynb ├── README.md ├── VGG.py └── synset.txt ├── Dataset ├── COCO-images │ └── README.md ├── README.md └── flickr30k-images │ └── README.md ├── Demo.ipynb ├── Images ├── gen_102617084.jpg ├── gen_2230458748.jpg ├── gen_2461372011.jpg ├── gen_2472980433.jpg ├── gen_2537697530.jpg ├── gen_283252248.jpg ├── gen_3126981064.jpg ├── gen_3273757324.jpg ├── gen_3920626767.jpg ├── gen_4013421575.jpg ├── gen_4752984291.jpg ├── gen_532999240.jpg ├── gen_6.png ├── gen_7125476937.jpg ├── gen_7148046575.jpg ├── gen_7526599338.jpg ├── gen_cat2.png ├── gen_comp.png ├── gen_football.png ├── gen_manlaptop.png ├── gen_plane.png ├── gen_suitselfie.png └── gen_womanbeach.png ├── LICENSE ├── README.md ├── caption_generator.py ├── configuration.py ├── convfeatures.py ├── eval.py ├── main.py ├── model ├── Decoder │ └── README.md ├── Encoder │ └── README.md ├── README.md ├── Trained_Graphs │ └── README.md └── log_dir │ └── README.md ├── results.txt └── utils ├── Image_PreProcessing_Exploration.ipynb ├── MaybeConnect.ipynb ├── PreProcessCOCOCaptions.ipynb ├── Serve-DualProtoBuf.ipynb ├── Serve-SingleProtoBuf.ipynb ├── __init__.py ├── data_util.py ├── merge_graphs.py └── save_graph.py /ConvNets/ImageNet-InceptionV4.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import tensorflow as tf\n", 12 | "from PIL import Image \n", 13 | "import numpy as np\n", 14 | "import skimage\n", 15 | "import skimage.io\n", 16 | "import skimage.transform\n", 17 | "from matplotlib.pyplot import imshow\n", 18 | "%matplotlib inline " 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": null, 24 | "metadata": { 25 | "collapsed": false 26 | }, 27 | "outputs": [], 28 | "source": [ 29 | "synset = [l.strip() for l in open('synset.txt').readlines()]\n", 30 | "\n", 31 | "def load_image(path):\n", 32 | " img = skimage.io.imread(path)\n", 33 | " imshow(Image.open(path,'r'))\n", 34 | " img = img / 255.0\n", 35 | " assert (0 <= img).all() and (img <= 1.0).all()\n", 36 | " #crop image from center\n", 37 | " short_edge = min(img.shape[:2])\n", 38 | " yy = int((img.shape[0] - short_edge) / 2)\n", 39 | " xx = int((img.shape[1] - short_edge) / 2)\n", 40 | " crop_img = img[yy : yy + short_edge, xx : xx + short_edge]\n", 41 | " resized_img = skimage.transform.resize(crop_img, (299, 299))\n", 42 | " return resized_img\n", 43 | "\n", 44 | "def print_prob(prob):\n", 45 | " pred = np.argsort(prob)[::-1]\n", 46 | " top1 = synset[pred[0]-1]\n", 47 | " print \"Top Prediction\", top1\n", 48 | " top5 = map(synset.__getitem__, pred[:5]-1)\n", 49 | " print \"Top 5 Prediction: \", top5\n" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": null, 55 | "metadata": { 56 | "collapsed": false 57 | }, 58 | "outputs": [], 59 | "source": [ 60 | "with open('inception_v4.pb', 'rb') as f:\n", 61 | " fileContent = f.read()\n", 62 | "\n", 63 | "graph_def = tf.GraphDef()\n", 64 | "graph_def.ParseFromString(fileContent)\n", 65 | "tf.import_graph_def(graph_def)\n", 66 | "graph = tf.get_default_graph()\n", 67 | "tensors = [n.name for n in tf.get_default_graph().as_graph_def().node]\n", 68 | "print \"graph loaded from disk\"" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": null, 74 | "metadata": { 75 | "collapsed": false 76 | }, 77 | "outputs": [], 78 | "source": [ 79 | "batch_size=1\n", 80 | "def forward_pass(path):\n", 81 | " image = load_image(path)\n", 82 | " with tf.Session(graph=graph) as sess:\n", 83 | " batch = image.reshape((batch_size, 299, 299, 3))\n", 84 | " assert batch.shape == (batch_size, 299, 299, 3)\n", 85 | " feed_dict = {graph.get_tensor_by_name(\"import/InputImage:0\"): batch}\n", 86 | " prob_tensor = graph.get_tensor_by_name(\"import/InceptionV4/Logits/Predictions:0\")\n", 87 | " prob = sess.run(prob_tensor, feed_dict=feed_dict) #1001 shape vector\n", 88 | " print_prob(prob[0])\n", 89 | " return prob[0]" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": null, 95 | "metadata": { 96 | "collapsed": false 97 | }, 98 | "outputs": [], 99 | "source": [ 100 | "forward_pass(\"/home/pranay360/Image_Captioning/Images/dog2.jpg\")" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": null, 106 | "metadata": { 107 | "collapsed": true 108 | }, 109 | "outputs": [], 110 | "source": [ 111 | "[ 3.99079763e-05, 2.55644027e-05, 6.72903116e-05, ...,\n", 112 | " 1.43715179e-05, 3.42611565e-05, 1.49928219e-05]\n", 113 | "[ 3.99079763e-05, 2.55644027e-05, 6.72903116e-05, ...,\n", 114 | " 1.43715179e-05, 3.42611565e-05, 1.49928219e-05]" 115 | ] 116 | }, 117 | { 118 | "cell_type": "code", 119 | "execution_count": null, 120 | "metadata": { 121 | "collapsed": false 122 | }, 123 | "outputs": [], 124 | "source": [ 125 | "for ten in tensors[::-1][:100]:\n", 126 | " print ten, graph.get_tensor_by_name(ten+\":0\").get_shape()" 127 | ] 128 | } 129 | ], 130 | "metadata": { 131 | "anaconda-cloud": {}, 132 | "kernelspec": { 133 | "display_name": "Python [conda root]", 134 | "language": "python", 135 | "name": "conda-root-py" 136 | }, 137 | "language_info": { 138 | "codemirror_mode": { 139 | "name": "ipython", 140 | "version": 2 141 | }, 142 | "file_extension": ".py", 143 | "mimetype": "text/x-python", 144 | "name": "python", 145 | "nbconvert_exporter": "python", 146 | "pygments_lexer": "ipython2", 147 | "version": "2.7.12" 148 | } 149 | }, 150 | "nbformat": 4, 151 | "nbformat_minor": 2 152 | } 153 | -------------------------------------------------------------------------------- /ConvNets/ImageNet-VGG.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [ 10 | { 11 | "name": "stderr", 12 | "output_type": "stream", 13 | "text": [ 14 | "/home/pranay360/anaconda2/envs/tensorflow/lib/python2.7/site-packages/matplotlib/font_manager.py:273: UserWarning: Matplotlib is building the font cache using fc-list. This may take a moment.\n", 15 | " warnings.warn('Matplotlib is building the font cache using fc-list. This may take a moment.')\n" 16 | ] 17 | } 18 | ], 19 | "source": [ 20 | "import tensorflow as tf\n", 21 | "from PIL import Image \n", 22 | "import numpy as np\n", 23 | "import skimage\n", 24 | "import skimage.io\n", 25 | "import skimage.transform\n", 26 | "from matplotlib.pyplot import imshow\n", 27 | "%matplotlib inline " 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": 2, 33 | "metadata": { 34 | "collapsed": false 35 | }, 36 | "outputs": [], 37 | "source": [ 38 | "synset = [l.strip() for l in open('synset.txt').readlines()]\n", 39 | "\n", 40 | "def load_image(path):\n", 41 | " img = skimage.io.imread(path)\n", 42 | " imshow(Image.open(path,'r'))\n", 43 | " img = img / 255.0\n", 44 | " assert (0 <= img).all() and (img <= 1.0).all()\n", 45 | " #crop image from center\n", 46 | " short_edge = min(img.shape[:2])\n", 47 | " yy = int((img.shape[0] - short_edge) / 2)\n", 48 | " xx = int((img.shape[1] - short_edge) / 2)\n", 49 | " crop_img = img[yy : yy + short_edge, xx : xx + short_edge]\n", 50 | " resized_img = skimage.transform.resize(crop_img, (224, 224))\n", 51 | " return resized_img\n", 52 | "\n", 53 | "def print_prob(prob):\n", 54 | " pred = np.argsort(prob)[::-1]\n", 55 | " top1 = synset[pred[0]]\n", 56 | " print \"Top Prediction\", top1\n", 57 | " top5 = map(synset.__getitem__, pred[:5])\n", 58 | " print \"Top 5 Prediction: \", top5\n" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 3, 64 | "metadata": { 65 | "collapsed": false 66 | }, 67 | "outputs": [ 68 | { 69 | "name": "stdout", 70 | "output_type": "stream", 71 | "text": [ 72 | "graph loaded from disk\n" 73 | ] 74 | } 75 | ], 76 | "source": [ 77 | "with open('vgg16-20160129.tfmodel', 'rb') as f:\n", 78 | " fileContent = f.read()\n", 79 | "\n", 80 | "graph_def = tf.GraphDef()\n", 81 | "graph_def.ParseFromString(fileContent)\n", 82 | "tf.import_graph_def(graph_def)\n", 83 | "graph = tf.get_default_graph()\n", 84 | "tensors = [n.name for n in tf.get_default_graph().as_graph_def().node]\n", 85 | "print \"graph loaded from disk\"" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 4, 91 | "metadata": { 92 | "collapsed": false 93 | }, 94 | "outputs": [], 95 | "source": [ 96 | "batch_size=1\n", 97 | "def forward_pass(path):\n", 98 | " image = load_image(path)\n", 99 | " with tf.Session() as sess:\n", 100 | " init = tf.global_variables_initializer()\n", 101 | " sess.run(init)\n", 102 | " batch = image.reshape((batch_size, 224, 224, 3))\n", 103 | " assert batch.shape == (batch_size, 224, 224, 3)\n", 104 | " feed_dict = {graph.get_tensor_by_name(\"import/images:0\"): batch}\n", 105 | " prob_tensor = graph.get_tensor_by_name(\"import/prob:0\") #1000 shape vector\n", 106 | " prob = sess.run(prob_tensor, feed_dict=feed_dict)\n", 107 | " \n", 108 | " print_prob(prob[0])" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 5, 114 | "metadata": { 115 | "collapsed": false 116 | }, 117 | "outputs": [ 118 | { 119 | "name": "stdout", 120 | "output_type": "stream", 121 | "text": [ 122 | "Top Prediction n02087046 toy terrier\n", 123 | "Top 5 Prediction: ['n02087046 toy terrier', 'n02107142 Doberman, Doberman pinscher', 'n02107312 miniature pinscher', 'n02089078 black-and-tan coonhound', 'n02106550 Rottweiler']\n" 124 | ] 125 | }, 126 | { 127 | "data": { 128 | "image/png": "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\n", 129 | "text/plain": [ 130 | "" 131 | ] 132 | }, 133 | "metadata": {}, 134 | "output_type": "display_data" 135 | } 136 | ], 137 | "source": [ 138 | "forward_pass(\"/home/pranay360/Image_Captioning/Images/dog2.jpg\")" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 6, 144 | "metadata": { 145 | "collapsed": false 146 | }, 147 | "outputs": [ 148 | { 149 | "name": "stdout", 150 | "output_type": "stream", 151 | "text": [ 152 | "import/prob (?, 1000)\n", 153 | "import/fc8/BiasAdd (?, 1000)\n", 154 | "import/fc8/MatMul (?, 1000)\n", 155 | "import/fc8/bias (1000,)\n", 156 | "import/fc8/weight (4096, 1000)\n", 157 | "import/fc8/Reshape (?, 4096)\n", 158 | "import/fc8/Reshape/shape (2,)\n", 159 | "import/Relu_1 (?, 4096)\n", 160 | "import/fc7/BiasAdd (?, 4096)\n", 161 | "import/fc7/MatMul (?, 4096)\n", 162 | "import/fc7/bias (4096,)\n", 163 | "import/fc7/weight (4096, 4096)\n", 164 | "import/fc7/Reshape (?, 4096)\n", 165 | "import/fc7/Reshape/shape (2,)\n", 166 | "import/Relu (?, 4096)\n", 167 | "import/fc6/BiasAdd (?, 4096)\n", 168 | "import/fc6/MatMul (?, 4096)\n", 169 | "import/fc6/bias (4096,)\n", 170 | "import/fc6/weight (25088, 4096)\n", 171 | "import/fc6/Reshape (?, 25088)\n", 172 | "import/fc6/Reshape/shape (2,)\n", 173 | "import/pool5 (?, ?, ?, 512)\n", 174 | "import/conv5_3/Relu (?, ?, ?, 512)\n", 175 | "import/conv5_3/BiasAdd (?, ?, ?, 512)\n", 176 | "import/conv5_3/bias (512,)\n", 177 | "import/conv5_3/Conv2D (?, ?, ?, 512)\n", 178 | "import/conv5_3/filter (3, 3, 512, 512)\n", 179 | "import/conv5_2/Relu (?, ?, ?, 512)\n", 180 | "import/conv5_2/BiasAdd (?, ?, ?, 512)\n", 181 | "import/conv5_2/bias (512,)\n", 182 | "import/conv5_2/Conv2D (?, ?, ?, 512)\n", 183 | "import/conv5_2/filter (3, 3, 512, 512)\n", 184 | "import/conv5_1/Relu (?, ?, ?, 512)\n", 185 | "import/conv5_1/BiasAdd (?, ?, ?, 512)\n", 186 | "import/conv5_1/bias (512,)\n", 187 | "import/conv5_1/Conv2D (?, ?, ?, 512)\n", 188 | "import/conv5_1/filter (3, 3, 512, 512)\n", 189 | "import/pool4 (?, ?, ?, 512)\n", 190 | "import/conv4_3/Relu (?, ?, ?, 512)\n", 191 | "import/conv4_3/BiasAdd (?, ?, ?, 512)\n", 192 | "import/conv4_3/bias (512,)\n", 193 | "import/conv4_3/Conv2D (?, ?, ?, 512)\n", 194 | "import/conv4_3/filter (3, 3, 512, 512)\n", 195 | "import/conv4_2/Relu (?, ?, ?, 512)\n", 196 | "import/conv4_2/BiasAdd (?, ?, ?, 512)\n", 197 | "import/conv4_2/bias (512,)\n", 198 | "import/conv4_2/Conv2D (?, ?, ?, 512)\n", 199 | "import/conv4_2/filter (3, 3, 512, 512)\n", 200 | "import/conv4_1/Relu (?, ?, ?, 512)\n", 201 | "import/conv4_1/BiasAdd (?, ?, ?, 512)\n", 202 | "import/conv4_1/bias (512,)\n", 203 | "import/conv4_1/Conv2D (?, ?, ?, 512)\n", 204 | "import/conv4_1/filter (3, 3, 256, 512)\n", 205 | "import/pool3 (?, ?, ?, 256)\n", 206 | "import/conv3_3/Relu (?, ?, ?, 256)\n", 207 | "import/conv3_3/BiasAdd (?, ?, ?, 256)\n", 208 | "import/conv3_3/bias (256,)\n", 209 | "import/conv3_3/Conv2D (?, ?, ?, 256)\n", 210 | "import/conv3_3/filter (3, 3, 256, 256)\n", 211 | "import/conv3_2/Relu (?, ?, ?, 256)\n", 212 | "import/conv3_2/BiasAdd (?, ?, ?, 256)\n", 213 | "import/conv3_2/bias (256,)\n", 214 | "import/conv3_2/Conv2D (?, ?, ?, 256)\n", 215 | "import/conv3_2/filter (3, 3, 256, 256)\n", 216 | "import/conv3_1/Relu (?, ?, ?, 256)\n", 217 | "import/conv3_1/BiasAdd (?, ?, ?, 256)\n", 218 | "import/conv3_1/bias (256,)\n", 219 | "import/conv3_1/Conv2D (?, ?, ?, 256)\n", 220 | "import/conv3_1/filter (3, 3, 128, 256)\n", 221 | "import/pool2 (?, ?, ?, 128)\n", 222 | "import/conv2_2/Relu (?, ?, ?, 128)\n", 223 | "import/conv2_2/BiasAdd (?, ?, ?, 128)\n", 224 | "import/conv2_2/bias (128,)\n", 225 | "import/conv2_2/Conv2D (?, ?, ?, 128)\n", 226 | "import/conv2_2/filter (3, 3, 128, 128)\n", 227 | "import/conv2_1/Relu (?, ?, ?, 128)\n", 228 | "import/conv2_1/BiasAdd (?, ?, ?, 128)\n", 229 | "import/conv2_1/bias (128,)\n", 230 | "import/conv2_1/Conv2D (?, ?, ?, 128)\n", 231 | "import/conv2_1/filter (3, 3, 64, 128)\n", 232 | "import/pool1 (?, ?, ?, 64)\n", 233 | "import/conv1_2/Relu (?, ?, ?, 64)\n", 234 | "import/conv1_2/BiasAdd (?, ?, ?, 64)\n", 235 | "import/conv1_2/bias (64,)\n", 236 | "import/conv1_2/Conv2D (?, ?, ?, 64)\n", 237 | "import/conv1_2/filter (3, 3, 64, 64)\n", 238 | "import/conv1_1/Relu (?, ?, ?, 64)\n", 239 | "import/conv1_1/BiasAdd (?, ?, ?, 64)\n", 240 | "import/conv1_1/bias (64,)\n", 241 | "import/conv1_1/Conv2D (?, ?, ?, 64)\n", 242 | "import/conv1_1/filter (3, 3, 3, 64)\n", 243 | "import/concat \n", 244 | "import/concat/concat_dim ()\n", 245 | "import/sub_2 \n", 246 | "import/sub_2/y ()\n", 247 | "import/sub_1 \n", 248 | "import/sub_1/y ()\n", 249 | "import/sub \n", 250 | "import/sub/y ()\n", 251 | "import/split \n", 252 | "import/split/split_dim ()\n", 253 | "import/mul \n", 254 | "import/mul/y ()\n", 255 | "import/images \n" 256 | ] 257 | } 258 | ], 259 | "source": [ 260 | "for ten in tensors[::-1][1:]:\n", 261 | " print ten, graph.get_tensor_by_name(ten+\":0\").get_shape()" 262 | ] 263 | } 264 | ], 265 | "metadata": { 266 | "anaconda-cloud": {}, 267 | "kernelspec": { 268 | "display_name": "Python [conda env:tensorflow]", 269 | "language": "python", 270 | "name": "conda-env-tensorflow-py" 271 | }, 272 | "language_info": { 273 | "codemirror_mode": { 274 | "name": "ipython", 275 | "version": 2 276 | }, 277 | "file_extension": ".py", 278 | "mimetype": "text/x-python", 279 | "name": "python", 280 | "nbconvert_exporter": "python", 281 | "pygments_lexer": "ipython2", 282 | "version": "2.7.12" 283 | } 284 | }, 285 | "nbformat": 4, 286 | "nbformat_minor": 2 287 | } 288 | -------------------------------------------------------------------------------- /ConvNets/README.md: -------------------------------------------------------------------------------- 1 | Put inception_v4.pb file here 2 | -------------------------------------------------------------------------------- /ConvNets/VGG.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from PIL import Image 3 | import numpy as np 4 | import skimage 5 | import skimage.io 6 | import skimage.transform 7 | import os 8 | import matplotlib.pyplot as plt 9 | 10 | img_path = "Dataset/flickr30k-images/" 11 | files = sorted(np.array(os.listdir("Dataset/flickr30k-images/"))) 12 | 13 | batch_size = 10 14 | n_batch = len(files) / batch_size 15 | 16 | with open('CNNs/vgg16.pb', 'rb') as f: 17 | fileContent = f.read() 18 | 19 | graph_def = tf.GraphDef() 20 | graph_def.ParseFromString(fileContent) 21 | tf.import_graph_def(graph_def) 22 | graph = tf.get_default_graph() 23 | tensors = [n.name for n in tf.get_default_graph().as_graph_def().node] 24 | print "graph loaded from disk\n\n" 25 | 26 | 27 | def load_image(path): 28 | img = skimage.io.imread(path) 29 | #fig = plt.figure() 30 | # a=fig.add_subplot(1,2,1) 31 | # x=skimage.io.imshow(img) 32 | # a.set_title('Before') 33 | # print img.shape 34 | img = img / 255.0 35 | assert (0 <= img).all() and (img <= 1.0).all() 36 | short_edge = min(img.shape[:2]) 37 | yy = int((img.shape[0] - short_edge) / 2) 38 | xx = int((img.shape[1] - short_edge) / 2) 39 | crop_img = img[yy: yy + short_edge, xx: xx + short_edge] 40 | resized_img = skimage.transform.resize(crop_img, (224, 224, 3)) 41 | # a=fig.add_subplot(1,2,2) 42 | # skimage.io.imshow(resized_img) 43 | # x.set_clim(0.0,0.7) 44 | # a.set_title('After') 45 | # plt.show() 46 | return resized_img 47 | 48 | 49 | def load_next_batch(): 50 | for batch_idx in range(0, len(files), batch_size): 51 | batch = files[batch_idx:batch_idx + batch_size] 52 | batch = np.array(map(lambda x: load_image(img_path + x), batch)) 53 | batch = batch.reshape((batch_size, 224, 224, 3)) 54 | yield batch 55 | 56 | 57 | def forward_pass(): 58 | with tf.Session() as sess: 59 | init = tf.global_variables_initializer() 60 | sess.run(init) 61 | batch_iter = load_next_batch() 62 | for i in xrange(n_batch): 63 | batch = batch_iter.next() 64 | assert batch.shape == (batch_size, 224, 224, 3) 65 | feed_dict = {graph.get_tensor_by_name( 66 | "import/images:0"): batch} 67 | prob_tensor = graph.get_tensor_by_name( 68 | "import/conv5_3/Relu:0") 69 | if i is 40: 70 | break 71 | if i is 0: 72 | prob = sess.run(prob_tensor, feed_dict=feed_dict).reshape(-1, 196, 512).swapaxes(1,2) 73 | else: 74 | prob = np.append(prob, sess.run(prob_tensor, feed_dict=feed_dict).reshape(-1, 196, 512).swapaxes(1,2), axis=0) 75 | if i % 500 == 0: 76 | print "Progress:" + str(((i + 1) / float(n_batch) * 100)) + "%\n" 77 | print "Progress:" + str(((n_batch) / float(n_batch) * 100)) + "%\n" 78 | print 79 | print "Saving Features : featuresVGG.npy\n" 80 | np.save('Dataset/featuresVGG', prob) 81 | 82 | 83 | def get_features(path): 84 | image = load_image(path) 85 | with tf.Session() as sess: 86 | init = tf.global_variables_initializer() 87 | sess.run(init) 88 | image = image.reshape((1, 224, 224, 3)) 89 | assert image.shape == (1, 224, 224, 3) 90 | feed_dict = {graph.get_tensor_by_name("import/InputImage:0"): image} 91 | prob_tensor = graph.get_tensor_by_name( 92 | "import/InceptionV4/Logits/AvgPool_1a/AvgPool:0") 93 | prob = sess.run(prob_tensor, feed_dict=feed_dict) 94 | return prob 95 | 96 | if __name__ == "__main__": 97 | print "#Images:", len(files) 98 | print "Extracting Features" 99 | forward_pass() 100 | print "done" 101 | -------------------------------------------------------------------------------- /ConvNets/synset.txt: -------------------------------------------------------------------------------- 1 | n01440764 tench, Tinca tinca 2 | n01443537 goldfish, Carassius auratus 3 | n01484850 great white shark, white shark, man-eater, man-eating shark, Carcharodon carcharias 4 | n01491361 tiger shark, Galeocerdo cuvieri 5 | n01494475 hammerhead, hammerhead shark 6 | n01496331 electric ray, crampfish, numbfish, torpedo 7 | n01498041 stingray 8 | n01514668 cock 9 | n01514859 hen 10 | n01518878 ostrich, Struthio camelus 11 | n01530575 brambling, Fringilla montifringilla 12 | n01531178 goldfinch, Carduelis carduelis 13 | n01532829 house finch, linnet, Carpodacus mexicanus 14 | n01534433 junco, snowbird 15 | n01537544 indigo bunting, indigo finch, indigo bird, Passerina cyanea 16 | n01558993 robin, American robin, Turdus migratorius 17 | n01560419 bulbul 18 | n01580077 jay 19 | n01582220 magpie 20 | n01592084 chickadee 21 | n01601694 water ouzel, dipper 22 | n01608432 kite 23 | n01614925 bald eagle, American eagle, Haliaeetus leucocephalus 24 | n01616318 vulture 25 | n01622779 great grey owl, great gray owl, Strix nebulosa 26 | n01629819 European fire salamander, Salamandra salamandra 27 | n01630670 common newt, Triturus vulgaris 28 | n01631663 eft 29 | n01632458 spotted salamander, Ambystoma maculatum 30 | n01632777 axolotl, mud puppy, Ambystoma mexicanum 31 | n01641577 bullfrog, Rana catesbeiana 32 | n01644373 tree frog, tree-frog 33 | n01644900 tailed frog, bell toad, ribbed toad, tailed toad, Ascaphus trui 34 | n01664065 loggerhead, loggerhead turtle, Caretta caretta 35 | n01665541 leatherback turtle, leatherback, leathery turtle, Dermochelys coriacea 36 | n01667114 mud turtle 37 | n01667778 terrapin 38 | n01669191 box turtle, box tortoise 39 | n01675722 banded gecko 40 | n01677366 common iguana, iguana, Iguana iguana 41 | n01682714 American chameleon, anole, Anolis carolinensis 42 | n01685808 whiptail, whiptail lizard 43 | n01687978 agama 44 | n01688243 frilled lizard, Chlamydosaurus kingi 45 | n01689811 alligator lizard 46 | n01692333 Gila monster, Heloderma suspectum 47 | n01693334 green lizard, Lacerta viridis 48 | n01694178 African chameleon, Chamaeleo chamaeleon 49 | n01695060 Komodo dragon, Komodo lizard, dragon lizard, giant lizard, Varanus komodoensis 50 | n01697457 African crocodile, Nile crocodile, Crocodylus niloticus 51 | n01698640 American alligator, Alligator mississipiensis 52 | n01704323 triceratops 53 | n01728572 thunder snake, worm snake, Carphophis amoenus 54 | n01728920 ringneck snake, ring-necked snake, ring snake 55 | n01729322 hognose snake, puff adder, sand viper 56 | n01729977 green snake, grass snake 57 | n01734418 king snake, kingsnake 58 | n01735189 garter snake, grass snake 59 | n01737021 water snake 60 | n01739381 vine snake 61 | n01740131 night snake, Hypsiglena torquata 62 | n01742172 boa constrictor, Constrictor constrictor 63 | n01744401 rock python, rock snake, Python sebae 64 | n01748264 Indian cobra, Naja naja 65 | n01749939 green mamba 66 | n01751748 sea snake 67 | n01753488 horned viper, cerastes, sand viper, horned asp, Cerastes cornutus 68 | n01755581 diamondback, diamondback rattlesnake, Crotalus adamanteus 69 | n01756291 sidewinder, horned rattlesnake, Crotalus cerastes 70 | n01768244 trilobite 71 | n01770081 harvestman, daddy longlegs, Phalangium opilio 72 | n01770393 scorpion 73 | n01773157 black and gold garden spider, Argiope aurantia 74 | n01773549 barn spider, Araneus cavaticus 75 | n01773797 garden spider, Aranea diademata 76 | n01774384 black widow, Latrodectus mactans 77 | n01774750 tarantula 78 | n01775062 wolf spider, hunting spider 79 | n01776313 tick 80 | n01784675 centipede 81 | n01795545 black grouse 82 | n01796340 ptarmigan 83 | n01797886 ruffed grouse, partridge, Bonasa umbellus 84 | n01798484 prairie chicken, prairie grouse, prairie fowl 85 | n01806143 peacock 86 | n01806567 quail 87 | n01807496 partridge 88 | n01817953 African grey, African gray, Psittacus erithacus 89 | n01818515 macaw 90 | n01819313 sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita 91 | n01820546 lorikeet 92 | n01824575 coucal 93 | n01828970 bee eater 94 | n01829413 hornbill 95 | n01833805 hummingbird 96 | n01843065 jacamar 97 | n01843383 toucan 98 | n01847000 drake 99 | n01855032 red-breasted merganser, Mergus serrator 100 | n01855672 goose 101 | n01860187 black swan, Cygnus atratus 102 | n01871265 tusker 103 | n01872401 echidna, spiny anteater, anteater 104 | n01873310 platypus, duckbill, duckbilled platypus, duck-billed platypus, Ornithorhynchus anatinus 105 | n01877812 wallaby, brush kangaroo 106 | n01882714 koala, koala bear, kangaroo bear, native bear, Phascolarctos cinereus 107 | n01883070 wombat 108 | n01910747 jellyfish 109 | n01914609 sea anemone, anemone 110 | n01917289 brain coral 111 | n01924916 flatworm, platyhelminth 112 | n01930112 nematode, nematode worm, roundworm 113 | n01943899 conch 114 | n01944390 snail 115 | n01945685 slug 116 | n01950731 sea slug, nudibranch 117 | n01955084 chiton, coat-of-mail shell, sea cradle, polyplacophore 118 | n01968897 chambered nautilus, pearly nautilus, nautilus 119 | n01978287 Dungeness crab, Cancer magister 120 | n01978455 rock crab, Cancer irroratus 121 | n01980166 fiddler crab 122 | n01981276 king crab, Alaska crab, Alaskan king crab, Alaska king crab, Paralithodes camtschatica 123 | n01983481 American lobster, Northern lobster, Maine lobster, Homarus americanus 124 | n01984695 spiny lobster, langouste, rock lobster, crawfish, crayfish, sea crawfish 125 | n01985128 crayfish, crawfish, crawdad, crawdaddy 126 | n01986214 hermit crab 127 | n01990800 isopod 128 | n02002556 white stork, Ciconia ciconia 129 | n02002724 black stork, Ciconia nigra 130 | n02006656 spoonbill 131 | n02007558 flamingo 132 | n02009229 little blue heron, Egretta caerulea 133 | n02009912 American egret, great white heron, Egretta albus 134 | n02011460 bittern 135 | n02012849 crane 136 | n02013706 limpkin, Aramus pictus 137 | n02017213 European gallinule, Porphyrio porphyrio 138 | n02018207 American coot, marsh hen, mud hen, water hen, Fulica americana 139 | n02018795 bustard 140 | n02025239 ruddy turnstone, Arenaria interpres 141 | n02027492 red-backed sandpiper, dunlin, Erolia alpina 142 | n02028035 redshank, Tringa totanus 143 | n02033041 dowitcher 144 | n02037110 oystercatcher, oyster catcher 145 | n02051845 pelican 146 | n02056570 king penguin, Aptenodytes patagonica 147 | n02058221 albatross, mollymawk 148 | n02066245 grey whale, gray whale, devilfish, Eschrichtius gibbosus, Eschrichtius robustus 149 | n02071294 killer whale, killer, orca, grampus, sea wolf, Orcinus orca 150 | n02074367 dugong, Dugong dugon 151 | n02077923 sea lion 152 | n02085620 Chihuahua 153 | n02085782 Japanese spaniel 154 | n02085936 Maltese dog, Maltese terrier, Maltese 155 | n02086079 Pekinese, Pekingese, Peke 156 | n02086240 Shih-Tzu 157 | n02086646 Blenheim spaniel 158 | n02086910 papillon 159 | n02087046 toy terrier 160 | n02087394 Rhodesian ridgeback 161 | n02088094 Afghan hound, Afghan 162 | n02088238 basset, basset hound 163 | n02088364 beagle 164 | n02088466 bloodhound, sleuthhound 165 | n02088632 bluetick 166 | n02089078 black-and-tan coonhound 167 | n02089867 Walker hound, Walker foxhound 168 | n02089973 English foxhound 169 | n02090379 redbone 170 | n02090622 borzoi, Russian wolfhound 171 | n02090721 Irish wolfhound 172 | n02091032 Italian greyhound 173 | n02091134 whippet 174 | n02091244 Ibizan hound, Ibizan Podenco 175 | n02091467 Norwegian elkhound, elkhound 176 | n02091635 otterhound, otter hound 177 | n02091831 Saluki, gazelle hound 178 | n02092002 Scottish deerhound, deerhound 179 | n02092339 Weimaraner 180 | n02093256 Staffordshire bullterrier, Staffordshire bull terrier 181 | n02093428 American Staffordshire terrier, Staffordshire terrier, American pit bull terrier, pit bull terrier 182 | n02093647 Bedlington terrier 183 | n02093754 Border terrier 184 | n02093859 Kerry blue terrier 185 | n02093991 Irish terrier 186 | n02094114 Norfolk terrier 187 | n02094258 Norwich terrier 188 | n02094433 Yorkshire terrier 189 | n02095314 wire-haired fox terrier 190 | n02095570 Lakeland terrier 191 | n02095889 Sealyham terrier, Sealyham 192 | n02096051 Airedale, Airedale terrier 193 | n02096177 cairn, cairn terrier 194 | n02096294 Australian terrier 195 | n02096437 Dandie Dinmont, Dandie Dinmont terrier 196 | n02096585 Boston bull, Boston terrier 197 | n02097047 miniature schnauzer 198 | n02097130 giant schnauzer 199 | n02097209 standard schnauzer 200 | n02097298 Scotch terrier, Scottish terrier, Scottie 201 | n02097474 Tibetan terrier, chrysanthemum dog 202 | n02097658 silky terrier, Sydney silky 203 | n02098105 soft-coated wheaten terrier 204 | n02098286 West Highland white terrier 205 | n02098413 Lhasa, Lhasa apso 206 | n02099267 flat-coated retriever 207 | n02099429 curly-coated retriever 208 | n02099601 golden retriever 209 | n02099712 Labrador retriever 210 | n02099849 Chesapeake Bay retriever 211 | n02100236 German short-haired pointer 212 | n02100583 vizsla, Hungarian pointer 213 | n02100735 English setter 214 | n02100877 Irish setter, red setter 215 | n02101006 Gordon setter 216 | n02101388 Brittany spaniel 217 | n02101556 clumber, clumber spaniel 218 | n02102040 English springer, English springer spaniel 219 | n02102177 Welsh springer spaniel 220 | n02102318 cocker spaniel, English cocker spaniel, cocker 221 | n02102480 Sussex spaniel 222 | n02102973 Irish water spaniel 223 | n02104029 kuvasz 224 | n02104365 schipperke 225 | n02105056 groenendael 226 | n02105162 malinois 227 | n02105251 briard 228 | n02105412 kelpie 229 | n02105505 komondor 230 | n02105641 Old English sheepdog, bobtail 231 | n02105855 Shetland sheepdog, Shetland sheep dog, Shetland 232 | n02106030 collie 233 | n02106166 Border collie 234 | n02106382 Bouvier des Flandres, Bouviers des Flandres 235 | n02106550 Rottweiler 236 | n02106662 German shepherd, German shepherd dog, German police dog, alsatian 237 | n02107142 Doberman, Doberman pinscher 238 | n02107312 miniature pinscher 239 | n02107574 Greater Swiss Mountain dog 240 | n02107683 Bernese mountain dog 241 | n02107908 Appenzeller 242 | n02108000 EntleBucher 243 | n02108089 boxer 244 | n02108422 bull mastiff 245 | n02108551 Tibetan mastiff 246 | n02108915 French bulldog 247 | n02109047 Great Dane 248 | n02109525 Saint Bernard, St Bernard 249 | n02109961 Eskimo dog, husky 250 | n02110063 malamute, malemute, Alaskan malamute 251 | n02110185 Siberian husky 252 | n02110341 dalmatian, coach dog, carriage dog 253 | n02110627 affenpinscher, monkey pinscher, monkey dog 254 | n02110806 basenji 255 | n02110958 pug, pug-dog 256 | n02111129 Leonberg 257 | n02111277 Newfoundland, Newfoundland dog 258 | n02111500 Great Pyrenees 259 | n02111889 Samoyed, Samoyede 260 | n02112018 Pomeranian 261 | n02112137 chow, chow chow 262 | n02112350 keeshond 263 | n02112706 Brabancon griffon 264 | n02113023 Pembroke, Pembroke Welsh corgi 265 | n02113186 Cardigan, Cardigan Welsh corgi 266 | n02113624 toy poodle 267 | n02113712 miniature poodle 268 | n02113799 standard poodle 269 | n02113978 Mexican hairless 270 | n02114367 timber wolf, grey wolf, gray wolf, Canis lupus 271 | n02114548 white wolf, Arctic wolf, Canis lupus tundrarum 272 | n02114712 red wolf, maned wolf, Canis rufus, Canis niger 273 | n02114855 coyote, prairie wolf, brush wolf, Canis latrans 274 | n02115641 dingo, warrigal, warragal, Canis dingo 275 | n02115913 dhole, Cuon alpinus 276 | n02116738 African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus 277 | n02117135 hyena, hyaena 278 | n02119022 red fox, Vulpes vulpes 279 | n02119789 kit fox, Vulpes macrotis 280 | n02120079 Arctic fox, white fox, Alopex lagopus 281 | n02120505 grey fox, gray fox, Urocyon cinereoargenteus 282 | n02123045 tabby, tabby cat 283 | n02123159 tiger cat 284 | n02123394 Persian cat 285 | n02123597 Siamese cat, Siamese 286 | n02124075 Egyptian cat 287 | n02125311 cougar, puma, catamount, mountain lion, painter, panther, Felis concolor 288 | n02127052 lynx, catamount 289 | n02128385 leopard, Panthera pardus 290 | n02128757 snow leopard, ounce, Panthera uncia 291 | n02128925 jaguar, panther, Panthera onca, Felis onca 292 | n02129165 lion, king of beasts, Panthera leo 293 | n02129604 tiger, Panthera tigris 294 | n02130308 cheetah, chetah, Acinonyx jubatus 295 | n02132136 brown bear, bruin, Ursus arctos 296 | n02133161 American black bear, black bear, Ursus americanus, Euarctos americanus 297 | n02134084 ice bear, polar bear, Ursus Maritimus, Thalarctos maritimus 298 | n02134418 sloth bear, Melursus ursinus, Ursus ursinus 299 | n02137549 mongoose 300 | n02138441 meerkat, mierkat 301 | n02165105 tiger beetle 302 | n02165456 ladybug, ladybeetle, lady beetle, ladybird, ladybird beetle 303 | n02167151 ground beetle, carabid beetle 304 | n02168699 long-horned beetle, longicorn, longicorn beetle 305 | n02169497 leaf beetle, chrysomelid 306 | n02172182 dung beetle 307 | n02174001 rhinoceros beetle 308 | n02177972 weevil 309 | n02190166 fly 310 | n02206856 bee 311 | n02219486 ant, emmet, pismire 312 | n02226429 grasshopper, hopper 313 | n02229544 cricket 314 | n02231487 walking stick, walkingstick, stick insect 315 | n02233338 cockroach, roach 316 | n02236044 mantis, mantid 317 | n02256656 cicada, cicala 318 | n02259212 leafhopper 319 | n02264363 lacewing, lacewing fly 320 | n02268443 dragonfly, darning needle, devil's darning needle, sewing needle, snake feeder, snake doctor, mosquito hawk, skeeter hawk 321 | n02268853 damselfly 322 | n02276258 admiral 323 | n02277742 ringlet, ringlet butterfly 324 | n02279972 monarch, monarch butterfly, milkweed butterfly, Danaus plexippus 325 | n02280649 cabbage butterfly 326 | n02281406 sulphur butterfly, sulfur butterfly 327 | n02281787 lycaenid, lycaenid butterfly 328 | n02317335 starfish, sea star 329 | n02319095 sea urchin 330 | n02321529 sea cucumber, holothurian 331 | n02325366 wood rabbit, cottontail, cottontail rabbit 332 | n02326432 hare 333 | n02328150 Angora, Angora rabbit 334 | n02342885 hamster 335 | n02346627 porcupine, hedgehog 336 | n02356798 fox squirrel, eastern fox squirrel, Sciurus niger 337 | n02361337 marmot 338 | n02363005 beaver 339 | n02364673 guinea pig, Cavia cobaya 340 | n02389026 sorrel 341 | n02391049 zebra 342 | n02395406 hog, pig, grunter, squealer, Sus scrofa 343 | n02396427 wild boar, boar, Sus scrofa 344 | n02397096 warthog 345 | n02398521 hippopotamus, hippo, river horse, Hippopotamus amphibius 346 | n02403003 ox 347 | n02408429 water buffalo, water ox, Asiatic buffalo, Bubalus bubalis 348 | n02410509 bison 349 | n02412080 ram, tup 350 | n02415577 bighorn, bighorn sheep, cimarron, Rocky Mountain bighorn, Rocky Mountain sheep, Ovis canadensis 351 | n02417914 ibex, Capra ibex 352 | n02422106 hartebeest 353 | n02422699 impala, Aepyceros melampus 354 | n02423022 gazelle 355 | n02437312 Arabian camel, dromedary, Camelus dromedarius 356 | n02437616 llama 357 | n02441942 weasel 358 | n02442845 mink 359 | n02443114 polecat, fitch, foulmart, foumart, Mustela putorius 360 | n02443484 black-footed ferret, ferret, Mustela nigripes 361 | n02444819 otter 362 | n02445715 skunk, polecat, wood pussy 363 | n02447366 badger 364 | n02454379 armadillo 365 | n02457408 three-toed sloth, ai, Bradypus tridactylus 366 | n02480495 orangutan, orang, orangutang, Pongo pygmaeus 367 | n02480855 gorilla, Gorilla gorilla 368 | n02481823 chimpanzee, chimp, Pan troglodytes 369 | n02483362 gibbon, Hylobates lar 370 | n02483708 siamang, Hylobates syndactylus, Symphalangus syndactylus 371 | n02484975 guenon, guenon monkey 372 | n02486261 patas, hussar monkey, Erythrocebus patas 373 | n02486410 baboon 374 | n02487347 macaque 375 | n02488291 langur 376 | n02488702 colobus, colobus monkey 377 | n02489166 proboscis monkey, Nasalis larvatus 378 | n02490219 marmoset 379 | n02492035 capuchin, ringtail, Cebus capucinus 380 | n02492660 howler monkey, howler 381 | n02493509 titi, titi monkey 382 | n02493793 spider monkey, Ateles geoffroyi 383 | n02494079 squirrel monkey, Saimiri sciureus 384 | n02497673 Madagascar cat, ring-tailed lemur, Lemur catta 385 | n02500267 indri, indris, Indri indri, Indri brevicaudatus 386 | n02504013 Indian elephant, Elephas maximus 387 | n02504458 African elephant, Loxodonta africana 388 | n02509815 lesser panda, red panda, panda, bear cat, cat bear, Ailurus fulgens 389 | n02510455 giant panda, panda, panda bear, coon bear, Ailuropoda melanoleuca 390 | n02514041 barracouta, snoek 391 | n02526121 eel 392 | n02536864 coho, cohoe, coho salmon, blue jack, silver salmon, Oncorhynchus kisutch 393 | n02606052 rock beauty, Holocanthus tricolor 394 | n02607072 anemone fish 395 | n02640242 sturgeon 396 | n02641379 gar, garfish, garpike, billfish, Lepisosteus osseus 397 | n02643566 lionfish 398 | n02655020 puffer, pufferfish, blowfish, globefish 399 | n02666196 abacus 400 | n02667093 abaya 401 | n02669723 academic gown, academic robe, judge's robe 402 | n02672831 accordion, piano accordion, squeeze box 403 | n02676566 acoustic guitar 404 | n02687172 aircraft carrier, carrier, flattop, attack aircraft carrier 405 | n02690373 airliner 406 | n02692877 airship, dirigible 407 | n02699494 altar 408 | n02701002 ambulance 409 | n02704792 amphibian, amphibious vehicle 410 | n02708093 analog clock 411 | n02727426 apiary, bee house 412 | n02730930 apron 413 | n02747177 ashcan, trash can, garbage can, wastebin, ash bin, ash-bin, ashbin, dustbin, trash barrel, trash bin 414 | n02749479 assault rifle, assault gun 415 | n02769748 backpack, back pack, knapsack, packsack, rucksack, haversack 416 | n02776631 bakery, bakeshop, bakehouse 417 | n02777292 balance beam, beam 418 | n02782093 balloon 419 | n02783161 ballpoint, ballpoint pen, ballpen, Biro 420 | n02786058 Band Aid 421 | n02787622 banjo 422 | n02788148 bannister, banister, balustrade, balusters, handrail 423 | n02790996 barbell 424 | n02791124 barber chair 425 | n02791270 barbershop 426 | n02793495 barn 427 | n02794156 barometer 428 | n02795169 barrel, cask 429 | n02797295 barrow, garden cart, lawn cart, wheelbarrow 430 | n02799071 baseball 431 | n02802426 basketball 432 | n02804414 bassinet 433 | n02804610 bassoon 434 | n02807133 bathing cap, swimming cap 435 | n02808304 bath towel 436 | n02808440 bathtub, bathing tub, bath, tub 437 | n02814533 beach wagon, station wagon, wagon, estate car, beach waggon, station waggon, waggon 438 | n02814860 beacon, lighthouse, beacon light, pharos 439 | n02815834 beaker 440 | n02817516 bearskin, busby, shako 441 | n02823428 beer bottle 442 | n02823750 beer glass 443 | n02825657 bell cote, bell cot 444 | n02834397 bib 445 | n02835271 bicycle-built-for-two, tandem bicycle, tandem 446 | n02837789 bikini, two-piece 447 | n02840245 binder, ring-binder 448 | n02841315 binoculars, field glasses, opera glasses 449 | n02843684 birdhouse 450 | n02859443 boathouse 451 | n02860847 bobsled, bobsleigh, bob 452 | n02865351 bolo tie, bolo, bola tie, bola 453 | n02869837 bonnet, poke bonnet 454 | n02870880 bookcase 455 | n02871525 bookshop, bookstore, bookstall 456 | n02877765 bottlecap 457 | n02879718 bow 458 | n02883205 bow tie, bow-tie, bowtie 459 | n02892201 brass, memorial tablet, plaque 460 | n02892767 brassiere, bra, bandeau 461 | n02894605 breakwater, groin, groyne, mole, bulwark, seawall, jetty 462 | n02895154 breastplate, aegis, egis 463 | n02906734 broom 464 | n02909870 bucket, pail 465 | n02910353 buckle 466 | n02916936 bulletproof vest 467 | n02917067 bullet train, bullet 468 | n02927161 butcher shop, meat market 469 | n02930766 cab, hack, taxi, taxicab 470 | n02939185 caldron, cauldron 471 | n02948072 candle, taper, wax light 472 | n02950826 cannon 473 | n02951358 canoe 474 | n02951585 can opener, tin opener 475 | n02963159 cardigan 476 | n02965783 car mirror 477 | n02966193 carousel, carrousel, merry-go-round, roundabout, whirligig 478 | n02966687 carpenter's kit, tool kit 479 | n02971356 carton 480 | n02974003 car wheel 481 | n02977058 cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM 482 | n02978881 cassette 483 | n02979186 cassette player 484 | n02980441 castle 485 | n02981792 catamaran 486 | n02988304 CD player 487 | n02992211 cello, violoncello 488 | n02992529 cellular telephone, cellular phone, cellphone, cell, mobile phone 489 | n02999410 chain 490 | n03000134 chainlink fence 491 | n03000247 chain mail, ring mail, mail, chain armor, chain armour, ring armor, ring armour 492 | n03000684 chain saw, chainsaw 493 | n03014705 chest 494 | n03016953 chiffonier, commode 495 | n03017168 chime, bell, gong 496 | n03018349 china cabinet, china closet 497 | n03026506 Christmas stocking 498 | n03028079 church, church building 499 | n03032252 cinema, movie theater, movie theatre, movie house, picture palace 500 | n03041632 cleaver, meat cleaver, chopper 501 | n03042490 cliff dwelling 502 | n03045698 cloak 503 | n03047690 clog, geta, patten, sabot 504 | n03062245 cocktail shaker 505 | n03063599 coffee mug 506 | n03063689 coffeepot 507 | n03065424 coil, spiral, volute, whorl, helix 508 | n03075370 combination lock 509 | n03085013 computer keyboard, keypad 510 | n03089624 confectionery, confectionary, candy store 511 | n03095699 container ship, containership, container vessel 512 | n03100240 convertible 513 | n03109150 corkscrew, bottle screw 514 | n03110669 cornet, horn, trumpet, trump 515 | n03124043 cowboy boot 516 | n03124170 cowboy hat, ten-gallon hat 517 | n03125729 cradle 518 | n03126707 crane 519 | n03127747 crash helmet 520 | n03127925 crate 521 | n03131574 crib, cot 522 | n03133878 Crock Pot 523 | n03134739 croquet ball 524 | n03141823 crutch 525 | n03146219 cuirass 526 | n03160309 dam, dike, dyke 527 | n03179701 desk 528 | n03180011 desktop computer 529 | n03187595 dial telephone, dial phone 530 | n03188531 diaper, nappy, napkin 531 | n03196217 digital clock 532 | n03197337 digital watch 533 | n03201208 dining table, board 534 | n03207743 dishrag, dishcloth 535 | n03207941 dishwasher, dish washer, dishwashing machine 536 | n03208938 disk brake, disc brake 537 | n03216828 dock, dockage, docking facility 538 | n03218198 dogsled, dog sled, dog sleigh 539 | n03220513 dome 540 | n03223299 doormat, welcome mat 541 | n03240683 drilling platform, offshore rig 542 | n03249569 drum, membranophone, tympan 543 | n03250847 drumstick 544 | n03255030 dumbbell 545 | n03259280 Dutch oven 546 | n03271574 electric fan, blower 547 | n03272010 electric guitar 548 | n03272562 electric locomotive 549 | n03290653 entertainment center 550 | n03291819 envelope 551 | n03297495 espresso maker 552 | n03314780 face powder 553 | n03325584 feather boa, boa 554 | n03337140 file, file cabinet, filing cabinet 555 | n03344393 fireboat 556 | n03345487 fire engine, fire truck 557 | n03347037 fire screen, fireguard 558 | n03355925 flagpole, flagstaff 559 | n03372029 flute, transverse flute 560 | n03376595 folding chair 561 | n03379051 football helmet 562 | n03384352 forklift 563 | n03388043 fountain 564 | n03388183 fountain pen 565 | n03388549 four-poster 566 | n03393912 freight car 567 | n03394916 French horn, horn 568 | n03400231 frying pan, frypan, skillet 569 | n03404251 fur coat 570 | n03417042 garbage truck, dustcart 571 | n03424325 gasmask, respirator, gas helmet 572 | n03425413 gas pump, gasoline pump, petrol pump, island dispenser 573 | n03443371 goblet 574 | n03444034 go-kart 575 | n03445777 golf ball 576 | n03445924 golfcart, golf cart 577 | n03447447 gondola 578 | n03447721 gong, tam-tam 579 | n03450230 gown 580 | n03452741 grand piano, grand 581 | n03457902 greenhouse, nursery, glasshouse 582 | n03459775 grille, radiator grille 583 | n03461385 grocery store, grocery, food market, market 584 | n03467068 guillotine 585 | n03476684 hair slide 586 | n03476991 hair spray 587 | n03478589 half track 588 | n03481172 hammer 589 | n03482405 hamper 590 | n03483316 hand blower, blow dryer, blow drier, hair dryer, hair drier 591 | n03485407 hand-held computer, hand-held microcomputer 592 | n03485794 handkerchief, hankie, hanky, hankey 593 | n03492542 hard disc, hard disk, fixed disk 594 | n03494278 harmonica, mouth organ, harp, mouth harp 595 | n03495258 harp 596 | n03496892 harvester, reaper 597 | n03498962 hatchet 598 | n03527444 holster 599 | n03529860 home theater, home theatre 600 | n03530642 honeycomb 601 | n03532672 hook, claw 602 | n03534580 hoopskirt, crinoline 603 | n03535780 horizontal bar, high bar 604 | n03538406 horse cart, horse-cart 605 | n03544143 hourglass 606 | n03584254 iPod 607 | n03584829 iron, smoothing iron 608 | n03590841 jack-o'-lantern 609 | n03594734 jean, blue jean, denim 610 | n03594945 jeep, landrover 611 | n03595614 jersey, T-shirt, tee shirt 612 | n03598930 jigsaw puzzle 613 | n03599486 jinrikisha, ricksha, rickshaw 614 | n03602883 joystick 615 | n03617480 kimono 616 | n03623198 knee pad 617 | n03627232 knot 618 | n03630383 lab coat, laboratory coat 619 | n03633091 ladle 620 | n03637318 lampshade, lamp shade 621 | n03642806 laptop, laptop computer 622 | n03649909 lawn mower, mower 623 | n03657121 lens cap, lens cover 624 | n03658185 letter opener, paper knife, paperknife 625 | n03661043 library 626 | n03662601 lifeboat 627 | n03666591 lighter, light, igniter, ignitor 628 | n03670208 limousine, limo 629 | n03673027 liner, ocean liner 630 | n03676483 lipstick, lip rouge 631 | n03680355 Loafer 632 | n03690938 lotion 633 | n03691459 loudspeaker, speaker, speaker unit, loudspeaker system, speaker system 634 | n03692522 loupe, jeweler's loupe 635 | n03697007 lumbermill, sawmill 636 | n03706229 magnetic compass 637 | n03709823 mailbag, postbag 638 | n03710193 mailbox, letter box 639 | n03710637 maillot 640 | n03710721 maillot, tank suit 641 | n03717622 manhole cover 642 | n03720891 maraca 643 | n03721384 marimba, xylophone 644 | n03724870 mask 645 | n03729826 matchstick 646 | n03733131 maypole 647 | n03733281 maze, labyrinth 648 | n03733805 measuring cup 649 | n03742115 medicine chest, medicine cabinet 650 | n03743016 megalith, megalithic structure 651 | n03759954 microphone, mike 652 | n03761084 microwave, microwave oven 653 | n03763968 military uniform 654 | n03764736 milk can 655 | n03769881 minibus 656 | n03770439 miniskirt, mini 657 | n03770679 minivan 658 | n03773504 missile 659 | n03775071 mitten 660 | n03775546 mixing bowl 661 | n03776460 mobile home, manufactured home 662 | n03777568 Model T 663 | n03777754 modem 664 | n03781244 monastery 665 | n03782006 monitor 666 | n03785016 moped 667 | n03786901 mortar 668 | n03787032 mortarboard 669 | n03788195 mosque 670 | n03788365 mosquito net 671 | n03791053 motor scooter, scooter 672 | n03792782 mountain bike, all-terrain bike, off-roader 673 | n03792972 mountain tent 674 | n03793489 mouse, computer mouse 675 | n03794056 mousetrap 676 | n03796401 moving van 677 | n03803284 muzzle 678 | n03804744 nail 679 | n03814639 neck brace 680 | n03814906 necklace 681 | n03825788 nipple 682 | n03832673 notebook, notebook computer 683 | n03837869 obelisk 684 | n03838899 oboe, hautboy, hautbois 685 | n03840681 ocarina, sweet potato 686 | n03841143 odometer, hodometer, mileometer, milometer 687 | n03843555 oil filter 688 | n03854065 organ, pipe organ 689 | n03857828 oscilloscope, scope, cathode-ray oscilloscope, CRO 690 | n03866082 overskirt 691 | n03868242 oxcart 692 | n03868863 oxygen mask 693 | n03871628 packet 694 | n03873416 paddle, boat paddle 695 | n03874293 paddlewheel, paddle wheel 696 | n03874599 padlock 697 | n03876231 paintbrush 698 | n03877472 pajama, pyjama, pj's, jammies 699 | n03877845 palace 700 | n03884397 panpipe, pandean pipe, syrinx 701 | n03887697 paper towel 702 | n03888257 parachute, chute 703 | n03888605 parallel bars, bars 704 | n03891251 park bench 705 | n03891332 parking meter 706 | n03895866 passenger car, coach, carriage 707 | n03899768 patio, terrace 708 | n03902125 pay-phone, pay-station 709 | n03903868 pedestal, plinth, footstall 710 | n03908618 pencil box, pencil case 711 | n03908714 pencil sharpener 712 | n03916031 perfume, essence 713 | n03920288 Petri dish 714 | n03924679 photocopier 715 | n03929660 pick, plectrum, plectron 716 | n03929855 pickelhaube 717 | n03930313 picket fence, paling 718 | n03930630 pickup, pickup truck 719 | n03933933 pier 720 | n03935335 piggy bank, penny bank 721 | n03937543 pill bottle 722 | n03938244 pillow 723 | n03942813 ping-pong ball 724 | n03944341 pinwheel 725 | n03947888 pirate, pirate ship 726 | n03950228 pitcher, ewer 727 | n03954731 plane, carpenter's plane, woodworking plane 728 | n03956157 planetarium 729 | n03958227 plastic bag 730 | n03961711 plate rack 731 | n03967562 plow, plough 732 | n03970156 plunger, plumber's helper 733 | n03976467 Polaroid camera, Polaroid Land camera 734 | n03976657 pole 735 | n03977966 police van, police wagon, paddy wagon, patrol wagon, wagon, black Maria 736 | n03980874 poncho 737 | n03982430 pool table, billiard table, snooker table 738 | n03983396 pop bottle, soda bottle 739 | n03991062 pot, flowerpot 740 | n03992509 potter's wheel 741 | n03995372 power drill 742 | n03998194 prayer rug, prayer mat 743 | n04004767 printer 744 | n04005630 prison, prison house 745 | n04008634 projectile, missile 746 | n04009552 projector 747 | n04019541 puck, hockey puck 748 | n04023962 punching bag, punch bag, punching ball, punchball 749 | n04026417 purse 750 | n04033901 quill, quill pen 751 | n04033995 quilt, comforter, comfort, puff 752 | n04037443 racer, race car, racing car 753 | n04039381 racket, racquet 754 | n04040759 radiator 755 | n04041544 radio, wireless 756 | n04044716 radio telescope, radio reflector 757 | n04049303 rain barrel 758 | n04065272 recreational vehicle, RV, R.V. 759 | n04067472 reel 760 | n04069434 reflex camera 761 | n04070727 refrigerator, icebox 762 | n04074963 remote control, remote 763 | n04081281 restaurant, eating house, eating place, eatery 764 | n04086273 revolver, six-gun, six-shooter 765 | n04090263 rifle 766 | n04099969 rocking chair, rocker 767 | n04111531 rotisserie 768 | n04116512 rubber eraser, rubber, pencil eraser 769 | n04118538 rugby ball 770 | n04118776 rule, ruler 771 | n04120489 running shoe 772 | n04125021 safe 773 | n04127249 safety pin 774 | n04131690 saltshaker, salt shaker 775 | n04133789 sandal 776 | n04136333 sarong 777 | n04141076 sax, saxophone 778 | n04141327 scabbard 779 | n04141975 scale, weighing machine 780 | n04146614 school bus 781 | n04147183 schooner 782 | n04149813 scoreboard 783 | n04152593 screen, CRT screen 784 | n04153751 screw 785 | n04154565 screwdriver 786 | n04162706 seat belt, seatbelt 787 | n04179913 sewing machine 788 | n04192698 shield, buckler 789 | n04200800 shoe shop, shoe-shop, shoe store 790 | n04201297 shoji 791 | n04204238 shopping basket 792 | n04204347 shopping cart 793 | n04208210 shovel 794 | n04209133 shower cap 795 | n04209239 shower curtain 796 | n04228054 ski 797 | n04229816 ski mask 798 | n04235860 sleeping bag 799 | n04238763 slide rule, slipstick 800 | n04239074 sliding door 801 | n04243546 slot, one-armed bandit 802 | n04251144 snorkel 803 | n04252077 snowmobile 804 | n04252225 snowplow, snowplough 805 | n04254120 soap dispenser 806 | n04254680 soccer ball 807 | n04254777 sock 808 | n04258138 solar dish, solar collector, solar furnace 809 | n04259630 sombrero 810 | n04263257 soup bowl 811 | n04264628 space bar 812 | n04265275 space heater 813 | n04266014 space shuttle 814 | n04270147 spatula 815 | n04273569 speedboat 816 | n04275548 spider web, spider's web 817 | n04277352 spindle 818 | n04285008 sports car, sport car 819 | n04286575 spotlight, spot 820 | n04296562 stage 821 | n04310018 steam locomotive 822 | n04311004 steel arch bridge 823 | n04311174 steel drum 824 | n04317175 stethoscope 825 | n04325704 stole 826 | n04326547 stone wall 827 | n04328186 stopwatch, stop watch 828 | n04330267 stove 829 | n04332243 strainer 830 | n04335435 streetcar, tram, tramcar, trolley, trolley car 831 | n04336792 stretcher 832 | n04344873 studio couch, day bed 833 | n04346328 stupa, tope 834 | n04347754 submarine, pigboat, sub, U-boat 835 | n04350905 suit, suit of clothes 836 | n04355338 sundial 837 | n04355933 sunglass 838 | n04356056 sunglasses, dark glasses, shades 839 | n04357314 sunscreen, sunblock, sun blocker 840 | n04366367 suspension bridge 841 | n04367480 swab, swob, mop 842 | n04370456 sweatshirt 843 | n04371430 swimming trunks, bathing trunks 844 | n04371774 swing 845 | n04372370 switch, electric switch, electrical switch 846 | n04376876 syringe 847 | n04380533 table lamp 848 | n04389033 tank, army tank, armored combat vehicle, armoured combat vehicle 849 | n04392985 tape player 850 | n04398044 teapot 851 | n04399382 teddy, teddy bear 852 | n04404412 television, television system 853 | n04409515 tennis ball 854 | n04417672 thatch, thatched roof 855 | n04418357 theater curtain, theatre curtain 856 | n04423845 thimble 857 | n04428191 thresher, thrasher, threshing machine 858 | n04429376 throne 859 | n04435653 tile roof 860 | n04442312 toaster 861 | n04443257 tobacco shop, tobacconist shop, tobacconist 862 | n04447861 toilet seat 863 | n04456115 torch 864 | n04458633 totem pole 865 | n04461696 tow truck, tow car, wrecker 866 | n04462240 toyshop 867 | n04465501 tractor 868 | n04467665 trailer truck, tractor trailer, trucking rig, rig, articulated lorry, semi 869 | n04476259 tray 870 | n04479046 trench coat 871 | n04482393 tricycle, trike, velocipede 872 | n04483307 trimaran 873 | n04485082 tripod 874 | n04486054 triumphal arch 875 | n04487081 trolleybus, trolley coach, trackless trolley 876 | n04487394 trombone 877 | n04493381 tub, vat 878 | n04501370 turnstile 879 | n04505470 typewriter keyboard 880 | n04507155 umbrella 881 | n04509417 unicycle, monocycle 882 | n04515003 upright, upright piano 883 | n04517823 vacuum, vacuum cleaner 884 | n04522168 vase 885 | n04523525 vault 886 | n04525038 velvet 887 | n04525305 vending machine 888 | n04532106 vestment 889 | n04532670 viaduct 890 | n04536866 violin, fiddle 891 | n04540053 volleyball 892 | n04542943 waffle iron 893 | n04548280 wall clock 894 | n04548362 wallet, billfold, notecase, pocketbook 895 | n04550184 wardrobe, closet, press 896 | n04552348 warplane, military plane 897 | n04553703 washbasin, handbasin, washbowl, lavabo, wash-hand basin 898 | n04554684 washer, automatic washer, washing machine 899 | n04557648 water bottle 900 | n04560804 water jug 901 | n04562935 water tower 902 | n04579145 whiskey jug 903 | n04579432 whistle 904 | n04584207 wig 905 | n04589890 window screen 906 | n04590129 window shade 907 | n04591157 Windsor tie 908 | n04591713 wine bottle 909 | n04592741 wing 910 | n04596742 wok 911 | n04597913 wooden spoon 912 | n04599235 wool, woolen, woollen 913 | n04604644 worm fence, snake fence, snake-rail fence, Virginia fence 914 | n04606251 wreck 915 | n04612504 yawl 916 | n04613696 yurt 917 | n06359193 web site, website, internet site, site 918 | n06596364 comic book 919 | n06785654 crossword puzzle, crossword 920 | n06794110 street sign 921 | n06874185 traffic light, traffic signal, stoplight 922 | n07248320 book jacket, dust cover, dust jacket, dust wrapper 923 | n07565083 menu 924 | n07579787 plate 925 | n07583066 guacamole 926 | n07584110 consomme 927 | n07590611 hot pot, hotpot 928 | n07613480 trifle 929 | n07614500 ice cream, icecream 930 | n07615774 ice lolly, lolly, lollipop, popsicle 931 | n07684084 French loaf 932 | n07693725 bagel, beigel 933 | n07695742 pretzel 934 | n07697313 cheeseburger 935 | n07697537 hotdog, hot dog, red hot 936 | n07711569 mashed potato 937 | n07714571 head cabbage 938 | n07714990 broccoli 939 | n07715103 cauliflower 940 | n07716358 zucchini, courgette 941 | n07716906 spaghetti squash 942 | n07717410 acorn squash 943 | n07717556 butternut squash 944 | n07718472 cucumber, cuke 945 | n07718747 artichoke, globe artichoke 946 | n07720875 bell pepper 947 | n07730033 cardoon 948 | n07734744 mushroom 949 | n07742313 Granny Smith 950 | n07745940 strawberry 951 | n07747607 orange 952 | n07749582 lemon 953 | n07753113 fig 954 | n07753275 pineapple, ananas 955 | n07753592 banana 956 | n07754684 jackfruit, jak, jack 957 | n07760859 custard apple 958 | n07768694 pomegranate 959 | n07802026 hay 960 | n07831146 carbonara 961 | n07836838 chocolate sauce, chocolate syrup 962 | n07860988 dough 963 | n07871810 meat loaf, meatloaf 964 | n07873807 pizza, pizza pie 965 | n07875152 potpie 966 | n07880968 burrito 967 | n07892512 red wine 968 | n07920052 espresso 969 | n07930864 cup 970 | n07932039 eggnog 971 | n09193705 alp 972 | n09229709 bubble 973 | n09246464 cliff, drop, drop-off 974 | n09256479 coral reef 975 | n09288635 geyser 976 | n09332890 lakeside, lakeshore 977 | n09399592 promontory, headland, head, foreland 978 | n09421951 sandbar, sand bar 979 | n09428293 seashore, coast, seacoast, sea-coast 980 | n09468604 valley, vale 981 | n09472597 volcano 982 | n09835506 ballplayer, baseball player 983 | n10148035 groom, bridegroom 984 | n10565667 scuba diver 985 | n11879895 rapeseed 986 | n11939491 daisy 987 | n12057211 yellow lady's slipper, yellow lady-slipper, Cypripedium calceolus, Cypripedium parviflorum 988 | n12144580 corn 989 | n12267677 acorn 990 | n12620546 hip, rose hip, rosehip 991 | n12768682 buckeye, horse chestnut, conker 992 | n12985857 coral fungus 993 | n12998815 agaric 994 | n13037406 gyromitra 995 | n13040303 stinkhorn, carrion fungus 996 | n13044778 earthstar 997 | n13052670 hen-of-the-woods, hen of the woods, Polyporus frondosus, Grifola frondosa 998 | n13054560 bolete 999 | n13133613 ear, spike, capitulum 1000 | n15075141 toilet tissue, toilet paper, bathroom tissue 1001 | -------------------------------------------------------------------------------- /Dataset/COCO-images/README.md: -------------------------------------------------------------------------------- 1 | COCO images here 2 | -------------------------------------------------------------------------------- /Dataset/README.md: -------------------------------------------------------------------------------- 1 | Put Flickr30K captions file: results_20130124.token and features.npy here 2 | 3 | -------------------------------------------------------------------------------- /Dataset/flickr30k-images/README.md: -------------------------------------------------------------------------------- 1 | Flickr 30K images here 2 | -------------------------------------------------------------------------------- /Images/gen_102617084.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_102617084.jpg -------------------------------------------------------------------------------- /Images/gen_2230458748.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_2230458748.jpg -------------------------------------------------------------------------------- /Images/gen_2461372011.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_2461372011.jpg -------------------------------------------------------------------------------- /Images/gen_2472980433.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_2472980433.jpg -------------------------------------------------------------------------------- /Images/gen_2537697530.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_2537697530.jpg -------------------------------------------------------------------------------- /Images/gen_283252248.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_283252248.jpg -------------------------------------------------------------------------------- /Images/gen_3126981064.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_3126981064.jpg -------------------------------------------------------------------------------- /Images/gen_3273757324.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_3273757324.jpg -------------------------------------------------------------------------------- /Images/gen_3920626767.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_3920626767.jpg -------------------------------------------------------------------------------- /Images/gen_4013421575.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_4013421575.jpg -------------------------------------------------------------------------------- /Images/gen_4752984291.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_4752984291.jpg -------------------------------------------------------------------------------- /Images/gen_532999240.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_532999240.jpg -------------------------------------------------------------------------------- /Images/gen_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_6.png -------------------------------------------------------------------------------- /Images/gen_7125476937.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_7125476937.jpg -------------------------------------------------------------------------------- /Images/gen_7148046575.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_7148046575.jpg -------------------------------------------------------------------------------- /Images/gen_7526599338.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_7526599338.jpg -------------------------------------------------------------------------------- /Images/gen_cat2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_cat2.png -------------------------------------------------------------------------------- /Images/gen_comp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_comp.png -------------------------------------------------------------------------------- /Images/gen_football.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_football.png -------------------------------------------------------------------------------- /Images/gen_manlaptop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_manlaptop.png -------------------------------------------------------------------------------- /Images/gen_plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_plane.png -------------------------------------------------------------------------------- /Images/gen_suitselfie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_suitselfie.png -------------------------------------------------------------------------------- /Images/gen_womanbeach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/Images/gen_womanbeach.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, Neural Nuts 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Deprecated] Image Caption Generator 2 | 3 | **Notice: This project uses an older version of TensorFlow, and is no longer supported. Please consider using other latest alternatives.** 4 | 5 | A Neural Network based generative model for captioning images. 6 | 7 | ## Checkout the android app made using this image-captioning-model: [Cam2Caption](https://github.com/neural-nuts/Cam2Caption) and [the associated paper](http://ieeexplore.ieee.org/document/8272660/). 8 | 9 | ### Work in Progress 10 | 11 | ###### Updates(Jan 14, 2018): 12 | 1. Some Code Refactoring. 13 | 2. Added MSCOCO dataset support. 14 | 15 | ###### Updates(Mar 12, 2017): 16 | 1. Added Dropout Layer for LSTM, Xavier Glorot Initializer for Weights 17 | 2. Significant Optimizations for Caption Generation i.e Decode Routine, computation time reduce from 3 seconds to 0.2 seconds 18 | 3. Functionality to Freeze Graphs and Merge them. 19 | 4. Direct Serving(Dual Graph and Single Graph) Routines in /util/ 20 | 5. Explored and chose the fastest and most efficient Image Preprocessing Method. 21 | 5. Ported code to TensorFlow r1.0 22 | 23 | ###### Updates(Feb 27, 2017): 24 | 1. Added BLEU evaluation metric and batch processing of images to produce batches of captions. 25 | 26 | ###### Updates(Feb 25, 2017): 27 | 1. Added optimizations and one-time pre-processing of Flickr30K data 28 | 2. Changed to a faster Image Preprocessing method using OpenCV 29 | 30 | ###### To-Do(Open for Contribution): 31 | 1. FIFO-queues in training 32 | 2. Attention-Model 33 | 3. Trained Models for Distribution. 34 | 35 | ## Pre-Requisites: 36 | 1. Tensorflow r1.0 37 | 2. NLTK 38 | 3. pandas 39 | 4. Download Flickr30K OR MSCOCO images and captions. 40 | 5. Download Pre-Trained InceptionV4 Tensorflow graph from DeepDetect available [here](https://deepdetect.com/models/tf/inception_v4.pb) 41 | 42 | ## Procedure to Train and Generate Captions: 43 | 1. Clone the Repository to preserve Directory Structure 44 | 2. For flickr30k put results_20130124.token and Flickr30K images in flickr30k-images folder OR For MSCOCO put captions_val2014.json and MSCOCO images in COCO-images folder . 45 | 3. Put inception_v4.pb in ConvNets folder 46 | 4. Generate features(features.npy) corresponding to the images in the dataset folder by running- 47 | - For Flickr30K: `python convfeatures.py --data_path Dataset/flickr30k-images --inception_path ConvNets/inception_v4.pb` 48 | - For MSCOCO: `python convfeatures.py --data_path Dataset/COCO-images --inception_path ConvNets/inception_v4.pb` 49 | 3. To Train the model run- 50 | - For Flickr30K: `python main.py --mode train --caption_path ./Dataset/results_20130124.token --feature_path ./Dataset/features.npy --resume` 51 | - For MSCOCO: `python main.py --mode train --caption_path ./Dataset/captions_val2014.json --feature_path ./Dataset/features.npy --data_is_coco --resume` 52 | 4. To Generate Captions for an Image run 53 | - `python main.py --mode test --image_path VALID_PATH` 54 | 5. For usage as a python library see [Demo.ipynb](https://github.com/neural-nuts/image-caption-generator/blob/master/Demo.ipynb) 55 | 56 | (see `python main.py -h` for more) 57 | 58 | ## Miscellaneous Notes: 59 | 60 | ### Freezing the encoder and decoder Graphs 61 | 1. It's necessary to save both encoder and decoder graphs while running test. This is a one-time necessary run before freezing the encoder/decoder. 62 | - `python main.py --mode test --image_path ANY_TEST_IMAGE.jpg/png --saveencoder --savedecoder` 63 | 2. In the project root directory use - `python utils/save_graph.py --mode encoder --model_folder model/Encoder/` additionally you may want to use `--read_file` if you want to freeze the encoder for directly generating caption for an image file(path). Similarly, for decoder use - `python utils/save_graph.py --mode decoder --model_folder model/Decoder/`, read_file argument is not necessary for the decoder. 64 | 3. To use frozen encoder and decoder models as dual blackbox [Serve-DualProtoBuf.ipynb](https://github.com/neural-nuts/image-caption-generator/blob/master/utils/Serve-DualProtoBuf.ipynb). Note: You must freeze encoder graph with --read_file to run this notebook 65 | 66 | (see `python utils/save_graph.py -h` for more) 67 | 68 | ### Merging the encoder and decoder graphs for serving the model as a blackbox: 69 | 1. It's necessary to freeze the encoder and decoder as mentioned above. 70 | 2. In the project root directory run- 71 | - `python utils/merge_graphs.py --encpb ./model/Trained_Graphs/encoder_frozen_model.pb --decpb ./model/Trained_Graphs/decoder_frozen_model.pb` additionally you may want to use `--read_file` if you want to freeze the encoder for directly generating caption for an image file(path). 72 | 3. To use merged encoder and decoder models as single frozen blackbox: [Serve-SingleProtoBuf.ipynb](https://github.com/neural-nuts/image-caption-generator/blob/master/utils/Serve-SingleProtoBuf.ipynb). Note: You must freeze and merge encoder graph with --read_file to run this notebook 73 | 74 | (see `python utils/merge_graphs.py -h` for more) 75 | 76 | ### Training Steps vs Loss Graph in Tensorboard: 77 | 1. `tensorboard --logdir model/log_dir` 78 | 2. Navigate to `localhost:6006` 79 | 80 | ## Citation: 81 | 82 | If you use our model or code in your research, please cite the paper: 83 | 84 | ``` 85 | @article{Mathur2017, 86 | title={Camera2Caption: A Real-time Image Caption Generator}, 87 | author={Pranay Mathur and Aman Gill and Aayush Yadav and Anurag Mishra and Nand Kumar Bansode}, 88 | journal={IEEE Conference Publication}, 89 | year={2017} 90 | } 91 | ``` 92 | 93 | ## Reference: 94 | Show and Tell: A Neural Image Caption Generator 95 | 96 | -Oriol Vinyals, Alexander Toshev, Samy Bengio, Dumitru Erhan 97 | 98 | ## License: 99 | Protected Under BSD-3 Clause License. 100 | 101 | ## Some Examples: 102 | 103 | ![Alt text](/Images/gen_3126981064.jpg) 104 | ![Alt text](/Images/gen_7148046575.jpg) 105 | ![Alt text](/Images/gen_suitselfie.png) 106 | ![Alt text](/Images/gen_6.png) 107 | ![Alt text](/Images/gen_7526599338.jpg) 108 | ![Alt text](/Images/gen_4013421575.jpg) 109 | ![Alt text](/Images/gen_football.png) 110 | ![Alt text](/Images/gen_plane.png) 111 | ![Alt text](/Images/gen_comp.png) 112 | ![Alt text](/Images/gen_womanbeach.png) 113 | ![Alt text](/Images/gen_102617084.jpg) 114 | ![Alt text](/Images/gen_2230458748.jpg) 115 | ![Alt text](/Images/gen_7125476937.jpg) 116 | ![Alt text](/Images/gen_4752984291.jpg) 117 | ![Alt text](/Images/gen_cat2.png) 118 | ![Alt text](/Images/gen_283252248.jpg) 119 | ![Alt text](/Images/gen_3920626767.jpg) 120 | ![Alt text](/Images/gen_manlaptop.png) 121 | ![Alt text](/Images/gen_2461372011.jpg) 122 | -------------------------------------------------------------------------------- /caption_generator.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | from random import shuffle 3 | from convfeatures import * 4 | import tensorflow as tf 5 | from PIL import Image 6 | import numpy as np 7 | import pickle 8 | import sys 9 | import os 10 | 11 | 12 | class Caption_Generator(): 13 | 14 | def __init__(self, config, data=None): 15 | self.dim_imgft = np.int(config.dim_imgft) 16 | self.embedding_size = np.int(config.embedding_size) 17 | self.num_hidden = np.int(config.num_hidden) 18 | self.batch_size = np.int(config.batch_size) 19 | self.num_timesteps = np.int(config.num_timesteps) 20 | self.max_len = config.max_len 21 | self.word_threshold = config.word_threshold 22 | self.bias_init = config.bias_init 23 | self.xavier_init = config.xavier_init 24 | self.dropout = config.dropout 25 | self.lstm_keep_prob = config.lstm_keep_prob 26 | self.beta = config.beta_l2 27 | self.mode = config.mode 28 | self.batch_decode = config.batch_decode 29 | self.learning_rate = config.learning_rate 30 | self.resume = config.resume 31 | self.savedecoder = config.savedecoder 32 | self.saveencoder = config.saveencoder 33 | 34 | if self.mode == 'train': 35 | self.vocab, self.wtoidx, self.features, self.captions = data 36 | self.num_batch = int(self.features.shape[0]) / self.batch_size 37 | 38 | print "Converting Captions to IDs" 39 | self.captions = self.Words_to_IDs(self.wtoidx, self.captions) 40 | if self.resume == 1: 41 | self.vocab = np.load("Dataset/vocab.npy").tolist() 42 | self.wtoidx = np.load("Dataset/wordmap.npy").tolist() 43 | 44 | self.current_epoch = 0 45 | self.current_step = 0 46 | if self.resume is 1 or self.mode == 'test': 47 | if os.path.isfile('model/save.npy'): 48 | self.current_epoch, self.current_step = np.load( 49 | "model/save.npy") 50 | else: 51 | print "No Checkpoints, Restarting Training.." 52 | self.resume = 0 53 | self.nb_epochs = config.nb_epochs 54 | 55 | if self.mode == 'test': 56 | self.vocab = np.load("Dataset/vocab.npy").tolist() 57 | self.wtoidx = np.load("Dataset/wordmap.npy").tolist() 58 | self.max_words = np.int(len(self.wtoidx)) 59 | self.idxtow = dict(zip(self.wtoidx.values(), self.wtoidx.keys())) 60 | self.model() 61 | self.image_features, self.IDs = self.build_decode_graph() 62 | self.load_image=config.load_image 63 | if not self.batch_decode: 64 | self.io = build_prepro_graph(config.inception_path) 65 | self.sess = self.init_decode() 66 | return 67 | 68 | self.max_words = np.int(len(self.wtoidx)) 69 | self.idxtow = dict(zip(self.wtoidx.values(), self.wtoidx.keys())) 70 | self.model() 71 | 72 | def Words_to_IDs(self, wtoidx, caption_batch): 73 | for i, caption in enumerate(caption_batch): 74 | cap = [] 75 | for word in caption.split(): 76 | try: 77 | cap.append(wtoidx[word]) 78 | except KeyError: 79 | cap.append(wtoidx[""]) 80 | caption_batch[i] = np.array(cap) 81 | return np.vstack(caption_batch) 82 | 83 | def IDs_to_Words(self, idxtow, ID_batch): 84 | return [idxtow[word] for IDs in ID_batch for word in IDs] 85 | 86 | def generate_mask(self, ID_batch, wtoidx): 87 | nonpadded = map(lambda x: len( 88 | ID_batch[0]) - x.count(wtoidx[""]), ID_batch.tolist()) 89 | ID_batch = np.zeros((ID_batch.shape[0], self.max_len + 2)) 90 | for ind, row in enumerate(ID_batch): 91 | row[:nonpadded[ind]] = 1 92 | return ID_batch 93 | 94 | def get_next_batch(self): 95 | batch_size = self.batch_size 96 | for batch_idx in range(0, len(self.features), batch_size): 97 | images_batch = self.features[batch_idx:batch_idx + batch_size] 98 | caption_batch = self.captions[batch_idx:batch_idx + batch_size] 99 | # print caption_batch 100 | yield images_batch, caption_batch 101 | 102 | # From NeuralTalk by Andrej Karpathy 103 | def init_bias(self): 104 | bias_init_vector = np.array( 105 | [1.0 * self.vocab[self.idxtow[i]] for i in self.idxtow]) 106 | bias_init_vector /= np.sum(bias_init_vector) 107 | bias_init_vector = np.log(bias_init_vector) 108 | bias_init_vector -= np.max(bias_init_vector) 109 | return bias_init_vector 110 | 111 | def assign_weights(self, dim1, dim2=None, name=None, Xavier=False): 112 | if Xavier: 113 | weight_initializer = tf.contrib.layers.xavier_initializer() 114 | return tf.get_variable( 115 | name, [dim1, dim2], initializer=weight_initializer) 116 | return tf.Variable(tf.truncated_normal([dim1, dim2]), 117 | name=name) 118 | 119 | def assign_biases(self, dim, name, bias_init=False): 120 | if bias_init: 121 | return tf.Variable(self.init_bias().astype(np.float32), name=name) 122 | return tf.Variable(tf.zeros([dim]), name=name) 123 | 124 | def model(self): 125 | self.word_embedding = { 126 | "weights": self.assign_weights( 127 | self.max_words, 128 | self.embedding_size, 129 | 'Weight_emb'), 130 | "biases": self.assign_biases( 131 | self.embedding_size, 132 | "Bias_emb")} 133 | 134 | self.image_embedding = { 135 | "weights": self.assign_weights( 136 | self.dim_imgft, 137 | self.embedding_size, 138 | 'Weight_img_emb'), 139 | "biases": self.assign_biases( 140 | self.embedding_size, 141 | 'Bias_img_emb')} 142 | 143 | self.target_word = { 144 | "weights": self.assign_weights( 145 | self.embedding_size, 146 | self.max_words, 147 | 'Weight_target'), 148 | "biases": self.assign_biases( 149 | self.max_words, 150 | 'Bias_target', bias_init=self.bias_init)} 151 | 152 | self.lstm_cell = tf.contrib.rnn.BasicLSTMCell(self.num_hidden) 153 | 154 | if self.dropout: 155 | self.lstm_cell = tf.contrib.rnn.DropoutWrapper( 156 | self.lstm_cell, self.lstm_keep_prob, self.lstm_keep_prob) 157 | 158 | self.inp_dict = { 159 | "features": tf.placeholder( 160 | tf.float32, [self.batch_size, self.dim_imgft], name="Train_Features"), 161 | "captions": tf.placeholder( 162 | tf.int32, [self.batch_size, self.num_timesteps], name="Train_Captions"), 163 | "mask": tf.placeholder( 164 | tf.float32, [self.batch_size, self.num_timesteps], name="Train_Mask") 165 | } 166 | 167 | def create_feed_dict(self, Ids, features, mask, mode="train"): 168 | feed_dict = {} 169 | feed_dict[self.inp_dict['captions']] = Ids 170 | feed_dict[self.inp_dict['features']] = features 171 | feed_dict[self.inp_dict['mask']] = mask 172 | return feed_dict 173 | 174 | def build_train_graph(self): 175 | init_c = tf.zeros([self.batch_size, self.lstm_cell.state_size[0]]) 176 | init_h = tf.zeros([self.batch_size, self.lstm_cell.state_size[1]]) 177 | initial_state = (init_c, init_h) 178 | image_emb = tf.matmul(self.inp_dict["features"], self.image_embedding[ 179 | 'weights']) + self.image_embedding['biases'] 180 | with tf.variable_scope("LSTM"): 181 | output, state = self.lstm_cell(image_emb, initial_state) 182 | loss = 0.0 183 | for i in range(1, self.num_timesteps): 184 | batch_embed = tf.nn.embedding_lookup( 185 | self.word_embedding['weights'], self.inp_dict['captions'][ 186 | :, i - 1]) + self.word_embedding['biases'] 187 | tf.get_variable_scope().reuse_variables() 188 | output, state = self.lstm_cell(batch_embed, state) 189 | words = tf.reshape(self.inp_dict['captions'][ 190 | :, i], shape=[self.batch_size, 1]) 191 | onehot_encoded = tf.one_hot(indices=words, depth=len( 192 | self.wtoidx), on_value=1, off_value=0, axis=-1) 193 | onehot_encoded = tf.reshape(onehot_encoded, shape=[ 194 | self.batch_size, self.max_words]) 195 | target_logit = tf.matmul( 196 | output, self.target_word['weights']) + self.target_word['biases'] 197 | cross_entropy = tf.nn.softmax_cross_entropy_with_logits( 198 | logits=target_logit, labels=onehot_encoded) 199 | cross_entropy = cross_entropy * self.inp_dict["mask"][:, i] 200 | current_loss = tf.reduce_sum(cross_entropy) 201 | loss = loss + current_loss 202 | loss = loss / tf.reduce_sum(self.inp_dict["mask"][:, 1:]) 203 | # introducing L2 regularization in Loss/Cost Function 204 | # self.beta=0 205 | #l2_loss = self.beta * sum([tf.nn.l2_loss(tf_var) for tf_var in tf.trainable_variables() if not "Bias" in tf_var.name]) 206 | #loss = tf.reduce_mean(loss+l2_loss) 207 | return loss, self.inp_dict 208 | 209 | def build_decode_graph(self): 210 | image_features = tf.placeholder( 211 | tf.float32, [1, self.dim_imgft], name='Input_Features') 212 | image_emb = tf.matmul(image_features, self.image_embedding[ 213 | 'weights']) + self.image_embedding['biases'] 214 | init_c = tf.zeros([1, self.lstm_cell.state_size[0]]) 215 | init_h = tf.zeros([1, self.lstm_cell.state_size[1]]) 216 | initial_state = (init_c, init_h) 217 | IDs = [] 218 | with tf.variable_scope("LSTM"): 219 | output, state = self.lstm_cell(image_emb, initial_state) 220 | pred_ID = tf.nn.embedding_lookup( 221 | self.word_embedding['weights'], [ 222 | self.wtoidx[""]]) + self.word_embedding['biases'] 223 | for i in range(self.num_timesteps): 224 | tf.get_variable_scope().reuse_variables() 225 | output, state = self.lstm_cell(pred_ID, state) 226 | logits = tf.matmul(output, self.target_word[ 227 | "weights"]) + self.target_word["biases"] 228 | predicted_next_idx = tf.argmax(logits, axis=1) 229 | pred_ID = tf.nn.embedding_lookup( 230 | self.word_embedding['weights'], predicted_next_idx) 231 | pred_ID = pred_ID + self.word_embedding['biases'] 232 | predicted_next_idx = tf.cast(predicted_next_idx, tf.int32, name="word_"+str(i)) 233 | IDs.append(predicted_next_idx) 234 | 235 | with open("model/Decoder/DecoderOutputs.txt", 'w') as f: 236 | for name in IDs: 237 | f.write(name.name.split(":0")[0] + "\n") 238 | 239 | return image_features, IDs 240 | 241 | def train(self, loss, inp_dict): 242 | self.loss = loss 243 | self.inp_dict = inp_dict 244 | saver = tf.train.Saver(max_to_keep=10) 245 | global_step = tf.Variable( 246 | self.current_step, 247 | name='global_step') 248 | starter_learning_rate = self.learning_rate 249 | learning_rate = tf.train.exponential_decay( 250 | starter_learning_rate, global_step, 100000, 0.95, staircase=True) 251 | optimizer = tf.train.AdamOptimizer(learning_rate).minimize( 252 | self.loss, global_step=global_step) 253 | tf.summary.scalar("loss", self.loss) 254 | tf.summary.scalar("learning_rate", learning_rate) 255 | summary_op = tf.summary.merge_all() 256 | 257 | with tf.Session() as sess: 258 | print "Initializing Training" 259 | init = tf.global_variables_initializer() 260 | sess.run(init) 261 | if self.resume is 1: 262 | print "Loading Previously Trained Model" 263 | print self.current_epoch, "Out of", self.nb_epochs, "Completed in previous run." 264 | try: 265 | ckpt_file = "./model/model.ckpt-" + str(self.current_step) 266 | saver.restore(sess, ckpt_file) 267 | print "Resuming Training" 268 | except Exception as e: 269 | print str(e).split('\n')[0] 270 | print "Checkpoints not found" 271 | sys.exit(0) 272 | writer = tf.summary.FileWriter( 273 | "model/log_dir/", graph=tf.get_default_graph()) 274 | 275 | for epoch in range(self.current_epoch, self.nb_epochs): 276 | loss=[] 277 | idx = np.random.permutation(self.features.shape[0]) 278 | self.captions = self.captions[idx] 279 | self.features = self.features[idx] 280 | batch_iter = self.get_next_batch() 281 | for batch_idx in xrange(self.num_batch): 282 | batch_features, batch_Ids = batch_iter.next() 283 | batch_mask = self.generate_mask(batch_Ids, self.wtoidx) 284 | run = [global_step, optimizer, self.loss, summary_op] 285 | feed_dict = self.create_feed_dict( 286 | batch_Ids, batch_features, batch_mask) 287 | step, _, current_loss, summary = sess.run( 288 | run, feed_dict=feed_dict) 289 | writer.add_summary(summary, step) 290 | if step % 100 == 0: 291 | print epoch, ": Global Step:", step, "\tLoss: ", current_loss 292 | loss.append(current_loss) 293 | print 294 | print "Epoch: ", epoch, "\tAverage Loss: ", np.mean(loss) 295 | print "\nSaving Model..\n" 296 | saver.save(sess, "./model/model.ckpt", global_step=global_step) 297 | np.save("model/save", (epoch, step)) 298 | 299 | def init_decode(self): 300 | saver = tf.train.Saver() 301 | ckpt_file = "./model/model.ckpt-" + str(self.current_step) #str(89994) 302 | sess = tf.Session() 303 | init = tf.global_variables_initializer() 304 | sess.run(init) 305 | saver.restore(sess, ckpt_file) 306 | return sess 307 | 308 | def decode(self, path): 309 | features = get_features(self.sess, self.io, path, self.saveencoder) 310 | caption_IDs = self.sess.run( 311 | self.IDs, feed_dict={ 312 | self.image_features: features}) 313 | sentence = " ".join(self.IDs_to_Words(self.idxtow, caption_IDs)) 314 | sentence = sentence.split("")[0] 315 | if self.load_image: 316 | plt.imshow(Image.open(path)) 317 | plt.axis("off") 318 | plt.title(sentence, fontsize='10', loc='left') 319 | name=path.split("/")[-1] 320 | plt.savefig("./results/"+"gen_"+name) 321 | plt.show() 322 | else: 323 | print sentence 324 | if self.savedecoder: 325 | saver = tf.train.Saver() 326 | saver.save(self.sess, "model/Decoder/model.ckpt") 327 | 328 | #return path, sentence 329 | 330 | def batch_decoder(self, filenames, features): 331 | saver = tf.train.Saver() 332 | ckpt_file = "./model/model.ckpt-" + str(self.current_step) 333 | sentences = [] 334 | filenames = np.unique(filenames) 335 | with open("model/Decoder/Generated_Captions.txt", 'w') as f: 336 | with tf.Session() as sess: 337 | init = tf.global_variables_initializer() 338 | sess.run(init) 339 | saver.restore(sess, ckpt_file) 340 | for i, feat in enumerate(features): 341 | feat = np.reshape(feat, newshape=(1, 1536)) 342 | caption_IDs = sess.run( 343 | self.IDs, feed_dict={ 344 | self.image_features: feat}) 345 | sentence = " ".join( 346 | self.IDs_to_Words( 347 | self.idxtow, caption_IDs)) 348 | sentence = sentence.split("")[0] 349 | if i % 1000 == 0: 350 | print "Progress", i, "out of", features.shape[0] 351 | f.write(filenames[i] + "\t" + sentence + "\n") 352 | -------------------------------------------------------------------------------- /configuration.py: -------------------------------------------------------------------------------- 1 | class Configuration(): 2 | 3 | def __init__(self, args): 4 | self.word_threshold = 2 5 | self.max_len = 20 6 | self.dim_imgft = 1536 7 | self.embedding_size = 256 8 | self.num_hidden = 256 9 | self.batch_size = 100 10 | self.num_timesteps = 22 11 | self.learning_rate = 0.002 12 | self.nb_epochs = 10000 13 | self.bias_init = True 14 | self.xavier_init = False 15 | self.dropout = False 16 | self.lstm_keep_prob = 0.7 17 | self.beta_l2 = 0.001 18 | self.batch_decode = False 19 | self.mode = args["mode"] 20 | self.resume = args["resume"] 21 | self.load_image = bool(args.get("load_image")) 22 | self.data_is_coco = bool(args.get("data_is_coco")) 23 | self.inception_path = args.get("inception_path", "ConvNets/inception_v4.pb") 24 | self.saveencoder = bool(args.get("saveencoder")) 25 | self.savedecoder = bool(args.get("savedecoder")) 26 | -------------------------------------------------------------------------------- /convfeatures.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import argparse 4 | import os 5 | 6 | batch_size = 10 7 | files, input_layer, output_layer = [None]*3 8 | 9 | def build_prepro_graph(inception_path): 10 | global input_layer, output_layer 11 | with open(inception_path, 'rb') as f: 12 | fileContent = f.read() 13 | 14 | graph_def = tf.GraphDef() 15 | graph_def.ParseFromString(fileContent) 16 | tf.import_graph_def(graph_def) 17 | graph = tf.get_default_graph() 18 | 19 | input_layer = graph.get_tensor_by_name("import/InputImage:0") 20 | output_layer = graph.get_tensor_by_name( 21 | "import/InceptionV4/Logits/AvgPool_1a/AvgPool:0") 22 | 23 | input_file = tf.placeholder(dtype=tf.string, name="InputFile") 24 | image_file = tf.read_file(input_file) 25 | jpg = tf.image.decode_jpeg(image_file, channels=3) 26 | png = tf.image.decode_png(image_file, channels=3) 27 | output_jpg = tf.image.resize_images(jpg, [299, 299]) / 255.0 28 | output_jpg = tf.reshape( 29 | output_jpg, [ 30 | 1, 299, 299, 3], name="Preprocessed_JPG") 31 | output_png = tf.image.resize_images(png, [299, 299]) / 255.0 32 | output_png = tf.reshape( 33 | output_png, [ 34 | 1, 299, 299, 3], name="Preprocessed_PNG") 35 | return input_file, output_jpg, output_png 36 | 37 | 38 | def load_image(sess, io, image): 39 | if image.split('.')[-1] == "png": 40 | return sess.run(io[2], feed_dict={io[0]: image}) 41 | return sess.run(io[1], feed_dict={io[0]: image}) 42 | 43 | 44 | def load_next_batch(sess, io, img_path): 45 | for batch_idx in range(0, len(files), batch_size): 46 | batch = files[batch_idx:batch_idx + batch_size] 47 | batch = np.array( 48 | map(lambda x: load_image(sess, io, img_path + x), batch)) 49 | batch = batch.reshape((batch_size, 299, 299, 3)) 50 | yield batch 51 | 52 | def forward_pass(io, img_path): 53 | global output_layer, files 54 | files = sorted(np.array(os.listdir(img_path))) 55 | print "#Images:", len(files) 56 | n_batch = len(files) / batch_size 57 | with tf.Session() as sess: 58 | init = tf.global_variables_initializer() 59 | sess.run(init) 60 | batch_iter = load_next_batch(sess, io, img_path) 61 | for i in xrange(n_batch): 62 | batch = batch_iter.next() 63 | assert batch.shape == (batch_size, 299, 299, 3) 64 | feed_dict = {input_layer: batch} 65 | if i is 0: 66 | prob = sess.run( 67 | output_layer, feed_dict=feed_dict).reshape( 68 | batch_size, 1536) 69 | else: 70 | prob = np.append( 71 | prob, 72 | sess.run( 73 | output_layer, 74 | feed_dict=feed_dict).reshape( 75 | batch_size, 76 | 1536), 77 | axis=0) 78 | if i % 5 == 0: 79 | print "Progress:" + str(((i + 1) / float(n_batch) * 100)) + "%\n" 80 | print "Progress:" + str(((n_batch) / float(n_batch) * 100)) + "%\n" 81 | print 82 | print "Saving Features : features.npy\n" 83 | np.save('Dataset/features', prob) 84 | 85 | 86 | def get_features(sess, io, img, saveencoder=False): 87 | global output_layer 88 | output_layer = tf.reshape(output_layer, [1,1536], name="Output_Features") 89 | image = load_image(sess, io, img) 90 | feed_dict = {input_layer: image} 91 | prob = sess.run(output_layer, feed_dict=feed_dict) 92 | 93 | if saveencoder: 94 | tensors = [n.name for n in sess.graph.as_graph_def().node] 95 | with open("model/Encoder/Encoder_Tensors.txt", 'w') as f: 96 | for t in tensors: 97 | f.write(t + "\n") 98 | saver = tf.train.Saver() 99 | saver.save(sess, "model/Encoder/model.ckpt") 100 | return prob 101 | 102 | def get_arguments(): 103 | parser = argparse.ArgumentParser() 104 | parser.add_argument( 105 | "--data_path", 106 | type=str, 107 | help="A valid path to MSCCOCO/flickr30k images(unzipped)", 108 | required=True) 109 | parser.add_argument( 110 | "--inception_path", 111 | type=str, 112 | help="A valid path to inception_v4.pb", 113 | required=True) 114 | args = parser.parse_args() 115 | return args 116 | 117 | if __name__ == "__main__": 118 | args=get_arguments() 119 | 120 | print "Extracting Features" 121 | io = build_prepro_graph(args.inception_path) 122 | forward_pass(io, args.data_path) 123 | print "done" 124 | -------------------------------------------------------------------------------- /eval.py: -------------------------------------------------------------------------------- 1 | import nltk 2 | import pandas as pd 3 | import numpy as np 4 | 5 | 6 | path_to_reference = 'Dataset/Validation_Captions.txt' # df -> image_id:str caption:str len(5000) 7 | path_to_model = 'model/Decoder/Generated_Captions.txt' 8 | 9 | with open(path_to_model) as f: 10 | model_data = f.readlines() 11 | model_filenames=[caps.split('\t')[0] for caps in model_data] 12 | model_captions = [caps.replace('\n', '').split('\t')[1] for caps in model_data] 13 | 14 | with open(path_to_reference, 'r') as f: 15 | ref_data = f.readlines() 16 | reference_filenames = [caps.split('\t')[0].split('#')[0] for caps in ref_data] 17 | reference_captions = [caps.replace('\n', '').split('\t')[1] for caps in ref_data] 18 | 19 | df = pd.DataFrame() 20 | df['image'] = reference_filenames 21 | df['caption'] = reference_captions 22 | df.caption = df.caption.str.decode('utf').str.split() 23 | df = pd.DataFrame(data = {'image':list(df.image.unique()),'caption':list(df.groupby('image')['caption'].apply(list))})[:len(model_captions)] 24 | 25 | bleu1_scores = [] 26 | bleu2_scores = [] 27 | bleu3_scores = [] 28 | bleu4_scores = [] 29 | index1=None 30 | index2=None 31 | 32 | for i, row in df.iterrows(): 33 | model = model_captions[i].split() 34 | reference = row.caption 35 | try: 36 | score1 = nltk.translate.bleu_score.sentence_bleu(reference, model, weights=[1.0]) 37 | score2 = nltk.translate.bleu_score.sentence_bleu(reference, model, weights=[0.5,0.5]) 38 | score3 = nltk.translate.bleu_score.sentence_bleu(reference, model, weights=[1.0/3,1.0/3,1-2*(1.0/3)]) 39 | score4 = nltk.translate.bleu_score.sentence_bleu(reference, model) 40 | bleu1_scores.append(score1) 41 | bleu2_scores.append(score2) 42 | bleu3_scores.append(score3) 43 | bleu4_scores.append(score4) 44 | if i%10000 == 0 and i!=0: 45 | print (float(i)/df.shape[0])*100,"%"," done" 46 | except: 47 | index1=df.index[i] 48 | index2=i 49 | print "Invalid Caption Generated for: ", model_filenames[i] 50 | 51 | print "\nMean Sentence-Level BLEU-1 score: ", np.mean(bleu1_scores) 52 | print "Mean Sentence-Level BLEU-2 score: ", np.mean(bleu2_scores) 53 | print "Mean Sentence-Level BLEU-3 score: ", np.mean(bleu3_scores) 54 | print "Mean Sentence-Level BLEU-4 score: ", np.mean(bleu4_scores) 55 | 56 | 57 | if index1 and index2: 58 | df=df.drop([index1]) 59 | df=df.reset_index(drop=True) 60 | del model_captions[index2] 61 | 62 | references=df.caption 63 | model_captions = [caption.split() for caption in model_captions] 64 | 65 | score1 = nltk.translate.bleu_score.corpus_bleu(references,model_captions, weights=[1.0]) 66 | print "\n\nCorpus-Level BLEU-1 score: ", score1 67 | score2 = nltk.translate.bleu_score.corpus_bleu(references,model_captions, weights=[0.5,0.5]) 68 | print "Corpus-Level BLEU-2 score: ", score2 69 | score3 = nltk.translate.bleu_score.corpus_bleu(references,model_captions, weights=[1.0/3,1.0/3,1-2*(1.0/3)]) 70 | print "Corpus-Level BLEU-3 score: ", score3 71 | score4 = nltk.translate.bleu_score.corpus_bleu(references,model_captions) 72 | print "Corpus-Level BLEU-4 score: ", score4 73 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from caption_generator import * 2 | from utils.data_util import generate_captions 3 | from configuration import Configuration 4 | import os, sys 5 | import argparse 6 | import json 7 | 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument( 10 | "--mode", 11 | type=str, 12 | help="train|test|eval", 13 | choices=[ 14 | "train", 15 | "test", 16 | "eval"], 17 | required=True) 18 | parser.add_argument( 19 | "--resume", 20 | help="make model training resumable", 21 | action="store_true") 22 | parser.add_argument( 23 | "--caption_path", 24 | type=str, 25 | help="A valid path to COCO/flickr30k caption file: results_20130124.token/captions_val2014.json") 26 | parser.add_argument( 27 | "--feature_path", 28 | type=str, 29 | help="A valid path to COCO/flickr30k image features: features.npy") 30 | parser.add_argument( 31 | "--data_is_coco", 32 | help="Is dataset MSCOCO? converts COCO caption data to flickr30k format", 33 | action="store_true") 34 | parser.add_argument( 35 | "--inception_path", 36 | type=str, 37 | help="A valid path to inception_v4.pb", 38 | default="ConvNets/inception_v4.pb") 39 | parser.add_argument( 40 | "--saveencoder", 41 | help="Save Decoder graph in model/Encoder/", 42 | action="store_true") 43 | parser.add_argument( 44 | "--savedecoder", 45 | help="Save Decoder graph in model/Decoder/", 46 | action="store_true") 47 | parser.add_argument( 48 | "--image_path", 49 | type=str, 50 | help="If mode is test then, Path to the Image for Generation of Captions") 51 | parser.add_argument( 52 | "--load_image", 53 | help="If mode is test then, displays and stores image with generated caption", 54 | action="store_true") 55 | parser.add_argument( 56 | "--validation_data", 57 | type=str, 58 | help="If mode is eval then, Path to the Validation Data for evaluation") 59 | args = parser.parse_args() 60 | config = Configuration(vars(args)) 61 | 62 | if config.mode == "train": 63 | vocab, wtoidx, training_data = generate_captions( 64 | config.word_threshold, config.max_len, args.caption_path, args.feature_path, 65 | config.data_is_coco) 66 | features, captions = training_data[:, 0], training_data[:, 1] 67 | features = np.array([feat.astype(float) for feat in features]) 68 | data = (vocab.tolist(), wtoidx.tolist(), features, captions) 69 | model = Caption_Generator(config, data=data) 70 | loss, inp_dict = model.build_train_graph() 71 | model.train(loss, inp_dict) 72 | 73 | elif config.mode == "test": 74 | if os.path.exists(args.image_path): 75 | model = Caption_Generator(config) 76 | model.decode(args.image_path) 77 | else: 78 | print "Please provide a valid image path.\n Usage:\n python main.py --mode test --image_path VALID_PATH" 79 | 80 | elif config.mode == "eval": 81 | config.mode = "test" 82 | config.batch_decode = True 83 | print args.validation_data 84 | if os.path.exists(args.validation_data): 85 | features = np.load(args.validation_data) 86 | #with open("Dataset/Validation_Captions.txt") as f: 87 | # data = f.readlines() 88 | with open("Dataset/image_info_test2014.json",'r') as f: 89 | data=json.load(f) 90 | 91 | #filenames = [caps.split('\t')[0].split('#')[0] for caps in data] 92 | filenames = sorted([d["file_name"].split('.')[0] for d in data['images']]) 93 | #captions = [caps.replace('\n', '').split('\t')[1] for caps in data] 94 | #features, captions = validation_data[:, 0], validation_data[:, 1] 95 | features = np.array([feat.astype(float) for feat in features]) 96 | model = Caption_Generator(config) 97 | generated_captions = model.batch_decoder(filenames, features) 98 | -------------------------------------------------------------------------------- /model/Decoder/README.md: -------------------------------------------------------------------------------- 1 | This directory will contain saved checkpoint, graph and output tensors of Decoder. 2 | -------------------------------------------------------------------------------- /model/Encoder/README.md: -------------------------------------------------------------------------------- 1 | This directory will contain saved checkpoint, graph and output tensors of Encoder. 2 | -------------------------------------------------------------------------------- /model/README.md: -------------------------------------------------------------------------------- 1 | This Directory will contain checkpoints while training the model 2 | 3 | -------------------------------------------------------------------------------- /model/Trained_Graphs/README.md: -------------------------------------------------------------------------------- 1 | This Directory contains final freezed decoder, encoder and combined protobuf files. 2 | -------------------------------------------------------------------------------- /model/log_dir/README.md: -------------------------------------------------------------------------------- 1 | Summaries for Tensorboard Stored Here. 2 | -------------------------------------------------------------------------------- /results.txt: -------------------------------------------------------------------------------- 1 | 24.6913580247 % done 2 | Invalid Caption Generated for: COCO_train2014_000000183988 3 | 49.3827160494 % done 4 | 74.0740740741 % done 5 | 98.7654320988 % done 6 | 7 | Mean Sentence-Level BLEU-1 score: 0.675701057637 8 | Mean Sentence-Level BLEU-2 score: 0.502045701894 9 | Mean Sentence-Level BLEU-3 score: 0.472399544356 10 | Mean Sentence-Level BLEU-4 score: 0.503704015943 11 | 12 | 13 | Corpus-Level BLEU-1 score: 0.680945536216 14 | Corpus-Level BLEU-2 score: 0.473736538727 15 | Corpus-Level BLEU-3 score: 0.327219332641 16 | Corpus-Level BLEU-4 score: 0.228155010438 17 | -------------------------------------------------------------------------------- /utils/MaybeConnect.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import tensorflow as tf\n", 12 | "from tensorflow.python.framework import graph_util" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 2, 18 | "metadata": { 19 | "collapsed": false 20 | }, 21 | "outputs": [], 22 | "source": [ 23 | "encpb=\"../model/Trained_Graphs/encoder_frozen_model.pb\"" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 3, 29 | "metadata": { 30 | "collapsed": false 31 | }, 32 | "outputs": [], 33 | "source": [ 34 | "with open(encpb, 'rb') as f:\n", 35 | " fileContent = f.read()\n", 36 | "graph_def = tf.GraphDef()\n", 37 | "graph_def.ParseFromString(fileContent)\n", 38 | "output1=\"Output_Features:0\"" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 4, 44 | "metadata": { 45 | "collapsed": false 46 | }, 47 | "outputs": [], 48 | "source": [ 49 | "output1 = tf.import_graph_def(\n", 50 | " graph_def,\n", 51 | " input_map=None,\n", 52 | " return_elements=[output1],\n", 53 | " name='encoder')\n", 54 | "graph = tf.get_default_graph()" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 5, 60 | "metadata": { 61 | "collapsed": false 62 | }, 63 | "outputs": [ 64 | { 65 | "data": { 66 | "text/plain": [ 67 | "[]" 68 | ] 69 | }, 70 | "execution_count": 5, 71 | "metadata": {}, 72 | "output_type": "execute_result" 73 | } 74 | ], 75 | "source": [ 76 | "output1" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 6, 82 | "metadata": { 83 | "collapsed": true 84 | }, 85 | "outputs": [], 86 | "source": [ 87 | "decpb = \"../model/Trained_Graphs/decoder_frozen_model.pb\"" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 7, 93 | "metadata": { 94 | "collapsed": false 95 | }, 96 | "outputs": [], 97 | "source": [ 98 | "with open(decpb, 'rb') as f:\n", 99 | " fileContent = f.read()\n", 100 | "graph_def = tf.GraphDef()\n", 101 | "graph_def.ParseFromString(fileContent)\n", 102 | "input2=\"Input_Features:0\"" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": 8, 108 | "metadata": { 109 | "collapsed": false 110 | }, 111 | "outputs": [], 112 | "source": [ 113 | "tf.import_graph_def(\n", 114 | " graph_def,\n", 115 | " input_map={input2:output1[0]},\n", 116 | " return_elements=None,\n", 117 | " name='decoder')\n", 118 | "graph = tf.get_default_graph()" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": { 125 | "collapsed": true 126 | }, 127 | "outputs": [], 128 | "source": [ 129 | "#output_node_names = [\n", 130 | "# \"Preprocessed_JPG\",\n", 131 | "# \"Preprocessed_PNG\",\n", 132 | "# \"OutputFeatures\"]" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": 13, 138 | "metadata": { 139 | "collapsed": false 140 | }, 141 | "outputs": [ 142 | { 143 | "data": { 144 | "text/plain": [ 145 | "['LSTM/word_0',\n", 146 | " 'LSTM/word_1',\n", 147 | " 'LSTM/word_2',\n", 148 | " 'LSTM/word_3',\n", 149 | " 'LSTM/word_4',\n", 150 | " 'LSTM/word_5',\n", 151 | " 'LSTM/word_6',\n", 152 | " 'LSTM/word_7',\n", 153 | " 'LSTM/word_8',\n", 154 | " 'LSTM/word_9',\n", 155 | " 'LSTM/word_10',\n", 156 | " 'LSTM/word_11',\n", 157 | " 'LSTM/word_12',\n", 158 | " 'LSTM/word_13',\n", 159 | " 'LSTM/word_14',\n", 160 | " 'LSTM/word_15',\n", 161 | " 'LSTM/word_16',\n", 162 | " 'LSTM/word_17',\n", 163 | " 'LSTM/word_18',\n", 164 | " 'LSTM/word_19',\n", 165 | " 'LSTM/word_20',\n", 166 | " 'LSTM/word_21']" 167 | ] 168 | }, 169 | "execution_count": 13, 170 | "metadata": {}, 171 | "output_type": "execute_result" 172 | } 173 | ], 174 | "source": [ 175 | "with open(\"../model/Decoder/DecoderOutputs.txt\", 'r') as f:\n", 176 | " output = f.read()\n", 177 | " prefix = \"\"\n", 178 | " outputs=[]\n", 179 | " outputs += [prefix + o for o in output.split('\\n')[:-1]]\n", 180 | "outputs" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 19, 186 | "metadata": { 187 | "collapsed": false 188 | }, 189 | "outputs": [], 190 | "source": [ 191 | "import numpy as np\n", 192 | "wtoidx = np.load(\"../Dataset/wordmap.npy\").tolist()\n", 193 | "idxtow = dict(zip(wtoidx.values(), wtoidx.keys()))\n", 194 | "def IDs_to_Words(ID_batch):\n", 195 | " return [idxtow[word] for IDs in ID_batch for word in IDs]" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 20, 201 | "metadata": { 202 | "collapsed": false 203 | }, 204 | "outputs": [ 205 | { 206 | "name": "stdout", 207 | "output_type": "stream", 208 | "text": [ 209 | "a man in a blue shirt and a woman in a white shirt are walking down a dirt road \n" 210 | ] 211 | } 212 | ], 213 | "source": [ 214 | "with tf.Session() as sess:\n", 215 | " in1 = graph.get_tensor_by_name(\"encoder/InputFile:0\")\n", 216 | " out1 = graph.get_tensor_by_name(\"encoder/Preprocessed_JPG:0\")\n", 217 | " feed_dict = {in1: \"../Images/3.jpg\"}\n", 218 | " prepro_image = sess.run(out1, feed_dict=feed_dict)\n", 219 | " in2 = graph.get_tensor_by_name(\"encoder/import/InputImage:0\")\n", 220 | " sentence = []\n", 221 | " for i,outs in enumerate(outputs):\n", 222 | " sentence.append(graph.get_tensor_by_name(\"decoder/\"+outs+\":0\"))\n", 223 | " feed_dict = {in2:prepro_image}\n", 224 | " prob= sess.run(sentence, feed_dict=feed_dict)\n", 225 | " print \" \".join(IDs_to_Words(prob)).split(\"\")[0]" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": null, 231 | "metadata": { 232 | "collapsed": true 233 | }, 234 | "outputs": [], 235 | "source": [] 236 | } 237 | ], 238 | "metadata": { 239 | "anaconda-cloud": {}, 240 | "kernelspec": { 241 | "display_name": "Python [conda root]", 242 | "language": "python", 243 | "name": "conda-root-py" 244 | }, 245 | "language_info": { 246 | "codemirror_mode": { 247 | "name": "ipython", 248 | "version": 2 249 | }, 250 | "file_extension": ".py", 251 | "mimetype": "text/x-python", 252 | "name": "python", 253 | "nbconvert_exporter": "python", 254 | "pygments_lexer": "ipython2", 255 | "version": "2.7.12" 256 | } 257 | }, 258 | "nbformat": 4, 259 | "nbformat_minor": 1 260 | } 261 | -------------------------------------------------------------------------------- /utils/Serve-DualProtoBuf.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": false 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "import tensorflow as tf\n", 12 | "import numpy as np" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "metadata": { 19 | "collapsed": false 20 | }, 21 | "outputs": [], 22 | "source": [ 23 | "tf.reset_default_graph()\n", 24 | "\n", 25 | "with open('../model/Trained_Graphs/encoder_frozen_model.pb', 'rb') as f:\n", 26 | " fileContent = f.read()\n", 27 | "graph_def = tf.GraphDef()\n", 28 | "graph_def.ParseFromString(fileContent)\n", 29 | "tf.import_graph_def(graph_def, input_map=None, return_elements=None, name='encoder', op_dict=None, producer_op_list=None)\n", 30 | "graph = tf.get_default_graph()\n", 31 | "tensors_encoder = [n.name for n in tf.get_default_graph().as_graph_def().node]\n", 32 | "\n", 33 | "def init_encoder():\n", 34 | " sess = tf.Session()\n", 35 | " return sess\n", 36 | "\n", 37 | "def encoder_forward_pass(sess, image_path):\n", 38 | " in1 = graph.get_tensor_by_name(\"encoder/InputImage:0\")\n", 39 | " out1 = graph.get_tensor_by_name(\"encoder/Preprocessed_JPG:0\")\n", 40 | " feed_dict = {in1: image_path}\n", 41 | " prepro_image = sess.run(out1, feed_dict=feed_dict)\n", 42 | " in2 = graph.get_tensor_by_name(\"encoder/import/InputImage:0\")\n", 43 | " outfinal = graph.get_tensor_by_name(\"encoder/import/InceptionV4/Logits/AvgPool_1a/AvgPool:0\")\n", 44 | " feed_dict = {in2: prepro_image}\n", 45 | " features = sess.run(outfinal, feed_dict=feed_dict)[0][0]\n", 46 | " return features" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": { 53 | "collapsed": true 54 | }, 55 | "outputs": [], 56 | "source": [ 57 | "sess = init_encoder()" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": null, 63 | "metadata": { 64 | "collapsed": false 65 | }, 66 | "outputs": [], 67 | "source": [ 68 | "features = encoder_forward_pass(sess, \"../Images/dog2.jpg\")" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": null, 74 | "metadata": { 75 | "collapsed": false 76 | }, 77 | "outputs": [], 78 | "source": [ 79 | "def IDs_to_Words(ID_batch):\n", 80 | " return [idxtow[word] for IDs in ID_batch for word in IDs]\n", 81 | "\n", 82 | "tf.reset_default_graph()\n", 83 | "\n", 84 | "with open('../model/Trained_Graphs/decoder_frozen_model.pb', 'rb') as f:\n", 85 | " fileContent = f.read()\n", 86 | "\n", 87 | "graph_def = tf.GraphDef()\n", 88 | "graph_def.ParseFromString(fileContent)\n", 89 | "tf.import_graph_def(graph_def, input_map=None, return_elements=None, name='decoder', op_dict=None, producer_op_list=None)\n", 90 | "graph = tf.get_default_graph()\n", 91 | "tensors_decoder = [n.name for n in tf.get_default_graph().as_graph_def().node]\n", 92 | "\n", 93 | "wtoidx = np.load(\"../Dataset/wordmap.npy\").tolist()\n", 94 | "idxtow = dict(zip(wtoidx.values(), wtoidx.keys()))\n", 95 | "\n", 96 | "with open(\"../model/Decoder/DecoderOutputs.txt\", 'r') as fr:\n", 97 | " outputs= fr.read()\n", 98 | " outputs=outputs.split('\\n')[:-1]\n", 99 | "\n", 100 | "def init_decoder():\n", 101 | " sess = tf.Session()\n", 102 | " return sess\n", 103 | "\n", 104 | "def decoder_forward_pass(sess, features):\n", 105 | " feed_dict = {graph.get_tensor_by_name(\"decoder/Input_Features:0\"): features}\n", 106 | " prob_tensor = []\n", 107 | " for i,outs in enumerate(outputs):\n", 108 | " prob_tensor.append(graph.get_tensor_by_name(\"decoder/\"+outs+\":0\"))\n", 109 | " prob = sess.run(prob_tensor, feed_dict=feed_dict)\n", 110 | " return \" \".join(IDs_to_Words(prob)).split(\"\")[0]" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "metadata": { 117 | "collapsed": true 118 | }, 119 | "outputs": [], 120 | "source": [ 121 | "sess= init_decoder()" 122 | ] 123 | }, 124 | { 125 | "cell_type": "code", 126 | "execution_count": null, 127 | "metadata": { 128 | "collapsed": false 129 | }, 130 | "outputs": [], 131 | "source": [ 132 | "print decoder_forward_pass(sess,features)" 133 | ] 134 | }, 135 | { 136 | "cell_type": "code", 137 | "execution_count": null, 138 | "metadata": { 139 | "collapsed": true 140 | }, 141 | "outputs": [], 142 | "source": [] 143 | } 144 | ], 145 | "metadata": { 146 | "anaconda-cloud": {}, 147 | "kernelspec": { 148 | "display_name": "Python [conda root]", 149 | "language": "python", 150 | "name": "conda-root-py" 151 | }, 152 | "language_info": { 153 | "codemirror_mode": { 154 | "name": "ipython", 155 | "version": 2 156 | }, 157 | "file_extension": ".py", 158 | "mimetype": "text/x-python", 159 | "name": "python", 160 | "nbconvert_exporter": "python", 161 | "pygments_lexer": "ipython2", 162 | "version": "2.7.12" 163 | } 164 | }, 165 | "nbformat": 4, 166 | "nbformat_minor": 2 167 | } 168 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neural-nuts/image-caption-generator/3fa3d7d78edc6824d01f54de2b04c4aa028d368c/utils/__init__.py -------------------------------------------------------------------------------- /utils/data_util.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from collections import Counter 4 | from nltk.tokenize import word_tokenize 5 | import pickle 6 | import json 7 | import os 8 | 9 | max_len = 20 10 | word_threshold = 2 11 | counter = None 12 | 13 | def prepare_coco_captions(filename="Dataset/captions_val2014.json"): 14 | ''' 15 | Prepare COCO Captions in the Flickr annotation file format 16 | ''' 17 | with open(filename, 'r') as f: 18 | data = json.load(f) 19 | images = data['images'] 20 | captions = data['annotations'] 21 | prefix = "COCO_train2014_" 22 | 23 | for cap in captions: 24 | image_id = str(cap['image_id']) 25 | len_id = len(image_id) 26 | zeros = '0'*(12-len_id) 27 | image_id = prefix+zeros+image_id 28 | cap['image_id'] = image_id 29 | cap['caption'] = cap['caption'].replace('\n','')\ 30 | .replace(',', ' ,').replace('.', '')\ 31 | .replace('"','" ').replace("'s"," 's")\ 32 | .replace("'t"," 't")+ " ." 33 | 34 | captions = sorted(captions, key=lambda k: k['image_id']) 35 | cap_path="Dataset/COCOcaptions.txt" 36 | with open(cap_path,'w') as f: 37 | for i, cap in enumerate(captions): 38 | f.write(cap['image_id']+'#'+str(i%5)+'\t'+cap['caption']+'\n') 39 | 40 | return cap_path 41 | 42 | def preprocess_coco_captions(filenames, captions): 43 | df = pd.DataFrame() 44 | df['FileNames'] = filenames 45 | df['caption'] = captions 46 | df.caption = df.caption.str.decode('utf') 47 | df['caption'] = df['caption'].apply(word_tokenize).apply(lambda x: x[:20]).apply(" ".join).str.lower() 48 | 49 | anomalies = df.FileNames.value_counts()[(df.FileNames.value_counts() > 5)].index.tolist() 50 | 51 | for name in anomalies: 52 | indexes = df[df.FileNames==name].index[5:] 53 | df = df.drop(indexes) 54 | df = df.reset_index(drop=True) 55 | 56 | with open("Dataset/COCOcaptions.txt",'w') as f: 57 | for i, row in df.iterrows(): 58 | f.write(row['FileNames']+'#'+str(i%5)+'\t'+row['caption']+'\n') 59 | 60 | return df 61 | 62 | def preprocess_flickr_captions(filenames, captions): 63 | global max_len 64 | print "Preprocessing Captions" 65 | df = pd.DataFrame() 66 | df['FileNames'] = filenames 67 | df['caption'] = captions 68 | df.caption = df.caption.str.decode('utf') 69 | df['caption'] = df['caption'].apply(word_tokenize).apply( 70 | lambda x: x[:max_len]).apply(" ".join).str.lower() 71 | #df = df[:158900] #uncomment if flickr 72 | return df 73 | 74 | 75 | def generate_vocab(df): 76 | global max_len, word_threshold, counter 77 | print "Generating Vocabulary" 78 | 79 | vocab = dict([w for w in counter.items() if w[1] >= word_threshold]) 80 | vocab[""] = len(counter) - len(vocab) 81 | vocab[""] = df.caption.str.count("").sum() 82 | vocab[""] = df.caption.str.count("").sum() 83 | vocab[""] = df.caption.str.count("").sum() 84 | wtoidx = {} 85 | wtoidx[""] = 1 86 | wtoidx[""] = 2 87 | wtoidx[""] = 0 88 | wtoidx[""] = 3 89 | print "Generating Word to Index and Index to Word" 90 | i = 4 91 | for word in vocab.keys(): 92 | if word not in ["", "", "", ""]: 93 | wtoidx[word] = i 94 | i += 1 95 | print "Size of Vocabulary", len(vocab) 96 | return vocab, wtoidx 97 | 98 | 99 | def pad_captions(df): 100 | global max_len 101 | print "Padding Caption to Max Length", max_len, "+ 2 for and " 102 | dfPadded = df.copy() 103 | dfPadded['caption'] = " " + dfPadded['caption'] + " " 104 | max_len = max_len + 2 105 | for i, row in dfPadded.iterrows(): 106 | cap = row['caption'] 107 | cap_len = len(cap.split()) 108 | if(cap_len < max_len): 109 | pad_len = max_len - cap_len 110 | pad_buf = " " * pad_len 111 | pad_buf = pad_buf.strip() 112 | dfPadded.set_value(i, 'caption', cap + " " + pad_buf) 113 | return dfPadded 114 | 115 | 116 | def load_features(feature_path): 117 | features = np.load(feature_path) 118 | features = np.repeat(features, 5, axis=0) 119 | print "Features Loaded", feature_path 120 | return features 121 | 122 | 123 | def split_dataset(df, features, ratio=0.8): 124 | split_idx = int(df.shape[0] * ratio) 125 | print "Data Statistics:" 126 | print "# Records Total Data: ", df.shape[0] 127 | print "# Records Training Data: ", split_idx 128 | print "# Records Training Data: ", df.shape[0] - split_idx 129 | print "Ration of Training: Validation = ", ratio * 100, ":", 100 - (ratio * 100) 130 | val_features = features[split_idx:] 131 | val_captions = np.array(df.caption)[split_idx:] 132 | np.save("Dataset/Validation_Data", zip(val_features, val_captions)) 133 | return df[:split_idx], features[:split_idx] 134 | 135 | 136 | def get_data(required_files): 137 | ret = [] 138 | for fil in required_files: 139 | ret.append(np.load("Dataset/" + fil + ".npy")) 140 | return ret 141 | 142 | 143 | def generate_captions( 144 | wt=2, 145 | ml=20, 146 | cap_path='Dataset/results_20130124.token',#default set to flickr30k captions 147 | feat_path='Dataset/features.npy', 148 | data_is_coco=False): 149 | required_files = ["vocab", "wordmap", "Training_Data"] 150 | generate = False 151 | for fil in required_files: 152 | if not os.path.isfile('Dataset/' + fil + ".npy"): 153 | generate = True 154 | print "Required Files not present. Regenerating Data." 155 | break 156 | if not generate: 157 | print "Dataset Present; Skipping Generation." 158 | return get_data(required_files) 159 | global max_len, word_threshold, counter 160 | max_len = ml 161 | word_threshold = wt 162 | print "Loading Caption Data", cap_path 163 | if data_is_coco: 164 | # Prepare COCO captions in Flickr format 165 | cap_path = prepare_coco_captions(cap_path) 166 | # Load the COCO captions data 167 | with open(cap_path, 'r') as f: 168 | data = f.readlines() 169 | filenames = [caps.split('\t')[0].split('#')[0] for caps in data] 170 | captions = [caps.split('\t')[1] for caps in data] 171 | df = preprocess_coco_captions(filenames, captions) 172 | else: 173 | with open(cap_path, 'r') as f: 174 | data = f.readlines() 175 | filenames = [caps.split('\t')[0].split('#')[0] for caps in data] 176 | captions = [caps.replace('\n', '').split('\t')[1] for caps in data] 177 | df = preprocess_flickr_captions(filenames, captions) 178 | 179 | features = load_features(feat_path) 180 | print features.shape, df.shape 181 | idx = np.random.permutation(features.shape[0]) 182 | df = df.iloc[idx] 183 | features = features[idx] 184 | # df, features = split_dataset(df, features) #use flickr8k for validation 185 | counter = Counter() 186 | for i, row in df.iterrows(): 187 | counter.update(row["caption"].lower().split()) 188 | df = pad_captions(df) 189 | vocab, wtoidx = generate_vocab(df) 190 | captions = np.array(df.caption) 191 | np.save("Dataset/Training_Data", zip(features, captions)) 192 | np.save("Dataset/wordmap", wtoidx) 193 | np.save("Dataset/vocab", vocab) 194 | 195 | print "Preprocessing Complete" 196 | return get_data(required_files) 197 | -------------------------------------------------------------------------------- /utils/merge_graphs.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | import tensorflow as tf 4 | from tensorflow.python.framework import graph_util 5 | 6 | parser = argparse.ArgumentParser() 7 | parser.add_argument("--encpb", type=str, help="ProtoBuf File of Decoder") 8 | parser.add_argument("--decpb", type=str, help="ProtoBuf File of Encoder") 9 | parser.add_argument( 10 | "--read_file", 11 | action="store_true") 12 | args = parser.parse_args() 13 | 14 | with open(args.encpb, 'rb') as f: 15 | fileContent = f.read() 16 | graph_def = tf.GraphDef() 17 | graph_def.ParseFromString(fileContent) 18 | output1="Output_Features:0" 19 | output1=tf.import_graph_def( 20 | graph_def, 21 | input_map=None, 22 | return_elements=[output1], 23 | name='encoder', 24 | op_dict=None, 25 | producer_op_list=None) 26 | graph = tf.get_default_graph() 27 | 28 | with open(args.decpb, 'rb') as f: 29 | fileContent = f.read() 30 | input2="Input_Features" 31 | graph_def2 = tf.GraphDef() 32 | graph_def2.ParseFromString(fileContent) 33 | tf.import_graph_def( 34 | graph_def2, 35 | input_map={input2:output1[0]}, 36 | return_elements=None, 37 | name='decoder', 38 | op_dict=None, 39 | producer_op_list=None) 40 | graph = tf.get_default_graph() 41 | tensors_decoder = [n.name for n in tf.get_default_graph().as_graph_def().node] 42 | 43 | 44 | if args.read_file==1: 45 | output_node_names = [ 46 | "encoder/Preprocessed_JPG", 47 | "encoder/Preprocessed_PNG"] 48 | else: 49 | print "without File I/O" 50 | output_node_names = [] 51 | 52 | with open("../model/Decoder/DecoderOutputs.txt", 'r') as f: 53 | output = f.read() 54 | prefix = "decoder/" 55 | output_node_names += [prefix + o for o in output.split('\n')[:-1]] 56 | 57 | 58 | input_graph_def = graph.as_graph_def() 59 | 60 | with tf.Session() as sess: 61 | init = tf.global_variables_initializer() 62 | sess.run(init) 63 | output_graph_def = graph_util.convert_variables_to_constants( 64 | sess, 65 | input_graph_def, 66 | output_node_names) 67 | output_graph = "../model/Trained_Graphs/merged_frozen_graph.pb" 68 | if args.read_file == 1: 69 | output_graph = "../model/Trained_Graphs/merged_frozen_graph_FILE.pb" 70 | 71 | with tf.gfile.GFile(output_graph, "wb") as f: 72 | f.write(output_graph_def.SerializeToString()) 73 | print "Merged ProtoBuf File Saved:", output_graph 74 | -------------------------------------------------------------------------------- /utils/save_graph.py: -------------------------------------------------------------------------------- 1 | import os 2 | import argparse 3 | import tensorflow as tf 4 | from tensorflow.python.framework import graph_util 5 | 6 | 7 | def freeze_graph(mode, read_file ,model_folder): 8 | 9 | checkpoint = tf.train.get_checkpoint_state(model_folder) 10 | input_checkpoint = checkpoint.model_checkpoint_path 11 | absolute_model_folder = "/".join(input_checkpoint.split('/')[:-1]) 12 | output_graph = "../model/Trained_Graphs/" + mode + "_frozen_model.pb" 13 | if mode == 'encoder': 14 | if read_file: 15 | output_node_names = [ 16 | "Preprocessed_JPG", 17 | "Preprocessed_PNG", 18 | "Output_Features"] 19 | else: 20 | print "without file I/O" 21 | output_node_names = ["Output_Features"] 22 | if mode == 'decoder': 23 | with open("../model/Decoder/DecoderOutputs.txt", 'r') as f: 24 | output_node_names = f.read() 25 | output_node_names = output_node_names.split('\n')[:-1] 26 | 27 | saver = tf.train.import_meta_graph(input_checkpoint + '.meta') 28 | graph = tf.get_default_graph() 29 | input_graph_def = graph.as_graph_def() 30 | 31 | with tf.Session() as sess: 32 | init = tf.global_variables_initializer() 33 | sess.run(init) 34 | saver.restore(sess, input_checkpoint) 35 | output_graph_def = graph_util.convert_variables_to_constants( 36 | sess, 37 | input_graph_def, 38 | output_node_names) 39 | 40 | with tf.gfile.GFile(output_graph, "wb") as f: 41 | f.write(output_graph_def.SerializeToString()) 42 | print "ProtoBuf File Saved:", output_graph 43 | 44 | 45 | if __name__ == '__main__': 46 | parser = argparse.ArgumentParser() 47 | parser.add_argument("--mode", type=str, choices=["encoder","decoder"]) 48 | parser.add_argument( 49 | "--model_folder", 50 | type=str, 51 | help="Model folder to export") 52 | parser.add_argument( 53 | "--read_file", 54 | action="store_true") 55 | args = parser.parse_args() 56 | freeze_graph(args.mode, args.read_file, args.model_folder) 57 | --------------------------------------------------------------------------------