{"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":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-10-09T13:25:46.432427Z","iopub.execute_input":"2022-10-09T13:25:46.433334Z","iopub.status.idle":"2022-10-09T13:25:46.463243Z","shell.execute_reply.started":"2022-10-09T13:25:46.433212Z","shell.execute_reply":"2022-10-09T13:25:46.461757Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"# import tensorflow as tf\n# (x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data(path=\"mnist.npz\")\n","metadata":{"execution":{"iopub.status.busy":"2022-10-09T14:30:59.389310Z","iopub.execute_input":"2022-10-09T14:30:59.389701Z","iopub.status.idle":"2022-10-09T14:31:00.021285Z","shell.execute_reply.started":"2022-10-09T14:30:59.389671Z","shell.execute_reply":"2022-10-09T14:31:00.020125Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x_train","metadata":{"execution":{"iopub.status.busy":"2022-10-09T14:37:09.805853Z","iopub.execute_input":"2022-10-09T14:37:09.806841Z","iopub.status.idle":"2022-10-09T14:37:09.815098Z","shell.execute_reply.started":"2022-10-09T14:37:09.806784Z","shell.execute_reply":"2022-10-09T14:37:09.813989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#!/usr/bin/env python\n\n\"\"\"\nFC GAN example below\nReferences from the video: \nhttps://www.thispersondoesnotexist.com/\nhttp://www.wisdom.weizmann.ac.il/~vision/courses/2018_2/Advanced_Topics_in_Computer_Vision/files/DomainTransfer.pdf\n\"\"\"\n\nfrom keras.datasets import mnist\nfrom keras.layers import Input, Dense, Reshape, Flatten\nfrom keras.layers import BatchNormalization\nfrom keras.layers.advanced_activations import LeakyReLU\nfrom keras.models import Sequential, Model\n# from keras.optimizers import Adam\nfrom tensorflow.keras.optimizers import Adam\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n#Define input image dimensions\n#Large images take too much time and resources.\nimg_rows = 28\nimg_cols = 28\nchannels = 1\nimg_shape = (img_rows, img_cols, channels)","metadata":{"execution":{"iopub.status.busy":"2022-10-09T14:31:48.518011Z","iopub.execute_input":"2022-10-09T14:31:48.518418Z","iopub.status.idle":"2022-10-09T14:31:48.525735Z","shell.execute_reply.started":"2022-10-09T14:31:48.518386Z","shell.execute_reply":"2022-10-09T14:31:48.524875Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n##########################################################################\n#Given input of noise (latent) vector, the Generator produces an image.\ndef build_generator():\n\n    noise_shape = (100,) #1D array of size 100 (latent vector / noise)\n\n#Define your generator network \n#Here we are only using Dense layers. But network can be complicated based\n#on the application. For example, you can use VGG for super res. GAN.         \n\n    model = Sequential()\n\n    model.add(Dense(256, input_shape=noise_shape))\n    model.add(LeakyReLU(alpha=0.2))\n    model.add(BatchNormalization(momentum=0.8))\n    model.add(Dense(512))\n    model.add(LeakyReLU(alpha=0.2))\n    model.add(BatchNormalization(momentum=0.8))\n    model.add(Dense(1024))\n    model.add(LeakyReLU(alpha=0.2))\n    model.add(BatchNormalization(momentum=0.8))\n    \n    model.add(Dense(np.prod(img_shape), activation='tanh'))\n    model.add(Reshape(img_shape))\n\n    model.summary()\n\n    noise = Input(shape=noise_shape)\n    img = model(noise)    #Generated image\n\n    return Model(noise, img)\n\n#Alpha — α is a hyperparameter which controls the underlying value to which the\n#function saturates negatives network inputs.\n#Momentum — Speed up the training\n##########################################################################\n\n#Given an input image, the Discriminator outputs the likelihood of the image being real.\n    #Binary classification - true or false (we're calling it validity)\n\ndef build_discriminator():\n\n\n    model = Sequential()\n\n    model.add(Flatten(input_shape=img_shape))\n    model.add(Dense(512))\n    model.add(LeakyReLU(alpha=0.2))\n    model.add(Dense(256))\n    model.add(LeakyReLU(alpha=0.2))\n    model.add(Dense(1, activation='sigmoid'))\n    model.summary()\n\n    img = Input(shape=img_shape)\n    validity = model(img)\n\n    return Model(img, validity)\n#The validity is the Discriminator’s guess of input being real or not.","metadata":{"execution":{"iopub.status.busy":"2022-10-09T14:31:49.791408Z","iopub.execute_input":"2022-10-09T14:31:49.792177Z","iopub.status.idle":"2022-10-09T14:31:49.804286Z","shell.execute_reply.started":"2022-10-09T14:31:49.792133Z","shell.execute_reply":"2022-10-09T14:31:49.803211Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\n\n\n#Now that we have constructed our two models it’s time to pit them against each other.\n#We do this by defining a training function, loading the data set, re-scaling our training\n#images and setting the ground truths. \ndef train(epochs, batch_size=128, save_interval=50):\n\n    # Load the dataset\n#     (X_train, _), (_, _) = mnist.load_data()\n    (X_train, _), (_, _) = tf.keras.datasets.mnist.load_data(path=\"mnist.npz\")\n\n    # Convert to float and Rescale -1 to 1 (Can also do 0 to 1)\n    X_train = (X_train.astype(np.float32) - 127.5) / 127.5\n\n#Add channels dimension. As the input to our gen and discr. has a shape 28x28x1.\n    X_train = np.expand_dims(X_train, axis=3) \n\n    half_batch = int(batch_size / 2)\n\n\n#We then loop through a number of epochs to train our Discriminator by first selecting\n#a random batch of images from our true dataset, generating a set of images from our\n#Generator, feeding both set of images into our Discriminator, and finally setting the\n#loss parameters for both the real and fake images, as well as the combined loss. \n    \n    for epoch in range(epochs):\n\n        # ---------------------\n        #  Train Discriminator\n        # ---------------------\n\n        # Select a random half batch of real images\n        idx = np.random.randint(0, X_train.shape[0], half_batch)\n        imgs = X_train[idx]\n\n \n        noise = np.random.normal(0, 1, (half_batch, 100))\n\n        # Generate a half batch of fake images\n        gen_imgs = generator.predict(noise)\n\n        # Train the discriminator on real and fake images, separately\n        #Research showed that separate training is more effective. \n        d_loss_real = discriminator.train_on_batch(imgs, np.ones((half_batch, 1)))\n        d_loss_fake = discriminator.train_on_batch(gen_imgs, np.zeros((half_batch, 1)))\n    #take average loss from real and fake images. \n    #\n        d_loss = 0.5 * np.add(d_loss_real, d_loss_fake) \n\n#And within the same loop we train our Generator, by setting the input noise and\n#ultimately training the Generator to have the Discriminator label its samples as valid\n#by specifying the gradient loss.\n        # ---------------------\n        #  Train Generator\n        # ---------------------\n#Create noise vectors as input for generator. \n#Create as many noise vectors as defined by the batch size. \n#Based on normal distribution. Output will be of size (batch size, 100)\n        noise = np.random.normal(0, 1, (batch_size, 100)) \n\n        # The generator wants the discriminator to label the generated samples\n        # as valid (ones)\n        #This is where the genrator is trying to trick discriminator into believing\n        #the generated image is true (hence value of 1 for y)\n        valid_y = np.array([1] * batch_size) #Creates an array of all ones of size=batch size\n\n        # Generator is part of combined where it got directly linked with the discriminator\n        # Train the generator with noise as x and 1 as y. \n        # Again, 1 as the output as it is adversarial and if generator did a great\n        #job of folling the discriminator then the output would be 1 (true)\n        g_loss = combined.train_on_batch(noise, valid_y)\n\n\n#Additionally, in order for us to keep track of our training process, we print the\n#progress and save the sample image output depending on the epoch interval specified.  \n# Plot the progress\n        \n        print (\"%d [D loss: %f, acc.: %.2f%%] [G loss: %f]\" % (epoch, d_loss[0], 100*d_loss[1], g_loss))\n\n        # If at save interval => save generated image samples\n        if epoch % save_interval == 0:\n            save_imgs(epoch)\n\n#when the specific sample_interval is hit, we call the\n#sample_image function. Which looks as follows.\n\ndef save_imgs(epoch):\n    r, c = 5, 5\n    noise = np.random.normal(0, 1, (r * c, 100))\n    gen_imgs = generator.predict(noise)\n\n    # Rescale images 0 - 1\n    gen_imgs = 0.5 * gen_imgs + 0.5\n\n    fig, axs = plt.subplots(r, c)\n    cnt = 0\n    for i in range(r):\n        for j in range(c):\n            axs[i,j].imshow(gen_imgs[cnt, :,:,0], cmap='gray')\n            axs[i,j].axis('off')\n            cnt += 1\n#     fig.savefig(\"./kaggle/working/\" % epoch)                                                                                  # this line causing problem\n    plt.close()\n#This function saves our images for us to view\n\n\n##############################################################################\n\n#Let us also define our optimizer for easy use later on.\n#That way if you change your mind, you can change it easily here\noptimizer = Adam(0.0002, 0.5)  #Learning rate and momentum.\n\n# Build and compile the discriminator first. \n#Generator will be trained as part of the combined model, later. \n#pick the loss function and the type of metric to keep track.                 \n#Binary cross entropy as we are doing prediction and it is a better\n#loss function compared to MSE or other. \ndiscriminator = build_discriminator()\ndiscriminator.compile(loss='binary_crossentropy',\n    optimizer=optimizer,\n    metrics=['accuracy'])\n\n#build and compile our Discriminator, pick the loss function\n\n#SInce we are only generating (faking) images, let us not track any metrics.\ngenerator = build_generator()\ngenerator.compile(loss='binary_crossentropy', optimizer=optimizer)\n\n##This builds the Generator and defines the input noise. \n#In a GAN the Generator network takes noise z as an input to produce its images.  \nz = Input(shape=(100,))   #Our random input to the generator\nimg = generator(z)\n\n#This ensures that when we combine our networks we only train the Generator.\n#While generator training we do not want discriminator weights to be adjusted. \n#This Doesn't affect the above descriminator training.     \ndiscriminator.trainable = False  \n\n#This specifies that our Discriminator will take the images generated by our Generator\n#and true dataset and set its output to a parameter called valid, which will indicate\n#whether the input is real or not.  \nvalid = discriminator(img)  #Validity check on the generated image\n\n\n#Here we combined the models and also set our loss function and optimizer. \n#Again, we are only training the generator here. \n#The ultimate goal here is for the Generator to fool the Discriminator.  \n# The combined model  (stacked generator and discriminator) takes\n# noise as input => generates images => determines validity\n\ncombined = Model(z, valid)\ncombined.compile(loss='binary_crossentropy', optimizer=optimizer)\n\n\ntrain(epochs=1000, batch_size=32, save_interval=100)\n\n#Save model for future use to generate fake images\n#Not tested yet... make sure right model is being saved..\n#Compare with GAN4\n\ngenerator.save('generator_model.h5')  #Test the model on GAN4_predict...\n#Change epochs back to 30K\n                \n#Epochs dictate the number of backward and forward propagations, the batch_size\n#indicates the number of training samples per backward/forward propagation, and the\n#sample_interval specifies after how many epochs we call our sample_image function.","metadata":{"execution":{"iopub.status.busy":"2022-10-09T14:45:19.840523Z","iopub.execute_input":"2022-10-09T14:45:19.840989Z","iopub.status.idle":"2022-10-09T14:47:00.297174Z","shell.execute_reply.started":"2022-10-09T14:45:19.840953Z","shell.execute_reply":"2022-10-09T14:47:00.296354Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Predicting from the trained model","metadata":{}},{"cell_type":"code","source":"#FOr single image\n# example of generating an image for a specific point in the latent space\nfrom keras.models import load_model\nfrom numpy import asarray\nfrom matplotlib import pyplot\nfrom numpy.random import randn\n\n# load model\nmodel = load_model('./generator_model.h5')\n\n#To create same image, suppy same vector each time\n# all 0s\n#vector = asarray([[0. for _ in range(100)]])  #Vector of all zeros\n\n#To create random images each time...\nvector = randn(100) #Vector of random numbers (creates a column, need to reshape)\nvector = vector.reshape(1, 100)\n\n# generate image\nX = model.predict(vector)\n\n# plot the result\npyplot.imshow(X[0, :, :, 0], cmap='gray_r')\npyplot.show()","metadata":{"execution":{"iopub.status.busy":"2022-10-09T14:47:34.645711Z","iopub.execute_input":"2022-10-09T14:47:34.646170Z","iopub.status.idle":"2022-10-09T14:47:35.224544Z","shell.execute_reply.started":"2022-10-09T14:47:34.646134Z","shell.execute_reply":"2022-10-09T14:47:35.223488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}