[
  {
    "path": "README.md",
    "content": "# tensorflow-MNIST-cGAN-cDCGAN\nTensorflow implementation of conditional Generative Adversarial Networks (cGAN) [1] and conditional Deep Convolutional Generative Adversarial Networks (cDCGAN) for MANIST [2] dataset.\n\n* you can download\n  - MNIST dataset: http://yann.lecun.com/exdb/mnist/\n \n ## Implementation details\n* cGAN\n\n![GAN](tensorflow_cGAN.png)\n \n## Resutls\n* Generate using fixed noise (fixed_z_)\n\n<table align='center'>\n<tr align='center'>\n<td> cGAN </td>\n<td> cDCGAN </td>\n</tr>\n<tr>\n<td><img src = 'MNIST_cGAN_results/MNIST_cGAN_generation_animation.gif'>\n<td><img src = 'MNIST_cDCGAN_results/MNIST_cDCGAN_generation_animation.gif'>\n</tr>\n</table>\n\n* MNIST vs Generated images\n\n<table align='center'>\n<tr align='center'>\n<td> MNIST </td>\n<td> cGAN after 100 epochs </td>\n<td> cDCGAN after 30 epochs </td>\n</tr>\n<tr>\n<td><img src = 'MNIST_cGAN_results/raw_MNIST_10.png'>\n<td><img src = 'MNIST_cGAN_results/MNIST_cGAN_100.png'>\n<td><img src = 'MNIST_cDCGAN_results/MNIST_cDCGAN_30.png'>\n</tr>\n</table>\n\n* Training loss\n\n<table align='center'>\n<tr align='center'>\n<td> cGAN </td>\n<td> cDCGAN </td>\n</tr>\n<tr>\n<td><img src = 'MNIST_cGAN_results/MNIST_cGAN_train_hist.png'>\n<td><img src = 'MNIST_cDCGAN_results/MNIST_cDCGAN_train_hist.png'>\n</tr>\n</table>\n\n* Learning time\n    * MNIST cGAN - Avg. per epoch: 3.21 sec; Total 100 epochs: 1800.37 sec\n    * MNIST cDCGAN - Avg. per epoch: 53.07 sec; Total 30 epochs: 2072.29 sec\n\n## Development Environment\n\n* Windows 7\n* GTX1080 ti\n* cuda 8.0\n* Python 3.5.3\n* tensorflow-gpu 1.2.1\n* numpy 1.13.1\n* matplotlib 2.0.2\n* imageio 2.2.0\n\n## Reference\n\n[1] Mirza, Mehdi, and Simon Osindero. \"Conditional generative adversarial nets.\" arXiv preprint arXiv:1411.1784 (2014).\n\n(Full paper: https://arxiv.org/pdf/1411.1784.pdf)\n\n[2] Y. LeCun, L. Bottou, Y. Bengio, and P. Haffner. \"Gradient-based learning applied to document recognition.\" Proceedings of the IEEE, 86(11):2278-2324, November 1998.\n"
  },
  {
    "path": "tensorflow_MNIST_cDCGAN.py",
    "content": "import os, time, itertools, imageio, pickle, random\r\nimport numpy as np\r\nimport matplotlib.pyplot as plt\r\nimport tensorflow as tf\r\nfrom tensorflow.examples.tutorials.mnist import input_data\r\n\r\n# leaky_relu\r\ndef lrelu(X, leak=0.2):\r\n    f1 = 0.5 * (1 + leak)\r\n    f2 = 0.5 * (1 - leak)\r\n    return f1 * X + f2 * tf.abs(X)\r\n\r\n# G(z)\r\ndef generator(x, y_label, isTrain=True, reuse=False):\r\n    with tf.variable_scope('generator', reuse=reuse):\r\n        # initializer\r\n        w_init = tf.truncated_normal_initializer(mean=0.0, stddev=0.02)\r\n        b_init = tf.constant_initializer(0.0)\r\n\r\n        # concat layer\r\n        cat1 = tf.concat([x, y_label], 3)\r\n\r\n        # 1st hidden layer\r\n        deconv1 = tf.layers.conv2d_transpose(cat1, 256, [7, 7], strides=(1, 1), padding='valid', kernel_initializer=w_init, bias_initializer=b_init)\r\n        lrelu1 = lrelu(tf.layers.batch_normalization(deconv1, training=isTrain), 0.2)\r\n\r\n        # 2nd hidden layer\r\n        deconv2 = tf.layers.conv2d_transpose(lrelu1, 128, [5, 5], strides=(2, 2), padding='same', kernel_initializer=w_init, bias_initializer=b_init)\r\n        lrelu2 = lrelu(tf.layers.batch_normalization(deconv2, training=isTrain), 0.2)\r\n\r\n        # output layer\r\n        deconv3 = tf.layers.conv2d_transpose(lrelu2, 1, [5, 5], strides=(2, 2), padding='same', kernel_initializer=w_init, bias_initializer=b_init)\r\n        o = tf.nn.tanh(deconv3)\r\n\r\n        return o\r\n\r\n# D(x)\r\ndef discriminator(x, y_fill, isTrain=True, reuse=False):\r\n    with tf.variable_scope('discriminator', reuse=reuse):\r\n        # initializer\r\n        w_init = tf.truncated_normal_initializer(mean=0.0, stddev=0.02)\r\n        b_init = tf.constant_initializer(0.0)\r\n\r\n        # concat layer\r\n        cat1 = tf.concat([x, y_fill], 3)\r\n\r\n        # 1st hidden layer\r\n        conv1 = tf.layers.conv2d(cat1, 128, [5, 5], strides=(2, 2), padding='same', kernel_initializer=w_init, bias_initializer=b_init)\r\n        lrelu1 = lrelu(conv1, 0.2)\r\n\r\n        # 2nd hidden layer\r\n        conv2 = tf.layers.conv2d(lrelu1, 256, [5, 5], strides=(2, 2), padding='same', kernel_initializer=w_init, bias_initializer=b_init)\r\n        lrelu2 = lrelu(tf.layers.batch_normalization(conv2, training=isTrain), 0.2)\r\n\r\n        # output layer\r\n        conv3 = tf.layers.conv2d(lrelu2, 1, [7, 7], strides=(1, 1), padding='valid', kernel_initializer=w_init)\r\n        o = tf.nn.sigmoid(conv3)\r\n\r\n        return o, conv3\r\n\r\n# preprocess\r\nimg_size = 28\r\nonehot = np.eye(10)\r\ntemp_z_ = np.random.normal(0, 1, (10, 1, 1, 100))\r\nfixed_z_ = temp_z_\r\nfixed_y_ = np.zeros((10, 1))\r\nfor i in range(9):\r\n    fixed_z_ = np.concatenate([fixed_z_, temp_z_], 0)\r\n    temp = np.ones((10, 1)) + i\r\n    fixed_y_ = np.concatenate([fixed_y_, temp], 0)\r\n\r\nfixed_y_ = onehot[fixed_y_.astype(np.int32)].reshape((100, 1, 1, 10))\r\ndef show_result(num_epoch, show = False, save = False, path = 'result.png'):\r\n    test_images = sess.run(G_z, {z: fixed_z_, y_label: fixed_y_, isTrain: False})\r\n\r\n    size_figure_grid = 10\r\n    fig, ax = plt.subplots(size_figure_grid, size_figure_grid, figsize=(5, 5))\r\n    for i, j in itertools.product(range(size_figure_grid), range(size_figure_grid)):\r\n        ax[i, j].get_xaxis().set_visible(False)\r\n        ax[i, j].get_yaxis().set_visible(False)\r\n\r\n    for k in range(10*10):\r\n        i = k // 10\r\n        j = k % 10\r\n        ax[i, j].cla()\r\n        ax[i, j].imshow(np.reshape(test_images[k], (img_size, img_size)), cmap='gray')\r\n\r\n    label = 'Epoch {0}'.format(num_epoch)\r\n    fig.text(0.5, 0.04, label, ha='center')\r\n\r\n    if save:\r\n        plt.savefig(path)\r\n\r\n    if show:\r\n        plt.show()\r\n    else:\r\n        plt.close()\r\n\r\ndef show_train_hist(hist, show = False, save = False, path = 'Train_hist.png'):\r\n    x = range(len(hist['D_losses']))\r\n\r\n    y1 = hist['D_losses']\r\n    y2 = hist['G_losses']\r\n\r\n    plt.plot(x, y1, label='D_loss')\r\n    plt.plot(x, y2, label='G_loss')\r\n\r\n    plt.xlabel('Epoch')\r\n    plt.ylabel('Loss')\r\n\r\n    plt.legend(loc=4)\r\n    plt.grid(True)\r\n    plt.tight_layout()\r\n\r\n    if save:\r\n        plt.savefig(path)\r\n\r\n    if show:\r\n        plt.show()\r\n    else:\r\n        plt.close()\r\n\r\n# training parameters\r\nbatch_size = 100\r\n# lr = 0.0002\r\ntrain_epoch = 30\r\nglobal_step = tf.Variable(0, trainable=False)\r\nlr = tf.train.exponential_decay(0.0002, global_step, 500, 0.95, staircase=True)\r\n# load MNIST\r\nmnist = input_data.read_data_sets(\"MNIST_data/\", one_hot=True, reshape=[])\r\n\r\n# variables : input\r\nx = tf.placeholder(tf.float32, shape=(None, img_size, img_size, 1))\r\nz = tf.placeholder(tf.float32, shape=(None, 1, 1, 100))\r\ny_label = tf.placeholder(tf.float32, shape=(None, 1, 1, 10))\r\ny_fill = tf.placeholder(tf.float32, shape=(None, img_size, img_size, 10))\r\nisTrain = tf.placeholder(dtype=tf.bool)\r\n\r\n# networks : generator\r\nG_z = generator(z, y_label, isTrain)\r\n\r\n# networks : discriminator\r\nD_real, D_real_logits = discriminator(x, y_fill, isTrain)\r\nD_fake, D_fake_logits = discriminator(G_z, y_fill, isTrain, reuse=True)\r\n\r\n# loss for each network\r\nD_loss_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_real_logits, labels=tf.ones([batch_size, 1, 1, 1])))\r\nD_loss_fake = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_fake_logits, labels=tf.zeros([batch_size, 1, 1, 1])))\r\nD_loss = D_loss_real + D_loss_fake\r\nG_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_fake_logits, labels=tf.ones([batch_size, 1, 1, 1])))\r\n\r\n# trainable variables for each network\r\nT_vars = tf.trainable_variables()\r\nD_vars = [var for var in T_vars if var.name.startswith('discriminator')]\r\nG_vars = [var for var in T_vars if var.name.startswith('generator')]\r\n\r\n# optimizer for each network\r\n\r\nwith tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)):\r\n    optim = tf.train.AdamOptimizer(lr, beta1=0.5)\r\n    D_optim = optim.minimize(D_loss, global_step=global_step, var_list=D_vars)\r\n    # D_optim = tf.train.AdamOptimizer(lr, beta1=0.5).minimize(D_loss, var_list=D_vars)\r\n    G_optim = tf.train.AdamOptimizer(lr, beta1=0.5).minimize(G_loss, var_list=G_vars)\r\n\r\n# open session and initialize all variables\r\nsess = tf.InteractiveSession()\r\ntf.global_variables_initializer().run()\r\n\r\n# MNIST resize and normalization\r\n# train_set = tf.image.resize_images(mnist.train.images, [img_size, img_size]).eval()\r\n# train_set = (train_set - 0.5) / 0.5  # normalization; range: -1 ~ 1\r\ntrain_set = (mnist.train.images - 0.5) / 0.5\r\ntrain_label = mnist.train.labels\r\n\r\n# results save folder\r\nroot = 'MNIST_cDCGAN_results/'\r\nmodel = 'MNIST_cDCGAN_'\r\nif not os.path.isdir(root):\r\n    os.mkdir(root)\r\nif not os.path.isdir(root + 'Fixed_results'):\r\n    os.mkdir(root + 'Fixed_results')\r\n\r\ntrain_hist = {}\r\ntrain_hist['D_losses'] = []\r\ntrain_hist['G_losses'] = []\r\ntrain_hist['per_epoch_ptimes'] = []\r\ntrain_hist['total_ptime'] = []\r\n\r\n# training-loop\r\nnp.random.seed(int(time.time()))\r\nprint('training start!')\r\nstart_time = time.time()\r\nfor epoch in range(train_epoch):\r\n    G_losses = []\r\n    D_losses = []\r\n    epoch_start_time = time.time()\r\n    shuffle_idxs = random.sample(range(0, train_set.shape[0]), train_set.shape[0])\r\n    shuffled_set = train_set[shuffle_idxs]\r\n    shuffled_label = train_label[shuffle_idxs]\r\n    for iter in range(shuffled_set.shape[0] // batch_size):\r\n        # update discriminator\r\n        x_ = shuffled_set[iter*batch_size:(iter+1)*batch_size]\r\n        y_label_ = shuffled_label[iter*batch_size:(iter+1)*batch_size].reshape([batch_size, 1, 1, 10])\r\n        y_fill_ = y_label_ * np.ones([batch_size, img_size, img_size, 10])\r\n        z_ = np.random.normal(0, 1, (batch_size, 1, 1, 100))\r\n\r\n        loss_d_, _ = sess.run([D_loss, D_optim], {x: x_, z: z_, y_fill: y_fill_, y_label: y_label_, isTrain: True})\r\n\r\n        # update generator\r\n        z_ = np.random.normal(0, 1, (batch_size, 1, 1, 100))\r\n        y_ = np.random.randint(0, 9, (batch_size, 1))\r\n        y_label_ = onehot[y_.astype(np.int32)].reshape([batch_size, 1, 1, 10])\r\n        y_fill_ = y_label_ * np.ones([batch_size, img_size, img_size, 10])\r\n        loss_g_, _ = sess.run([G_loss, G_optim], {z: z_, x: x_, y_fill: y_fill_, y_label: y_label_, isTrain: True})\r\n\r\n        errD_fake = D_loss_fake.eval({z: z_, y_label: y_label_, y_fill: y_fill_, isTrain: False})\r\n        errD_real = D_loss_real.eval({x: x_, y_label: y_label_, y_fill: y_fill_, isTrain: False})\r\n        errG = G_loss.eval({z: z_, y_label: y_label_, y_fill: y_fill_, isTrain: False})\r\n\r\n        D_losses.append(errD_fake + errD_real)\r\n        G_losses.append(errG)\r\n\r\n    epoch_end_time = time.time()\r\n    per_epoch_ptime = epoch_end_time - epoch_start_time\r\n    print('[%d/%d] - ptime: %.2f loss_d: %.3f, loss_g: %.3f' % ((epoch + 1), train_epoch, per_epoch_ptime, np.mean(D_losses), np.mean(G_losses)))\r\n    fixed_p = root + 'Fixed_results/' + model + str(epoch + 1) + '.png'\r\n    show_result((epoch + 1), save=True, path=fixed_p)\r\n    train_hist['D_losses'].append(np.mean(D_losses))\r\n    train_hist['G_losses'].append(np.mean(G_losses))\r\n    train_hist['per_epoch_ptimes'].append(per_epoch_ptime)\r\n\r\nend_time = time.time()\r\ntotal_ptime = end_time - start_time\r\ntrain_hist['total_ptime'].append(total_ptime)\r\n\r\nprint('Avg per epoch ptime: %.2f, total %d epochs ptime: %.2f' % (np.mean(train_hist['per_epoch_ptimes']), train_epoch, total_ptime))\r\nprint(\"Training finish!... save training results\")\r\nwith open(root + model + 'train_hist.pkl', 'wb') as f:\r\n    pickle.dump(train_hist, f)\r\n\r\nshow_train_hist(train_hist, save=True, path=root + model + 'train_hist.png')\r\n\r\nimages = []\r\nfor e in range(train_epoch):\r\n    img_name = root + 'Fixed_results/' + model + str(e + 1) + '.png'\r\n    images.append(imageio.imread(img_name))\r\nimageio.mimsave(root + model + 'generation_animation.gif', images, fps=5)\r\n\r\nsess.close()"
  },
  {
    "path": "tensorflow_MNIST_cGAN.py",
    "content": "import os, time, itertools, imageio, pickle\r\nimport numpy as np\r\nimport matplotlib.pyplot as plt\r\nimport tensorflow as tf\r\nfrom tensorflow.examples.tutorials.mnist import input_data\r\n\r\n# leaky_relu\r\ndef lrelu(X, leak=0.2):\r\n    f1 = 0.5 * (1 + leak)\r\n    f2 = 0.5 * (1 - leak)\r\n    return f1 * X + f2 * tf.abs(X)\r\n\r\n# G(z)\r\ndef generator(x, y, isTrain=True, reuse=False):\r\n    with tf.variable_scope('generator', reuse=reuse):\r\n        w_init = tf.contrib.layers.xavier_initializer()\r\n\r\n        cat1 = tf.concat([x, y], 1)\r\n\r\n        dense1 = tf.layers.dense(cat1, 128, kernel_initializer=w_init)\r\n        relu1 = tf.nn.relu(dense1)\r\n\r\n        dense2 = tf.layers.dense(relu1, 784, kernel_initializer=w_init)\r\n        o = tf.nn.tanh(dense2)\r\n\r\n        return o\r\n\r\n# D(x)\r\ndef discriminator(x, y, isTrain=True, reuse=False):\r\n    with tf.variable_scope('discriminator', reuse=reuse):\r\n        w_init = tf.contrib.layers.xavier_initializer()\r\n\r\n        cat1 = tf.concat([x, y], 1)\r\n\r\n        dense1 = tf.layers.dense(cat1, 128, kernel_initializer=w_init)\r\n        lrelu1 = lrelu(dense1, 0.2)\r\n\r\n        dense2 = tf.layers.dense(lrelu1, 1, kernel_initializer=w_init)\r\n        o = tf.nn.sigmoid(dense2)\r\n\r\n        return o, dense2\r\n\r\n# label preprocess\r\nonehot = np.eye(10)\r\n\r\ntemp_z_ = np.random.normal(0, 1, (10, 100))\r\nfixed_z_ = temp_z_\r\nfixed_y_ = np.zeros((10, 1))\r\n\r\nfor i in range(9):\r\n    fixed_z_ = np.concatenate([fixed_z_, temp_z_], 0)\r\n    temp = np.ones((10,1)) + i\r\n    fixed_y_ = np.concatenate([fixed_y_, temp], 0)\r\n\r\nfixed_y_ = onehot[fixed_y_.astype(np.int32)].squeeze()\r\ndef show_result(num_epoch, show = False, save = False, path = 'result.png'):\r\n    test_images = sess.run(G_z, {z: fixed_z_, y: fixed_y_, isTrain: False})\r\n\r\n    size_figure_grid = 10\r\n    fig, ax = plt.subplots(size_figure_grid, size_figure_grid, figsize=(5, 5))\r\n    for i, j in itertools.product(range(size_figure_grid), range(size_figure_grid)):\r\n        ax[i, j].get_xaxis().set_visible(False)\r\n        ax[i, j].get_yaxis().set_visible(False)\r\n\r\n    for k in range(size_figure_grid*size_figure_grid):\r\n        i = k // size_figure_grid\r\n        j = k % size_figure_grid\r\n        ax[i, j].cla()\r\n        ax[i, j].imshow(np.reshape(test_images[k], (28, 28)), cmap='gray')\r\n\r\n    label = 'Epoch {0}'.format(num_epoch)\r\n    fig.text(0.5, 0.04, label, ha='center')\r\n\r\n    if save:\r\n        plt.savefig(path)\r\n\r\n    if show:\r\n        plt.show()\r\n    else:\r\n        plt.close()\r\n\r\ndef show_train_hist(hist, show = False, save = False, path = 'Train_hist.png'):\r\n    x = range(len(hist['D_losses']))\r\n\r\n    y1 = hist['D_losses']\r\n    y2 = hist['G_losses']\r\n\r\n    plt.plot(x, y1, label='D_loss')\r\n    plt.plot(x, y2, label='G_loss')\r\n\r\n    plt.xlabel('Epoch')\r\n    plt.ylabel('Loss')\r\n\r\n    plt.legend(loc=4)\r\n    plt.grid(True)\r\n    plt.tight_layout()\r\n\r\n    if save:\r\n        plt.savefig(path)\r\n\r\n    if show:\r\n        plt.show()\r\n    else:\r\n        plt.close()\r\n\r\n# training parameters\r\nbatch_size = 100\r\nlr = 0.0002\r\ntrain_epoch = 100\r\n\r\n# load MNIST\r\nmnist = input_data.read_data_sets(\"MNIST_data/\", one_hot=True)\r\ntrain_set = (mnist.train.images - 0.5) / 0.5  # normalization; range: -1 ~ 1\r\ntrain_label = mnist.train.labels\r\n\r\n# variables : input\r\nx = tf.placeholder(tf.float32, shape=(None, 784))\r\ny = tf.placeholder(tf.float32, shape=(None, 10))\r\nz = tf.placeholder(tf.float32, shape=(None, 100))\r\nisTrain = tf.placeholder(dtype=tf.bool)\r\n\r\n# networks : generator\r\nG_z = generator(z, y, isTrain)\r\n\r\n# networks : discriminator\r\nD_real, D_real_logits = discriminator(x, y, isTrain)\r\nD_fake, D_fake_logits = discriminator(G_z, y, isTrain, reuse=True)\r\n\r\n# loss for each network\r\nD_loss_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_real_logits, labels=tf.ones([batch_size, 1])))\r\nD_loss_fake = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_fake_logits, labels=tf.zeros([batch_size, 1])))\r\nD_loss = D_loss_real + D_loss_fake\r\nG_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_fake_logits, labels=tf.ones([batch_size, 1])))\r\n\r\n# trainable variables for each network\r\nT_vars = tf.trainable_variables()\r\nD_vars = [var for var in T_vars if var.name.startswith('discriminator')]\r\nG_vars = [var for var in T_vars if var.name.startswith('generator')]\r\n\r\n# optimizer for each network\r\nwith tf.control_dependencies(tf.get_collection(tf.GraphKeys.UPDATE_OPS)):\r\n    D_optim = tf.train.AdamOptimizer(lr, beta1=0.5).minimize(D_loss, var_list=D_vars)\r\n    G_optim = tf.train.AdamOptimizer(lr, beta1=0.5).minimize(G_loss, var_list=G_vars)\r\n\r\n# open session and initialize all variables\r\nsess = tf.InteractiveSession()\r\ntf.global_variables_initializer().run()\r\n\r\n# results save folder\r\nroot = 'MNIST_cGAN_results/'\r\nmodel = 'MNIST_cGAN_'\r\nif not os.path.isdir(root):\r\n    os.mkdir(root)\r\nif not os.path.isdir(root + 'Fixed_results'):\r\n    os.mkdir(root + 'Fixed_results')\r\n\r\ntrain_hist = {}\r\ntrain_hist['D_losses'] = []\r\ntrain_hist['G_losses'] = []\r\ntrain_hist['per_epoch_ptimes'] = []\r\ntrain_hist['total_ptime'] = []\r\n\r\n# training-loop\r\nnp.random.seed(int(time.time()))\r\nprint('training start!')\r\nstart_time = time.time()\r\nfor epoch in range(train_epoch):\r\n    G_losses = []\r\n    D_losses = []\r\n    epoch_start_time = time.time()\r\n    for iter in range(len(train_set) // batch_size):\r\n        # update discriminator\r\n        x_ = train_set[iter * batch_size:(iter + 1) * batch_size]\r\n        y_ = train_label[iter * batch_size:(iter + 1) * batch_size]\r\n\r\n        z_ = np.random.normal(0, 1, (batch_size, 100))\r\n\r\n        loss_d_, _ = sess.run([D_loss, D_optim], {x: x_, y: y_, z: z_, isTrain: True})\r\n        D_losses.append(loss_d_)\r\n\r\n        # update generator\r\n        z_ = np.random.normal(0, 1, (batch_size, 100))\r\n        y_ = np.random.randint(0, 9, (batch_size, 1))\r\n        y_ = onehot[y_.astype(np.int32)].squeeze()\r\n        loss_g_, _ = sess.run([G_loss, G_optim], {z: z_, x: x_, y: y_, isTrain: True})\r\n        G_losses.append(loss_g_)\r\n\r\n    epoch_end_time = time.time()\r\n    per_epoch_ptime = epoch_end_time - epoch_start_time\r\n    print('[%d/%d] - ptime: %.2f loss_d: %.3f, loss_g: %.3f' % ((epoch + 1), train_epoch, per_epoch_ptime, np.mean(D_losses), np.mean(G_losses)))\r\n    fixed_p = root + 'Fixed_results/' + model + str(epoch + 1) + '.png'\r\n    show_result((epoch + 1), save=True, path=fixed_p)\r\n    train_hist['D_losses'].append(np.mean(D_losses))\r\n    train_hist['G_losses'].append(np.mean(G_losses))\r\n    train_hist['per_epoch_ptimes'].append(per_epoch_ptime)\r\n\r\nend_time = time.time()\r\ntotal_ptime = end_time - start_time\r\ntrain_hist['total_ptime'].append(total_ptime)\r\n\r\nprint('Avg per epoch ptime: %.2f, total %d epochs ptime: %.2f' % (np.mean(train_hist['per_epoch_ptimes']), train_epoch, total_ptime))\r\nprint(\"Training finish!... save training results\")\r\nwith open(root + model + 'train_hist.pkl', 'wb') as f:\r\n    pickle.dump(train_hist, f)\r\n\r\nshow_train_hist(train_hist, save=True, path=root + model + 'train_hist.png')\r\n\r\nimages = []\r\nfor e in range(train_epoch):\r\n    img_name = root + 'Fixed_results/' + model + str(e + 1) + '.png'\r\n    images.append(imageio.imread(img_name))\r\nimageio.mimsave(root + model + 'generation_animation.gif', images, fps=5)\r\n\r\nsess.close()"
  }
]