{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Auto-Encoder Example\n",
    "\n",
    "Build a 2 layers auto-encoder with TensorFlow to compress images to a lower latent space and then reconstruct them.\n",
    "\n",
    "- Author: Aymeric Damien\n",
    "- Project: https://github.com/aymericdamien/TensorFlow-Examples/"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Auto-Encoder Overview\n",
    "\n",
    "<img src=\"http://kvfrans.com/content/images/2016/08/autoenc.jpg\" alt=\"ae\" style=\"width: 800px;\"/>\n",
    "\n",
    "References:\n",
    "- [Gradient-based learning applied to document recognition](http://yann.lecun.com/exdb/publis/pdf/lecun-01a.pdf). Y. LeCun, L. Bottou, Y. Bengio, and P. Haffner. Proceedings of the IEEE, 86(11):2278-2324, November 1998.\n",
    "\n",
    "## MNIST Dataset Overview\n",
    "\n",
    "This example is using MNIST handwritten digits. The dataset contains 60,000 examples for training and 10,000 examples for testing. The digits have been size-normalized and centered in a fixed-size image (28x28 pixels) with values from 0 to 1. For simplicity, each image has been flattened and converted to a 1-D numpy array of 784 features (28*28).\n",
    "\n",
    "![MNIST Dataset](http://neuralnetworksanddeeplearning.com/images/mnist_100_digits.png)\n",
    "\n",
    "More info: http://yann.lecun.com/exdb/mnist/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from __future__ import division, print_function, absolute_import\n",
    "\n",
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting /tmp/data/train-images-idx3-ubyte.gz\n",
      "Extracting /tmp/data/train-labels-idx1-ubyte.gz\n",
      "Extracting /tmp/data/t10k-images-idx3-ubyte.gz\n",
      "Extracting /tmp/data/t10k-labels-idx1-ubyte.gz\n"
     ]
    }
   ],
   "source": [
    "# Import MNIST data\n",
    "from tensorflow.examples.tutorials.mnist import input_data\n",
    "mnist = input_data.read_data_sets(\"/tmp/data/\", one_hot=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Training Parameters\n",
    "learning_rate = 0.01\n",
    "num_steps = 30000\n",
    "batch_size = 256\n",
    "\n",
    "display_step = 1000\n",
    "examples_to_show = 10\n",
    "\n",
    "# Network Parameters\n",
    "num_hidden_1 = 256 # 1st layer num features\n",
    "num_hidden_2 = 128 # 2nd layer num features (the latent dim)\n",
    "num_input = 784 # MNIST data input (img shape: 28*28)\n",
    "\n",
    "# tf Graph input (only pictures)\n",
    "X = tf.placeholder(\"float\", [None, num_input])\n",
    "\n",
    "weights = {\n",
    "    'encoder_h1': tf.Variable(tf.random_normal([num_input, num_hidden_1])),\n",
    "    'encoder_h2': tf.Variable(tf.random_normal([num_hidden_1, num_hidden_2])),\n",
    "    'decoder_h1': tf.Variable(tf.random_normal([num_hidden_2, num_hidden_1])),\n",
    "    'decoder_h2': tf.Variable(tf.random_normal([num_hidden_1, num_input])),\n",
    "}\n",
    "biases = {\n",
    "    'encoder_b1': tf.Variable(tf.random_normal([num_hidden_1])),\n",
    "    'encoder_b2': tf.Variable(tf.random_normal([num_hidden_2])),\n",
    "    'decoder_b1': tf.Variable(tf.random_normal([num_hidden_1])),\n",
    "    'decoder_b2': tf.Variable(tf.random_normal([num_input])),\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Building the encoder\n",
    "def encoder(x):\n",
    "    # Encoder Hidden layer with sigmoid activation #1\n",
    "    layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x, weights['encoder_h1']),\n",
    "                                   biases['encoder_b1']))\n",
    "    # Encoder Hidden layer with sigmoid activation #2\n",
    "    layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, weights['encoder_h2']),\n",
    "                                   biases['encoder_b2']))\n",
    "    return layer_2\n",
    "\n",
    "\n",
    "# Building the decoder\n",
    "def decoder(x):\n",
    "    # Decoder Hidden layer with sigmoid activation #1\n",
    "    layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x, weights['decoder_h1']),\n",
    "                                   biases['decoder_b1']))\n",
    "    # Decoder Hidden layer with sigmoid activation #2\n",
    "    layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, weights['decoder_h2']),\n",
    "                                   biases['decoder_b2']))\n",
    "    return layer_2\n",
    "\n",
    "# Construct model\n",
    "encoder_op = encoder(X)\n",
    "decoder_op = decoder(encoder_op)\n",
    "\n",
    "# Prediction\n",
    "y_pred = decoder_op\n",
    "# Targets (Labels) are the input data.\n",
    "y_true = X\n",
    "\n",
    "# Define loss and optimizer, minimize the squared error\n",
    "loss = tf.reduce_mean(tf.pow(y_true - y_pred, 2))\n",
    "optimizer = tf.train.RMSPropOptimizer(learning_rate).minimize(loss)\n",
    "\n",
    "# Initialize the variables (i.e. assign their default value)\n",
    "init = tf.global_variables_initializer()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Step 1: Minibatch Loss: 0.438300\n",
      "Step 1000: Minibatch Loss: 0.146586\n",
      "Step 2000: Minibatch Loss: 0.130722\n",
      "Step 3000: Minibatch Loss: 0.117178\n",
      "Step 4000: Minibatch Loss: 0.109027\n",
      "Step 5000: Minibatch Loss: 0.102582\n",
      "Step 6000: Minibatch Loss: 0.099183\n",
      "Step 7000: Minibatch Loss: 0.095619\n",
      "Step 8000: Minibatch Loss: 0.089006\n",
      "Step 9000: Minibatch Loss: 0.087125\n",
      "Step 10000: Minibatch Loss: 0.083930\n",
      "Step 11000: Minibatch Loss: 0.077512\n",
      "Step 12000: Minibatch Loss: 0.077137\n",
      "Step 13000: Minibatch Loss: 0.073983\n",
      "Step 14000: Minibatch Loss: 0.074218\n",
      "Step 15000: Minibatch Loss: 0.074492\n",
      "Step 16000: Minibatch Loss: 0.074374\n",
      "Step 17000: Minibatch Loss: 0.070909\n",
      "Step 18000: Minibatch Loss: 0.069438\n",
      "Step 19000: Minibatch Loss: 0.068245\n",
      "Step 20000: Minibatch Loss: 0.068402\n",
      "Step 21000: Minibatch Loss: 0.067113\n",
      "Step 22000: Minibatch Loss: 0.068241\n",
      "Step 23000: Minibatch Loss: 0.062454\n",
      "Step 24000: Minibatch Loss: 0.059754\n",
      "Step 25000: Minibatch Loss: 0.058687\n",
      "Step 26000: Minibatch Loss: 0.059107\n",
      "Step 27000: Minibatch Loss: 0.055788\n",
      "Step 28000: Minibatch Loss: 0.057263\n",
      "Step 29000: Minibatch Loss: 0.056391\n",
      "Step 30000: Minibatch Loss: 0.057672\n"
     ]
    }
   ],
   "source": [
    "# Start Training\n",
    "# Start a new TF session\n",
    "sess = tf.Session()\n",
    "\n",
    "# Run the initializer\n",
    "sess.run(init)\n",
    "\n",
    "# Training\n",
    "for i in range(1, num_steps+1):\n",
    "    # Prepare Data\n",
    "    # Get the next batch of MNIST data (only images are needed, not labels)\n",
    "    batch_x, _ = mnist.train.next_batch(batch_size)\n",
    "\n",
    "    # Run optimization op (backprop) and cost op (to get loss value)\n",
    "    _, l = sess.run([optimizer, loss], feed_dict={X: batch_x})\n",
    "    # Display logs per step\n",
    "    if i % display_step == 0 or i == 1:\n",
    "        print('Step %i: Minibatch Loss: %f' % (i, l))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original Images\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f2c8925bdd0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Reconstructed Images\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f2c7e2c87d0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Testing\n",
    "# Encode and decode images from test set and visualize their reconstruction.\n",
    "n = 4\n",
    "canvas_orig = np.empty((28 * n, 28 * n))\n",
    "canvas_recon = np.empty((28 * n, 28 * n))\n",
    "for i in range(n):\n",
    "    # MNIST test set\n",
    "    batch_x, _ = mnist.test.next_batch(n)\n",
    "    # Encode and decode the digit image\n",
    "    g = sess.run(decoder_op, feed_dict={X: batch_x})\n",
    "    \n",
    "    # Display original images\n",
    "    for j in range(n):\n",
    "        # Draw the generated digits\n",
    "        canvas_orig[i * 28:(i + 1) * 28, j * 28:(j + 1) * 28] = batch_x[j].reshape([28, 28])\n",
    "    # Display reconstructed images\n",
    "    for j in range(n):\n",
    "        # Draw the generated digits\n",
    "        canvas_recon[i * 28:(i + 1) * 28, j * 28:(j + 1) * 28] = g[j].reshape([28, 28])\n",
    "\n",
    "print(\"Original Images\")     \n",
    "plt.figure(figsize=(n, n))\n",
    "plt.imshow(canvas_orig, origin=\"upper\", cmap=\"gray\")\n",
    "plt.show()\n",
    "\n",
    "print(\"Reconstructed Images\")\n",
    "plt.figure(figsize=(n, n))\n",
    "plt.imshow(canvas_recon, origin=\"upper\", cmap=\"gray\")\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2.0
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}