{ "cells": [ { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Deep Convolutional Generative Adversarial Network Example\n", "\n", "Build a deep convolutional generative adversarial network (DCGAN) 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": [ "## DCGAN Overview\n", "\n", "\"dcgan\"\n", "\n", "References:\n", "- [Unsupervised representation learning with deep convolutional generative adversarial networks](https://arxiv.org/pdf/1511.06434). A Radford, L Metz, S Chintala, 2016.\n", "- [Understanding the difficulty of training deep feedforward neural networks](www.cs.cmu.edu/~bhiksha/courses/deeplearning/Fall.../AISTATS2010_Glorot.pdf). X Glorot, Y Bengio. Aistats 9, 249-256\n", "- [Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift](https://arxiv.org/abs/1502.03167). Sergey Ioffe, Christian Szegedy. 2015.\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 = 10000\n", "batch_size = 128\n", "lr_generator = 0.002\n", "lr_discriminator = 0.002\n", "\n", "# Network Params\n", "image_dim = 784 # 28*28 pixels * 1 channel\n", "noise_dim = 100 # Noise data points" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Build Networks\n", "# Network Inputs\n", "noise_input = tf.placeholder(tf.float32, shape=[None, noise_dim])\n", "real_image_input = tf.placeholder(tf.float32, shape=[None, 28, 28, 1])\n", "# A boolean to indicate batch normalization if it is training or inference time\n", "is_training = tf.placeholder(tf.bool)\n", "\n", "#LeakyReLU activation\n", "def leakyrelu(x, alpha=0.2):\n", " return 0.5 * (1 + alpha) * x + 0.5 * (1 - alpha) * abs(x)\n", "\n", "# Generator Network\n", "# Input: Noise, Output: Image\n", "# Note that batch normalization has different behavior at training and inference time,\n", "# we then use a placeholder to indicates the layer if we are training or not.\n", "def generator(x, reuse=False):\n", " with tf.variable_scope('Generator', reuse=reuse):\n", " # TensorFlow Layers automatically create variables and calculate their\n", " # shape, based on the input.\n", " x = tf.layers.dense(x, units=7 * 7 * 128)\n", " x = tf.layers.batch_normalization(x, training=is_training)\n", " x = tf.nn.relu(x)\n", " # Reshape to a 4-D array of images: (batch, height, width, channels)\n", " # New shape: (batch, 7, 7, 128)\n", " x = tf.reshape(x, shape=[-1, 7, 7, 128])\n", " # Deconvolution, image shape: (batch, 14, 14, 64)\n", " x = tf.layers.conv2d_transpose(x, 64, 5, strides=2, padding='same')\n", " x = tf.layers.batch_normalization(x, training=is_training)\n", " x = tf.nn.relu(x)\n", " # Deconvolution, image shape: (batch, 28, 28, 1)\n", " x = tf.layers.conv2d_transpose(x, 1, 5, strides=2, padding='same')\n", " # Apply tanh for better stability - clip values to [-1, 1].\n", " x = tf.nn.tanh(x)\n", " return x\n", "\n", "\n", "# Discriminator Network\n", "# Input: Image, Output: Prediction Real/Fake Image\n", "def discriminator(x, reuse=False):\n", " with tf.variable_scope('Discriminator', reuse=reuse):\n", " # Typical convolutional neural network to classify images.\n", " x = tf.layers.conv2d(x, 64, 5, strides=2, padding='same')\n", " x = tf.layers.batch_normalization(x, training=is_training)\n", " x = leakyrelu(x)\n", " x = tf.layers.conv2d(x, 128, 5, strides=2, padding='same')\n", " x = tf.layers.batch_normalization(x, training=is_training)\n", " x = leakyrelu(x)\n", " # Flatten\n", " x = tf.reshape(x, shape=[-1, 7*7*128])\n", " x = tf.layers.dense(x, 1024)\n", " x = tf.layers.batch_normalization(x, training=is_training)\n", " x = leakyrelu(x)\n", " # Output 2 classes: Real and Fake images\n", " x = tf.layers.dense(x, 2)\n", " return x\n", "\n", "# Build Generator Network\n", "gen_sample = generator(noise_input)\n", "\n", "# Build 2 Discriminator Networks (one from noise input, one from generated samples)\n", "disc_real = discriminator(real_image_input)\n", "disc_fake = discriminator(gen_sample, reuse=True)\n", "\n", "# Build the stacked generator/discriminator\n", "stacked_gan = discriminator(gen_sample, reuse=True)\n", "\n", "# Build Loss (Labels for real images: 1, for fake images: 0)\n", "# Discriminator Loss for real and fake samples\n", "disc_loss_real = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(\n", " logits=disc_real, labels=tf.ones([batch_size], dtype=tf.int32)))\n", "disc_loss_fake = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(\n", " logits=disc_fake, labels=tf.zeros([batch_size], dtype=tf.int32)))\n", "# Sum both loss\n", "disc_loss = disc_loss_real + disc_loss_fake\n", "# Generator Loss (The generator tries to fool the discriminator, thus labels are 1)\n", "gen_loss = tf.reduce_mean(tf.nn.sparse_softmax_cross_entropy_with_logits(\n", " logits=stacked_gan, labels=tf.ones([batch_size], dtype=tf.int32)))\n", "\n", "# Build Optimizers\n", "optimizer_gen = tf.train.AdamOptimizer(learning_rate=lr_generator, beta1=0.5, beta2=0.999)\n", "optimizer_disc = tf.train.AdamOptimizer(learning_rate=lr_discriminator, beta1=0.5, beta2=0.999)\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 = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='Generator')\n", "# Discriminator Network Variables\n", "disc_vars = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='Discriminator')\n", "\n", "# Create training operations\n", "# TensorFlow UPDATE_OPS collection holds all batch norm operation to update the moving mean/stddev\n", "gen_update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS, scope='Generator')\n", "# `control_dependencies` ensure that the `gen_update_ops` will be run before the `minimize` op (backprop)\n", "with tf.control_dependencies(gen_update_ops):\n", " train_gen = optimizer_gen.minimize(gen_loss, var_list=gen_vars)\n", "disc_update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS, scope='Discriminator')\n", "with tf.control_dependencies(disc_update_ops):\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": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Step 1: Generator Loss: 3.590350, Discriminator Loss: 1.907586\n", "Step 500: Generator Loss: 1.254698, Discriminator Loss: 1.005236\n", "Step 1000: Generator Loss: 1.730409, Discriminator Loss: 0.837684\n", "Step 1500: Generator Loss: 1.962198, Discriminator Loss: 0.618827\n", "Step 2000: Generator Loss: 2.767945, Discriminator Loss: 0.378071\n", "Step 2500: Generator Loss: 2.370605, Discriminator Loss: 0.561247\n", "Step 3000: Generator Loss: 3.427798, Discriminator Loss: 0.402951\n", "Step 3500: Generator Loss: 4.904454, Discriminator Loss: 0.554856\n", "Step 4000: Generator Loss: 4.045284, Discriminator Loss: 0.454970\n", "Step 4500: Generator Loss: 4.577699, Discriminator Loss: 0.687195\n", "Step 5000: Generator Loss: 3.476081, Discriminator Loss: 0.210492\n", "Step 5500: Generator Loss: 3.898139, Discriminator Loss: 0.143352\n", "Step 6000: Generator Loss: 4.089877, Discriminator Loss: 1.082561\n", "Step 6500: Generator Loss: 5.911457, Discriminator Loss: 0.154059\n", "Step 7000: Generator Loss: 3.594872, Discriminator Loss: 0.152970\n", "Step 7500: Generator Loss: 6.067883, Discriminator Loss: 0.084864\n", "Step 8000: Generator Loss: 6.737456, Discriminator Loss: 0.402566\n", "Step 8500: Generator Loss: 6.630128, Discriminator Loss: 0.034838\n", "Step 9000: Generator Loss: 6.480587, Discriminator Loss: 0.427419\n", "Step 9500: Generator Loss: 7.200409, Discriminator Loss: 0.124268\n", "Step 10000: Generator Loss: 5.479313, Discriminator Loss: 0.191389\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", "\n", " # Prepare Input 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", " batch_x = np.reshape(batch_x, newshape=[-1, 28, 28, 1])\n", " # Rescale to [-1, 1], the input range of the discriminator\n", " batch_x = batch_x * 2. - 1.\n", "\n", " # Discriminator Training\n", " # Generate noise to feed to the generator\n", " z = np.random.uniform(-1., 1., size=[batch_size, noise_dim])\n", " _, dl = sess.run([train_disc, disc_loss], feed_dict={real_image_input: batch_x, noise_input: z, is_training:True})\n", " \n", " # Generator Training\n", " # Generate noise to feed to the generator\n", " z = np.random.uniform(-1., 1., size=[batch_size, noise_dim])\n", " _, gl = sess.run([train_gen, gen_loss], feed_dict={noise_input: z, is_training:True})\n", " \n", " if i % 500 == 0 or i == 1:\n", " print('Step %i: Generator Loss: %f, Discriminator Loss: %f' % (i, gl, dl))" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXIAAAFpCAYAAACBNaNRAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsnXm4TWX7xz8Pv1elmQZlbpCISicJrwalidKsIo0kzSWh\nee6taFRpkEZpUNEoDZoIqUShJBmikgbKdNbvj32+6zlnHceZ9rD2dn+uy7WdffbZ+3n2etZa3/t+\n7sEFQYBhGIaRvVTJ9AAMwzCMymEXcsMwjCzHLuSGYRhZjl3IDcMwshy7kBuGYWQ5diE3DMPIcuxC\nbhiGkeWk7ELunDvUOTfDOfedc+6KVH2OYRjG+o5LRUKQc64qMBM4GJgHTAROCoJgetI/zDAMYz0n\nVYq8JfBdEASzgyBYCQwHjkrRZxmGYazX/F+K3rc28FOhn+cB+5T04q222ipo0KBBioZiGGVHFqpz\nLsMjMdZ35syZw6+//lqmhZiqC3mpOOd6AD0A6tWrx6RJkzI1FMMwjBJZvXo1AFWqFHVgRH9ONnl5\neWV+bapGMh+oW+jnOgXPhQRBMCQIgrwgCPK23nrrFA3DMAwj90mVIp8I7Oyca0jiAt4FODlFn2UY\nWUd+fj4A33//PeDV3eabbw5AzZo1AXPxxIGFCxcC0KJFCwD++OMPAAYOHAjAeeedl5mBFSIlF/Ig\nCFY7584D3gKqAo8FQTAtFZ9lGIaxvpMyH3kQBK8Dr6fq/Y3sZs2aNQDce++9nHXWWQBssskmmRxS\nWtBmauvWrQGYOHEi4BW6lPmGG24IJPykY8eOBeD//i9jW1rrNVLev/76a5Hn+/TpA8RDkVtmp2EY\nRpZjt/hyko3haVK/q1atYoMNNgAyN/5vvvkG8P7GlStXcsUVicRf+YWl0Pv16wd4dZrNyM96+OGH\nAzB/fmLvf6ONNgL88dDjqlWrAPj666+ZPHkyAPvsU2IEr5ECVqxYAcCTTz651t9vscUW6RzOOjFF\nbhiGkeXkrCL/66+/APjnn38A+O677wD47bffAK98dFd9/PHHAZg1axYAX3zxBeDvylKFd955JwBn\nnnlmSsdfGWQ1vPHGGwB069YNgI033jiMib3hhhsAOO200wCoWrVqWsZ08smJ4CWNo1q1aqF/WMfm\ntttuA+DBBx8EYPz48QA0bNgwpWNMBbKGrrvuOsAr8YcffhiA9u3bA359/fvvv4D3u77xxhuMGjUK\nyE5FrvPp6quvBuCVV14p8nudf8cffzwARx2VSADff//9gdTHaq8NrVX5wP/8888iv9deRdu2bdM7\nsHVgitwwDCPLyTlF/ssvvwBw5ZVXAvD8888DsGzZMsArJKnAaNEwKQAp9v/85z8A7LHHHgB07Ngx\nZWOvLJrbIYccAsCHH35Y5PkgCNh2220B2G677YD0KR593/rcLbfcEoDevXuzzTbbAD6CY8SIEQB8\n/vnngPcry7+eTSxfvhyAjz76CIC6dRN5ckcccQRQPBJFkTtdunQB4KWXXuKDDz4A4r0/o+M7Y8YM\nAM4//3wAJkyYAPjvQXPQutP5+tBDDwHw2GOPAd6KHDx4cMrHHkXXii+//BLwc9P3rlj/66+/Pu1j\nKwlT5IZhGFlOTinyIAhCH/awYcOARFSEfrc2dJeVMqpevToAzZo1A+Cmm24CfJTFxhtvnIqhVwrt\nBxxzzDEAvP/++4Cfs+ZUv3597rnnHsD791Kt7uQL//bbbwF4+umnAe8bLfz5//3vfwHvH1YUi3yU\nsixS7c9PJtprUdTKZZddBpQeE77LLruE///pp0T9uTgqcp1fb731FgC9evUCYMmSJUDRvRDwUTra\nC9Cjvg8d45dffhnw39cOO+yQwlkUZeTIkUAiYqgw2sdo06YNALvuumvaxlQapsgNwzCynJxS5LNm\nzQp94orDlXpR/HSTJk0AOProowG/S96oUaMir8sG5s2bB8App5wCeH+k1I+iHB555BEgoWrSreak\ntHbbbbcy/43GL79yz549AXj22WcB6Nq1azKHmFL0fUtNlzX2eLPNNgv/Lo4WiPzGo0ePBvwxke+7\ndu3agLf8tFb79u0LeP+z1uYtt9wC+Oixd955B/B+6KFDhwKptUY++eQTwO+vyVeu9Si//f/+97+U\njaGimCI3DMPIcnJKkVevXj2sTCakEDp37gzAkCFDANh0003TO7gk8sMPPwDQqVMnwFfQkw/vvvvu\nA7xSj5NPtTxon0J7AFJvijnOButJ/tRzzz0X8FE7pfm7Ff2xcuXKUJ3HhSAIWLBgAQCXXHJJkd/p\nGGm/Rv597c3o+9B+SI0aNQC/hyBfu3zrn376aZGfFUWWTHTNuPDCCwEfSaNrh84jzSGO6y6nLuR1\n6tTh0ksvBXxSiUxZhTdl8wVc7iJdFJTkpJPh/vvvB7zbKNvRRU4nvRKcZIZfc801RV4XRzS2G2+8\nsVx/p8SZDTfcsMjGZxxwzjFnzhwAli5dCviwSYVVyh2hzl/9+/cP/xZ82rs2R6MhfrqJ63WpuIDr\nM5V4ps1NjV0X9ssvvxyI5wVcmGvFMAwjy8kpRb5y5cpwg2KnnXYC4LnnngN82GAcQ7jKisKilCCi\nTbC7774byB0lLnSMDjroIABeeOEFwB9TbbDpWOcCCudT+F21atXo3r07kJl09ZKQ0tYaVMLP77//\nDnjLV7/X+aeNRK1ZuUykduWqkbWVShW8ePFiAJ555hnAXxuUjKWxpsIaSDbxWRmGYRhGhcgpRX7B\nBReEPjX5xuUrly9Oiqdly5ZAdijzaKErqRylrh977LGZGViaeOqppwD4+++/Aa/+lCwiRaXEp2xG\nKvHnn38GoHHjxhx44IGZHNJa2X777QEf4qpNSu1RKQxYKld7BI8++ijgrYv69esDPixRxejkp04l\nP/74I+CDBbQRfe2111ZqDPn5+eFxlCWS6r05U+SGYRhZTk4p8tdeey1UaypfqwQDFePRHVIhRQru\nj3ObMSkHJVVIzdx8881Ffi4NpT9DdqS5K6pA0QSap9K8Dz30UCA3Gk8INdPQOt5zzz1jGS2hY3Hr\nrbcCXpHrMZpcowJuWndKEFM5BoXSpkOJ6zxQ9JMs3osvvhggLCxXXhRCecYZZzB9+nTAz2f48OEA\n7LXXXhUc9boxRW4YhpHl5JQiL6w4hWKvhZJLpNDHjBkD+BRgNcWNU4SA/P4qMKQoDZV/jRYEi7YL\nU3JJp06dOOeccwDvk4wzUuSFy/CCbzCh1P1s2OcoK9GIpDg09l0XUtatWrUCYNKkSUDxomxbb701\n4Pd5on+XzmMoa0dlkfVdq1xHec/9aH7HuHHjQpWvtat9LPnjk20Rx+dqZRiGYVSInFLkNWrUCNNr\ndceTepN/WXdP/V7PKyNNLbkuuOACILPKXHd1pT3rZxW2V7laFd/X79WiSqU/Bw4cCMCiRYvC99Jr\n4mR5RIlaFpqfLJE4KnFZDUr7Voq6lKqUWTTtXs009HdqdaYib3FFx0QNM5RSr+9Be1IqYxyHhsVT\npkwB/LkvZDWUFZVXlhUvH3mLFi1C1T9t2jQAfv3114oPuAzE9yw2DMMwykROKfLBgweH8eLKHJMP\nTo19x40bB/hIEBWYUkaaMsrULi2TxeNVx0LZqlKgiuI47rjjgOKxuh06dCjyPioF+vbbb4d7BIqn\nj3PEh/yL+h7088yZMwGvBktr0pAKFBWlZsqvv/464BXYq6++CvgCTPL3n3322QCceuqpgI8bf/vt\ntwEfb6ws3rhaTDpfFBf+5ptvAn68etx7772B4hZIJtHY1G5Q+QmagzKkS7P4tK8mZS9lfsghh4TN\ntbVmZbGk6njGc5UYhmEYZSanFHm7du1CRRRFceIqDi+FpAgQRUBI/SquderUqYCPXU4nilLRZ2ts\n8jNKOUSz5aLUqlULSNSMkMqQComzIpefUapGY5dvUo+q/pgO5Ac96aSTAB+FIB+ojoGOnfZiGjdu\nDMCAAQMAwuqBqqmi9ajXxfG4yPKbMmVKGKGhBhHRhhIrVqwAfKu7aMu3TKJsUu0/KOZdDaOVIaw8\nhShS4Cpru+OOOwLQvn17IDFnVSYVqpeTqlpPpsgNwzCynJxS5OVBCuKEE04AfMMJ+dClvKTw8/Ly\n0j1E6tSpA8Add9wBeP+9ajVrH6A0v5vaZv31119hPYlsqOj21VdfAV6tSs3Iz6/mBulU5LJ+Pvvs\nsyJj0/e51VZbAdC8eXPAV2ws6ft+4IEHAG9dSMnGMSJH+yqffPIJc+fOBfy8VDN95513BvwegfYS\ndD5JDWcSWQ06RmqRKL9/7969Ae/zVsSR/PzRvSudf7fffjvgjyH47+Wiiy4q8tpkU+F3dc7Vdc69\n55yb7pyb5py7sOD5Gs65Mc65WQWPWyZvuIZhGEaUyijy1cClQRB87pzbFJjsnBsDnAaMDYLgVufc\nFcAVQGzTCOV/lSKSwpIvT1XeMonqI6t+gzqaSN1IqeuuLxSTfNVVVwEJlScfbBx8laWh+hRRv6L8\nzmr8W57GzhVFYxg2bBjgVZciZk4//XTAV85TRERpynrJkiWAX3c6xoqdj4PlpLFJZd9+++2h0lbt\nEM27Zs2aALz33nuAV61PPPEE4NdiJtExUSanxqoMaO1f6DGaOa1jonUoC7Fwjor2pbSGU13LqcKK\nPAiChUEQfF7w/7+Ab4DawFHAsIKXDQM6V3aQhmEYRskkxUfunGsA7AlMALYNgmBhwa9+BipWSqwM\nKBZcsbrl8WPrLjt79mwAZs2aBfi7tXydUiOZRH411UeRX1VKQP0QFdOs6m3y58qfuf3224f+v0xE\n4ZSXkjI4pXyUoadjlI6Ya0VfSI3JYlM0iiydsvq4lfkoZa9Kh9qb2WOPPZIx7KSgGuNLliwJFaYq\nCMrfrO9FfmQhP3QciPaCVb0lRappXSnyqCQ0V11LFO3SunXrcF8rXZm5lV75zrlNgBeBi4Ig+LPw\n74LEDIMS/q6Hc26Sc26SLsSGYRhG+amUInfO/YfERfzpIAheKnh6kXNuuyAIFjrntgMWr+1vgyAY\nAgwByMvLW+vFviR0B1QGo3ab+/XrF8a3Rn2LUlJCfjH1CJQvT4pIVefi4CMXyvrTjU81VlRHWTVV\nRLR+d58+fWjXrl1axpoMZD2oprzqluj4K2swHUpcKk55BarNo8gZKVIpMGVqlubjVocd+fnll1UV\nxKZNm2bcTy4LSGNavnx5OF49So1+9NFHQPHzTRZuHFHU08cffwz49SVLT3NRHSZdO9TFSZE6d911\nFwCNGjVKe7ZxZaJWHPAo8E0QBIWvIK8C3Qv+3x14peLDMwzDMErDRXdky/yHzrUFPgSmAnIk9yfh\nJx8B1AN+BE4IgmDJut4rLy8vUKxmWVCkSZs2bQDv5161alUYt6nKf4pG0Y60fHd6jM5f2ZKqAR7H\nDLsoqhejqBXNSdaFfOjq1pItKG5ZGXPKwJNClTqWIkonWoNSpMrkk/UjH7dqbJSEVJ0q70n9qVrg\nbrvtlvFuThqTInGWLVsW5jgoYkrnr6I0tH+jsSvDM5O1i7KNvLw8Jk2aVKbNlgrr/yAIPgJK+pD2\nFX1fwzAMo3xUWJEnk4oq8kGDBgHw0EMPAYmoDamHaLRJtHuQfJ6K8FBdBfmdsyGqI8rkyZMBr5yk\n8lLdwTvVaE9Aak4VLUeNGgXEMwsyl9C506hRIyARLSYfsM43HQO9VtbgAQccAMCLL74IZOd5lSnK\no8it1ophGEaWk5W1VuR3U1SD4o0ffvjh0Fep6n7RjkDqGNS1a9ci76GKgtms7lLVoTvTyLJIdZcV\nY+0oKujqq68GEn03Vd9fsdZS6Irauffee4v8bEo8tZgiNwzDyHKy0ke+LlQDQ5ENce2wYhiGsS7M\nR24YhrEekZU+8nWh3XLDMIz1BVPkhmEYWY5dyA3DMLKcnHOtGIaxdtQMIhdCAZXw55zL6pDhZGGK\n3DAMI8sxRW4Y6wm5oMSFhRUXxb4NwzCMLMcu5IZhGFmOXcgNwzCyHPORZzEqrzB+/HjAt6pq27Yt\n4Mu9GoaR25giNwzDyHJMkWchiqG99tprAV8y9I8//gCgZs2agG9Xp6YZ2YIsjZLig6OF3pYsSXQS\nfPXVVwF49tlnAejZsyfg2/dZpIORaZYvXw74ZtXJwla2YRhGlpNzZWyTxfHHHw/ARx99BPhmsl9/\n/TUADRo0yMi4wCvP7t27Az5jT2221Optu+22A6BatWoAjBgxImysERfy8/NZtGgRAPfccw/gv2s1\nK5gzZw7gGxxLqS9YsADwzQ30PQg1ZVaTZn0PyUBjvvvuuwHfbHnjjTcGvOJSMwx9duvWrQE46KCD\nAMJm4bIW9Jgr2YpR60oNX9R0Wr/faaedirwuTui8UpMarc/nn38egPfffx+AiRMnAol1p+Mta1hW\n81ZbbQX468q65mtlbA3DMNYjzEceQc1kN998cwBWrlwJQI0aNQDv48oE8o337dsX8ApUyluNbqV2\nPvnkE8AriBYtWvDDDz8AvrVdppDKufPOO3nssccAr7CjylmvldrdZJNNAH9MpGLVpFkWydtvv73W\n90vGuA8//HAApk+fDvh1I4WpR7UYlPJ65ZVXAH8sVXZZ7ezatGkDwBNPPFFkbnFHavXTTz8FYOjQ\noQBMmTIF8NaUzqfatWsDcPHFFwPQrVs3wB+7OKG5DRs2DIBrrrkGgD///BPwe1JXXXUVADNnzgzX\n9JgxYwB/vJO5FguTHavEMAzDKBFT5BHee+89AJ577jnA30GPOuooABo1apSZgQHjxo0D4McffwRg\nww03BLz/LS8vD/Aq8LLLLgPgqaeeAmDZsmWce+65AKFi0HukmzfeeAPwDX3Bt+dr0aIFAPvssw8A\nZ511FuCbbGvMmfCn6ruVctSYtU5kJdSqVQvwY9XrZdFpT0g/y+f+2muvATB48GAAzjvvvFRNJSlI\nlZ5xxhkAvPvuu0BxS6Ru3boAtGzZEiBs3jxr1iwg8xbi2pD1MGHCBMArcUVJqXbN66+/DsBuu+0G\nJCzlr776CvC5HXov7a0le+2aIjcMw8hyTJEXoBjs888/H/C+UPksdTdWJEU6kb9VUR26u2+66aYA\ntG/fHihe3e7RRx8FfKTN119/zejRowG4+eabAbj++utTOfQS0djy8/NDNXbppZcCcM455wCw2Wab\nAfGMZHjnnXeK/KxoDEXQRKNWtt12W8D7vHVMf//9dwBeeuklAG666SbA5wg0a9aM/fbbLyVzqAzy\nG19wwQWA34/QvC+66CLAH1OdN/p+9PoOHToA8TrG8mfPnTsXgJNPPhnwe02Khnr55ZeL/CyqV68e\n7qHMmDED8OeZ9gKSjSlywzCMLGe9V+S6+/bq1Qvwd+G99toL8MpV8Z+Z4MsvvwTgrbfeArya69y5\nM1BynWmpICmHvfbaK7Q8tAPfo0cPAOrUqZOKoZeIomfAqzuNTaouTiqtNBRJo0dRr169df6d/P7H\nHXccAAMHDgQS+xkA8+fPT+o4k0F+fn5oOSiWWpaGfOXan9Ea1Hm2ePFiAI488kggnsdYfvuOHTsC\n3ieuvA0do5KyM1euXMlDDz0EEFpTJ510EpC6KCRT5IZhGFlOzinymTNnAl7xSfHsscceQHEFMGjQ\nIMCrVkUf3HfffYDfic4kzzzzDODVnSJr5HctDantAQMGcMUVVwBeGSmiRbHp6VJIUmQzZswI/aaK\n2FBWrXyPsjgUCZFLSHkPGDAA8Apcyl6RO3Hiiy++4PHHHwdg1113BeDBBx8EvCUrZGXJl37iiScC\nUL9+/XQMtVzIMrz11lsBHx0ma/yGG24ASlbiWsenn356mEGt6LBU761VWpE756o656Y450YX/NzQ\nOTfBOfedc+4551xqIuANwzAMIAm1VpxzlwB5wGZBEHR0zo0AXgqCYLhz7kHgyyAIHljXeySr1sqi\nRYvYc889AZ/l16VLF8BnyklxqjKgYpSFlMVpp51W5PWZQJEzO+64I+AzORXXWt56L7/99hvNmzcP\n/w8+vlcqP12+8qVLlwKJ2umyDhT5oQxORa3897//BXzm6imnnAJkJoIoWegYyu8qv6xQHPqcOXPC\nWPVM88033wAJa0rx8ZMnTwaKZyxqrSq3QZbFkCFDgHgdO10DVf9EOSOKkf/f//4HwCWXXLLWv5cP\nffvttwcSuQWqvxK1UMpD2mqtOOfqAEcAjxT87IADgRcKXjIM6FyZzzAMwzDWTWVvi3cBlwObFvxc\nE1gaBMHqgp/nAbUr+RmlojoX1113Xag0Vf9A8axCfqzLL7+8yN/usMMOgI8eKEmJSzVGoxNSwYsv\nvggU95tW1IqqWbMmd911F+CjVRSlc8QRRwBeKaY641Ox4++8805YzVGx+oqt1rFSZMQHH3wA+Do4\nitrJBnTMVHtEFp/2cqS6VXPliy++KPJ8HFBs+x9//MGpp54KeGWt+emYaX1JiatKZJyUuFBEzdix\nY4Hi53inTp2KvE7XjJ9++gnwsfDysW+55ZY0bdo0HUMPqbAid851BBYHQTC5gn/fwzk3yTk3SW4Q\nwzAMo/xU5vbYBjjSOXc4sCGwGXA3sIVz7v8KVHkdYK2BsEEQDAGGQMJHXpEB6A6pSIxHHnkk9Csr\nXlPRKBdeeCHga1MrWkBKQnWDS9qRVvU21RxWXGgq0JjOPvtswM9TPmOpNikDRRB8//33ANxyyy0l\nvrciQvQ96TPko9VOvepkp5patWqF6k2P8q+qsqDmIx9mnz59AF/XpF27dmkZa2VQDRKt1dmzZwM+\nO/ewww4DfPRQnKoAaq1ozCtXrgxrEWnNyUeu80PKW/5m1ZTRfOOEziNl60YrU77wQsJTrOqcqhMk\nS1mZ1uKaa65Jew2jCivyIAj6BUFQJwiCBkAX4N0gCE4B3gOOK3hZd+CVSo/SMAzDKJFUOKz6AsOd\nczcCU4BHU/AZgK+3rUpxq1evDpW4fOWKCZWqKAlVNVQ9Ze2uS6HK93fllVcmbfwlMX78+CKfKRSL\nK1eUMs8UOy+1o2zUdUXcqDqb1K98sfreMonixrXjP2LECMBXAlRWqiI+5GNv1qxZWsdZFoYPHw4Q\nVp1UXLXQMVYFvZEjRwKw//77A4lOQqo9I4WY7kgqxe8fe+yxQKLmj9Spso113qlypear/Q7lY6if\nqjokxYGSKloqskrnvJS6iB4H7d1oXaaTpFzIgyB4H3i/4P+zgZbJeF/DMAyjdLKyZ6fUtbI2decE\nr0qV9ahuOdqJFpq31J98x/KFy6cp35/8YLoLpzKaQBE1qukg5F9VlxlVNRTySz7yyCPA2pWB5qEd\neakMqS0pyDjWwNAx0/w1P8XTqxuL1kUmUWyxquBpb0ZEux7puGiOK1asCH+WElf9jq5du6Zy6CWi\nsf3555+hipUSj54PWouKilJPTu3vzJs3r8jfxwGdT0cffTQACxcuBLzVFO3yo+xNWe2KVPnss8+S\ncv5Yz07DMIz1iPgFdZYBZVxFu61vv/32YWamFEPPnj0BH6Wi55XRKOVdWpW6VPXaK4x2z5VlKQWg\n+akWiTLsRNRKUCZolCAIwnrrem/5nRVfHmc0T0VC7L333oBXu7JgVBMjkzHYiqhR7PX9998PFO+o\no7noGCt6SH7/QYMGhWtXFQeV2Zpuq0mfJ19wWdB5tvvuuwNe5Wr9xUmRS1HLstM5oX0AZam2bt0a\n8HkNygXQ32fCmo3Pt2gYhmFUiKxU5Npd7t27N+ArsJ1++umhCpMPMrrTrIxC+eTj1CtQEQ3y0wv5\nUeXHlj/122+/LfI6VWlTPKyiPmRNdO/ePcySVIRH1A+fDUjxSHkrG1cRH8pSVY2WTKL8BD2WhmoF\nqVpn/fr1Q6tSfT3VdaZx48ZJHWsqkF9dnbZUgySOezDR/qLKCpf1JCtLin3UqFGAv9a0bds2fYON\nYIrcMAwjy8lKRS5US3xtyN+smGtlWqmHYJyUuJDyVs0GoYxOKQMpUMWRKyJHCi0avaL6KaNGjQr3\nAuTfi5OPsrzIElPVOWUZPvBAothmHBR5RZE67NixY3g8FfNfOEor7kiRq3aMzrs4rzuNWdcQIWt/\n2rRpRX4vi7dVq1bpGmIxsvpCvjZ0EVQCgtwQSqq4+OKLMzOwMqAws5YtE2H448aNA/zNSGGJWjg6\n2WXaKTFIqexCC6569eoMHToU8DeHTFE4zK6i6czadJOrTd9HHNPAy4s2BQ899NAw/E2F3UrazI4j\nmsecOXMA3yg8jq4VIXesQpgVoqxQZgUj6LySgCpvWelkEt/bomEYhlEmck6RK2lCKlblbFUcPk5l\nQaNIpSiNWWUD5DpRso7MUikHqVsloehnvZ8U77nnnsu+++6b2kmUESXzrFixImxlV95Wbpq/EjKk\nkORqiQOylkqbm8auUDYV0frhhx/C4y2XmtZ0NqCCU7/++itQephvJtD50r9/fwCOOeYYwIcTKmRU\npUAUZCDLTyHPco1mAlPkhmEYWU5OKfK///47vDtKxd52221A6hslJBP55hReJ6WgUqBSolLc0TIL\nUnDaWLr++uuBRCJJXBoYK6lpzpw5YfGz0jYntcmn8Du9h1rFqU1dSS250olK8J588smA9+er8JmO\noZ7XJryKUWmuzrmwwNSNN94IpH+jMFreoixNVRRKGw1vjeMelc4fJQBpPWqvSoX0FLKs779Xr16A\nb56RSb+/KXLDMIwsJyuLZpXErFmzwmgVKU8pgzj7xktDylMKoXBBpcJIESgs7+GHHwZ8YlBc1DjA\n6NGjgYSvXL5FReXIj6/C/SrxqobZ8icrmkBNMO68807AJ59kUiGpkYlCQBVNpcgkIXWn0MLo84cc\ncki4Z1JS05N0oXICZ5xxBkceeSRQ/DuWeldhL6W3KyFKSVtxQqU+lPCjqDCdL4oa0nrT/o723VJl\n7VvRLMMwjPWInPKRX3755aFaU0xnHJu9lhcpbCkHEU1YkIqLc7KFkEJr1KhR2ORCfmKh+ekYal61\natUCfOlhKXlFc8QhRlnJIWrDp7noMVoWWWpbBZnU3q5JkybFVHymkEIdOHBguB+hshCTJyda9953\n331Fflb+BoRDAAAgAElEQVRJYVlTcaYk60iKW3sv2rOKk5Uf/zPeMAzDWCc55SPfZ599QiVw7733\nAn5n2Ygna9asYcqUKYD3K6vJr6Ju1OhaGZwqTaCY5Dj5/oXOK8WFq5yEUtVlVSiKpUmTJoCfcxzn\npHj9E044IfSFK8Za+zbao1JRtgEDBgDxaPZRGmrvqNLOsvC096IIpHRhPnLDMIz1iJxS5GvWrAl9\nkHHxKxpGrlC41Z4sCWVs1q9fH4Cnn34a8FnJZYk5N9aOKXLDMIz1iOwP6ShE1apVY+lbNIxcQBE2\nnTt3pnPnzhkejVEYU+SGYRhZjl3IDcMwshy7kBuGYWQ5diE3DMPIcuxCbhiGkeXYhdwwDCPLsQu5\nYRhGlmMXcsMwjCynUhdy59wWzrkXnHPfOue+cc7t65yr4Zwb45ybVfC4ZbIGaxiGYRSnsor8buDN\nIAgaA7sD3wBXAGODINgZGFvws2EYa+Hff//l33//Za+99mKvvfaiVq1a1KpVi7///rtYr0zDKIkK\nX8idc5sD7YBHAYIgWBkEwVLgKGBYwcuGAZbLaxiGkUIqU2ulIfALMNQ5tzswGbgQ2DYIgoUFr/kZ\n2LZyQyyOeuipQ4dqQKxatSrs0fnbb78B8PvvvwOEfSFnzZoF+OqIe+yxB+A7sMehu0xFUWd2dTJ5\n4oknABg7diwAe+65Z2YGZhRDlQRV+3rq1KmArxaouuVt27bNwOjWb1RBVZ2C1JtT9cp1bdE15Iwz\nzgB8V6dMVHysjGvl/4AWwANBEOwJLCPiRgkSq3WtdXKdcz2cc5Occ5N++eWXSgzDMAxj/abC9cid\nc7WA8UEQNCj4+b8kLuQ7AfsHQbDQObcd8H4QBLus673KWo9cd8oDDjgA8LWQC3dV0d1w+vTpAKFC\nX758OVC887z6QZ577rkA3HbbbUC8+vGVFc11n332AeCnn34CfGedzz//PCs6tVSWefPmAXDQQQcB\nXikdffTRGRtTFK33du3aAd6aevjhhwHo0qULEI91qLG99957ALRo0SJcUxVl3LhxALz22muAt0zq\n1q1bqfetDDpfPvjgAwD69OkDeAW+Zs0awH8fst6rVasGeOt+5MiRbLfddpUeT1rqkQdB8DPwk3NO\nF+n2wHTgVaB7wXPdgVcq+hmGYRhG6VS2Hvn5wNPOuWrAbOB0EjeHEc65M4EfgRMq+Rkh6nK9ZMkS\nwPcQlN87CILwLinlHX3Ue+jnVatWATB06FAAvv32WwBeffVVwCv2bOC7774DYOHCxBaF9hI0h19/\n/TWnFbnWxWGHHQbAokWLAHj++eeBeCjylStXAnDaaacB3sq8+uqrATjllFMAv07jwOeffw7A8ccf\nD8DOO+/Mp59+CpR/nJr/+eefD/ien9ddd11SxloZBg8eDHhfuCxcKfDoNSQ6d/Webdy4MU8++SQA\nhx9+OJD660il3j0Igi+AvLX8qn1l3tcwDMMoO9kjN/F3wOeeew6ANm3aAH532TlX4l2zadOmALRq\n1QqAbbdNBNMMHz4c8Gr27bffBryfrH377Lknffjhh0Dx/YDmzZsDsNNOO2VmYClGiql3794AfP/9\n94D3t95www2ZGdhamDNnDuD9sZtuuing/bFxUuJC8eyyXmfMmMGKFSsA2Gijjcr1XvKz6z11Xmay\nx672Kx544AHAj03HQl3HNtxwQ8Cr62hE0TvvvBP+/VlnnQX4tdezZ8+UjR8sRd8wDCPrySpFLnbb\nbTfA+8alvApHrcyYMQOAn3/+GUj49cDvNEvFSYFLvepuu/XWW6d2EklEc5F1od11IZ95HNVeYeTj\nvvjiiwEYOHAgADVr1lzn3ylC6d133wX8MZTltuOOOyZ/sBXkzjvvBHw0ygknJLaQMqlIS0O5GIWt\nXfm6y6rI9bfag9KaPO6444DM5G9oTN26dQP8npKsJFkLLVu2BHw0mL6PY489FiC0TvQ+n3zyCUuX\nLgXgkUceAaBHjx5A6uYZ7zPbMAzDKJWsVORCERi6I64Nxbvqbiv1evPNNwPw5ZdfFnm9fv/DDz8A\n3r8cZ6RklVglpaG7v3x8K1eujF0UTn5+fug37dSpE+CP1e677w74TNUo2htRNMpff/0FeCXVqFGj\nFI26/CiC5vXXXwe8Aj/77LMzNqbSkE98bZZeea07rcnHH3+8yHvLqtZ7a62mA1kVJ598MgCtW7cu\n8iifeFlVtHIAWrZsGUbjbL/99skb8DqI11mdArRADj74YADmzp0LeJeLfq8TS5sSSjrKBhYvXgz4\nxIUoW221FQDVq1dP25hKQzffe+65J0zY0XM6mUs7qbU5pYuk3GFyXyhRIw5ce+21gL/Z6mKhJJI4\notDIBQsWAP7im5+fXyyxrjT0+tmzZwPetSTBpOQ+BSGkA53zV111VVLeT+fZxhtvzLJlywCoXbt2\nUt67NMy1YhiGkeXkrCKX0r7vvvsA+OabbwBvtkvtNW7cGIBbb70V8Gnd6TTxKorMt169ehX5Wcj8\n3X///dM6rnUh98eJJ54IwJgxY8JjpfFecUWiZI/CCaMoYaN///6AL1L0wgsvALD33nunYugVQpte\nI0aMALzrbuTIkUC8i7QpwUUblFLVm266aViErqxIcUup6vyKbkwrVT/uG/OF0fei8MNly5aFa3ry\n5MlFXmObnYZhGMZayTlFrmSYrl27AvDRRx8VeV5+PvlPtdkidffVV18BPlxo8803B+KpEOQbL1yi\noDAqJiYVnEmkROUPV6hglSpVwgJD2ghUeGkU+cJvvPHGIu+pEL4WLVoUeb2OdSYLTymxTJZg/fr1\ngcyUOi0r+t4GDRoE+FR1ra86deqUej5E16IsE6Fjp+StYcMSLQwUJqwyC3FEY9c+26WXXgp4Rf7n\nn3+G8y/vhmlFid/VyTAMwygXOaXIFyxYwGWXXQb48pjyVemOqJ1qhR5pZ15hiEoukR9W/udzzjkH\niJeSeumll4Di0SryPyqKo1+/fukd2FpQESGpPB2XPfbYg5tuugkoXkJAqkYWhUL15s+fX+T3KuD0\n7LPPAj7K4qijjgJgl13WWUU5JUi13XXXXYCf75VXXlnk95qb1qGSTd58800gUc423clpCmdVcwuN\nVaxatSp8TmtN81MJggcffBCAzz77DPDRKNESsJq/fq9knDgyZswYoPg61JxkpTjnQotfJUFMkRuG\nYRjrpMKNJZJJWRtLlITUQOvWrcNdYt0ltSt+yCGHAD6dX80HpAKltKUc5dNTbLPU76GHHlrhcSYL\nWRNKGZY1oWMpq0MlNDX2TKBjU69ePcD7FXVcWrVqFUbb6HdK9JFvW7G4UqsqOCWipYnV0u6TTz4B\nMhNPrnlrfWmOarunufbt2xfw/n/NXce4efPmTJgwIU2jTqCytR06dAD89y7+85//0LFjRwA6d060\n5FWij/5W548UuxS39nVkgUipynpS9EocGmpob0Bz1XmmY6RjrLmpXeS3334bzk8JQfrb8lj0aWks\nYRiGYcSDnPCR664/e/bsYkpcad6KpdZuuO6em222GeDvrirsr9fLh6dGAIoQyaQvT4pUpXejVpUU\n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\ndxzHqXD+H+DTZ0YHtS3wAAAAAElFTkSuQmCC\n", "text/plain": [ "" ] }, "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={noise_input: z, is_training:False})\n", " # Rescale values to the original [0, 1] (from tanh -> [-1, 1])\n", " g = (g + 1.) / 2.\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 }