Deep Convolutional GANs

In this notebook, you'll build a GAN using convolutional layers in the generator and discriminator. This is called a Deep Convolutional GAN, or DCGAN for short. The DCGAN architecture was first explored last year and has seen impressive results in generating new images, you can read the original paper here.

You'll be training DCGAN on the Street View House Numbers (SVHN) dataset. These are color images of house numbers collected from Google street view. SVHN images are in color and much more variable than MNIST.

So, we'll need a deeper and more powerful network. This is accomplished through using convolutional layers in the discriminator and generator. It's also necessary to use batch normalization to get the convolutional networks to train. The only real changes compared to what you saw previously are in the generator and discriminator, otherwise the rest of the implementation is the same.


In [1]:
%matplotlib inline

import pickle as pkl

import matplotlib.pyplot as plt
import numpy as np
from scipy.io import loadmat
import tensorflow as tf

In [2]:
!mkdir data


mkdir: cannot create directory ‘data’: File exists

Getting the data

Here you can download the SVHN dataset. Run the cell above and it'll download to your machine.


In [3]:
from urllib.request import urlretrieve
from os.path import isfile, isdir
from tqdm import tqdm

data_dir = 'data/'

if not isdir(data_dir):
    raise Exception("Data directory doesn't exist!")

class DLProgress(tqdm):
    last_block = 0

    def hook(self, block_num=1, block_size=1, total_size=None):
        self.total = total_size
        self.update((block_num - self.last_block) * block_size)
        self.last_block = block_num

if not isfile(data_dir + "train_32x32.mat"):
    with DLProgress(unit='B', unit_scale=True, miniters=1, desc='SVHN Training Set') as pbar:
        urlretrieve(
            'http://ufldl.stanford.edu/housenumbers/train_32x32.mat',
            data_dir + 'train_32x32.mat',
            pbar.hook)

if not isfile(data_dir + "test_32x32.mat"):
    with DLProgress(unit='B', unit_scale=True, miniters=1, desc='SVHN Testing Set') as pbar:
        urlretrieve(
            'http://ufldl.stanford.edu/housenumbers/test_32x32.mat',
            data_dir + 'test_32x32.mat',
            pbar.hook)


SVHN Training Set: 182MB [00:50, 3.62MB/s]                            
SVHN Testing Set: 64.3MB [00:18, 3.57MB/s]                            

These SVHN files are .mat files typically used with Matlab. However, we can load them in with scipy.io.loadmat which we imported above.


In [4]:
trainset = loadmat(data_dir + 'train_32x32.mat')
testset = loadmat(data_dir + 'test_32x32.mat')

Here I'm showing a small sample of the images. Each of these is 32x32 with 3 color channels (RGB). These are the real images we'll pass to the discriminator and what the generator will eventually fake.


In [5]:
idx = np.random.randint(0, trainset['X'].shape[3], size=36)
fig, axes = plt.subplots(6, 6, sharex=True, sharey=True, figsize=(5,5),)
for ii, ax in zip(idx, axes.flatten()):
    ax.imshow(trainset['X'][:,:,:,ii], aspect='equal')
    ax.xaxis.set_visible(False)
    ax.yaxis.set_visible(False)
plt.subplots_adjust(wspace=0, hspace=0)


Here we need to do a bit of preprocessing and getting the images into a form where we can pass batches to the network. First off, we need to rescale the images to a range of -1 to 1, since the output of our generator is also in that range. We also have a set of test and validation images which could be used if we're trying to identify the numbers in the images.


In [6]:
def scale(x, feature_range=(-1, 1)):
    # scale to (0, 1)
    x = ((x - x.min())/(255 - x.min()))
    
    # scale to feature_range
    min, max = feature_range
    x = x * (max - min) + min
    return x

