├── Autoencoder, MNIST dataset.ipynb ├── Autoencoder, cifar-100 dataset.ipynb ├── README.md ├── autoencoder_MNIST_final.h5 ├── autoencoder_cifar100_final.h5 └── autoencoder_utils.py /Autoencoder, MNIST dataset.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "

Part 1 -- Autoencoder

\n", 8 | "
Each MNIST image is 28 X 28 X 1. This will be compressed to 4 X 4 X 4 using an autoencoder (784 variables to 64 variables).
" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": 1, 14 | "metadata": {}, 15 | "outputs": [ 16 | { 17 | "name": "stderr", 18 | "output_type": "stream", 19 | "text": [ 20 | "Using TensorFlow backend.\n" 21 | ] 22 | } 23 | ], 24 | "source": [ 25 | "from keras.datasets import mnist\n", 26 | "from keras.layers import Conv2D, MaxPooling2D, UpSampling2D\n", 27 | "from keras.models import Model, Sequential, load_model\n", 28 | "\n", 29 | "import copy\n", 30 | "import matplotlib.pyplot as plt\n", 31 | "import numpy as np\n", 32 | "from autoencoder_utils import *\n", 33 | "\n", 34 | "(X_train, _), (X_test, _) = mnist.load_data()\n", 35 | "\n", 36 | "X_train = np.reshape(X_train, (len(X_train), 28, 28, 1)) / 255.\n", 37 | "X_test = np.reshape(X_test, (len(X_test), 28, 28, 1)) / 255.\n" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": { 44 | "collapsed": true 45 | }, 46 | "outputs": [], 47 | "source": [ 48 | "autoencoder = Sequential()\n", 49 | "\n", 50 | "input_shape = (28, 28, 1)\n", 51 | "autoencoder.add(Conv2D(32, (3, 3), activation='relu', padding='same', kernel_initializer='he_normal', input_shape=input_shape))\n", 52 | "autoencoder.add(Conv2D(16, (3, 3), activation='relu', padding='same', kernel_initializer='he_normal'))\n", 53 | "autoencoder.add(MaxPooling2D((2, 2)))\n", 54 | "autoencoder.add(Conv2D(8, (3, 3), activation='relu', padding='same', kernel_initializer='he_normal'))\n", 55 | "autoencoder.add(MaxPooling2D((2, 2)))\n", 56 | "autoencoder.add(Conv2D(4, (3, 3), activation='relu', padding='same', kernel_initializer='he_normal'))\n", 57 | "autoencoder.add(MaxPooling2D((2, 2), padding='same')) #padding=same here, to maxpool 7*7 to 4*4\n", 58 | "autoencoder.add(Conv2D(4, (1, 1), activation='sigmoid', padding='same', name='encoded_layer')) #sigmoid to convert all to values between 0 and 1, for comparison later on using binary_crossentropy\n", 59 | "#at this point, encoded layer has shape (4, 4, 4)\n", 60 | "\n", 61 | "autoencoder.add(UpSampling2D((2, 2)))\n", 62 | "autoencoder.add(Conv2D(8, (3, 3), activation='relu', padding='same', kernel_initializer='he_normal'))\n", 63 | "autoencoder.add(UpSampling2D((2, 2)))\n", 64 | "autoencoder.add(Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal')) #no padding=same here, to convert 16*16 to 14*14\n", 65 | "autoencoder.add(Conv2D(32, (3, 3), activation='relu', padding='same', kernel_initializer='he_normal'))\n", 66 | "autoencoder.add(UpSampling2D((2, 2)))\n", 67 | "autoencoder.add(Conv2D(1, (3, 3), activation='sigmoid', padding='same'))\n", 68 | "\n", 69 | "autoencoder.compile(optimizer='adam', loss='binary_crossentropy', metrics=['binary_crossentropy'])" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": { 76 | "collapsed": true 77 | }, 78 | "outputs": [], 79 | "source": [ 80 | "epochs = 30\n", 81 | "batch_size = 128\n", 82 | "\n", 83 | "autoencoder.fit(X_train, X_train,\n", 84 | " epochs=epochs,\n", 85 | " batch_size=batch_size,\n", 86 | " shuffle=True,\n", 87 | " validation_data=(X_test, X_test))" 88 | ] 89 | }, 90 | { 91 | "cell_type": "code", 92 | "execution_count": 2, 93 | "metadata": { 94 | "collapsed": true 95 | }, 96 | "outputs": [], 97 | "source": [ 98 | "# from h5py import h5py\n", 99 | "\n", 100 | "# autoencoder.save('autoencoder_MNIST.h5')\n", 101 | "# autoencoder = load_model('autoencoder_MNIST_final.h5')" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "metadata": {}, 107 | "source": [ 108 | "
\n", 109 | "The code below displays the original and autoencoded versions of 10 images.\n", 110 | "
\n", 111 | "They look pretty similar\n", 112 | "
" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 6, 118 | "metadata": {}, 119 | "outputs": [ 120 | { 121 | "data": { 122 | "image/png": "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\n5c9Mnz49Op45c6bFK1assJh1mTf9m4cQwssvv2xxjRo1LF65cmU0T9u8a1v3EFhHm1uZMmUs1nW0\n1157RfP0s9BfM60tdckll1g8ceLEaF5JXFfsxAEAAAAAAEgAHuIAAAAAAAAkAOlUAIAQwoYpTqlS\nLnyaRrqxbbbZxuIqVapYfNaeYcy1AAAgAElEQVRZZ0XzOnXqZHGvXr2isRkzZmz03LPVllv+/THd\no0ePaOyYY46xuF69ehZru9QQ4u3Czz//vMUjR46M5v3888+bdrLYqNKlS0fHu+66q8XNmjWzeLfd\ndovmrVq1yuJy5cpZXL58+Whe9erV85wXQgg//PBDnvGPP/6Ycl6rVq2iMU17vOeeeyz+8MMPo3lr\n1661mJSD/NP7ZuvWraOx008/3eIWLVpYrNcthBDGjx9v8QsvvBCNzZ8/32Jd91yrwqNrvU2bNtHY\nnXfeabGu9Z9++imaN3r0aIsfeOCBaOz7778vlPPMZppuqJ99IaROXatQoUJ0PGzYMIv333//aGz1\n6tWbeorIB/8dddy4cRa3b9/eYn8fW758ucX6GRZCCE2bNrX4uuuus7h3797RvNmzZxfgjIsWO3EA\nAAAAAAASgIc4AAAAAAAACZD4dCq/dV+3JQ4cONDipUuXRvN0y9SyZcuiMbaTApuHX8+6FTZddflM\nO63oVkzf1UNTUNasWRON/fbbb+lOO3H0b6n3zP322y+a98EHH1isKTn+76F/c5/Ko+keVatWtdhv\nS95ll13yfL1co+lTIYRw7rnnWnzNNdeknKudE3x3L02xOfDAAy2+4IILonm33HKLxcOHD4/G1q1b\nt9FzR940rUlTkEIIoUOHDhZrCs2iRYuieZo6oevXby/X3+W7uu20004W63uiUqVK0bwddtghz5/x\n6tevb/FVV10Vjb322msW+/sp/qTXUdPqQgihT58+Fp966qnRmM7V+61PD9Hro6l6IcT383fffdfi\njz/+OJqnaQj+/VQSu7UUN72GlStXjsb0up100knRmKYW69/RpyXefPPNFs+bNy8a0+vBtcibdi+q\nWLFiRj/jv4fuvvvuFvs0108//XQTzg751bFjx+hYv0fqdZs7d24075lnnrF4zz33jMY0ZVjXZbrO\nfyVFyT9DAAAAAAAA8BAHAAAAAAAgCXiIAwAAAAAAkACJrImjeWq+Te2ll15q8fbbb2/xr7/+Gs3T\n2gxPPPFENKatGH0OMOBrEOj7kboRG+db7LZr187iY489NhrTug3bbrutxd999100T2uDfPPNN9FY\nzZo1LdacaJ9f/t///tdi34rSt+BNOs3dv/HGGy3+8ssvo3lvvvmmxfreTndf9PVsfNvbv/j2qPr6\nCxYsSPn62a5s2bLRsbYV9/eeFStWWPzJJ59Y7Fuy165d2+KGDRtarHWIQgjhpptusrhv377RmOae\n01Y1Pd/CdNCgQRZ37949GtN7l97X9H4UQghvvfWWxdoS2l+LdPW79P2jbXT33XffaJ7WVqlVq1Y0\npj+na91/x+KzMG9aw0ZrbfznP/+J5h1wwAEW62dfCCG8/fbbeb6ebymvtbH8a3Tq1Mninj175vna\nIcQ1Wb799ttoLFfrsOg6atKkicWDBw+O5mm9q6233joaW7lypcVav0PrdYYQ/83T1aJD3rS+l35e\nhhDfy/Sa+po4eu18Lb/PPvvMYq5H0dDrMWDAgGhM73/6+XnllVdG87RGW5s2baKx+++/32L9/qVr\ntKRiJw4AAAAAAEAC8BAHAAAAAAAgARKTTqXbqQ477DCLNX0qhHhLr26f0jaJIcRb5w499NBobOHC\nhRZPmzbN4lzdOppN/DbJdGOajtetWzeLfTtWTbUZP358NObfd9nM//10+7ZuDe/Xr180T7en+vbK\nmiqgbWr9tnFNX/BtVvU6artJ/e8hxPcLv/U86elUPoXt3nvvtVhbZg4dOjSap9tTM22z7u+Tmnql\nf3P/99fULd8iO5doqkwIIbz00ksW//TTT9GYtqueNGmSxf7vp39rbSPv0xc7d+5scePGjaOxI488\n0uKRI0em/h+Qo/T+py1LQwjh6KOPttinVeg11dTu22+/PZq3bNkyi3Ut+i38eh7+nqypv3ovnDVr\nVjRP7xe+xbj+vjlz5ljsW6LzfelPPj1S19zJJ59scbVq1aJ5mvrhU/5HjBhhsV4fTZX0x/466j1B\nywtoW/IQ4s/CJLTcLQp+zWoq2rXXXmtxnTp1onn6fcanDw8bNsxiTZ3UtNgQ4rRE0nXyT/9+er8K\nIW4nvc0221js05a5l21emjLl03v1+k6YMMHiV155JZqnn7P6ev419D2SqhRASZKbd2QAAAAAAICE\n4SEOAAAAAABAAvAQBwAAAAAAIAESUxNHcxdvueUWizVPPIQQzjzzTIs//PBDi32NC63DoW0AQ4jz\n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\n", 123 | "text/plain": [ 124 | "" 125 | ] 126 | }, 127 | "metadata": {}, 128 | "output_type": "display_data" 129 | } 130 | ], 131 | "source": [ 132 | "n = 10\n", 133 | "img_to_show_idx = np.random.choice(range(X_test.shape[0]), n, replace=False)\n", 134 | "X_test_to_show = X_test[img_to_show_idx]\n", 135 | "aft_autoencode = autoencoder.predict(X_test_to_show)\n", 136 | "\n", 137 | "fig = plt.figure(figsize=(n*2, 5))\n", 138 | "plt.gray()\n", 139 | "img_shape = (28, 28)\n", 140 | "\n", 141 | "for i in range(n):\n", 142 | " #display original\n", 143 | " display_single_subplot(X_test_to_show[i].reshape(img_shape), n_row=2, n_col=n, cell_num=i+1)\n", 144 | " #display aft autoencoding\n", 145 | " display_single_subplot(aft_autoencode[i].reshape(img_shape), n_row=2, n_col=n, cell_num=n+i+1)\n", 146 | "\n", 147 | "plt.show()" 148 | ] 149 | }, 150 | { 151 | "cell_type": "markdown", 152 | "metadata": {}, 153 | "source": [ 154 | "

\n", 155 | "Part 2 -- selecting similar images\n", 156 | "

\n", 157 | "
\n", 158 | "Given an image, select the most similar and dissimilar images, using binary cross entropy to determine similarity\n", 159 | "
" 160 | ] 161 | }, 162 | { 163 | "cell_type": "code", 164 | "execution_count": 7, 165 | "metadata": { 166 | "collapsed": true 167 | }, 168 | "outputs": [], 169 | "source": [ 170 | "#find images similar to the image at this index\n", 171 | "img_to_find_idx = 0\n", 172 | "\n", 173 | "layer_name = 'encoded_layer'\n", 174 | "encoder = Model(inputs=autoencoder.input, outputs=autoencoder.get_layer(layer_name).output)\n", 175 | "\n", 176 | "similarity_sorted = get_sorted_similarity_idx(encoder, img_to_find_idx, dataset=X_test, loss='binary_crossentropy')" 177 | ] 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": 8, 182 | "metadata": {}, 183 | "outputs": [ 184 | { 185 | "data": { 186 | "image/png": "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\nhJDza+x89NFHbel2I2iosTho0KCQTzvttKRt+PDhIY8dOzZpu+uuu9r71jU3adKkkN9///26vlcj\njcWf/OQnId93331J23/+85+Qy92zeFzF30OyLMvGjBnT3i42qorGoidxAAAAAArAJA4AAABAAXRq\nOdVVV12VHO+6667tvuYbb7wRcvyYd/4x0x/+8IfTfU1e/Lr8Y8vHH398yOVKvGqhkR6PK+eYY44J\nOf/4Y2eJH2McMmRI0nbRRRd1ZFca6lHVWFwWlWXly6lK+frrr5Pj+LPlsssuC/nMM89MzuvkErc2\na9SxuMEGGyTHDz30UEWvi+/b6NGjk7ZHHnmkomvEj8LmPwt/9rOfhXzttddWdL0333wzOX7rrbcq\nel0bNOxYnGWWWZLjO++8M+SNNtooaevSpUst37oq+RKdo48+OuSzzjqrru/dqGPx0UcfTY7jcqr8\n+Jg4cWLI+bLHWPy6Sl+T/2z973//G/ICCywQcr5kKv7es9NOOyVtN910U8n3q1LDjsVll102OX7t\ntdfKvXfIbfle/T9xaUGWlS/FifsRl0Cuv/76yXlx2eO6667b5j61RSONxX322Sfkf//730nbSiut\nFHK+BHm99dab7vV69eqVHMf3t9x9j0uthg4dmrTdc889Ib/66qvTfd9O0FBj8eKLLw45vqdFFJcB\n5cudf/Ob34Rci1KrRhqLSy+9dMj/+Mc/krYllliizdfL/53x4IMPVtexSLwUxFdffRXyww8/nJyX\nX3aizpRTAQAAADQLkzgAAAAABWASBwAAAKAAOnVNnIUWWig5juvS8vW7cf12o9hxxx1DrkOdeKKR\nahzLmX/++UOudFvMcjbddNOQ89t9xuKtzbMsXSdg5plnDjmud8yyLNtvv/1CvuKKK6ruZ4Uaqt44\nVm4NnHw9eH6L3P/Jr2nVvXv36Z6X36I2XlPjmmuuSdrimv78GlqdpVHHYryNdJalP88777xzLd+q\n7vK1x//6179C3mSTTWrxFg07FsvJbxm96qqrhrzWWmu1+XrlxlT8uZll6WdqvM7RDjvskJz361//\nOuS//OUvbe5TWzTqWDzooIOS43POOSd+r6Qt/g5Wahv3vBEjRoT8+uuvlzwvv5bU+PHjQ44/n196\n6aXkvAUXXDDkGXlNnFlnnTU5jtdTue6665K2Aw88MOR4ncV4/cUs++56X/+TXwuj0vUX4n7E30mz\nLP25O/zwwyu6XrUadSzWwmabbZYcb7vttiHH6xDlv/OWWy8nXuPq1ltvDTm/dk4Hr5fTUGNxzjnn\nDPmoo45K2uJ1xvJrw8XfWeeaa672dqNi8f3O//4sZ6uttgr57rvvbnc/GnUsDhw4MDn+xS9+EfKW\nW25Zy7f6ztqC1Xj33XeT43iNtKlTp7b7+t/DmjgAAAAAzcIkDgAAAEABdGo5VTn50pn4sbq4dCa/\nveaPfvSjkOOtpfPboMbbN+Yfmd1rr71CnmeeeUr28cUXXww5/yj7tGnTSr6uGo36eFyjih/xHz58\neMj5e33jjTeGnH9svA4a6lHVWptvvvmS43j7zt122y3kbbbZJjlvkUUWKXnNb775JuT4MfRzzz03\nOW/kyJEhv/zyy5V1uEpFGYuzzz57yPlH+uPHwz/99NOQd9999+S8xRdfvN39WHjhhUOOP4fbso19\nvFX1EUcc0e4+ZU0+Fust/v2Zv4/9+vUL+amnnqprPxp1LMbfV7Isy7p161bR6+ISi3h74nqIvys9\n9thjSVv8WT4jl1M1qrXXXjvkeKvq+DtvlmXZKqusEnK+jLnWGnUsdqZ4W+ztttsuaYt/B8d/h+XH\nffz3ztNPP13rLuYZi+2w2mqrhfzcc8+VPC+/dMOee+5Z034Yi1m2xx57JMf5v/1i6623XshxiVde\nXJKa/xukDpRTAQAAADQLkzgAAAAABVD58tkd7L333ivZdsEFF9T1ve+7776Q40dV83r06BFyvuwq\nftycjhffw/gR9XKP1NE++Ue5491V4nzCCSck5y211FIh77vvvknbRhttFPIyyywT8vnnn5+cF68i\nv/nmmydt9S6valRffvllyPkdLkrteFGPHdriso0VV1wx5FtuuSU5b6aZ/u//U4jL6LLsu7vn0PGG\nDBkSclxuE3/WZln9S6iKIF+6Uu9Slmr07ds35HwpbH4HLRpLvDPPvPPOG3J+d8dG/LmbkVx66aXT\nzVmWllNdeeWVIcd/V2RZurxDB5RT0UZxqXr+O03s/vvvD/m3v/1tPbtE1radMePvw+XKqcaOHdue\nLtWFJ3EAAAAACsAkDgAAAEABmMQBAAAAKICGXROnM/Xq1aui8z7//POQrYHTWOIt4+Ka8bypU6d2\nRHeI5LfQjI/z62ksuOCCIR9wwAEhH3/88cl58TblG2+8cdI2o66J0yhef/31kE8//fSQ4zVwsizd\nZjW/jXi8ZgAdI96iPsuy7LDDDgs5vndnnHFGh/WJ9onXp/rd734Xcjz2sixdgypez4zO0bNnz+Q4\n/v0Xrwd34IEHdlifaJ9777035HHjxoW80EILdUZ3qFCXLl2S46OOOirkpZdeOuS33347OW+33XYL\n+f33369T76jGcccdN93//euvv06O77rrro7oTpt4EgcAAACgAEziAAAAABSAcqrsu9tOb7PNNhW9\nrtz243SsmWdOf5R333336Z6XL58677zz6tYn2m+dddYJeddddy153iOPPBLy8OHD69on2qZ///4h\nb7fddiXPO+ecc0I+99xz69klKhBvbZtl6TbUkyZNCvmNN97osD7RNnPOOWdyPHTo0JC7detW8nWb\nb755yOPHj699x2iTPfbYIznu3r17yPltxSmGFVZYYbr522+/Tc6Ltz+m8+VL+ffdd9+Qv/rqq5DP\nPPPM5DwlVI2jX79+yXH8HTUWl/9nWXp/G4UncQAAAAAKwCQOAAAAQAEop8qybNttt02O+/TpM93z\n4h0bsqz0itZ0vF/96lfJ8cCBA6d73t///vfk+Jlnnqlbn2i7/E5i8S5FSy21VMjPPfdcct6wYcNC\n/vjjj+vUOyqRL8O57LLLpnvexIkTk+PTTjutbn2iMvHOKEOGDCl53uDBg0N+66236tonqhfvDJdl\npXe+iXf+yzIlVI0g3s1mn332SdqmTJkSclyGSnHccsstIcdlj/FOVVmmXK4RxH8TDho0qOR5jz76\naMgXXHBBXftE9bbccsvkOL/j2P/ccMMNHdGddvEkDgAAAEABmMQBAAAAKACTOAAAAAAFYE2cLMtO\nPvnkkm0tLS0h33333UnbJ598Urc+8f1mmWWWkHfeeeeS502bNi1k6240nngdnMsvvzxpW3fddUN+\n9913Q95ss82S8z766KM69Y5KLLbYYiEffPDBFb0m3pozy6xl1AjWW2+9kPPrp3zxxRch33777R3W\nJ9pm7rnnDnnhhRdO2lpbW0N+/vnnQ7722mvr3zHaZJdddgk5/q6TZVl24403hpxfH47GFG8jnmVZ\ntvzyy4ccj8tLLrkkOc93m4632mqrJcfx337zzTdf0vbEE0+EnF9flcZx4IEHhnz44YeXPO+BBx4I\n+bXXXqtrn2rBkzgAAAAABWASBwAAAKAAZphyqrgsKsuy7PTTTw85fqwx76abbgr5mGOOqX3HqFpc\njtG/f/+S591xxx0hx48+0hg233zzkLfbbruk7aWXXgr5vPPOC9kjxo3l5ptvDnmVVVYped7FF18c\n8m233VbXPtF222+/fcm2Sy+9NORJkyZ1RHeoQPfu3ZPjW2+9NeS4TCPLsmzy5Mkhn3LKKdP93+kc\niy66aHIclxLn70++5IbGtOSSS4acv2fx3yTx95lhw4bVv2N8R9euXUM+8cQTk7a4hOqf//xn0hZ/\nZ/3000/r1Dvaq2/fviHntxSPS/l//etfh/z111/Xv2Pt5EkcAAAAgAIwiQMAAABQACZxAAAAAApg\nhlkTZ9ZZZ02OjzjiiJLnxnXk8VoP3377be07RsU23njj5Lhc7XC8fequu+5atz7RdltttVVyfP75\n54c8ZcqUpO2QQw4J+cEHH6xvx6hYv379kuPVV1+95LmjRo0Kef/9969bn2i7/Gfqz3/+85DzY3Hw\n4MEd0ifaZqONNkqO47VU8o4//viQ47Vz6Hz77bdfchyv0XHyyScnbY888kiH9In22WuvvUKO1+TI\nsvTvjN12263D+sT0xevB5ddmjF144YXJ8cSJE+vWJ6o3++yzJ8fx+lR5zz77bMjjxo2rW5/qwZM4\nAAAAAAVgEgcAAACgAGaYcqorr7yy4nOPO+64kK+77rp6dIcqnHPOOcnxXHPNFfKECROStvgx1qlT\np9a3Y3yveeaZJ+T89o3dunUL+fDDD0/alFA1jt69e4f8j3/8I2mLy1WvvfbapO2AAw6ob8eoWn5L\n8fgR/2eeeaaju0OFFllkkZDjEqm8zz77LDkeOXJk3fpE2y2wwAIh53/3xduKK58qhvXXXz85HjJk\nSMjxZ2uWZdl999033UzHib97HnbYYSXPu/HGG0NWhloMm266aXK89tprlzz31FNPrXd36saTOAAA\nAAAFYBIHAAAAoACaupxqjTXWCHnAgAElz8s/cjxixIi69Ym2iXdEWXXVVUued9pppyXHTz/9dN36\nRNvFpXC9evVK2saMGRNyvhSHzjXTTP83z3/VVVeFnN/t74knngg5Xz41adKkOvWOaiy//PIhDxw4\nMGmLd2A8/fTTO6xPfL/55psv5AceeCDk5ZZbruRr8jtXxbs20vninRlnm222pC3+vM2Xr9I4evTo\nEfLZZ5+dtMUlVPlyKjtSdb64jGaVVVYped6+++4b8rRp0+raJ2ojXhYl76GHHkqOH3300Tr3pn48\niQMAAABQACZxAAAAAArAJA4AAABAATTdmjiLLrpoyKecckrI+Xrj2E477ZQcv/DCC7XvGBX76U9/\nGvJRRx0VcktLS3LeX//615CHDx9e/47RJvGaVNtss03IU6ZMSc6L18t577336t8xKnbFFVeEvOKK\nK4b86aefJufF2+NaA6exrbPOOiHHWxxnWZaNHj06ZGvDNZb4d9yyyy4bcn6tjfHjx4dsbbjGE6+h\nkt8GN+beFcPFF18ccs+ePZO2+LvO0KFDk7aPPvqovh3jOzbbbLPkeO+9957uefnffZMnT65bn6iP\n+Hdk3htvvJEcf/311/XuTt14EgcAAACgAEziAAAAABRA05VTHXnkkSFvtdVWJc8bOXJkyPfff39d\n+0R5+UdQr7zyypDnn3/+kONtjLMsyw466KCQJ0yYUKfeUam55porOT700END7t69+3T/9yzLsksu\nuaS+HaNigwYNSo5333336Z73hz/8ITl+5JFH6tYnaitfPhx78sknO7AnlHPCCSckx1tuuWXIcQlV\nvP1tlvk+0+ji8pt555035BtvvDE5Ly5lpbEMGTIk5G233TbkfGnjrbfeGvKwYcPq3zHKOvroo5Pj\nLl26hDxu3LiQ89+Dvvnmm/p2jJrYeeedQ44/W/Piz+Ci8yQOAAAAQAGYxAEAAAAoAJM4AAAAAAVQ\n+DVx+vXrlxzvuuuu0z0vX9MYn/fVV1/VvmOUFW/5fvvttydt8To48VbG8ZoAWZZlEydOrFPvqMb5\n55+fHO+yyy4hT506NWTrbjSWOeaYI+R4u/e8++67L+Qzzzyzrn2itpZccsmQ878zYzfffHNHdIcK\nrLnmmhWd9/LLLyfHb731Vj26Q5Xya/6tt956Ib/77rshH3XUUcl5vpc2jvjzM8vS9Rhnmun//r/w\nU089NTnv+OOPr2/H+F5zzz13yAsssEDS1tLSEnL8vfTtt9+uf8eoua233rpk2yeffBLypEmTOqI7\nHcKTOAAAAAAFYBIHAAAAoAAKWU7VtWvXkPPb9sWlONOmTQt5//33T85755136tQ7SolLqIYOHRry\noosumpz3+eefhxw/+q98qvHE97R3795JW/w4+BFHHBHyqFGj6t8xKnbccceFPOussyZtY8aMCTne\nSvWLL76of8eombh8OP79+cILLyTn3XvvvR3WJ75rhx12CHmbbbZJ2uJH/3/3u9+F/Pjjj9e/Y7RJ\nPMauv/76pK179+4hH3rooSG/+eabde8X1dlrr72S4/gefvDBByFfdtllHdYnKrPddtuFvPLKKydt\ncZm/EvFiWm211UIeMGBAyfOOPfbYkOPvtUXnSRwAAACAAjCJAwAAAFAAhSyninfB6du3b8nzXnrp\npZCvuOKKuvaJ7xc/Yjx48OCS5/3lL38JOb6HNJ74kf+VVlopabv//vtDvvjiizusT3y/+HHweKeN\nvEGDBoWshKq4+vTpM93//ZVXXkmO3ePOtdVWW4Xc2tqatE2YMCHkCy+8sMP6RNvtvffeIS+99NIl\nz4tL/mlc++67b3Iclzb+4Q9/CNmuRo2nf//+JdviHTefeOKJDugNtRbvrjr77LOXPK9Zl+PwJA4A\nAABAAZjEAQAAACgAkzgAAAAABVDINXHiLRvjrVOzLMu6dOkS8tlnn91hfeL7xVv9lfP73/++zj2h\nVuLa8LxNNtkk5HhNDluMd76tt9465Hitqrx//vOfHdEdamyxxRZLjn/84x+HHG8rHm9VTedYZZVV\nQt52221LnhdvkfrOO+/UtU+0T3yv8j788MOQH3zwwY7oDu20xRZbJMcjRowIOR6zp512Wof1ifbL\n/56EovEkDgAAAEABmMQBAAAAKIBCllPdfffdIR988MFJ25prrhnydddd12F94vs99NBDIcePg48b\nNy4577PPPuuoLtFO8Rbw77//ftL26aefhmzrzcZSroQqdvjhh4d8yimn1Ks71Niee+6ZHMdbbw4e\nPDjk5557rsP6xPTFv+8mT54c8ujRo5Pz/vSnP3VYn2ifuEzqlVdeSdrOPffckCdNmtRhfaJ6Tz/9\ndHL8gx/8oJN6Qludc845IW+22WZJW/wdleYyZcqU5HjMmDGd1JP68iQOAAAAQAGYxAEAAAAoAJM4\nAAAAAAXQ0traWvnJLS2Vn0xNtba2lt7LuQ3cw071dGtra+9aXMh97DzGYlMwFpuAsdgUjMUmYCw2\nBWOxCRiLTaGisehJHAAAAIACMIkDAAAAUABt3WL8oyzL3qpHRyhryRpeyz3sPO5j8bmHzcF9LD73\nsDm4j8XnHjYH97H43MPmUNF9bNOaOAAAAAB0DuVUAAAAAAVgEgcAAACgAEziAAAAABSASRwAAACA\nAjCJAwAAAFAAJnEAAAAACsAkDgAAAEABmMQBAAAAKACTOAAAAAAFYBIHAAAAoABM4gAAAAAUgEkc\nAAAAgAIwiQMAAABQACZxAAAAAArAJA4AAABAAZjEAQAAACgAkzgAAAAABWASBwAAAKAATOIAAAAA\nFIBJHAAAAIACMIkDAAAAUAAmcQAAAAAKwCQOAAAAQAGYxAEAAAAoAJM4AAAAAAVgEgcAAACgAEzi\nAAAAABSASRwAAACAAjCJAwBFJtk5AAAfQElEQVQAAFAAJnEAAAAACsAkDgAAAEABmMQBAAAAKICZ\n23JyS0tLa706Qnmtra0ttbiOe9ipPmptbe1Riwu5j53HWGwKxmITMBabgrHYBIzFpmAsNgFjsSlU\nNBY9iQMd563O7gCQZZmxCI3CWITGYCxCY6hoLJrEAQAAACgAkzgAAAAABWASBwAAAKAATOIAAAAA\nFECbdqeCRvXggw8mx/379w95ww03DPmhhx7qoB4BAABAbXkSBwAAAKAATOIAAAAAFEBTl1Pts88+\nIV944YVJ22677Rbys88+m7Stv/76JV8XW2WVVUJ+9dVXq+4nlYlLpLLsuyVUpcTnxaVVWaa8CgAA\nZlSbbrppyEcffXTSFv/dMGrUqKRt2LBhId9555116h1MnydxAAAAAArAJA4AAABAAZjEAQAAACiA\nplsTp0ePHiH37ds35G+//TY578orrwz5nXfeSdr++c9/lnxd7Kqrrgp57bXXbntn+V7xOjiVroFT\nTv4ath/vGEsssUTIra2tSdu4ceNCfuCBB5K2+P63tLSUvEa8xtU111zTrr4CADOuWWaZJeTjjjsu\naTv++OMrukb8nWWnnXZK2p5//vnpvtdrr72WnPfVV19V9F58v/nnnz853m+//UI+4YQTQo7vR5al\nfwf26dMnabvxxhtDXnXVVUMeM2ZM+zpLRbbYYouQF1tssZDPOuus5Ly555475BEjRiRtO++8c8if\nffZZrbtYV57EAQAAACgAkzgAAAAABdB05VQXXXRRyNtss01Fr4lLPbIsfSTrkUceCblfv37t7B2V\niEtoTjzxxA57L+VUbTfnnHOG3LNnz6TtqKOOCnnhhRcOOV8K9d5774UcP46aPzf/utjvf//7kKdN\nm5a03XTTTRVdY0ay+OKLh7zOOuuEHJe25cWfkwcffHDStu6664acL0GdaaaZptsWl7tmWZY9/vjj\n39dtcjbYYIOQBw8eHHL+Hqyxxhohb7755iGPHj265LX33nvv5Lhr167TPe/hhx9Ojp955pkyPaZa\nW2+9dci9evUKOV/aUWq8tcXll18e8lNPPZW0XXrppVVdc0YVP6qfZVm2/PLLhxzfu/i+ZVnl9+72\n228PuVu3biXbrrvuuqRt/PjxFV1/RhV/nubLqSr9HhGfd+211yZt8edk/D3q7rvvTs774osvQr76\n6quTtnzpFeXFv/uyLMtOOeWUdl8zLr3q0qVLTa+X/+yIl/CYkSyyyCIhx0umZFk6NuPvsnnxWNxy\nyy2TtnjeIC7D+vDDD5Pz3n333Qp73HE8iQMAAABQACZxAAAAAAqgpS3lBS0tLQ1XizB8+PDkOH78\nrNLHUfOPJMaPWh177LEh77nnnsl5U6dODXno0KFJ27Bhwyp670q1tra2fP9Z368R72Fc0pRltdmF\nqpR8ydTJJ59csq0Onm5tbe1diws1yn0888wzQz700EM7sSelxY+Yf/LJJ+2+XhHHYvxoeJZl2cCB\nA0OOd9bLPy4a/36IS7AqLZkq15Z/r8ceeyzkn//859P5V9RUYcZi9+7dQ/7Zz36WtMXjL959odzv\n9YkTJ4acL7GId1PZZ599krZSj4rnx9Rdd90V8gUXXJC01bpkrohjsZyFFloo5P333z9pi8tT87un\nxMrt4leN/Hi+8MILQz7kkEPaff2sQGOxUvFn5X333Ze0LbfcctN9TXzfsqy6e1fuGoMGDUraLrnk\nkjZfv5wijsX8Z1r8ezIu5Y/LnTpT/m+VeCfdfffdtxZv0XRjMf4ucfHFFydtpUqE8+JxNWTIkKTt\n1ltvDfmNN94IOV/WX6l55pkn5Ph3dZZl2cwzV7YCShHHYl78uzD+ThGXhtfbs88+mxzHcwMffPBB\nvd++orHoSRwAAACAAjCJAwAAAFAAJnEAAAAACqBh18SZa665kuMVVlgh5GOOOSbkbbfdNjmvmu01\nK60zfPLJJ5PjeJvP/Hvtt99+If/pT3+q6PrlNEONYyxeB6eea+DkbbjhhslxB28rXsh64/nnnz85\njreYjbf0i7cBbCQz6po4O+64Y8j57U1LfU6W2+a23Fob1bSVW78h3hY+y7Jsp512ymqsMGMxrunP\nbzGb60fI1a6FUutrfPTRR0nbbbfdFnIt1nAoyliMLbHEEsnx9ddfH/JSSy0V8gILLFDV9Wu9Jk7e\nN998E3K8btKVV15Z7SULMxbLiddjPOGEE0IutQZOXr3XxJk8eXLSFq+vVYvvYEUZi/369Qt5k002\nSdriLd+L4NVXXw05vp/t2Hq8KcZiLF6TaqONNqrqGvH33Pw6KfHnYS1YE+f/s8cee4R8+eWXd1Y3\nEi+//HLI+bmHsWPH1vrtrIkDAAAA0CxM4gAAAAAUQGXPZnWCuHwqy9LtZ2PlSqbitngrvixLH0Os\nVP7x1vj6+X7Ej2zGj5DnHy+fkZx00kkhx9s31kNcJpUvoaJt8luT5rc5bnSHHXZYyDfccEPIL730\nUmd0p8McfPDBIVf6OVmurZptxMu1lSvdih9fzh/XepvqRnPRRRclx9tvv30n9aT94u3Rsyx9BDne\nmvWee+7psD51hriEKv53Z1mWrb766jV9r9GjR4ccP/5dzgYbbJAc50toY/G2zPHv8fx3tLgfzWi+\n+eZLjo888siQKy2hKmfKlCkh58soZp111jZfb+65506O4+3hO7KkvbOdccYZIffp06ei1zz33HPJ\n8fDhw0OOl3eotgSyWvHfSX/5y19C3m233ZLzxowZ01FdagjbbLNNyGuuuWZFr4nLooYNG5a0PfXU\nU7XpGCVtttlmyfG5557bST0pbeWVVw45/rs+y7LsJz/5Scjvv/9+h/XJkzgAAAAABWASBwAAAKAA\nTOIAAAAAFEDDrokT15lWK14HJ7+uRzVr4rTFL37xi5DPO++8kGfkNXHquQ5Ofqvwk08+uW7vNSOI\n13Q68MAD6/peEyZMCDm/7fDSSy8dcrym0pxzzlnx9YcMGRLyF198EXKzrYkTb1WcZVm27rrrhlxu\nnZpK/vcsS7evza9L8+6774acXzssXg8kXoMgvx1u/N6LL7540havC9Psa+JsueWWyXG3bt06qSe1\nF6+RE6/9E2+t3QzyP79x/fxqq63W7ut//fXXIT/88MNJ25577hnyO++8U9H1VlpppeQ4/szcaaed\nSr4uHtuHH3540hZvP94s4nVw/v73vydt8X2txdbuI0aMCPn2229P2o444oiQq11TqRY/h0WQ/65Q\n6TbNb7/9dsj5dQDfeuutkOP1Um655ZZquph17do15Nlmm62qa6y99tohx2t3ZFnzr4mTX0Pvz3/+\nc8j5tatKefPNN0OOv2vSMQ444IDkON5qvRHlx1j8eb311luHPH78+Lr2w5M4AAAAAAVgEgcAAACg\nABqqnCreti/eijTLym+DG3vllVdC3mOPPUIeN25c+zpHm9V720rbiNdOXD6VZVl27bXXhlzrbTOv\n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\n2U022SRp69u3b8izzTZbRdfLr7XxwAMPhDxgwICKrvE9On0sxt/fzjrrrKreu71jp9rvoeWu8eqr\nr4Ycr8+SZenPay000liMfz9V+zk2bdq0kPNbTldq9dVXD7naz4RYfk2RuF/59eyq1OljsZTll18+\nOY6/38w333y1fKvvqMWaOPG6qfF28FmWZffee2/I8bb3b775ZnJet27dKnqvRhqLv/rVr0K+9NJL\nk7b851WRTJkyJTmO102t0Xp2FY3F4v4XBAAAAJiBmMQBAAAAKIAOKaeKrbDCCiFfeOGFSVtcXtUo\n5VTXXHNNyPHje1mWPh532223VfRe1Wqkx+OqddJJJ4W8wQYbhNyRZVb5sqiHH3445Lh/ddLpj6ru\nsssuIV911VW16EqHee+990I+9dRTk7arr7465FqXT+UVZSzG2xzG5Wb//3uHXG5r71Jt+d8b1bRV\n+l75tsMPPzzkeAv0Nur0sVjKXnvtlRxffPHFlfYj5Gof+a7FNV5//fWQ858xf/rTn0L+8MMPq7p+\nrJHGYrxF7dNPP520zTHHHO29fMVqcQ/jkr582e35559fXcdK6/Sx2LVr15Cvv/76kDfbbLO2vHfI\n1fx3L/eZV6l47GVZlm2xxRYh50szaq2RxuKLL74Y8korrdTey9Xd6NGjQ47/rsiydJvtP/7xj0nb\nN998U+uudPpYrFRcktS7d9rl+HvunHPOGfLMM89c1XtVOrY///zzkON7mmVZtt1224Vcrux71lln\nDXmVVVZJ2p555pnv72zWWGMxNnTo0OT4qKOOquXl6y7+OyM/FmtUQhVTTgUAAADQLEziAAAAABSA\nSRwAAACAAujwNXFiSyyxRHIcb5+Wry+L60Lj+sRtt902OS9e3yZ+zbBhw6rqY1y7mK9V7UiNWuNI\nm3R6vXFcb7vAAguEfM899yTnrbzyylX2rO3GjRsXclzLnnfMMceE/NJLL9W1T+UUZSwutthiIffp\n0ydpu+GGG0KuZtvvSrcsL9fWli3Gzz777JCPPPLIrAY6fSyW0r179+T4z3/+c8hbbbVVuX6EXI81\nceK1puLxd8cddyTnxWuK1Hob47xGHYvnnXdecrz//vuH3KVLl1q+1XdU83OQX59o4MCBIefXAqyD\nhhqL8fiLt1PPsvK/FztyTZypU6eGHK+Tseuuuybn1Xv8xRppLC6zzDIhX3HFFUlb375923v5qkyY\nMCE5jtc6iz8zX3755Q7r03Q01FishZ133jnk/N+csdlmmy3kE044IWkbOXJkyPF24Hnxmm/5+92R\nGmksxpZddtnkePjw4SHHf49kWZYtvfTStXzr7Kuvvgr52Wefreg1+XsdzyPEn8F1Yk0cAAAAgGZh\nEgcAAACgADq1nIrKNerjcbRJwz6qGm+Pm2VZ1qtXr5AHDBiQtK211lohH3fccSHnt/KMH4+MH0fN\nGzt2bMhPPPFEhT3uPM02FgcPHhxyvC15lqVbmMaPobdli/H//ve/IY8aNWq6r8m/Lv9z0I6txEtp\n2LGYF5d35MuH4/EXl6DNPvvsyXnxfSz3GHB8jd/+9rdJWzxOH3zwwe/rdocoyliMt8MdMmRI0rbk\nkkuGXItSq3Jj8bPPPgs53jo8v439Bx980O5+tEHDjsUNN9wwOT7kkENCXm211ZK2eeaZJ+R55523\nze+V/zz8+OOPQz7rrLOStueffz7ku+++u83vVQ+NOhbzZRnxd50RI0bU8q2+4/TTTw/5b3/7W9LW\noN91GnYsUrlGHYvl5EutNthgg+meF/9tkmVZNmXKlJBfeeWVktePz7v22mur6WJHU04FAAAA0CxM\n4gAAAAAUgHKqgiji43F8h0dVm0Azj8V4R6u8ddZZJ+Rqy6kef/zx9naxVpp6LObLI+OdpcaPH9/R\n3ambZhiLcalV797/9yMZ72iVF5fE5cveyo3FCy64IOS4tKqTNcVY7NmzZ8jrr79+u68XlyDnx2wj\njuFmGIs0x1ic0RmLTUE5FQAAAECzMIkDAAAAUAAmcQAAAAAKwJo4BaHGsSmoN24CxmJTMBabgLHY\nFIzFJmAsNgVjsQkYi03BmjgAAAAAzcIkDgAAAEABmMQBAAAAKACTOAAAAAAFYBIHAAAAoABM4gAA\nAAAUgEkcAAAAgAIwiQMAAABQACZxAAAAAApg5jae/1GWZW/VoyOUtWQNr+Uedh73sfjcw+bgPhaf\ne9gc3Mficw+bg/tYfO5hc6joPra0trbWuyMAAAAAtJNyKgAAAIACMIkDAAAAUAAmcQAAAAAKwCQO\nAAAAQAGYxAEAAAAoAJM4AAAAAAVgEgcAAACgAEziAAAAABSASRwAAACAAvh/UwEoFWv/nSkAAAAA\nSUVORK5CYII=\n", 187 | "text/plain": [ 188 | "" 189 | ] 190 | }, 191 | "metadata": {}, 192 | "output_type": "display_data" 193 | } 194 | ], 195 | "source": [ 196 | "#show original image, n most similar images, n most dissimilar images\n", 197 | "n = 10\n", 198 | "image_dataset = X_test\n", 199 | "\n", 200 | "plt.figure(figsize=(n*2, n/1.5))\n", 201 | "img_shape = (28,28)\n", 202 | "\n", 203 | "#display original\n", 204 | "display_single_subplot(image_dataset[img_to_find_idx].reshape(img_shape), n_row=3, n_col=n, cell_num=1)\n", 205 | "\n", 206 | "# #display most similar\n", 207 | "for i in range(n):\n", 208 | " similar_idx = similarity_sorted[i]\n", 209 | " display_single_subplot(image_dataset[similar_idx].reshape(img_shape), n_row=3, n_col=n, cell_num=n+i+1)\n", 210 | "\n", 211 | "# #display most dissimilar\n", 212 | "for i in range(n):\n", 213 | " dissimilar_idx = similarity_sorted[-i-1]\n", 214 | " display_single_subplot(image_dataset[dissimilar_idx].reshape(img_shape), n_row=3, n_col=n, cell_num=2*n+i+1)\n", 215 | "\n", 216 | "plt.show()" 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "metadata": { 222 | "collapsed": true 223 | }, 224 | "source": [ 225 | "
Check if this result can handle rotations, shifts, rescaling etc.
" 226 | ] 227 | }, 228 | { 229 | "cell_type": "code", 230 | "execution_count": 34, 231 | "metadata": { 232 | "collapsed": true 233 | }, 234 | "outputs": [], 235 | "source": [ 236 | "#generate dataset of 21 images - 1 original image, 10 images augmented from the original image, 10 images randomly selected from dataset\n", 237 | "from keras.preprocessing.image import ImageDataGenerator\n", 238 | "\n", 239 | "#generate n modified images of an image, append n randomly selected image\n", 240 | "img_to_test_index = 0\n", 241 | "image_dataset = X_test\n", 242 | "n=10\n", 243 | "\n", 244 | "datagen = ImageDataGenerator(\n", 245 | " rotation_range=15,\n", 246 | " width_shift_range=0.15,\n", 247 | " height_shift_range=0.15,\n", 248 | " shear_range=0.15\n", 249 | " )\n", 250 | "datagen.fit(image_dataset)\n", 251 | "\n", 252 | "selected_images = np.zeros((2*n+1,28,28,1))\n", 253 | "selected_images[0] = image_dataset[img_to_test_index]\n", 254 | "\n", 255 | "for i in range(n):\n", 256 | " for _, img in enumerate(datagen.flow(image_dataset[img_to_test_index].reshape(1,28,28,1), batch_size=1)):\n", 257 | " selected_images[i+1] = copy.deepcopy(img)\n", 258 | " break\n", 259 | "\n", 260 | "random_selected_img_idx = np.random.choice(image_dataset.shape[0], 10, replace=False)\n", 261 | "for i, img_idx in enumerate(random_selected_img_idx):\n", 262 | " selected_images[n+1+i] = (image_dataset[img_idx])\n" 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": 35, 268 | "metadata": { 269 | "collapsed": true 270 | }, 271 | "outputs": [], 272 | "source": [ 273 | "layer_name = 'encoded_layer'\n", 274 | "encoder = Model(inputs=autoencoder.input, outputs=autoencoder.get_layer(layer_name).output)\n", 275 | "\n", 276 | "similarity_sorted = get_sorted_similarity_idx(encoder, 0, dataset=selected_images, loss='binary_crossentropy')" 277 | ] 278 | }, 279 | { 280 | "cell_type": "markdown", 281 | "metadata": {}, 282 | "source": [ 283 | "
\n", 284 | "Here, we arrange the 20 images (10 augmented from the original image, 10 randomly selected from the wider pool of images), arranged by how similar they are to the original image.\n", 285 | "

\n", 286 | "The modified images are mostly deemed to be similar to the original image.\n", 287 | "

\n", 288 | "Modified images deemed to be dissimilar have mostly undergone a significant height/width shift. This is to be expected, since we're essentially comparing all pixels to each other, rather than objects in the image (the digit, in this case.)\n", 289 | "
" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": 36, 295 | "metadata": {}, 296 | "outputs": [ 297 | { 298 | "data": { 299 | "image/png": "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\nEAcAAACgBUa6xfj9EfGnQTSEYS0/0Q0AAAAAJtaI1sQBAAAAYGJIpwIAAABoAYM4AAAAAC1gEAcA\nAACgBQziAAAAALSAQRwAAACAFjCIAwAAANACBnEAAAAAWsAgDgAAAEALGMQBAAAAaAGDOAAAAAAt\nYBAHAAAAoAUM4gAAAAC0gEEcAAAAgBYwiAMAAADQAgZxAAAAAFrAIA4AAABACxjEAQAAAGgBgzgA\nAAAALWAQBwAAAKAFDOIAAAAAtIBBHAAAAIAWMIgDAAAA0AIGcQAAAABawCAOAAAAQAsYxAEAAABo\nAYM4AAAAAC1gEAcAAACgBQziAAAAALSAQRwAAACAFjCIAwAAANACBnEAAAAAWsAgDgAAAEALzDuS\nyimlalANYXhVVaWxOI97OKHur6pq2licyH2cOPrilKAvTgH64pSgL04B+uKUoC9OAfrilNBXXzQT\nB8bPnya6AUBE6IswWeiLMDnoizA59NUXDeIAAAAAtIBBHAAAAIAWMIgDAAAA0AIGcQAAAABawCAO\nAAAAQAsYxAEAAABoAYM4AAAAAC1gEAcAAACgBQziAAAAALSAQRwAAACAFjCIAwAAANAC8050AwAA\nAAAmwlve8pYc77777rWyrbfeOsennXZarewd73jHYBvWg5k4AAAAAC1gEAcAAACgBaRTAQAAMCWt\nvPLKteP9998/x6usskqOl1xyyVq9iy66KMeHHnporezmm28eyyYyDjbYYIPa8SGHHJLj17/+9Tl+\n+umna/VuueWWHP/2t78dUOtGxkwcAAAAgBYwiAMAAADQAhOaTrX99tvXjnfZZZcc33333bWynXba\naTyaxBRUriJ+xBFH1MquuOKK8W4OADAXWHDBBWvHe++9d44PPPDAnvVKDz/8cO34c5/7XI6PPfbY\nHD/77LOjbidMRSmlHH/3u9+tla255po5njlzZo6rqqrVe9/73pfjjTbaqFb2pje9KcczZsyYs8Yy\nZp773OfWjo855pgcv/3tb6+VLbDAAjk+/PDDc/z1r3+9Vu+2224byyaOCTNxAAAAAFrAIA4AAABA\nCxjEAQAAAGiBCV0T54tf/GLteIUVVuhZ96mnnsrxySefnON77rmnVu/WW28dm8YxKscff3yOTznl\nlFpZea+Gu0+XXnrpmLZp3XXXzfEdd9xRK7MmDnODtdZaq3Z89tln53jatGk5vuGGG2r1DjvssJ5l\nY63sm3/9618Hei2AQXnZy16W4wMOOKBW9v73v3/Ix9x333214wsvvDDHiy++eK3sS1/6Uo4333zz\nHH/wgx+s1bvzzjv7azBMUeV6JxdffHGt7H//939zfMYZZ+R43nnrX40vueSSHC+77LK1snJLamvi\nTKwNN9wwxyeeeGKtbPnll89xea8jIvbYY48cP/jggzluro00GZmJAwAAANACBnEAAAAAWmBC06l2\n3nnn2vFqq62W4+bU/XPOOSfHu+66a44fffTRWr3p06cPea3Xve51o24n9e3gP/ShD+W4uRV8OVW4\nvE8R9XvV6z5F1NOfhlNup9lMv3jBC14w5GNMdxxaeX8jhr/HZWpjmTIntXHyKu9nRMRSSy2V43LK\n6Ctf+cpavZNOOmnIeuW2naMta05VveCCC3K82WabDfFT0AY/+tGPclxu1xkhfZWpq0x5KvvAq1/9\n6lq9sg8svfTSOd5vv/1q9c4888wc77TTTrWy//iP/8hxueXx6quvXqs3ldOpzjvvvNpx+Tml12eU\niP7T+oczmpT/u+66q3Z8xBFH5Njr4uCUz4WPfvSjfT2m2Y/KlCwm1sILL1w7LlP+/+u//ivHf/7z\nn2v1ttxyyxz/4he/GFDrxp+ZOAAAAAAtYBAHAAAAoAUM4gAAAAC0wISuifPLX/5y2OPSXnvtleM1\n11wzx+WWYhH19VTKfODLLrtstM3M5uZ1dcr83eG2gt97771zXN6niPq96nWfIiI22WSTvtpU5rre\nfPPNtbJyTaUyN/LUU0/t69xzm/L+Rgx/j0vDrU/V3BaVwVpkkUVqx9/97ndzvO2229bKZs6cmePm\nGjalXmWjeczsyhg75RbHEf2v/TAW75Pla3u5bXyEtR+G0u96c73W+Whum8vE+NrXvpbjcn3H3/3u\nd7V6W221VY6ba/mVttlmmxw3tykvle/d5To6U1HZV/r9nDjatRmHU77GjWZtxoj6a6PXxcnlzW9+\nc8+y5hpL55577qCbM9ebb775clyuNxZRXz+xfA3eZ599avUee+yxAbVuYpmJAwAAANACBnEAAAAA\nWmBC06lG4stf/vKQ/77EEkvUjsut4a688soc/+1vf+v7Wr2mRzanmpdbBk71rVTLad7DbQU/3NTC\n8l71uk8REWuvvXaOh0uxK2233XY9r1VOp33wwQf7Ot/cprkF9XD3eKWVVsrxcKmNo9mGc7TKvthM\nDZtqfbGXFVdcsXa89dZb57hMn4qob+99//335/inP/3pqK59+umn53jllVeulZVpAeuvv/6QbWie\nY25WpgxEROyyyy45Hi7F5uSTT87x2WefXavXb9pAmSbQ1Ot9cbiUgdFu4Ts36TdVuVS+p73iFa+o\nlfmdj48ll1yydvyWt7wlx9eT2eFaAAAgAElEQVRdd12Ot9hii1q9fj+DnHHGGTlupmSVn2+aqeRT\nWdlXytT9iPrnlF6fUSJ6p/VH1FP7l1122Z7tKFO5+k3rbz5fZsyY0fP8jL83vvGNOf7v//7vWln5\nmvrBD36wVvbMM88MtmHERz7ykRyX6VMREZtuummOL7jgghw3P1/2q0zdWnrppWtlzW3LJwMzcQAA\nAABawCAOAAAAQAukkUw5SimNbn7SJLDxxhv3XbfX9Mj77ruv52OOPPLI2nFzquecqqpqTLZ1afM9\nbCqnul177bU9y171qlfluJzmPAGurKrqNWNxosl4H5upjQ888ECO+52m3DSaFI5mX2yuUj+nJmtf\nnDZtWu3497//fY6baRpletXuu++e43J1/7Hyve99L8c77rhjjpvvPfPMM8+YX3sYk7Yv/vGPf6wd\n95tiUyrTCyMiXvSiF+W4377Y3KGj1/vijTfeWKtXTjlupliOdTrrZO2LI1F+NhlNGmu521HE6Hfc\nGY3yebbDDjuM9jSTti8O5+CDD64df/rTn87xu971rhyPxY6Yzfe78rX9/PPPz/FXv/rVWr3/9//+\n3xxfu1/j0RfLvtJvqn1Tr7T+iHpqf5nW39Tr2s20/tNOOy3Hzc+eG220UY4nUZp/K/tiv5q7Nr7z\nne/Mcfn61Uyj2WOPPXL8k5/8ZECtGztT4X2xdP311+e4uWxAmU482lTieef958oy5dItzZ2wfvOb\n34zq/KPUV180EwcAAACgBQziAAAAALSAQRwAAACAFmjNFuNzarT5s2WOazNvtdwy0Lae46/MUz3h\nhBNqZZ/61Kdy3NzakcF46KGHasdl/nq/ueZNvdbhaK4XUd7juXXrznLNoIj61uHLLbdcrWy02y/2\n421ve1vtuNxivLxumefMP+28886149Gsk9LcIrVc+2FO132IqL8vNtfCKrdEL9d9iGjHegLjrfw9\nD/c7P/fcc4f893KNo4j6tsnNsn7XI+u1FllE7/XIXvOaevr+FVdc0de12mrrrbeuHV911VU5Puus\ns8b0Ws1tjZdZZpkc77TTTjk+55xzavXGc02c8TDaz/Gl8nPKr3/96zm+Vrl+ynHHHVcre85z/vl3\n8s9+9rO1skm0Ds5co1wfMyLigAMOyPH888+f429/+9u1euedd95gG8awyu9zzXtzzTXX5Pjkk0/O\ncXN9sD/84Q85bq6/+NOf/nTI843zGjijYiYOAAAAQAsYxAEAAABogblmi/GRKKdHltsCPu95z6vV\nK8tspTr+3vCGN+T4V7/6Va1svvnmy/ECCyyQ42eeeWbwDettSm/fOGhlCke5dWdEvS82Uzjm1r5Y\nprU00w3L1/3tt98+x6effvocX7eZMlOmUz3xxBM5ft/73lerNxbXHgF9cQ70eo+MqL/2rr/++rWy\nZt051Za+OEjN17vRpK6WaasR/aeulinNxx9/fF/XGkIr++Ltt99eO545c2aOX/va1+a4mY7Wr3XW\nWSfHX/nKV2pla621Vo7L19TyuhH9p6x+4AMfyHEzXaFfc2tf/MxnPpPjMu0jIuLhhx/O8Rvf+MZa\n2Vi/Fo6RVvbF0XrPe96T4xNPPDHHCy20UK3eXXfdlePyc1VE7zTXiTSV++Kqq65aO95rr71yvO22\n2+Z40UUXrdUrvyM2v8svvvjiOS7T1x9//PE5a+ycscU4AAAAwFRhEAcAAACgBeaa3amG01w1vpwS\nWU6HfPvb316rZ6eNibX55pvnuJzCH1HfWWCCU6iYA712fih3fYio92G7PnSUK+6vscYatbIbb7wx\nx2ORxrTiiivmuEyfiqinbo31dZkYH/7wh3M8bdq0WtkGG2yQ40maMjCljMUOO03D7T527bXX5vjU\nU08d1fmngs9//vO14zJldb/99svxvvvu29f5VllllZ7nb6bFlalbxx57bI5Hu+PfwgsvPKrHza3K\nVP7999+/Z73yvdBr4eRT7mZ09dVX57iZMlW+35199tm1svK10meawWv2o3Lnvo9//OM53m233Wr1\nyrTHpnKHvwlOoRoxM3EAAAAAWsAgDgAAAEALGMQBAAAAaIG5dk2cfnNat9566xxba2NiNbf923TT\nTXP89NNP18oOOuigcWkTg1VuYVuuvfHQQw/V6t10003j1qa2uP/++3O8++67D/RaBx54YI5T6r27\n5W9/+9uBtoPB6fc987LLLhuP5jCGyrXHIqw/1o/mVtzl9rbltrfl2n0R9fVspk+fnuPy80xExGKL\n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\nAAAA0AIGcQAAAABawCAOAAAAQAvMO9ENAAZn++23rx1/6EMfyvHdd9+d46eeeqpWb/fddx9swwAA\nABgxM3EAAAAAWsAgDgAAAEALGMQBAAAAaAFr4jCp/fKXv8zxEkssUStbc801x7s5rXPEEUfUjldY\nYYW+HnfKKafk+J577qmV3XrrrXPcLoZXrmVUrmMU0Xsto/KeRdTvm3vGWNpll11yfMIJJ9TKtt12\n2xyfccYZ49YmmEiLLrpojrfYYoscb7nllrV6O+64Y46/853v5PiRRx6p1TvzzDNz/Nvf/rZW9vTT\nT89RWwFoPzNxAAAAAFrAIA4AAABAC6SqqvqvnFL/lRlTVVWlsThP2+7hL37xixxvtNFGtbIXv/jF\nOb7jjjvGrU1z4Mqqql4zFifq9z5uvPHGtePVVlstxzfccEOOV1pppVq9//mf/8nxo48+WiubPn16\n/w2dQ3fddVeOy9SwK664Ytza0DQeffG2227Lcb8pcE3lfZuoexYxee5bw7j3xYn0whe+MMerrrpq\nju+9995avauvvrrnOXbfffccH3XUUTm+/vrra/U23XTTnucfa3Pr++Jorbjiijm+6qqrcrzgggvW\n6pX38Lzzzht0s1rZF/fdd9/a8Tve8Y4cr7HGGiM+X0r1p3L52fyTn/xkreywww4b8fkHTV+cElrZ\nF6nTFwfj0ksvzfE4fM7tqy+aiQMAAADQAgZxAAAAAFpg3HenKqeMzj///KM6xzPPPJPjmTNnznGb\nRutnP/tZjrfaaqta2Vve8pYcn3/++ePWprnJ2972thwfffTRE9iSyavc3Wuo41nOPffc2nG589eG\nG25YK1t33XVzfOedd+Z42WWX7atNzz77bO34r3/9a45f8IIX9HxcmTI3idJyBqLckapMgYvonQbX\n3K2tvG/lPYuY8/tW3rMI920yWGCBBXJ80EEH1co+/OEP53iRRRbJ8Te/+c1avXLXqcUXX7xW9p73\nvCfHf//733O833771eoNOoWK0Svvb/l8ab4m/+53vxu3NrVVM2WqVwrVQw89VDv+6U9/muNVVlkl\nx6973et6XmvvvfeuHZfpjE8++eTsGwuM2lJLLZXj5mfltdZaK8fl99vmUiVvfOMbc3zxxRePdRNb\nr5m2O6e7sJapT4NQ7iAbMXGfc83EAQAAAGgBgzgAAAAALWAQBwAAAKAFxmVNnMUWWyzHn//853Nc\n5umPxBlnnJHjz372s7Wy6667LsfNPO851VwbZJNNNslxM/+xXJPAmjiDsfDCC090E6as9773vTle\nYoklamWrr756jq+88socr7322n2du8xvjYi4+eabc1yu9xIRseSSS+Z4xowZfZ1/KijXLuq1jlHE\nv+Znl8r7Vt6ziDm/b+U9i6jft/KeRcxd9228lWsdff3rX8/xyiuvXKtXPk/K96bm1vPlOjjlmm/N\na+2zzz45vuCCC0babCbI8ssvP+S//+IXv6gdP/zww+PRnFZ74oknasflOlHnnHNOjsu1pCLqa9jM\nN998OT7xxBNr9d7//vfnuPke3NyOHJgz//7v/57jfffdt1a211575bj5Xa88Lte/uuWWW2r1brvt\ntjFp51T18pe/vHZcfr8u7brrrj3P8eijj+a4HHeIGPv1Ox988MFaWfkcKT/zHn/88X1da7TMxAEA\nAABoAYM4AAAAAC0wkHSq5jSmX/3qVzkut2MbrW222WbIOCLiS1/6Uo6bW5+ORjmN9Yc//GGtbMEF\nF+z5uB//+MdzfG2G96IXvWiimzBXaG6R+utf/3rIesOl/Qxnu+22y3Fz2vi1116b41NPPXVU559b\nlfet1z2LGN19K+9ZRP2+lfcswn0bS+uss07tuLyvZYrFF7/4xVq9Mu24mQZS+sIXvpDj9ddfv1Z2\n3HHH5fgrX/lKny1mIi299NK14w022GDIes3UOWZv//33rx1/4xvfyPHll1/e1znKVKuddtqpVlam\naZTT+CMiZs6c2W8zga7md9ODDz44x7vttluOm9/tyr5Yvg9G1FPTL7zwwhzffvvtc9DSuc+HPvSh\n2vFqq62W4zJdf6WVVqrVW3PNNXNcLnnSvNevetWrcjwWSz+UW5tHTNx3FTNxAAAAAFrAIA4AAABA\nCxjEAQAAAGiBgayJ01x/ocxZK3N577333p7nmHfeetOmTZvW17Wb+XKj8eY3vznHP/3pT3O86KKL\n9nzM448/Xju2ZsDgNbc5ph2a6zSUOcbPeU59XLlcy6O5pR/jq7xvzbzw8r6V9yzCfZtTr3jFK3L8\n/e9/v1ZWroNTrlP085//vK9zN9eoe9e73pXj66+/vlZ24IEH5viZZ57p6/yMTLmO33/8x3/Uyi67\n7LIcf+pTn+rrfCuuuGLteMkllxyyXrk9Nv25//77hz3u5dhjj83xzjvv3NdjyrUeI/51rQZgaP/2\nb/+W45NOOqlWttVWW+W4XHfqxhtvrNU75JBDcnz66aePdROJf12bsddajeeee27Pc5RrM66++uq1\nskceeWS2556d8jPWZPmuYiYOAAAAQAsYxAEAAABogYGkUzWnaJfbsz388MM5fuELX9jzHIsvvnjt\nePvtt+/r2sNNteplk002qR3/6Ec/yvFwKVSPPvpojjfbbLNamenmo1dOU5tnnnkmsCUMwh577FE7\nLlMlm9uZ33TTTePSJmavvG/N9NbyvrlnY2uXXXbJ8Ytf/OJaWZkG87e//W3E5/7a175WO15kkUVy\nvOeee9bKyunIjJ0dd9wxxwcccECOyzSAiIgZM2aM+NxbbLFFz7I///nPOS4/8zC2milt5Va68803\nX8/HlcsSHHXUUWPfMJiiVl111RyXaS5l+lREfUmPL3zhCzk+5phjxrxNr371q3Pc3P663Kb8ySef\nHPNrzy3Kz6HNZV1GY7ilHybLdxUzcQAAAABawCAOAAAAQAsMJJ1qOGWqTLnrRkR9altzavg3v/nN\nMW1HmSb11a9+tVbWnMbcyxe/+MUcX3rppWPTMGLllVfO8Rvf+Mae9TbeeOMcH3300QNtE3PmDW94\nQ47333//nvW22Wab2vF11103sDYxe6O5b+7Z2PrhD3+Y4//8z/+slZXvVeeff37Pej/4wQ9yvNtu\nu+V4jTXWqNUrd1W88MILR9dghrXwwgvXjg8++OAcl/ez+RmouSNcL/PPP3+Om6nipW984xs5fuyx\nx/o6NyPX3Gm1VwpVM13xc5/7XI6fffbZsW/YFPPtb387x+XuXaecckqt3j333JPjW2+9dVTXGs3n\n/bvuuqt2fMQRR+T4iiuuGFU76Nhpp51qx+VubuWORc0Um/K9cLTPhVL5+v3Od76zVnb44YcPWS+i\n/twt09btGjix7rvvvtrxCSeckOPmDpG9dn4cNDNxAAAAAFrAIA4AAABACxjEAQAAAGiBgayJ89Of\n/rR2/La3vS3Hz33uc3N844031uqVeaHNHNFe+eB/+tOfasfltt+l5pZuZQ7iy172siEf09TMrS1z\nWhk7t99+e46vvvrqHK+++uq1equsssp4NYk5tPnmm+e4uSbAL3/5yxxfdtll49YmZu+SSy7JcZln\n/olPfKJWr8wPLu91RMQzzzwzoNbNHcr3wg9/+MO1sve+9705LtcIK9/fIiJWWGGFHG+33XY5/sc/\n/lGrd+SRR85RW5m9d7zjHbXjl770pUPW+853vlM7vuaaa/o6f3l/m++ZpTvuuKOv8zFnys8zEb0/\n0zTXyfjJT36S47e//e21srHYPreNtt9++xyXW7VH9F7/adddd60dl98Rpk+fPqp2rLvuujku1yv6\n61//Wqv3ghe8oOc5yv5nTZyRW2655XL88Y9/vFZWroNTfobZeeeda/WafbOX8jPre97znlrZnnvu\nmeOFFloox801X4dTrqcyc+bMvh/HYJVrQkYMvy7kRH13MRMHAAAAoAUM4gAAAAC0wEDSqQ488MDa\n8d13353jHXbYIcfTpk2r1XvNa14zZBxR3wqudPnll9eOy23Kb7vtthw306623XbbIc/X9MADD+T4\nYx/7WK3s6aef7uscjEy53elDDz00gS1hTpRTSzfddNMcN/vNQQcdlGOpN5OLezi5NFN6y+My3a35\nXnXIIYcMeb5jjz22dtzv9HJGZsEFF8zxAQcc0LNeuc3tJz/5yVFda9VVV+1Z9uSTT+b4rLPOGtX5\nGZnm9u1bbLFFjk888cQcv/Wtb63VK1NCzjjjjFrZZpttluPRbHfdVuUSBmWKaEQ9jXellVbK8Zpr\nrlmrt+GGG+a4TIuKiLjzzjtzvOyyy/ZsR5m6VW5nfvPNN9fq3XDDDTlubkE8Y8aMnufnXy288MK1\n4/K9q5m6VH4P3GeffXqe8wMf+MCQ//7617++dvymN70px83nXS9lGyIizj777Bw3lxL57ne/m2Of\nnyaP5tIAZVpduQxExMTdNzNxAAAAAFrAIA4AAABACwwknao5VaxcvbvccaGcShrxr9Me+9GcDjnW\nymms999//0CvRcf888+f4zKdI6VUq9c8ZnLZd999c7zGGmvk+Nxzz63Vm5umg7eNe9ge5bTx3/72\nt7Wy008/fcjHfOQjH6kdv/a1r83xTjvtVCu76aab5rCFc6+tttoqx712o4qo7945XJ965JFHcnzB\nBRfUypq7X5UuvPDCHDd30mF83HPPPTneeuutc/zpT3+6Vq987W3urlrWLdNcp7pyR6rVVlutVla+\nJzXfn0plmlpz97Yrr7wyx2uvvXbPczRTKWYpd4ZrXuvaa6+tlZ166qk9z8+/WnzxxWvHW265Zc+6\nZepa+R2uTGsd6py9lN81qqrq6zHN9+DPfOYzOS7T9phcei0hEFFfRqBcQmAimYkDAAAA0AIGcQAA\nAABawCAOAAAAQAukfvP7IiJSSv1X7sMCCyxQOz788MNz3MxVXWSRRXK81lprjWUzhvXnP/85x7vs\nskut7Be/+EWOB729WFVVY7IAzFjfw0Eot0i95ppretYrt8Mdbp2BSeTKqqpeMxYnmoz3sdw6NaKe\ni/z444/nuJlnevnll9YraZ0AAAtxSURBVA+2YWNsKvfFueUexhTvi7vuumvt+LjjjsvxVVddlePm\nOnTl54G77767Vrbzzjvn+LzzzhuTds6ptvTFHXbYIcc//OEPB3mpYe299945/vKXvzxh7WiY0n1x\ntNZZZ50cN9dPef7zn5/jsl+ecsopg29YD23pi4O09NJL147LdXCaZdtvv32Of/KTnwy2Yf2btH2x\nuS7Ub37zmxw310eaU831yC677LIcl6+hTX/4wx9y3FxT6dlnnx2j1s2evjg2muuUHXzwwTlurrvV\n3I58DPTVF83EAQAAAGgBgzgAAAAALTCQLcb79fe//712/NGPfrRn3TKdqtzqtqmcIjwWaVcvfOEL\nc/zzn/+8Vnb00UfnuNwOMmJ8p87NraZPnz7RTZjrLbXUUjk+5phjamXzzDNPjs8+++wctzD1Zkpz\nD6eecqp+RMTMmTNzXL7PNrdYPeGEE3K8zDLL1Mq+9rWv5XizzTbL8fXXXz9njZ0LlOkS5TbJEf+a\nZjHLr371q9rxAw88kONll102x9tuu22t3h577NGzHeecc87sG8uk8Pvf/z7HZb+MiDj00EOHLGtu\nY12mdzB4zb43bdq0HD/00EO1sptuumlc2jRVPProo7XjjTfeOMfN9OFevvWtb9WO77333r4eV35G\n2meffWplZQryBRdckGPfAdupXFLgU5/6VK3skUceyfFnP/vZcWvTcMzEAQAAAGgBgzgAAAAALWAQ\nBwAAAKAFJnRNnJEot7e9+OKLe9Z7+OGHR3zud7/73bXjciu7o446KscLLbRQrd5HPvKRHN922221\nsmOPPXbE7WBkfvnLX050E+ZK5Top5TZ7L37xi2v1ZsyYkeNmbikTyz2ceuaff/4cL7nkkrWycg2j\n4d4/N9lkkxx//etfr5W9/vWvz3G5PlJza01r5Pyrf/zjHzn+5je/Ocfnu/XWW3O84YYb9qzXXFen\nfBztUa6H1LTwwgvnuPkZlcF7wxvekOP999+/Z71tttmmdnzdddcNrE1zgwcffDDHhx122Jiee9FF\nF60dl1tNl2vgRERcffXVOd5vv/3GtB2Mj17rQpafkyMm57qQZuIAAAAAtIBBHAAAAIAWaE061Vj7\n85//nONLLrmkVnbnnXfm+Mknn8xxc3r5AgsskOMDDzywVlZu+/jMM8/MWWMZ0qabbprjcrt3Buul\nL31pjtdaa62e9fbaa68cl2k5TDz3cOp52cteluPVV1+9Vrb33nv3dY4bb7wxx81tW8upxOUW1+W/\nR9TTq6RWDV4zna103nnn1Y5tewtjq+x/8803X62sTPm/7LLLxq1NzJk999yz5/Fjjz1WK9tll13G\npU0MznBLCpTWXnvtHJefoSMm7vOxmTgAAAAALWAQBwAAAKAFplw6VZnGtPHGG/es9/vf/z7HZfpU\n08knn5zjcrp6RH3F8qWXXnpE7aS3cqevK6+8MsfNtI9yV4711luvVjbcDiyMzPLLL187Pv/884es\nt++++9aOzzrrrIG1iZFxD6e+cifFptGkNTUfs/POO+e4TNMpU6siIj7wgQ/kuPl8YmzssMMOOX71\nq1/ds96ZZ545Hs2ZK6266qq14zLdvvwcetJJJ/V1vuaOOG9961tzPFzKxj333DNkzOCUu4CVaf1P\nP/10rd5BBx2UY8sqTG7Tpk3L8XbbbVcrmzlzZo6/+tWv1sqG2zmOdthxxx1zXKaUN03G5QXMxAEA\nAABoAYM4AAAAAC1gEAcAAACgBabcmjjTp0/P8X333ZfjsViz5u1vf/scn4PZe+KJJ3J8xBFH5PiH\nP/xhrV65xft+++1XK7Mmzsg01xTabLPNcvyJT3yi5+PWWWedHF9xxRVj3zDGRHNNheWWW27Iehdd\ndFHtuKqqgbWJsTXo9TBe8pKX9FXvpptuGmg7iFhxxRVzPO+89Y9xF1xwQY5vueWWcWvT3Ka5hk35\nXlhuRdv8bFKus1hacskla8fl+gvDufvuu4eMGZxyra811lgjx+VWxRERl1566bi1iZF7/vOfn+Of\n/exnOS7vaUR9nZThPg/TTm1eI9JMHAAAAIAW+P/t3UuIzl0cB/AzI7OxUbxJyrisbFyaSTak7CTs\nsNcsyC0pkY1IipqUvbIiISaXBZGN1JvspFzGRrwot4Vcnnf1ns755+mdZzzzPHP+Pp/V99//+Dt1\nOozj/M6xiAMAAABQgNqVU6Xb3tJt3eMtp9q8eXPMc+bMGX/HGJcLFy7EPDo6mr1Lt/enVz7SupUr\nV2bPO3bs6FJPaJe0RM541t/Dhw9jTq/MDCG/Bjfd4r969eqsXXpd+MDAQPau+s3/PH/+PHs+d+7c\n2DrMuKXXT1fduXMn5h8/fnSgN3+mZ8+eZc9pOfHg4GDMaelbCCEcOXLkl9/r7c3/TzW91rgqHdd0\nvrnGujMOHToU88ePH2M+fPhwN7rDOK1atSrmRYsWNW1XneuUrb+/P3su+XgBO3EAAAAACmARBwAA\nAKAAFnEAAAAAClC7M3FSaY1y9cyPtWvXxvzq1aum35g5c2bMU6ZMaWPv+F2TsT6xLqrXp6aePn0a\n8+fPnzvRHcYh/TPPeNbf9evXY65eT7xr166YN23aFPPs2bOzdmP9M/X169e//F4IIXz69GlM36A1\n6RyeMWNG03bpzz1MnDdv3mTP69evj3l4eDjmFStWZO2anb/Qys8zBw4ciPnEiRNj/nW0x8aNG2O+\nevVqzDt37sza3b9/v2N9onXp+VTTpk1r2m7r1q2d6A4dMjQ0lD0fO3Ys5vQK+QcPHmTtli9fHvNk\n+XvWThwAAACAAljEAQAAAChArcup9u/fH3NfX1/2bvv27THPmjXrt3+v6vWr379//+1vktu9e3f2\nfPbs2ZgvXrzY6e7USrqdMIQQjh49GvOjR4+yd2vWrIn5/fv3E9sxJkQ6psazHh4/fhxztXw4vWI+\n3RJcvYL63r17Tb9/5cqVmEdGRmL+8uVL652lZenPLPPmzYv55s2bWbtbt251qksk0hLDLVu2xJyW\n5IcQwpIlS2Jet25dzAsWLMjapSWQVS9fvhx3P2ldtXzx1KlTMaflyOnV40w+6b8JQ2he2rht27bs\nOZ3blC8tPQ8hhGvXrv2yXTq3Q5icxw3YiQMAAABQAIs4AAAAAAWodTnVt2/fYt6zZ0/2Lt0mdfDg\nwexds5sfTp8+nT3fvn075suXL2fv3JzUfuktACGEMH369C71pP56e63vli4tkauWy1FvL168yJ73\n7t3bnY7QNk+ePIn5w4cPMZ8/fz5r9/Pnz471if/39u3b7Dktd1P6Nnmlt9HeuHEjezd//vyYN2zY\nEHO1/ILuS0tPly5dmr2bOnVqzGmJ+ZkzZya6W3RRtdw8vfmx2VEDIUzO4wb8Sw0AAACgABZxAAAA\nAApgEQcAAACgALU+EydVvfJ7eHg45upZN4sXL455dHQ05nfv3mXtnHsDAEy0S5cu/TID7bdw4cKY\nBwYGmrYbGRnpRHcYp76+vpjTM3Cqjh8/HvPXr18ntE9MXsuWLet2F1piJw4AAABAASziAAAAABSg\np5WSoJ6eHvVDXdJoNHra8R1j2FV/NxqNwXZ8yDh2j7lYC+ZiDZiLtWAu1kAd5mJ/f3/Md+/ejXnu\n3LlZu3379sV88uTJie9Y55iLNVCHucjY5qKdOAAAAAAFsIgDAAAAUACLOAAAAAAF+GOuGAcAAKga\nGhqKuXoOTio9LwegW+zEAQAAACiARRwAAACAArR6xfg/IYTRiesOTfQ3Go2/2vEhY9hVxrF8xrAe\njGP5jGE9GMfyGcN6MI7lM4b1MKZxbGkRBwAAAIDuUE4FAAAAUACLOAAAAAAFsIgDAAAAUACLOAAA\nAAAFsIgDAAAAUACLOAAAAAAFsIgDAAAAUACLOAAAAAAFsIgDAAAAUIB/AUmmpdBoxeyQAAAAAElF\nTkSuQmCC\n", 300 | "text/plain": [ 301 | "" 302 | ] 303 | }, 304 | "metadata": {}, 305 | "output_type": "display_data" 306 | } 307 | ], 308 | "source": [ 309 | "fig = plt.figure(figsize=(n*2, n/1.5))\n", 310 | "fig.suptitle('First row: original image. Second row: most similar images. Third row: least similar images')\n", 311 | "\n", 312 | "img_shape = (28, 28)\n", 313 | "#display original\n", 314 | "display_single_subplot(selected_images[0].reshape(img_shape), n_row=3, n_col=n, cell_num=1)\n", 315 | "\n", 316 | "#display most similar\n", 317 | "for i in range(n):\n", 318 | " similar_idx = similarity_sorted[i]\n", 319 | " display_single_subplot(selected_images[similar_idx].reshape(img_shape), n_row=3, n_col=n, cell_num=n+i+1)\n", 320 | " \n", 321 | "#display most dissimilar\n", 322 | "for i in range(n):\n", 323 | " dissimilar_idx = similarity_sorted[-i-1]\n", 324 | " display_single_subplot(selected_images[dissimilar_idx].reshape(img_shape), n_row=3, n_col=n, cell_num=2*n+i+1)\n", 325 | "\n", 326 | "plt.show()" 327 | ] 328 | }, 329 | { 330 | "cell_type": "markdown", 331 | "metadata": { 332 | "collapsed": true 333 | }, 334 | "source": [ 335 | "
Compare to 'baseline', binary cross entropy comparison of original image pixels.
" 336 | ] 337 | }, 338 | { 339 | "cell_type": "code", 340 | "execution_count": 39, 341 | "metadata": { 342 | "collapsed": true 343 | }, 344 | "outputs": [], 345 | "source": [ 346 | "import tensorflow as tf\n", 347 | "from keras.losses import binary_crossentropy, cosine_proximity\n", 348 | "\n", 349 | "img_to_find_idx = 0\n", 350 | "dataset = copy.deepcopy(X_test)\n", 351 | "dataset = dataset.reshape(dataset.shape[0], -1)\n", 352 | "#initializing vars to pass into tensorflow\n", 353 | "X_selected = [dataset[img_to_find_idx].tolist() for _ in range(dataset.shape[0])]\n", 354 | "X_all = dataset.tolist()\n", 355 | "\n", 356 | "X_selected_tf = tf.Variable(X_selected, tf.float32)\n", 357 | "X_all_tf = tf.Variable(X_all, tf.float32)\n", 358 | "loss_tf = binary_crossentropy(X_selected_tf, X_all_tf)\n", 359 | "init_op = tf.global_variables_initializer()\n", 360 | "\n", 361 | "similarity = []\n", 362 | "with tf.Session() as sess:\n", 363 | " sess.run(init_op)\n", 364 | " similarity = sess.run(loss_tf)\n", 365 | "similarity_sorted = np.argsort(np.array(similarity))[1:] #the same figure appears in X_all too, so remove it" 366 | ] 367 | }, 368 | { 369 | "cell_type": "markdown", 370 | "metadata": {}, 371 | "source": [ 372 | "
Same digits are deemed to be more similar.
" 373 | ] 374 | }, 375 | { 376 | "cell_type": "code", 377 | "execution_count": 40, 378 | "metadata": {}, 379 | "outputs": [ 380 | { 381 | "data": { 382 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABHEAAAGmCAYAAAD76xhxAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4wLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvpW3flQAAIABJREFUeJzt3Xv8fVOdOP7XikihkIqISheNVNTo\nwtB0mZDSpIsmqaYakswYapoK3S8zdP1R+TalC91TUVHkUzLV0BURQkQXyTV3+/fHOZ9t7d3nnM95\nv9/7vM9Z5/18Ph4e1v7sy1nn7L322ef1Xq+1UlVVAQAAAMB0u9OkKwAAAADAygniAAAAABRAEAcA\nAACgAII4AAAAAAUQxAEAAAAogCAOAAAAQAEEcYBFkVK6X0rpupTSKpOuyySllP4zpfT/ut52hGNV\nKaXNBqz7Rkppzy5ehzsM+8xZsZTSP6WUTpznvtullM7Nli9KKT25o3otmftXSmnT/rW76oD1c74v\ndXkuupJS+nhK6a2Trscg/evtAfPc96yU0g798iEppU91WC/fFwATtsIvaID5SildFBH3jojbsn9+\ncFVVv4mINed5zBdHxMuqqtp2wRWcsKqq3j6ObReiqqodF+N1upRSukdEHBYRO0XE3SLi8oj4aFVV\n75poxVhQe62q6tMR8en5vG5VVd+LiIfMZ98Rjj3v+9e0SSl9KCJe2F9cLSJSRNzUX/5eROw9bP/F\nui/NgpRSFREPqqrq/LnuW1XVvK+3qqr+Zr77jnDs4r4vAGaNnjjAOOxSVdWa2X+XDds49XR2P+r6\neF0Z9Jdt5uU90ftRvXlE3D0inhERF0y0RvM0rdfrUjXr7bSqqr2W35sj4u0R8dnsXr2gH+hdfHZL\nobdTKZwLgOnkoRFYFO0u+imlU1JKb0spfT8i/hIRD0gpvTil9OuU0rUppQv7qRWbR8SHIuJx/e7l\nVw04/oqOt2FK6asppStTSuenlF7e3/YuKaUbUkr37C+/IaV0a0pp7f7yW1NK7x3xfa3wNfrrDkkp\nfSGl9KmU0jUR8eJ21/aU0otSShenlP6UUnpjnnaQb5t9fnumlH6TUroipfT67Dh/m1L635TSVSml\ny1NKH0wprTbiezglpfSyfvnFKaXvp5Te0z/Wr1NKj+//+yUppT/kXelTSjunlH6SUrqmv/6Q1rGH\nvb87pZT+I6V0QX/951JK645S54h4TEQcXVXVn6uqur2qqnOqqvpC9roPTSl9q39ezk0pPTdbt0ZK\n6dB+va5OKZ2aUlqjv+4ZqZeKcFX/c9k82++ilNIBKaWf9/f7bErpLtn6A/uf/WUppZeO8JlP4no9\npb/9af329LWU0noppU/3z+H/pZQ2zbZ/fP/fru7///HZuoW017/aN/v3U7PtqpTSK1NK5/W3fUtK\n6YH9a/2a/jWzWn/bHVJKlw54vaHto/86+6SUzouI81aw/4ruX3P5HN/Xbx/XpJTOSCltl61bI6V0\nVErpzymlX6aUXpO/j/518cWU0h/7n9WrW+/r9P5xf59SOmxF73+e/imt+F6zovvSP6eUfhMRJ/f/\nfY90R7t//YDjLz/ex1NKR6SUvp5Suj4inphSuntK6RP993xx/5q/U3/7i1NKW/fLL+y//sP6yy9L\nKR07nzebUnp6Sumn/WvktJTSltm65fepa1NKZ6eUnpWt2yyltKzfRq5IKX22/+/f7W/ys/418rwV\nvOYK9+2vq9Mx+5/R4amXynRd6t2j75NSem//ujknpfSobN+B6Wsppc+nlH7Xf83vppT+Jlv3V+di\nBftP3fdF6t0jP9X/96tSr/3de4UnGmAGCOIAk7RHRLwiItaKiD9GxPsjYseqqtaKiMdHxE+rqvpl\nROwVEf/b/0vxPUY83sURcUxEXBoRG0bEbhHx9pTSk6qqujEi/i8itu/v93f97Z+QLS+LiEgpvSCl\n9PMhr7nC18jWPzMivhAR94hWmkj/h8fhEfFPEbFB9HqU3HfIa0VEbBu9lJEnRcRB6Y4gw20R8W8R\ncc+IeFx//StXcqxBtomIn0fEehFxdER8JnpBk82il4bxwZTS8q7+10fEi/rvb+eI2DultOuI7+/V\nEbFr9M7DhhHx54j4/0as4w8i4m0ppZeklB6Ur0gp3S0ivtWv+70iYveIODz7sfLfEbF19K6xdSPi\nNRFxe0rpwdE7n/8aEetHxNcj4mupGQx7bkQ8LSLuHxFbRsSL+6/5tIg4ICKeEhEPiohRxv+YxPUa\nEfH8/mvfNyIeGBH/GxEf638Wv4yIg/vHWjcijo9eu1wveulrx6desOJuMc/2OmjfIfV9WvTO12Oj\nd64+Er1rauOI2CJ653dlRmkfu0bv2n/YCMeLGPFz7Pu/iHhkf93REfH5dEcA8OCI2DQiHhC962d5\n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\n3RFHHDHy643CFOMAAACwtOmJAwAAAFAAQRwAAACAAhSfTjVuz372s+vy5z73uca6M888sy4/8YlP\nbKy78sorO62HdCoAAABY2vTEAQAAACiAIA4AAABAAQRxAAAAAApgTJwVuNe97lWXf/GLX6zw3yMi\ndtttt7r8xS9+cax1MiYOAAAALG164gAAAAAUQBAHAAAAoACrTroC02ifffapy+uvv35d/vOf/9zY\n7txzz120OgEAAABLm544AAAAAAUQxAEAAAAogNmpIuIJT3hCY/nkk0+uy3e+853r8g477NDY7rvf\n/e5Y65UzOxUAAAAsbXriAAAAABRAEAcAAACgAII4AAAAAAUwxXhE7LTTTo3lfByck046qS7/7//+\n76LVCQAAACCnJw4AAABAAQRxAAAAAAqwZNOp1lhjjbr8tKc9rbHu5ptvrssHH3xwXb7lllvGXzEA\nAACAFdATBwAAAKAAgjgAAAAABRDEAQAAACjAkh0T58ADD6zLj3rUoxrrvvnNb9bl0047bdHqBAAA\nADCInjgAAAAABRDEAQAAAChAqqpq9I1TGn3jKbPzzjs3lo899ti6fP311zfW5VOO/+AHPxhvxUZU\nVVWadB0AAACAydETBwAAAKAAgjgAAAAABZjp2anWW2+9uvz+97+/sW6VVVapy1//+tcb66YlhQoA\nAABgOT1xAAAAAAogiAMAAABQAEEcAAAAgALM3BTj+Vg3+dg2W2+9dWO7Cy64oC7nU4q3100LU4wD\nAADA0qYnDgAAAEABBHEAAAAACjBzU4w/8IEPrMvtFKrc/vvvX5enMX0KAAAAIKcnDgAAAEABBHEA\nAAAACiCIAwAAAFCA4sfE2WSTTRrLJ5544gq3O/DAAxvLxx133NjqBAAAANA1PXEAAAAACiCIAwAA\nAFCA4tOpXvGKVzSW73e/+61wu2XLljWWq6oaW50AAAAAuqYnDgAAAEABBHEAAAAAClBkOtW2225b\nl/fdd98J1gQAAABgceiJAwAAAFAAQRwAAACAAgjiAAAAABSgyDFxtttuu7q85pprDtzuggsuqMvX\nXXfdWOsEAAAAME564gAAAAAUQBAHAAAAoABFplMN87Of/awuP+lJT6rLV1555SSqAwAAANAJPXEA\nAAAACiCIAwAAAFAAQRwAAACAAqSqqkbfOKXRN6ZTVVWlSdcBAAAAmBw9cQAAAAAKIIgDAAAAUIC5\n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\nm266aWN51DTF448/vi7/8Y9/7LJK86YnDgAAAEABBHEAAAAACiCIAwAAAFAAY+JExJve9KaB61JK\ndfkb3/hGY93VV189tjqxcvlYRmuvvfbA7a655pq6/KpXvaqx7pRTTum8XsxNPn3qiSee2FiXj++Q\nu/jiixvLBx10UPcVY17a43CsueaaK9yuPSbAYo7vUpJ8OuG8PG5rrbVWYzmfEvfGG2+sy+176KWX\nXjrOarEST37yk+vysKmL8+lTjz766Ma6v/zlL91XjDn5t3/7t7qcTzMdEXH77bfX5fxcvfnNbx5/\nxRjZRhttVJf322+/kfb5l3/5l8Zye+w4Ft8aa6xRl//pn/6psW6DDTaoy/nU4YcccsjY68XoVltt\ntbr8+te/vrFu4403HukY7d8n00BPHAAAAIACCOIAAAAAFGDJpFPlaVEREe985zvr8kMe8pCB+33h\nC1+oy6973eu6rxgjW2+99RrLeRfjQWk3ERE333xzXZY+NX1e85rX1OVh5zH30pe+tLF87rnndlon\n5mbPPfesy89+9rNH2ueb3/zmuKrDPOX32C9/+cuNdXkKR5628Y53vGP8FWNk7a7ig7z73e+uy6ai\nnj55mkbe9iKaqXCvfOUr67KU1OnyxS9+sS5vscUWA7f70Ic+VJePPfbYsdaJuct/I37kIx8ZuN2L\nXvSiunzOOeeMtU7MzROe8IS6/JKXvGSkfQ499NDG8umnn95pnbqgJw4AAABAAQRxAAAAAAogiAMA\nAABQgCUzJk4+vVhExIEHHjhw2zzfOM9pbecls7jynMaIiE022WTgtrfddltdfsMb3lCXf/vb33Zf\nMeakPbbR/vvvP9J+5513Xl0+//zzO60Tc3Of+9ynsXzAAQfU5dVXX33gfs94xjPq8rJly7qvGAuy\n11571eXHP/7xjXXf//736/KwcQFYXPlU1BERW2+99Uj7vfWtbx1HdZinvO1FRLzqVa8auO2XvvSl\numwMlemx7bbbNpYf8YhHDNz2tNNOq8t777332OrE3OXjUUVEfPKTnxxpP8800+Pud797Y/kf//Ef\n63J7jNzc2WefXZff//73N9bdeuutHdWuO3riAAAAABRAEAcAAACgAEsmneqoo44aeds8/eYzn/nM\nOKrDPLSnlR7mhhtuqMtHHnnkOKrDHKy55pp1+YQTTmisy9MX2/Kpw5/2tKfV5UsuuaTD2jFX3/rW\ntxrLm2++eV1un888Deekk04ab8WYk3bqzbDpqXfeeee6fO21146tTqzcRhttVJfb6airrLLKwP0+\n/elP1+X8O5LJ22OPPRrL+RAAl112WWPdnnvuWZedx8l69KMfXZfb32/5OTzmmGMa6/Kp4Zkuf//3\nf99Y/pu/+Zu63B5W4+Uvf3ldvvLKK8dbMUb2wQ9+sLG8++671+Vhvzny3xklDL+hJw4AAABAAQRx\nAAAAAAow0+lUj3zkI+vyM5/5zIHbXXfddY3l448/fmx1Ym7y8/bwhz985P1e/OIXj6E2zNfBBx9c\nl9spHHnXxnPOOaexbqeddqrLF1988Zhqxyie85zn1OWHPexhjXX5OfzTn/7UWJef+xtvvHFMtWNU\nG2+8cV3O02simjOLtWfakEI1Wauuesfj2mtf+9q6vOGGGw7c55prrmks5ykdw7qUszi22GKLurzp\npps21uUzqBx33HGNdVKoJutOd7rj79+f+MQn6nJ7Ftwf/vCHdbmdPnXVVVeNqXYs1Gte85qB6/7w\nhz80lj/2sY+NuzqMKP+ObN9Pc7fccktjOZ8JsIQUqpyeOAAAAAAFEMQBAAAAKIAgDgAAAEABZm5M\nnPve9751+S1veUtdznP92573vOc1ln/+8593XzEGyvOLIyL23nvvuvy+972vLuc54m3t8Ru++tWv\ndlQ75mv99devy6NOp/nud7+7sXzRRRd1WSUWIJ96cZhPfepTjeVTTjllDLVhvt71rnfV5c0226yx\nLh8nxdhw02Wbbbapy6PeT3/xi180lr/xjW90Wifmbr311qvLeRu7973v3dguHwcnfyZi8vJxUDbf\nfPO63B6D6oADDqjLxsCZbjvuuGNdbo+/mU8rnk8pznR5xzveUZcf97jHDdzu85//fGP5ox/96Njq\nNG564gAAAAAUQBAHAAAAoAAzl06VTw238847D9zuu9/9bl3+9re/PdY6MVy7S//73//+OR9j9913\nbyzfdtttC6oTC3fsscfW5TXWWKMu511TI5pTUGuL0yWfVnyPPfYYuN1RRx1Vl1/3uteNtU7M3YMf\n/OC6nKcPt6eZPvnkk+vyBz7wgfFXjIF22223xnI7TXGQ3//+93V51LQrFs+WW25Zl/P0/7Zf/epX\ni1EdRrDPPvs0ll/0ohetcLv2s+upp546tjqxcPlz6V577TVwu/PPP78uSzOeLltssUVd3n///ety\n+9km/82fTyleOj1xAAAAAAogiAMAAABQAEEcAAAAgAIUPybOtttu21h+4QtfuMLt2mOk5Nvdcsst\n3VeMofJpxd/4xjfO6xh5juPVV1+94DoxdxtssEFd3nPPPRvrHv3oR69wn7/85S+N5be+9a3dV4x5\nWX311RvLBx10UF1eZZVV6vL111/f2O7QQw+tyzfffPOYaseo8jFwIiK+9a1vjbTfu9/97rrsPC6+\ntdZaqy63n2XufOc7j3SMww8/vC6feeaZ3VSMedt6660by/lYccP8+Mc/Hkd1GFE+Xsphhx02cLsT\nTzyxLv/Xf/3XWOtEt/KxUXbZZZe6fN111zW222+//RatTgzXfrY55ZRT6nL+u7I99uaXv/zlunzN\nNdeMp3IToCcOAAAAQAEEcQAAAAAKUGQ61ZprrlmX3/GOdzTWrbPOOnU57w6+9957N7a79NJLx1Q7\nRvGCF7xgheVh2t2LDznkkLp84403dlIv5uZjH/tYXX7qU5860j4HHnjguKrDPOTdxttTpG6++eZ1\nOZ+y8aUvfWlju7PPPntMtWM+9t1338byRhttVJfzbsa77rprY7tvf/vb460YfyVPk/r0pz9dl3fe\neeeR9s+7iUdEfPzjH++kXnTj7/7u7xrLa6+9dl3O22J72ttjjjlmvBVjqDe84Q11ebXVVmusy6ec\nzu+hN9xww/grxry1U1K32mqrFW73ve99r7F8wgknjK1OzM12223XWL7HPe5Rl/P7aZ5mFRFx1FFH\njbVek6InDgAAAEABBHEAAAAAClBkOtUHP/jBuvyEJzxh4Hb5zAx52geTd//733/O+xx99NGN5WXL\nlnVVHebgM5/5TF3eYYcdRtonT2f88Ic/3HWVWICnPOUpdfklL3nJSPtcdNFFY6oN85XPbNRO4chT\n4Y488si6fPzxx4+/Ygx1z3vesy6PmkJ100031eWvfOUrjXVSxadLPoNjRLPLf94uf/KTnyxanVix\n9dZbry6/+tWvHrjdPvvsU5elUJVjt912ayw/73nPW+F2+SyNTN6OO+5Ylz/wgQ8M3C6fhbo96/Es\nzUiV0xMHAAAAoACCOAAAAAAFEMQBAAAAKECRY+J89rOfrcsvfOELG+tWWWWVunzooYcuWp0Yj//5\nn/+py0ccccQEa8Jy973vfetye+rNXD4Ozkc+8pGx1om5yacVP+CAA0baJ59G/PTTT++8TiyO8847\nb9JVIJNPZTyqr33ta3X5k5/8ZJfVoWODxt2IaI7beNZZZy1GdRhil112qctrrrnmwO3aU1BThmc/\n+9kjbWe8zenyt3/7t3V52G+O73znO3X5tNNOG2udpoWeOAAAAAAFEMQBAAAAKECR6VTf+MY36vJ+\n++3XWPeoRz2qLudTITNdDjvssLr89Kc/vbEun348T4m78cYbx18x5u3nP/95YzmfEj6fSpXJW3XV\nO27966yzzsDt8hSqJz/5yWOtEwtz7bXX1uX3vve9jXV5auOPf/zjRasTK3fqqafW5b322muk7V7+\n8pePtU6Mz3XXXVeX86mq8/bLZAxLocrlKchvectbxlUdOpZPVd12/fXXL2JNmIs87XSY3Xfffcw1\nmT564gAAAAAUQBAHAAAAoACCOAAAAAAFSHMZqyKlZGCLCamqKnVxHOdwos6oqurRXRzIeZwcbXEm\naIszQFucCdriDNAWZ8JMt8WTTjqpsfyb3/ymLudTUh955JGLVqdx0BZnwkhtUU8cAAAAgAII4gAA\nAAAUYK5TjF8RERePoyIMtUmHx3IOJ8d5LJ9zOBucx/I5h7PBeSyfczgbZvo8PulJT5p0FRbDTJ/D\nJWSk8zinMXEAAAAAmAzpVAAAAAAFEMQBAAAAKIAgDgAAAEABBHEAAAAACiCIAwAAAFAAQRwAAACA\nAgjiAAAAABRAEAcAAACgAII4AAAAAAUQxAEAAAAogCAOAAAAQAEEcQAAAAAKIIgDAAAAUABBHAAA\nAIACCOIAAAAAFEAQBwAAAKAAgjgAAAAABRDEAQAAACiAIA4AAABAAQRxAAAAAAogiAMAAABQAEEc\nAAAAgAII4gAAAAAUQBAHAAAAoACCOAAAAAAFEMQBAAAAKIAgDgAAAEABBHEAAAAACiCIAwAAAFAA\nQRwAAACAAgjiAAAAABRAEAcAAACgAKvOZeOUUjWuijBcVVWpi+M4hxN1RVVV63dxIOdxcrTFmaAt\nzgBtcSZoizNAW5wJ2uIM0BZnwkhtUU8cWDwXT7oCQERoizAttEWYDtoiTIeR2qIgDgAAAEABBHEA\nAAAACiCIAwAAAFAAQRwAAACAAsxpdqpZ9Z3vfKexvMMOO9TlJz7xiXX5lFNOWaQaAQAAADTpiQMA\nAABQAEEcAAAAgAIsmXSqPEUq4q9TqAbJt8tTqyKkVwEAAJSkqqoV/vub3vSmxvIhhxyyCLWBudMT\nBwAAAKAAgjgAAAAABRDEAQAAACjATI+Jk4+DM+oYOMO0j2H68eHaeaQHH3zwCrdrf3bt8YsGyfdr\n75PntMpnhdG021G+vP322w/cLm9v7fbs3ji9hp3vLrj3jl/7nA36nm1btmzZwHV5m9V+gVkw6vdR\n+x6aP/u0x0Zl/Iadt1G/72b197qeOAAAAAAFEMQBAAAAKEAaNMXaCjdOafSNJyTvWpx3s+q6m3jE\n4qbsVFWVujjOYp7DdvrZOM7BQi1yF7szqqp6dBcHKqEtDtLFdTHJKSBLbIvD5J/dqF1T52uK0q6W\nVFtczO/F3Ljb6ay1xVEtZpttS6mTjzxXTFvMn5fb13Zu1HvZLHXrn7W2OJ/hGNrnc1jKYm6K0k6L\naYuj6npYjXY61TS24RLbYvtZpItzNUgJ5zBGbIt64gAAAAAUQBAHAAAAoADFp1MtZhesdperYakB\nXSuxe9xcrq1psAgpOjPXVXWYrruxDpO3v/Z57LptltgW2xbz3IwqP0+LMAPETLfFUWcGXGxdn+NZ\naIujmpY2O+heu4D77MTb4qTSDUdtD+16TGP3/1loi9PQxoY9v0j5n7v8PHbRnieZyj+qUtripNKC\nJ/lbfg6kUwEAAADMCkEcAAAAgAII4gAAAAAUoMgxcSaVtzrJaclKyXHMTeu4DKMaw/TjM5dvPEzX\nucjzlee7dpG/XGJbbJv28ara7W0MY+TMdFuc1vNrTJzRlfD92dG9deJtcZJTti/XHmtjWD3G8Gyy\nYCW2xRLaWM64jaMZ57NnSp1c5mM1rW1xMcewnYuufyN0xJg4AAAAALNCEAcAAACgAKtOugKjWszu\nros81e3MandLy5fzbnXt7sDD1g3S7qbXxTSh+TGmpcvyNGuf71E/92HTgw86xlzuAYO2naJuk2M3\nLd1WRzWs26178oqVcI6XLVs26SpMta6fc0adrni+aSXbb7/9fKs2Vbp4H/nnOep1nn/Ow+rQxTMS\nPflnV9r1226Xef2ndJrkieg6hWqpf55dKeEZpTR64gAAAAAUQBAHAAAAoACCOAAAAAAFKGaK8XFO\nmdrOd5zG3NJpnTKuBF1MST8rU6mO06httItpMrsYA6k9tsqobb2UtjgN0+aOQ0djls1EW+zi3pYb\nNj5Vvq6L7+MupmotpS0Os9Bz2L5v5eOxzPe7aj73jgXc1yfeFru+V456beev2z6Pw9rbNE6JW0pb\nnM/00+1rOx+LJm9v7TF2uh6bZVTta2kO35MTb4vzMe6pq0uYVjw3rW1xvs8Nw8Yby9vcfNvbNN5P\nwxTjAAAAALNDEAcAAACgAFM7xfi4pyIzjfjSMSxFYNSu0/l2U9TdblG0uyjmn+d8ui92kaI4l2MM\nqmP7HlNal9mVGef0qQvorl1rf/6jXkuT6qI+jbr+LNr3x1zXKc1Lddr4rrv+D0t7YzRd3yuHndP8\nWh/1WWLWvpsWU7u9jXrPzNtRF2mJ7WPMJ61rVEvhO7LrVOLcUvo+Wkxz+f2Vn4Nh32lLfdpyPXEA\nAAAACiCIAwAAAFCAqUqnyrsbdt0dcL7d/4fVI1+31FJsStU+T12MbD6LhqVO5G1nUulUw47ZPv44\nZ7abJvNNTxpV1yP4t2cZmE99h6X6MXeL2TV5qd5vu5j9aNj9blLGmb5ZmmHXdv59NOo9ddi6Yc8w\n+fHb192o6Qqlm+99pouUmmHnbT7Hbx9vlmadnKtxPt+Muz20z+NS+f3Yxftu79PFdTBqO5rG86Qn\nDgAAAEABBHEAAAAACiCIAwAAAFCANJfxIlJKnQ4u0fVUm22jTiM+jjzTrvONq6rqZI7Jrs9h6fJz\nP+p5X8B0n2dUVfXo+e7cqkOn53Eu46kMy7MfZZ/Fzisd9R436nmd1rY4jrF/Rr2HjqrraUHbU1bO\n4dqa2rY4F/O5f02LLq6taW2LbV2cp67b4jDzqW/JbXGc0xWXoIvn1Wlti/P9XixhWveun21iCtri\nqLp+3umiDeT3kfZ9c9SxW7p4Vp7Wtjhf+T15WsbSa38Hj2EcpZHaop44AAAAAAUQxAEAAAAowESn\nGB93t9V2997cuKcdzt/bUpnKsW3U6bznO/37pMzKtMb5+RnWRbH9/kpO4Zg1405N67otdn3Pn8Yp\nHxlskmmVkzSf++QC0pPmrH3/X2r39UGpasM+h2np1j9f+XvO32epzzO5+Z6b0t77fFLbucN8phUf\ndq/serrrdp1Kuz4XYhpTqHLtZ9lJ/c7XEwcAAACgAII4AAAAAAWYaDrVOAzqCjvJGQfy1y5hxPu5\n6GKGsfYx8lS3rj+vLrqNL6UujRERy5YtW/Ax8lS6cVuKs4tMs2nsCsv4LNWUqVwX1/xifs/M956Z\n13FWznX+nuZyDkqe4WrY0AMlmm/7K+1zWEopVOO4v4x6zC5mnZqP9n1k1n4/DlPac+OkfufriQMA\n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\nAACgAP8/5J8r8zJuLHkAAAAASUVORK5CYII=\n", 383 | "text/plain": [ 384 | "" 385 | ] 386 | }, 387 | "metadata": {}, 388 | "output_type": "display_data" 389 | } 390 | ], 391 | "source": [ 392 | "n=10\n", 393 | "fig = plt.figure(figsize=(n*2, n/1.5))\n", 394 | "plt.gray()\n", 395 | "fig.suptitle('First row: original image. Second row: most similar images. Third row: least similar images')\n", 396 | "\n", 397 | "img_shape = (28, 28)\n", 398 | "\n", 399 | "#display original\n", 400 | "display_single_subplot(X_test[img_to_find_idx].reshape(img_shape), n_row=3, n_col=n, cell_num=1)\n", 401 | "#display most similar\n", 402 | "for i in range(n):\n", 403 | " similar_idx = similarity_sorted[i]\n", 404 | " display_single_subplot(X_test[similar_idx].reshape(img_shape), n_row=3, n_col=n, cell_num=n+i+1)\n", 405 | " \n", 406 | "#display most dissimilar\n", 407 | "for i in range(n):\n", 408 | " dissimilar_idx = similarity_sorted[-i-1]\n", 409 | " display_single_subplot(X_test[dissimilar_idx].reshape(img_shape), n_row=3, n_col=n, cell_num=2*n+i+1)\n", 410 | "\n", 411 | "plt.show()" 412 | ] 413 | }, 414 | { 415 | "cell_type": "code", 416 | "execution_count": null, 417 | "metadata": { 418 | "collapsed": true 419 | }, 420 | "outputs": [], 421 | "source": [] 422 | } 423 | ], 424 | "metadata": { 425 | "kernelspec": { 426 | "display_name": "Python [conda env:defaultenv]", 427 | "language": "python", 428 | "name": "conda-env-defaultenv-py" 429 | }, 430 | "language_info": { 431 | "codemirror_mode": { 432 | "name": "ipython", 433 | "version": 3 434 | }, 435 | "file_extension": ".py", 436 | "mimetype": "text/x-python", 437 | "name": "python", 438 | "nbconvert_exporter": "python", 439 | "pygments_lexer": "ipython3", 440 | "version": "3.6.3" 441 | } 442 | }, 443 | "nbformat": 4, 444 | "nbformat_minor": 2 445 | } 446 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The main purpose of this exercise is to understand autoencoders. 2 | 3 | In part 1, I model autoencoder networks for the MNIST and cifar-100 datasets. 4 | 5 | The MNIST dataset was reduced from from 784 dimensions to 64 dimensions, while the cifar-100 dataset was reduced from 3072 dimensions to 512 dimensions.

