{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Importing Libraries we will need.","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport glob\nfrom PIL import Image\nfrom numpy import expand_dims,zeros,ones\nfrom numpy.random import randn,randint\nfrom sklearn.model_selection import train_test_split\nfrom tensorflow.keras.datasets.mnist import load_data\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input, Dense, Reshape, Flatten, Conv2D, Conv2DTranspose, LeakyReLU, ReLU\nfrom tensorflow.keras.layers import Dropout, Embedding, Concatenate, BatchNormalization\nfrom tensorflow.keras.initializers import RandomNormal","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:07:04.110758Z","iopub.execute_input":"2021-06-28T10:07:04.111119Z","iopub.status.idle":"2021-06-28T10:07:04.587662Z","shell.execute_reply.started":"2021-06-28T10:07:04.111081Z","shell.execute_reply":"2021-06-28T10:07:04.586865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Setting up basic parameters","metadata":{}},{"cell_type":"code","source":"IMAGE_SIZE = (28,28,1)\nBATCH_SIZE = 200\nSTEPS = 500\nEPOCHS = 20\nLATENT_DIM = 100\nN_CLASSES = 10","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:02:13.180715Z","iopub.execute_input":"2021-06-28T10:02:13.181048Z","iopub.status.idle":"2021-06-28T10:02:13.187138Z","shell.execute_reply.started":"2021-06-28T10:02:13.181015Z","shell.execute_reply":"2021-06-28T10:02:13.186179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Fixed Values\n\nHere we are fixing z_vis which is basically a noise vector. At every epoch we will pass this to the generator to see how the generator is improving for the same set of noise. \n\ny_vis is basically a one hot encoded array of out labels (0-9). We will use to see how effective the model is for generating the images of the different labels. ","metadata":{}},{"cell_type":"code","source":"z_vis = tf.random.normal([10, LATENT_DIM])\ny_vis = tf.constant(np.eye(10), dtype='float32')","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:02:33.089916Z","iopub.execute_input":"2021-06-28T10:02:33.090275Z","iopub.status.idle":"2021-06-28T10:02:35.101902Z","shell.execute_reply.started":"2021-06-28T10:02:33.090243Z","shell.execute_reply":"2021-06-28T10:02:35.101044Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loading the Dataset\n\nWe will load the data from the csv and then reshape it into how the images were. ","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv(\"../input/digit-recognizer/train.csv\")\ny = train_df['label']\ntrain_df.drop('label',axis=1,inplace=True)\ntraining_images=train_df.to_numpy()\ntraining_images = training_images.reshape(42000, 28, 28, 1)","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:06:29.263660Z","iopub.execute_input":"2021-06-28T10:06:29.263993Z","iopub.status.idle":"2021-06-28T10:06:31.642760Z","shell.execute_reply.started":"2021-06-28T10:06:29.263960Z","shell.execute_reply":"2021-06-28T10:06:31.641912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We will be splitting the data into train and test sets. We will then be normalizing our training data for better performance. We will also one hot encode the labels which will improve our training process.","metadata":{}},{"cell_type":"code","source":"x_train, x_test, y_train, y_test = train_test_split(training_images,y,test_size=0.2)\nx_train = x_train / 255.0\ny_train = tf.one_hot(y_train, depth=10, dtype='float32')\ndata_iter = iter(tf.data.Dataset.from_tensor_slices((x_train, y_train)).shuffle(4 * BATCH_SIZE).batch(BATCH_SIZE).repeat())","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:08:48.140463Z","iopub.execute_input":"2021-06-28T10:08:48.140791Z","iopub.status.idle":"2021-06-28T10:08:48.916646Z","shell.execute_reply.started":"2021-06-28T10:08:48.140759Z","shell.execute_reply":"2021-06-28T10:08:48.915636Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualize the Data","metadata":{}},{"cell_type":"code","source":"for i in range(25):\n    plt.subplot(5, 5, 1 + i)\n    plt.axis('off')\n    plt.imshow(x_train[i], cmap='gray_r')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:08:50.864428Z","iopub.execute_input":"2021-06-28T10:08:50.864753Z","iopub.status.idle":"2021-06-28T10:08:51.786560Z","shell.execute_reply.started":"2021-06-28T10:08:50.864724Z","shell.execute_reply":"2021-06-28T10:08:51.785620Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Generator\n\nIn a GAN the role of a generator is to  take noise as input and create as realistic image as possible. In a conditional gan we also provide the label alongside the noise to tell the model what type of image it should try to generate.","metadata":{}},{"cell_type":"code","source":"def Generator():\n    z = Input(shape=(LATENT_DIM,), dtype='float32')#input for noize vector\n    y = Input(shape=(10,), dtype='float32')#input for the label\n\n    x = Concatenate()([z, y])\n    x = Dense(7 * 7 * 128)(x)\n    x = Reshape((7, 7, 128))(x)\n\n    x = Conv2DTranspose(128, 5, 2, 'same')(x)\n    x = BatchNormalization()(x)\n    x = LeakyReLU(0.2)(x)\n    \n    x = Conv2DTranspose(64, 5, 2, 'same')(x)\n    x = BatchNormalization()(x)\n    x = LeakyReLU(0.2)(x)\n\n    out = Conv2DTranspose(1,  5, 1, 'same', activation='sigmoid')(x)\n\n    return tf.keras.Model(inputs=[z, y], outputs=out)","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:08:53.309444Z","iopub.execute_input":"2021-06-28T10:08:53.309762Z","iopub.status.idle":"2021-06-28T10:08:53.316762Z","shell.execute_reply.started":"2021-06-28T10:08:53.309732Z","shell.execute_reply":"2021-06-28T10:08:53.315649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Discriminator\n\nIn GANs the role of the discriminator is to differentiate between the real and fake images.","metadata":{}},{"cell_type":"code","source":"def Discriminator():\n    X = Input(shape=(28, 28), dtype='float32')#input for real or fake images\n    Y = Input(shape=(10,), dtype='float32')#input for the label\n\n    y = tf.tile(tf.reshape(Y,[-1, 1, 1, 10]), [1, 28, 28, 1])\n    x = Reshape((28, 28, 1))(X)\n    x = Concatenate()([x, y])\n\n    x = Conv2D(32,  5, 2, 'same')(x)\n\n    x = Conv2D(64,  4, 2, 'same')(x)\n    x = BatchNormalization()(x)\n    x = LeakyReLU(0.2)(x)\n    \n    x = Conv2D(128,  3, 2, 'same')(x)\n    x = BatchNormalization()(x)\n    x = LeakyReLU(0.2)(x)\n    \n    x = Flatten()(x)\n    x = Dense(128)(x)\n    x = BatchNormalization()(x)\n\n    out = Dense(1)(x)\n\n    return tf.keras.Model(inputs=[X, Y], outputs=out)","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:08:54.915930Z","iopub.execute_input":"2021-06-28T10:08:54.916322Z","iopub.status.idle":"2021-06-28T10:08:54.924674Z","shell.execute_reply.started":"2021-06-28T10:08:54.916288Z","shell.execute_reply":"2021-06-28T10:08:54.923625Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"G = Generator()\nD = Discriminator()","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:08:56.472656Z","iopub.execute_input":"2021-06-28T10:08:56.472980Z","iopub.status.idle":"2021-06-28T10:08:56.683640Z","shell.execute_reply.started":"2021-06-28T10:08:56.472948Z","shell.execute_reply":"2021-06-28T10:08:56.682818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Loss Functions\n\nFor the generator the goal is to make as realisitc images as possible. For it the loss is high when discriminates labels its generated images as fake. \n\nFor the discriminator the goal is to label the fake images as fake and real as real. For it loss is high when the generator creates realisitic images and fools the the discriminator.","metadata":{}},{"cell_type":"code","source":"cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits = True)\ndef G_loss(D, x_fake, y):\n    return cross_entropy(tf.ones_like(D([x_fake, y])), D([x_fake, y]))\ndef D_loss(D, x_real, x_fake, y):\n    return cross_entropy(tf.ones_like(D([x_real, y])), D([x_real, y])) + cross_entropy(tf.zeros_like(D([x_fake, y])), D([x_fake, y]))","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:08:57.576942Z","iopub.execute_input":"2021-06-28T10:08:57.577321Z","iopub.status.idle":"2021-06-28T10:08:57.584201Z","shell.execute_reply.started":"2021-06-28T10:08:57.577289Z","shell.execute_reply":"2021-06-28T10:08:57.582167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"G_opt = Adam(2e-4,0.5)\nD_opt = Adam(2e-4,0.5)","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:17:27.414639Z","iopub.execute_input":"2021-06-28T10:17:27.414964Z","iopub.status.idle":"2021-06-28T10:17:27.424286Z","shell.execute_reply.started":"2021-06-28T10:17:27.414929Z","shell.execute_reply":"2021-06-28T10:17:27.423428Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Function to save images at specific epochs","metadata":{}},{"cell_type":"code","source":"def generate_and_save_images(model, epoch, noise,label):\n    predictions = model([noise,label])\n\n    fig = plt.figure(figsize=(8, 2))\n\n    for i in range(predictions.shape[0]):\n        plt.subplot(2, 5, i+1)\n        plt.imshow(model([noise,label])[i,:,:] * 255.0)\n        plt.axis('off')\n    plt.tight_layout()\n    plt.savefig('image_at_epoch_{:04d}.png'.format(epoch))\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:08:59.506759Z","iopub.execute_input":"2021-06-28T10:08:59.507096Z","iopub.status.idle":"2021-06-28T10:08:59.513157Z","shell.execute_reply.started":"2021-06-28T10:08:59.507045Z","shell.execute_reply":"2021-06-28T10:08:59.512233Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Custom Training Loop\n\nreference: https://www.tensorflow.org/tutorials/generative/dcgan","metadata":{}},{"cell_type":"code","source":"for epoch in range(EPOCHS):\n    for step in range(STEPS):\n        z_mb = tf.random.normal([BATCH_SIZE, LATENT_DIM])\n        x_real, y = next(data_iter)\n        with tf.GradientTape() as G_tape, tf.GradientTape() as D_tape:  \n            x_fake = G([z_mb, y])\n            G_loss_curr = G_loss(D, x_fake, y)\n            D_loss_curr = D_loss(D, x_real, x_fake, y)\n\n        G_grad = G_tape.gradient(G_loss_curr, G.trainable_variables)\n        D_grad = D_tape.gradient(D_loss_curr, D.trainable_variables)\n\n        G_opt.apply_gradients(zip(G_grad, G.trainable_variables))\n        D_opt.apply_gradients(zip(D_grad, D.trainable_variables))\n    \n    print('epoch: {}; G_loss: {:.6f}; D_loss: {:.6f}'.format(epoch+1, G_loss_curr, D_loss_curr))\n    generate_and_save_images(G,epoch,z_vis,y_vis)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2021-06-28T10:09:00.483347Z","iopub.execute_input":"2021-06-28T10:09:00.483667Z","iopub.status.idle":"2021-06-28T10:17:21.143980Z","shell.execute_reply.started":"2021-06-28T10:09:00.483636Z","shell.execute_reply":"2021-06-28T10:17:21.141957Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Evaluation\n\nHere we will check the performance of our model by seeing how well it is performing in generating images of each label","metadata":{}},{"cell_type":"code","source":"new_noise = tf.random.normal([100, LATENT_DIM])\nlabels = np.asarray([np.eye(10)[i//10] for i in range(100)])\npred = G([new_noise,labels])\nfor i in range(100):\n    plt.subplot(10, 10, 1 + i)\n    plt.axis('off')\n    plt.imshow(pred[i, :, :], cmap='gray_r')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:18:34.866902Z","iopub.execute_input":"2021-06-28T10:18:34.867271Z","iopub.status.idle":"2021-06-28T10:18:38.484197Z","shell.execute_reply.started":"2021-06-28T10:18:34.867238Z","shell.execute_reply":"2021-06-28T10:18:38.483376Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Save the images generated during training as a gif","metadata":{}},{"cell_type":"code","source":"fp_in = \"./image_*.png\"\nfp_out = \"./MNIST_training.gif\"\n\nimg, *imgs = [Image.open(f) for f in sorted(glob.glob(fp_in))]\nimg.save(fp=fp_out, format='GIF', append_images=imgs,\n         save_all=True, duration=200, loop=0)","metadata":{"execution":{"iopub.status.busy":"2021-06-28T10:19:21.042077Z","iopub.execute_input":"2021-06-28T10:19:21.042405Z","iopub.status.idle":"2021-06-28T10:19:21.107703Z","shell.execute_reply.started":"2021-06-28T10:19:21.042376Z","shell.execute_reply":"2021-06-28T10:19:21.106945Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Save the models for future use","metadata":{}},{"cell_type":"code","source":"G.save('mnist_gen.hdf5')\nD.save('mnist_dis.hdf5')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"If you found this notebook helpful please dont forget to leave an upvote!!!","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}