In [7]:
class Dataset:
    def __init__(self, train, test, val_frac=0.5, shuffle=False, scale_func=None):
        split_idx = int(len(test['y'])*(1 - val_frac))
        self.test_x, self.valid_x = test['X'][:,:,:,:split_idx], test['X'][:,:,:,split_idx:]
        self.test_y, self.valid_y = test['y'][:split_idx], test['y'][split_idx:]
        self.train_x, self.train_y = train['X'], train['y']
        
        self.train_x = np.rollaxis(self.train_x, 3)
        self.valid_x = np.rollaxis(self.valid_x, 3)
        self.test_x = np.rollaxis(self.test_x, 3)
        
        if scale_func is None:
            self.scaler = scale
        else:
            self.scaler = scale_func
        self.shuffle = shuffle
        
    def batches(self, batch_size):
        if self.shuffle:
            idx = np.arange(len(dataset.train_x))
            np.random.shuffle(idx)
            self.train_x = self.train_x[idx]
            self.train_y = self.train_y[idx]
        
        n_batches = len(self.train_y)//batch_size
        for ii in range(0, len(self.train_y), batch_size):
            x = self.train_x[ii:ii+batch_size]
            y = self.train_y[ii:ii+batch_size]
            
            yield self.scaler(x), y

Network Inputs

Here, just creating some placeholders like normal.


In [8]:
def model_inputs(real_dim, z_dim):
    inputs_real = tf.placeholder(tf.float32, (None, *real_dim), name='input_real')
    inputs_z = tf.placeholder(tf.float32, (None, z_dim), name='input_z')
    
    return inputs_real, inputs_z

Generator

Here you'll build the generator network. The input will be our noise vector z as before. Also as before, the output will be a $tanh$ output, but this time with size 32x32 which is the size of our SVHN images.

What's new here is we'll use convolutional layers to create our new images. The first layer is a fully connected layer which is reshaped into a deep and narrow layer, something like 4x4x1024 as in the original DCGAN paper. Then we use batch normalization and a leaky ReLU activation. Next is a transposed convolution where typically you'd halve the depth and double the width and height of the previous layer. Again, we use batch normalization and leaky ReLU. For each of these layers, the general scheme is convolution > batch norm > leaky ReLU.

You keep stacking layers up like this until you get the final transposed convolution layer with shape 32x32x3. Below is the archicture used in the original DCGAN paper:

Note that the final layer here is 64x64x3, while for our SVHN dataset, we only want it to be 32x32x3.

Exercise: Build the transposed convolutional network for the generator in the function below. Be sure to use leaky ReLUs on all the layers except for the last tanh layer, as well as batch normalization on all the transposed convolutional layers except the last one.


In [ ]:
def generator(z, output_dim, reuse=False, alpha=0.2, training=True):
    with tf.variable_scope('generator', reuse=reuse):
        # First fully connected layer
        x1 = tf.layers.dense(z, 4*4*512)
        x1 = tf.reshape(x1, (-1, 4, 4, 512))
        x1 = tf.layers.batch_normalization(x1, training=training)
        x1 = tf.maximum(x1, x1 * alpha)
        
        x2 = tf.layers.conv2d_transpose(x1, 256, 5, strides=2, padding='same')
        x2 = tf.layers.batch_normalization(x2, training=training)
        x2 = tf.maximum(x2, x2 * alpha)
        
        x3 = tf.layers.conv2d_transpose(x2, 128, 5, strides=2, padding='same')
        x3 = tf.layers.batch_normalization(x3, training=training)
        x3 = tf.maximum(x3, x3 * alpha)
        
        
        # Output layer, 32x32x3
        logits = tf.layers.conv2d_transpose(x3, 3, 5, strides=2, padding='same')
        
        out = tf.tanh(logits)
        
        return out

Discriminator

Here you'll build the discriminator. This is basically just a convolutional classifier like you've built before. The input to the discriminator are 32x32x3 tensors/images. You'll want a few convolutional layers, then a fully connected layer for the output. As before, we want a sigmoid output, and you'll need to return the logits as well. For the depths of the convolutional layers I suggest starting with 16, 32, 64 filters in the first layer, then double the depth as you add layers. Note that in the DCGAN paper, they did all the downsampling using only strided convolutional layers with no maxpool layers.

You'll also want to use batch normalization with tf.layers.batch_normalization on each layer except the first convolutional and output layers. Again, each layer should look something like convolution > batch norm > leaky ReLU.

Note: in this project, your batch normalization layers will always use batch statistics. (That is, always set training to True.) That's because we are only interested in using the discriminator to help train the generator. However, if you wanted to use the discriminator for inference later, then you would need to set the training parameter appropriately.

Exercise: Build the convolutional network for the discriminator. The input is a 32x32x3 images, the output is a sigmoid plus the logits. Again, use Leaky ReLU activations and batch normalization on all the layers except the first.