6 | In both cases, the object category can generally still be discerned from the reconstrucuted autoencoded images.

7 | I'd hoped to achieve more dimensionality reduction on the cifar-100 dataset, but reconstruction quality is too low with further reduction. Perhaps the cifar images are pretty low resolution to begin with, making any loss of information through autoencoding more significant?

8 | I used binary cross entropy as the loss function. The model runs much slower if cosine similarity is used.

9 | 10 | In part 2, I use the encoded representation of the images to find similar images. 11 | 12 | I tried using binary cross entropy and cosine similarity to determine similarity of the encoded vectors, as a proxy for image similarity. The results returned by both tend to be visually similar.

13 | For the MNIST dataset, where most images are centered, this similarity comparison tends to work well, and digits of the same type are deemed to be similar. However, any significant shifts in the position of the digit will lead to it being deemed to be dissimilar.

14 | For the cifar-100 dataset, images with a similar background color / shape are deemed to be similar, rather than images of the same type of object (e.g. with the current similarity metric, flowers are not usually deemed to be similar to other flowers).

15 | As a baseline comparison, I used binary cross entropy to determine image similarity based on the original image dimensions (rather than the encoded dimensions). 16 | Much like the results from the reduced dimensions, images with a similar background color / shape are deemed to be similar.

17 | My original hope was that the image features learned by the autoencoder in the encoded layer would have led to a decent way of determining image similarity. 18 | Unfortunately, since the autoencoder simply tries to reconstruct the original image, it does not necessarily encode features which would have been useful in determining image similarity (in the sense of flowers being deemed to be similar to flowers). Also, the similarity metric places equal focus on all parts of the images, rather than the parts which could be more important (e.g. the subject of the image). 19 | -------------------------------------------------------------------------------- /autoencoder_MNIST_final.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Puayny/Autoencoder-image-similarity/dfbd805f5bfdaff37cfe32d713a8d9d8a7281908/autoencoder_MNIST_final.h5 -------------------------------------------------------------------------------- /autoencoder_cifar100_final.h5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Puayny/Autoencoder-image-similarity/dfbd805f5bfdaff37cfe32d713a8d9d8a7281908/autoencoder_cifar100_final.h5 -------------------------------------------------------------------------------- /autoencoder_utils.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import tensorflow as tf 3 | from keras.losses import binary_crossentropy, cosine_proximity 4 | import numpy as np 5 | 6 | def display_single_subplot(img, n_row, n_col, cell_num): 7 | ax = plt.subplot(n_row, n_col, cell_num) 8 | plt.imshow(img) 9 | ax.get_xaxis().set_visible(False) 10 | ax.get_yaxis().set_visible(False) 11 | 12 | def get_sorted_similarity_idx(encoder, img_to_find_idx, dataset, loss='binary_crossentropy'): 13 | encoded_images = encoder.predict(dataset) 14 | encoded_images = encoded_images.reshape(encoded_images.shape[0], -1) 15 | 16 | #initializing vars to pass into tensorflow 17 | X_selected = [encoded_images[img_to_find_idx].tolist() for _ in range(encoded_images.shape[0])] 18 | X_all = encoded_images.tolist() 19 | 20 | X_selected_tf = tf.Variable(X_selected, tf.float32) 21 | X_all_tf = tf.Variable(X_all, tf.float32) 22 | if loss=='binary_crossentropy': 23 | loss_tf = binary_crossentropy(X_selected_tf, X_all_tf) 24 | elif loss=='cosine_proximity': 25 | loss_tf = cosine_proximity(X_selected_tf, X_all_tf) 26 | else: 27 | print('Unknown loss, using binary_crossentropy.') 28 | loss_tf = binary_crossentropy(X_selected_tf, X_all_tf) 29 | init_op = tf.global_variables_initializer() 30 | 31 | similarity = [] 32 | with tf.Session() as sess: 33 | sess.run(init_op) 34 | similarity = sess.run(loss_tf) 35 | similarity_sorted = np.argsort(np.array(similarity))[1:] #the same figure appears in X_all too, so remove it 36 | return similarity_sorted --------------------------------------------------------------------------------