{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "# Generative Adversarial Network Example\n",
    "\n",
    "Build a generative adversarial network (GAN) to generate digit images from a noise distribution with TensorFlow.\n",
    "\n",
    "- Author: Aymeric Damien\n",
    "- Project: https://github.com/aymericdamien/TensorFlow-Examples/"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## GAN Overview\n",
    "\n",
    "<img src=\"http://www.timzhangyuxuan.com/static/images/project_DCGAN/structure.png\" alt=\"nn\" style=\"width: 800px;\"/>\n",
    "\n",
    "References:\n",
    "- [Generative adversarial nets](https://arxiv.org/pdf/1406.2661.pdf). I Goodfellow, J Pouget-Abadie, M Mirza, B Xu, D Warde-Farley, S Ozair, Y. Bengio. Advances in neural information processing systems, 2672-2680.\n",
    "- [Understanding the difficulty of training deep feedforward neural networks](http://proceedings.mlr.press/v9/glorot10a.html). X Glorot, Y Bengio. Aistats 9, 249-256\n",
    "\n",
    "Other tutorials:\n",
    "- [Generative Adversarial Networks Explained](http://kvfrans.com/generative-adversial-networks-explained/). Kevin Frans.\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": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from __future__ import division, print_function, absolute_import\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import tensorflow as tf"
   ]
  },
  {
   "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 Params\n",
    "num_steps = 70000\n",
    "batch_size = 128\n",
    "learning_rate = 0.0002\n",
    "\n",
    "# Network Params\n",
    "image_dim = 784 # 28*28 pixels\n",
    "gen_hidden_dim = 256\n",
    "disc_hidden_dim = 256\n",
    "noise_dim = 100 # Noise data points\n",
    "\n",
    "# A custom initialization (see Xavier Glorot init)\n",
    "def glorot_init(shape):\n",
    "    return tf.random_normal(shape=shape, stddev=1. / tf.sqrt(shape[0] / 2.))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Store layers weight & bias\n",
    "weights = {\n",
    "    'gen_hidden1': tf.Variable(glorot_init([noise_dim, gen_hidden_dim])),\n",
    "    'gen_out': tf.Variable(glorot_init([gen_hidden_dim, image_dim])),\n",
    "    'disc_hidden1': tf.Variable(glorot_init([image_dim, disc_hidden_dim])),\n",
    "    'disc_out': tf.Variable(glorot_init([disc_hidden_dim, 1])),\n",
    "}\n",
    "biases = {\n",
    "    'gen_hidden1': tf.Variable(tf.zeros([gen_hidden_dim])),\n",
    "    'gen_out': tf.Variable(tf.zeros([image_dim])),\n",
    "    'disc_hidden1': tf.Variable(tf.zeros([disc_hidden_dim])),\n",
    "    'disc_out': tf.Variable(tf.zeros([1])),\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Generator\n",
    "def generator(x):\n",
    "    hidden_layer = tf.matmul(x, weights['gen_hidden1'])\n",
    "    hidden_layer = tf.add(hidden_layer, biases['gen_hidden1'])\n",
    "    hidden_layer = tf.nn.relu(hidden_layer)\n",
    "    out_layer = tf.matmul(hidden_layer, weights['gen_out'])\n",
    "    out_layer = tf.add(out_layer, biases['gen_out'])\n",
    "    out_layer = tf.nn.sigmoid(out_layer)\n",
    "    return out_layer\n",
    "\n",
    "\n",
    "# Discriminator\n",
    "def discriminator(x):\n",
    "    hidden_layer = tf.matmul(x, weights['disc_hidden1'])\n",
    "    hidden_layer = tf.add(hidden_layer, biases['disc_hidden1'])\n",
    "    hidden_layer = tf.nn.relu(hidden_layer)\n",
    "    out_layer = tf.matmul(hidden_layer, weights['disc_out'])\n",
    "    out_layer = tf.add(out_layer, biases['disc_out'])\n",
    "    out_layer = tf.nn.sigmoid(out_layer)\n",
    "    return out_layer\n",
    "\n",
    "# Build Networks\n",
    "# Network Inputs\n",
    "gen_input = tf.placeholder(tf.float32, shape=[None, noise_dim], name='input_noise')\n",
    "disc_input = tf.placeholder(tf.float32, shape=[None, image_dim], name='disc_input')\n",
    "\n",
    "# Build Generator Network\n",
    "gen_sample = generator(gen_input)\n",
    "\n",
    "# Build 2 Discriminator Networks (one from noise input, one from generated samples)\n",
    "disc_real = discriminator(disc_input)\n",
    "disc_fake = discriminator(gen_sample)\n",
    "\n",
    "# Build Loss\n",
    "gen_loss = -tf.reduce_mean(tf.log(disc_fake))\n",
    "disc_loss = -tf.reduce_mean(tf.log(disc_real) + tf.log(1. - disc_fake))\n",
    "\n",
    "# Build Optimizers\n",
    "optimizer_gen = tf.train.AdamOptimizer(learning_rate=learning_rate)\n",
    "optimizer_disc = tf.train.AdamOptimizer(learning_rate=learning_rate)\n",
    "\n",
    "# Training Variables for each optimizer\n",
    "# By default in TensorFlow, all variables are updated by each optimizer, so we\n",
    "# need to precise for each one of them the specific variables to update.\n",
    "# Generator Network Variables\n",
    "gen_vars = [weights['gen_hidden1'], weights['gen_out'],\n",
    "            biases['gen_hidden1'], biases['gen_out']]\n",
    "# Discriminator Network Variables\n",
    "disc_vars = [weights['disc_hidden1'], weights['disc_out'],\n",
    "            biases['disc_hidden1'], biases['disc_out']]\n",
    "\n",
    "# Create training operations\n",
    "train_gen = optimizer_gen.minimize(gen_loss, var_list=gen_vars)\n",
    "train_disc = optimizer_disc.minimize(disc_loss, var_list=disc_vars)\n",
    "\n",
    "# Initialize the variables (i.e. assign their default value)\n",
    "init = tf.global_variables_initializer()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Step 1: Generator Loss: 0.774581, Discriminator Loss: 1.300602\n",
      "Step 2000: Generator Loss: 4.521158, Discriminator Loss: 0.030166\n",
      "Step 4000: Generator Loss: 3.685439, Discriminator Loss: 0.125958\n",
      "Step 6000: Generator Loss: 4.412449, Discriminator Loss: 0.097088\n",
      "Step 8000: Generator Loss: 3.996747, Discriminator Loss: 0.150800\n",
      "Step 10000: Generator Loss: 3.850827, Discriminator Loss: 0.225699\n",
      "Step 12000: Generator Loss: 2.950704, Discriminator Loss: 0.279967\n",
      "Step 14000: Generator Loss: 3.741951, Discriminator Loss: 0.241062\n",
      "Step 16000: Generator Loss: 3.117743, Discriminator Loss: 0.432293\n",
      "Step 18000: Generator Loss: 3.647199, Discriminator Loss: 0.278121\n",
      "Step 20000: Generator Loss: 3.186711, Discriminator Loss: 0.313830\n",
      "Step 22000: Generator Loss: 3.737114, Discriminator Loss: 0.201730\n",
      "Step 24000: Generator Loss: 3.042442, Discriminator Loss: 0.454414\n",
      "Step 26000: Generator Loss: 3.340376, Discriminator Loss: 0.249428\n",
      "Step 28000: Generator Loss: 3.423218, Discriminator Loss: 0.369653\n",
      "Step 30000: Generator Loss: 3.219242, Discriminator Loss: 0.463535\n",
      "Step 32000: Generator Loss: 3.313017, Discriminator Loss: 0.276070\n",
      "Step 34000: Generator Loss: 3.413397, Discriminator Loss: 0.367721\n",
      "Step 36000: Generator Loss: 3.240625, Discriminator Loss: 0.446160\n",
      "Step 38000: Generator Loss: 3.175355, Discriminator Loss: 0.377628\n",
      "Step 40000: Generator Loss: 3.154558, Discriminator Loss: 0.478812\n",
      "Step 42000: Generator Loss: 3.210753, Discriminator Loss: 0.497502\n",
      "Step 44000: Generator Loss: 2.883431, Discriminator Loss: 0.395812\n",
      "Step 46000: Generator Loss: 2.584176, Discriminator Loss: 0.420783\n",
      "Step 48000: Generator Loss: 2.581381, Discriminator Loss: 0.469289\n",
      "Step 50000: Generator Loss: 2.752729, Discriminator Loss: 0.373544\n",
      "Step 52000: Generator Loss: 2.649749, Discriminator Loss: 0.463755\n",
      "Step 54000: Generator Loss: 2.468188, Discriminator Loss: 0.556129\n",
      "Step 56000: Generator Loss: 2.653330, Discriminator Loss: 0.377572\n",
      "Step 58000: Generator Loss: 2.697943, Discriminator Loss: 0.424133\n",
      "Step 60000: Generator Loss: 2.835973, Discriminator Loss: 0.413252\n",
      "Step 62000: Generator Loss: 2.751346, Discriminator Loss: 0.403332\n",
      "Step 64000: Generator Loss: 3.212001, Discriminator Loss: 0.534427\n",
      "Step 66000: Generator Loss: 2.878227, Discriminator Loss: 0.431244\n",
      "Step 68000: Generator Loss: 3.104266, Discriminator Loss: 0.426825\n",
      "Step 70000: Generator Loss: 2.871485, Discriminator Loss: 0.348638\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",
    "    # Generate noise to feed to the generator\n",
    "    z = np.random.uniform(-1., 1., size=[batch_size, noise_dim])\n",
    "\n",
    "    # Train\n",
    "    feed_dict = {disc_input: batch_x, gen_input: z}\n",
    "    _, _, gl, dl = sess.run([train_gen, train_disc, gen_loss, disc_loss],\n",
    "                            feed_dict=feed_dict)\n",
    "    if i % 2000 == 0 or i == 1:\n",
    "        print('Step %i: Generator Loss: %f, Discriminator Loss: %f' % (i, gl, dl))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7fd21f080c90>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Testing\n",
    "# Generate images from noise, using the generator network.\n",
    "n = 6\n",
    "canvas = np.empty((28 * n, 28 * n))\n",
    "for i in range(n):\n",
    "    # Noise input.\n",
    "    z = np.random.uniform(-1., 1., size=[n, noise_dim])\n",
    "    # Generate image from noise.\n",
    "    g = sess.run(gen_sample, feed_dict={gen_input: z})\n",
    "    # Reverse colours for better display\n",
    "    g = -1 * (g - 1)\n",
    "    for j in range(n):\n",
    "        # Draw the generated digits\n",
    "        canvas[i * 28:(i + 1) * 28, j * 28:(j + 1) * 28] = g[j].reshape([28, 28])\n",
    "\n",
    "plt.figure(figsize=(n, n))\n",
    "plt.imshow(canvas, 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
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