In [ ]:
def discriminator(x, reuse=False, alpha=0.2):
    with tf.variable_scope('discriminator', reuse=reuse):
        # Input layer is 32x32x3
        x = tf.layers.conv2d(x, 64, 5, strides=2, padding='same')
        x = tf.maximum(x, x*alpha)
        
        x = tf.layers.conv2d(x, 128, 5, strides=2, padding='same')
        x = tf.layers.batch_normalization(x, training=True)
        x = tf.maximum(x, x*alpha)
        
        x = tf.layers.conv2d(x, 256, 5, strides=2, padding='same')
        x = tf.layers.batch_normalization(x, training=True)
        x = tf.maximum(x, x*alpha)
        
        flat = tf.reshape(x, (-1, 4*4*256))
        logits = tf.layers.dense(flat, 1)
        out = tf.nn.sigmoid(logits)
        
        return out, logits

Model Loss

Calculating the loss like before, nothing new here.


In [ ]:
def model_loss(input_real, input_z, output_dim, alpha=0.2):
    """
    Get the loss for the discriminator and generator
    :param input_real: Images from the real dataset
    :param input_z: Z input
    :param out_channel_dim: The number of channels in the output image
    :return: A tuple of (discriminator loss, generator loss)
    """
    g_model = generator(input_z, output_dim, alpha=alpha)
    d_model_real, d_logits_real = discriminator(input_real, alpha=alpha)
    d_model_fake, d_logits_fake = discriminator(g_model, reuse=True, alpha=alpha)

    d_loss_real = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(logits=d_logits_real, labels=tf.ones_like(d_model_real)))
    d_loss_fake = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(logits=d_logits_fake, labels=tf.zeros_like(d_model_fake)))
    g_loss = tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(logits=d_logits_fake, labels=tf.ones_like(d_model_fake)))

    d_loss = d_loss_real + d_loss_fake

    return d_loss, g_loss

Optimizers

Not much new here, but notice how the train operations are wrapped in a with tf.control_dependencies block so the batch normalization layers can update their population statistics.


In [ ]:
def model_opt(d_loss, g_loss, learning_rate, beta1):
    """
    Get optimization operations
    :param d_loss: Discriminator loss Tensor
    :param g_loss: Generator loss Tensor
    :param learning_rate: Learning Rate Placeholder
    :param beta1: The exponential decay rate for the 1st moment in the optimizer
    :return: A tuple of (discriminator training operation, generator training operation)
    """
    # Get weights and bias to update
    t_vars = tf.trainable_variables()
    d_vars = [var for var in t_vars if var.name.startswith('discriminator')]
    g_vars = [var for var in t_vars if var.name.startswith('generator')]

    # Optimize
    with tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)):
        d_train_opt = tf.train.AdamOptimizer(learning_rate, beta1=beta1).minimize(d_loss, var_list=d_vars)
        g_train_opt = tf.train.AdamOptimizer(learning_rate, beta1=beta1).minimize(g_loss, var_list=g_vars)

    return d_train_opt, g_train_opt

Building the model

Here we can use the functions we defined about to build the model as a class. This will make it easier to move the network around in our code since the nodes and operations in the graph are packaged in one object.


In [ ]:
class GAN:
    def __init__(self, real_size, z_size, learning_rate, alpha=0.2, beta1=0.5):
        tf.reset_default_graph()
        
        self.input_real, self.input_z = model_inputs(real_size, z_size)
        
        self.d_loss, self.g_loss = model_loss(self.input_real, self.input_z,
                                              real_size[2], alpha=alpha)
        
        self.d_opt, self.g_opt = model_opt(self.d_loss, self.g_loss, learning_rate, beta1)

Here is a function for displaying generated images.


In [ ]:
def view_samples(epoch, samples, nrows, ncols, figsize=(5,5)):
    fig, axes = plt.subplots(figsize=figsize, nrows=nrows, ncols=ncols, 
                             sharey=True, sharex=True)
    for ax, img in zip(axes.flatten(), samples[epoch]):
        ax.axis('off')
        img = ((img - img.min())*255 / (img.max() - img.min())).astype(np.uint8)
        ax.set_adjustable('box-forced')
        im = ax.imshow(img, aspect='equal')
   
    plt.subplots_adjust(wspace=0, hspace=0)
    return fig, axes

And another function we can use to train our network. Notice when we call generator to create the samples to display, we set training to False. That's so the batch normalization layers will use the population statistics rather than the batch statistics. Also notice that we set the net.input_real placeholder when we run the generator's optimizer. The generator doesn't actually use it, but we'd get an error without it because of the tf.control_dependencies block we created in model_opt.


In [ ]:
def train(net, dataset, epochs, batch_size, print_every=10, show_every=100, figsize=(5,5)):
    saver = tf.train.Saver()
    sample_z = np.random.uniform(-1, 1, size=(72, z_size))

    samples, losses = [], []
    steps = 0

    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        for e in range(epochs):
            for x, y in dataset.batches(batch_size):
                steps += 1

                # Sample random noise for G
                batch_z = np.random.uniform(-1, 1, size=(batch_size, z_size))

                # Run optimizers
                _ = sess.run(net.d_opt, feed_dict={net.input_real: x, net.input_z: batch_z})
                _ = sess.run(net.g_opt, feed_dict={net.input_z: batch_z, net.input_real: x})

                if steps % print_every == 0:
                    # At the end of each epoch, get the losses and print them out
                    train_loss_d = net.d_loss.eval({net.input_z: batch_z, net.input_real: x})
                    train_loss_g = net.g_loss.eval({net.input_z: batch_z})

                    print("Epoch {}/{}...".format(e+1, epochs),
                          "Discriminator Loss: {:.4f}...".format(train_loss_d),
                          "Generator Loss: {:.4f}".format(train_loss_g))
                    # Save losses to view after training
                    losses.append((train_loss_d, train_loss_g))

                if steps % show_every == 0:
                    gen_samples = sess.run(
                                   generator(net.input_z, 3, reuse=True, training=False),
                                   feed_dict={net.input_z: sample_z})
                    samples.append(gen_samples)
                    _ = view_samples(-1, samples, 6, 12, figsize=figsize)
                    plt.show()

        saver.save(sess, './checkpoints/generator.ckpt')

    with open('samples.pkl', 'wb') as f:
        pkl.dump(samples, f)
    
    return losses, samples

Hyperparameters

GANs are very sensitive to hyperparameters. A lot of experimentation goes into finding the best hyperparameters such that the generator and discriminator don't overpower each other. Try out your own hyperparameters or read the DCGAN paper to see what worked for them.

Exercise: Find hyperparameters to train this GAN. The values found in the DCGAN paper work well, or you can experiment on your own. In general, you want the discriminator loss to be around 0.3, this means it is correctly classifying images as fake or real about 50% of the time.


In [39]:
real_size = (32,32,3)
z_size = 100
learning_rate = 0.001
batch_size = 64
epochs = 1
alpha = 0.01
beta1 = 0.9

# Create the network
net = GAN(real_size, z_size, learning_rate, alpha=alpha, beta1=beta1)

In [40]:
# Load the data and train the network here
dataset = Dataset(trainset, testset)
losses, samples = train(net, dataset, epochs, batch_size, figsize=(10,5))


Epoch 1/1... Discriminator Loss: 0.2982... Generator Loss: 1.5523
Epoch 1/1... Discriminator Loss: 0.1104... Generator Loss: 4.0053
Epoch 1/1... Discriminator Loss: 0.0406... Generator Loss: 5.3023
Epoch 1/1... Discriminator Loss: 0.0125... Generator Loss: 8.5758
Epoch 1/1... Discriminator Loss: 0.0127... Generator Loss: 4.6429
Epoch 1/1... Discriminator Loss: 0.0247... Generator Loss: 3.8279
Epoch 1/1... Discriminator Loss: 0.0067... Generator Loss: 11.1372
Epoch 1/1... Discriminator Loss: 0.0048... Generator Loss: 5.5092
Epoch 1/1... Discriminator Loss: 0.0017... Generator Loss: 7.0905
Epoch 1/1... Discriminator Loss: 0.0046... Generator Loss: 5.8505
Epoch 1/1... Discriminator Loss: 0.0076... Generator Loss: 5.0754
Epoch 1/1... Discriminator Loss: 0.0027... Generator Loss: 7.2872
Epoch 1/1... Discriminator Loss: 0.0048... Generator Loss: 5.7463
Epoch 1/1... Discriminator Loss: 0.0135... Generator Loss: 4.9390
Epoch 1/1... Discriminator Loss: 0.0024... Generator Loss: 11.5754
Epoch 1/1... Discriminator Loss: 0.0003... Generator Loss: 9.6180
Epoch 1/1... Discriminator Loss: 0.0063... Generator Loss: 6.5446
Epoch 1/1... Discriminator Loss: 0.0045... Generator Loss: 6.6522
Epoch 1/1... Discriminator Loss: 0.0036... Generator Loss: 7.7740
Epoch 1/1... Discriminator Loss: 0.0031... Generator Loss: 6.3806
Epoch 1/1... Discriminator Loss: 0.0060... Generator Loss: 7.6387
Epoch 1/1... Discriminator Loss: 0.0014... Generator Loss: 6.7476
Epoch 1/1... Discriminator Loss: 0.0009... Generator Loss: 7.4511
Epoch 1/1... Discriminator Loss: 0.0092... Generator Loss: 5.6150
Epoch 1/1... Discriminator Loss: 0.0031... Generator Loss: 6.3205
Epoch 1/1... Discriminator Loss: 0.0061... Generator Loss: 6.3022
Epoch 1/1... Discriminator Loss: 0.0050... Generator Loss: 6.7296
Epoch 1/1... Discriminator Loss: 0.0054... Generator Loss: 7.2895
Epoch 1/1... Discriminator Loss: 0.0010... Generator Loss: 7.2702
Epoch 1/1... Discriminator Loss: 0.0011... Generator Loss: 7.0133
Epoch 1/1... Discriminator Loss: 0.0011... Generator Loss: 6.9254
Epoch 1/1... Discriminator Loss: 0.0014... Generator Loss: 7.2540
Epoch 1/1... Discriminator Loss: 0.0011... Generator Loss: 7.6109
Epoch 1/1... Discriminator Loss: 0.0008... Generator Loss: 7.4066
Epoch 1/1... Discriminator Loss: 0.0013... Generator Loss: 7.3502
Epoch 1/1... Discriminator Loss: 0.0007... Generator Loss: 7.5695
Epoch 1/1... Discriminator Loss: 0.0003... Generator Loss: 8.3147
Epoch 1/1... Discriminator Loss: 0.0005... Generator Loss: 7.9194
Epoch 1/1... Discriminator Loss: 0.0004... Generator Loss: 8.3194
Epoch 1/1... Discriminator Loss: 0.0005... Generator Loss: 7.7396
Epoch 1/1... Discriminator Loss: 0.0003... Generator Loss: 8.3414
Epoch 1/1... Discriminator Loss: 0.0002... Generator Loss: 8.5695
Epoch 1/1... Discriminator Loss: 0.0002... Generator Loss: 8.8034
Epoch 1/1... Discriminator Loss: 0.0002... Generator Loss: 8.9500
Epoch 1/1... Discriminator Loss: 0.0002... Generator Loss: 8.7150
Epoch 1/1... Discriminator Loss: 0.0004... Generator Loss: 8.7968
Epoch 1/1... Discriminator Loss: 0.0002... Generator Loss: 9.0867
Epoch 1/1... Discriminator Loss: 0.0001... Generator Loss: 9.3713
Epoch 1/1... Discriminator Loss: 0.0001... Generator Loss: 9.1880
Epoch 1/1... Discriminator Loss: 0.0004... Generator Loss: 8.5923
Epoch 1/1... Discriminator Loss: 0.0005... Generator Loss: 7.6592
Epoch 1/1... Discriminator Loss: 0.0143... Generator Loss: 6.1864
Epoch 1/1... Discriminator Loss: 0.0004... Generator Loss: 23.8861
Epoch 1/1... Discriminator Loss: 0.0007... Generator Loss: 17.2061
Epoch 1/1... Discriminator Loss: 0.0007... Generator Loss: 11.1110
Epoch 1/1... Discriminator Loss: 0.0165... Generator Loss: 4.1642
Epoch 1/1... Discriminator Loss: 0.0222... Generator Loss: 3.9265
Epoch 1/1... Discriminator Loss: 0.0021... Generator Loss: 6.3262
Epoch 1/1... Discriminator Loss: 0.0014... Generator Loss: 6.7859
Epoch 1/1... Discriminator Loss: 0.0335... Generator Loss: 5.8984
Epoch 1/1... Discriminator Loss: 0.1950... Generator Loss: 20.7951
Epoch 1/1... Discriminator Loss: 0.0040... Generator Loss: 8.2681
Epoch 1/1... Discriminator Loss: 0.0674... Generator Loss: 3.0692
Epoch 1/1... Discriminator Loss: 0.0567... Generator Loss: 8.8103
Epoch 1/1... Discriminator Loss: 0.0597... Generator Loss: 5.4601
Epoch 1/1... Discriminator Loss: 0.0010... Generator Loss: 14.0416
Epoch 1/1... Discriminator Loss: 0.0053... Generator Loss: 11.9578
Epoch 1/1... Discriminator Loss: 0.0049... Generator Loss: 12.4953
Epoch 1/1... Discriminator Loss: 0.0023... Generator Loss: 12.1744
Epoch 1/1... Discriminator Loss: 0.0144... Generator Loss: 16.0769
Epoch 1/1... Discriminator Loss: 0.0048... Generator Loss: 10.5079
Epoch 1/1... Discriminator Loss: 0.0010... Generator Loss: 12.1395
Epoch 1/1... Discriminator Loss: 0.0019... Generator Loss: 9.5175
Epoch 1/1... Discriminator Loss: 0.0013... Generator Loss: 8.9957
Epoch 1/1... Discriminator Loss: 0.0176... Generator Loss: 7.7066
Epoch 1/1... Discriminator Loss: 0.0410... Generator Loss: 5.3193
Epoch 1/1... Discriminator Loss: 0.1308... Generator Loss: 3.4376
Epoch 1/1... Discriminator Loss: 0.1005... Generator Loss: 3.8162
Epoch 1/1... Discriminator Loss: 0.1475... Generator Loss: 3.9652
Epoch 1/1... Discriminator Loss: 0.0956... Generator Loss: 6.7458
Epoch 1/1... Discriminator Loss: 0.1815... Generator Loss: 4.6731
Epoch 1/1... Discriminator Loss: 0.1344... Generator Loss: 7.4439
Epoch 1/1... Discriminator Loss: 0.1648... Generator Loss: 7.0635
Epoch 1/1... Discriminator Loss: 0.0763... Generator Loss: 6.1047
Epoch 1/1... Discriminator Loss: 0.1681... Generator Loss: 3.9276
Epoch 1/1... Discriminator Loss: 0.0377... Generator Loss: 4.7887
Epoch 1/1... Discriminator Loss: 0.0197... Generator Loss: 6.1853
Epoch 1/1... Discriminator Loss: 0.1816... Generator Loss: 4.3672
Epoch 1/1... Discriminator Loss: 0.3416... Generator Loss: 4.4897
Epoch 1/1... Discriminator Loss: 0.0702... Generator Loss: 6.3023
Epoch 1/1... Discriminator Loss: 1.0340... Generator Loss: 0.9764
Epoch 1/1... Discriminator Loss: 0.7718... Generator Loss: 9.3758
Epoch 1/1... Discriminator Loss: 0.3182... Generator Loss: 3.2840
Epoch 1/1... Discriminator Loss: 0.0953... Generator Loss: 4.7568
Epoch 1/1... Discriminator Loss: 0.1362... Generator Loss: 3.7196
Epoch 1/1... Discriminator Loss: 0.3839... Generator Loss: 5.1192
Epoch 1/1... Discriminator Loss: 0.5569... Generator Loss: 1.8259
Epoch 1/1... Discriminator Loss: 0.5760... Generator Loss: 8.4335
Epoch 1/1... Discriminator Loss: 0.2929... Generator Loss: 4.9763
Epoch 1/1... Discriminator Loss: 1.0197... Generator Loss: 1.6185
Epoch 1/1... Discriminator Loss: 1.2236... Generator Loss: 8.5159
Epoch 1/1... Discriminator Loss: 0.1233... Generator Loss: 3.7166
Epoch 1/1... Discriminator Loss: 0.4580... Generator Loss: 2.4531
Epoch 1/1... Discriminator Loss: 0.0489... Generator Loss: 5.3334
Epoch 1/1... Discriminator Loss: 0.3048... Generator Loss: 2.4130
Epoch 1/1... Discriminator Loss: 0.2135... Generator Loss: 3.7052
Epoch 1/1... Discriminator Loss: 0.3055... Generator Loss: 8.5598
Epoch 1/1... Discriminator Loss: 0.0824... Generator Loss: 5.3192
Epoch 1/1... Discriminator Loss: 0.0187... Generator Loss: 5.8995
Epoch 1/1... Discriminator Loss: 0.0810... Generator Loss: 3.2267
Epoch 1/1... Discriminator Loss: 0.7397... Generator Loss: 6.1812
Epoch 1/1... Discriminator Loss: 0.2906... Generator Loss: 3.7154
Epoch 1/1... Discriminator Loss: 0.1440... Generator Loss: 2.8008
Epoch 1/1... Discriminator Loss: 0.4342... Generator Loss: 9.4906
---------------------------------------------------------------------------
InvalidArgumentError                      Traceback (most recent call last)
~/miniconda3/envs/dl/lib/python3.6/site-packages/tensorflow/python/client/session.py in _do_call(self, fn, *args)
   1138     try:
-> 1139       return fn(*args)
   1140     except errors.OpError as e:

~/miniconda3/envs/dl/lib/python3.6/site-packages/tensorflow/python/client/session.py in _run_fn(session, feed_dict, fetch_list, target_list, options, run_metadata)
   1120                                  feed_dict, fetch_list, target_list,
-> 1121                                  status, run_metadata)
   1122 

~/miniconda3/envs/dl/lib/python3.6/contextlib.py in __exit__(self, type, value, traceback)
     87             try:
---> 88                 next(self.gen)
     89             except StopIteration:

~/miniconda3/envs/dl/lib/python3.6/site-packages/tensorflow/python/framework/errors_impl.py in raise_exception_on_not_ok_status()
    465           compat.as_text(pywrap_tensorflow.TF_Message(status)),
--> 466           pywrap_tensorflow.TF_GetCode(status))
    467   finally:

InvalidArgumentError: Input to reshape is a tensor with 83968 values, but the requested shape requires a multiple of 4096
	 [[Node: discriminator/Reshape = Reshape[T=DT_FLOAT, Tshape=DT_INT32, _device="/job:localhost/replica:0/task:0/gpu:0"](discriminator/Maximum_2, discriminator/Reshape/shape)]]

During handling of the above exception, another exception occurred:

InvalidArgumentError                      Traceback (most recent call last)
<ipython-input-40-44f7f3b1a182> in <module>()
      1 # Load the data and train the network here
      2 dataset = Dataset(trainset, testset)
----> 3 losses, samples = train(net, dataset, epochs, batch_size, figsize=(10,5))

<ipython-input-38-e173767cd948> in train(net, dataset, epochs, batch_size, print_every, show_every, figsize)
     16 
     17                 # Run optimizers
---> 18                 _ = sess.run(net.d_opt, feed_dict={net.input_real: x, net.input_z: batch_z})
     19                 _ = sess.run(net.g_opt, feed_dict={net.input_z: batch_z, net.input_real: x})
     20 

~/miniconda3/envs/dl/lib/python3.6/site-packages/tensorflow/python/client/session.py in run(self, fetches, feed_dict, options, run_metadata)
    787     try:
    788       result = self._run(None, fetches, feed_dict, options_ptr,
--> 789                          run_metadata_ptr)
    790       if run_metadata:
    791         proto_data = tf_session.TF_GetBuffer(run_metadata_ptr)

~/miniconda3/envs/dl/lib/python3.6/site-packages/tensorflow/python/client/session.py in _run(self, handle, fetches, feed_dict, options, run_metadata)
    995     if final_fetches or final_targets:
    996       results = self._do_run(handle, final_targets, final_fetches,
--> 997                              feed_dict_string, options, run_metadata)
    998     else:
    999       results = []

~/miniconda3/envs/dl/lib/python3.6/site-packages/tensorflow/python/client/session.py in _do_run(self, handle, target_list, fetch_list, feed_dict, options, run_metadata)
   1130     if handle is None:
   1131       return self._do_call(_run_fn, self._session, feed_dict, fetch_list,
-> 1132                            target_list, options, run_metadata)
   1133     else:
   1134       return self._do_call(_prun_fn, self._session, handle, feed_dict,

~/miniconda3/envs/dl/lib/python3.6/site-packages/tensorflow/python/client/session.py in _do_call(self, fn, *args)
   1150         except KeyError:
   1151           pass
-> 1152       raise type(e)(node_def, op, message)
   1153 
   1154   def _extend_graph(self):

InvalidArgumentError: Input to reshape is a tensor with 83968 values, but the requested shape requires a multiple of 4096
	 [[Node: discriminator/Reshape = Reshape[T=DT_FLOAT, Tshape=DT_INT32, _device="/job:localhost/replica:0/task:0/gpu:0"](discriminator/Maximum_2, discriminator/Reshape/shape)]]

Caused by op 'discriminator/Reshape', defined at:
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/ipykernel_launcher.py", line 16, in <module>
    app.launch_new_instance()
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/traitlets/config/application.py", line 658, in launch_instance
    app.start()
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/ipykernel/kernelapp.py", line 477, in start
    ioloop.IOLoop.instance().start()
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/zmq/eventloop/ioloop.py", line 177, in start
    super(ZMQIOLoop, self).start()
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/tornado/ioloop.py", line 888, in start
    handler_func(fd_obj, events)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/tornado/stack_context.py", line 277, in null_wrapper
    return fn(*args, **kwargs)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/zmq/eventloop/zmqstream.py", line 440, in _handle_events
    self._handle_recv()
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/zmq/eventloop/zmqstream.py", line 472, in _handle_recv
    self._run_callback(callback, msg)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/zmq/eventloop/zmqstream.py", line 414, in _run_callback
    callback(*args, **kwargs)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/tornado/stack_context.py", line 277, in null_wrapper
    return fn(*args, **kwargs)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/ipykernel/kernelbase.py", line 283, in dispatcher
    return self.dispatch_shell(stream, msg)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/ipykernel/kernelbase.py", line 235, in dispatch_shell
    handler(stream, idents, msg)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/ipykernel/kernelbase.py", line 399, in execute_request
    user_expressions, allow_stdin)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/ipykernel/ipkernel.py", line 196, in do_execute
    res = shell.run_cell(code, store_history=store_history, silent=silent)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/ipykernel/zmqshell.py", line 533, in run_cell
    return super(ZMQInteractiveShell, self).run_cell(*args, **kwargs)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2698, in run_cell
    interactivity=interactivity, compiler=compiler, result=result)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2802, in run_ast_nodes
    if self.run_code(code, result):
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2862, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-39-73bbab4af074>", line 10, in <module>
    net = GAN(real_size, z_size, learning_rate, alpha=alpha, beta1=beta1)
  File "<ipython-input-36-d0631196b6a9>", line 8, in __init__
    real_size[2], alpha=alpha)
  File "<ipython-input-34-74037dc94ccb>", line 10, in model_loss
    d_model_real, d_logits_real = discriminator(input_real, alpha=alpha)
  File "<ipython-input-33-e9206da4de15>", line 15, in discriminator
    flat = tf.reshape(x, (-1, 4*4*256))
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/tensorflow/python/ops/gen_array_ops.py", line 2451, in reshape
    name=name)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/tensorflow/python/framework/op_def_library.py", line 767, in apply_op
    op_def=op_def)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/tensorflow/python/framework/ops.py", line 2506, in create_op
    original_op=self._default_original_op, op_def=op_def)
  File "/home/moox/miniconda3/envs/dl/lib/python3.6/site-packages/tensorflow/python/framework/ops.py", line 1269, in __init__
    self._traceback = _extract_stack()

InvalidArgumentError (see above for traceback): Input to reshape is a tensor with 83968 values, but the requested shape requires a multiple of 4096
	 [[Node: discriminator/Reshape = Reshape[T=DT_FLOAT, Tshape=DT_INT32, _device="/job:localhost/replica:0/task:0/gpu:0"](discriminator/Maximum_2, discriminator/Reshape/shape)]]

In [ ]:
fig, ax = plt.subplots()
losses = np.array(losses)
plt.plot(losses.T[0], label='Discriminator', alpha=0.5)
plt.plot(losses.T[1], label='Generator', alpha=0.5)
plt.title("Training Losses")
plt.legend()

In [ ]:
_ = view_samples(-1, samples, 6, 12, figsize=(10,5))

In [ ]: