{"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":"# Generative Adverserial Networks\n\nDeep neural networks are used mainly for supervised learning: classification or regression. Generative Adverserial Networks or GANs, however, use neural networks for a very different purpose: Generative modeling\n\nWhile there are many approaches used for generative modeling, a Generative Adverserial Network takes the following approach: \n\n![GAN Flowchart](https://i.imgur.com/6NMdO9u.png)","metadata":{}},{"cell_type":"markdown","source":"## 0.Libraries","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport zipfile\nimport cv2 as cv\nimport matplotlib.pyplot as plt\nimport time\nfrom IPython.display import Image","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:50.641452Z","iopub.execute_input":"2021-07-26T12:10:50.641866Z","iopub.status.idle":"2021-07-26T12:10:50.647906Z","shell.execute_reply.started":"2021-07-26T12:10:50.641820Z","shell.execute_reply":"2021-07-26T12:10:50.646791Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import DataLoader\nfrom torchvision.datasets import ImageFolder\nimport torchvision.transforms as T","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:50.649750Z","iopub.execute_input":"2021-07-26T12:10:50.650183Z","iopub.status.idle":"2021-07-26T12:10:50.669350Z","shell.execute_reply.started":"2021-07-26T12:10:50.650147Z","shell.execute_reply":"2021-07-26T12:10:50.668603Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 1.Image Loader and Transforms","metadata":{}},{"cell_type":"code","source":"image_size = 64\nbatch_size = 128\nstats = (0.5, 0.5, 0.5), (0.5, 0.5, 0.5)","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:50.670885Z","iopub.execute_input":"2021-07-26T12:10:50.671421Z","iopub.status.idle":"2021-07-26T12:10:50.680455Z","shell.execute_reply.started":"2021-07-26T12:10:50.671383Z","shell.execute_reply":"2021-07-26T12:10:50.679477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_ds = ImageFolder(IMG_DIR, transform = T.Compose([\n    T.Resize(image_size),\n    T.CenterCrop(image_size),\n    T.ToTensor(),\n    T.Normalize(*stats)\n]))\n\ntrain_dl = DataLoader(train_ds, batch_size, shuffle = True, num_workers = 3, pin_memory = True)","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:50.682073Z","iopub.execute_input":"2021-07-26T12:10:50.682664Z","iopub.status.idle":"2021-07-26T12:10:51.293314Z","shell.execute_reply.started":"2021-07-26T12:10:50.682621Z","shell.execute_reply":"2021-07-26T12:10:51.292389Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_ds","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:51.294875Z","iopub.execute_input":"2021-07-26T12:10:51.295443Z","iopub.status.idle":"2021-07-26T12:10:51.303832Z","shell.execute_reply.started":"2021-07-26T12:10:51.295404Z","shell.execute_reply":"2021-07-26T12:10:51.303040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2.Show a batch of images","metadata":{}},{"cell_type":"code","source":"import torch\nfrom torchvision.utils import make_grid","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:51.305297Z","iopub.execute_input":"2021-07-26T12:10:51.306002Z","iopub.status.idle":"2021-07-26T12:10:51.312417Z","shell.execute_reply.started":"2021-07-26T12:10:51.305966Z","shell.execute_reply":"2021-07-26T12:10:51.311420Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# denormalize\ndef denormalize(img_tensors):\n    return img_tensors * stats[1][0] + stats[0][0]\n\n# to show the images\ndef show_images(images, n_max = 64):\n    fig, ax = plt.subplots(figsize = (12,8))\n    ax.set_xticks([]); ax.set_yticks([])\n    ax.imshow(make_grid(denormalize(images.detach()[:n_max]), nrow = 8).permute(1,2,0))\n    \ndef show_batch(dl, n_max = 64):\n    for images, _ in dl:\n        show_images(images,n_max)\n        break","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:51.315667Z","iopub.execute_input":"2021-07-26T12:10:51.316231Z","iopub.status.idle":"2021-07-26T12:10:51.325738Z","shell.execute_reply.started":"2021-07-26T12:10:51.316186Z","shell.execute_reply":"2021-07-26T12:10:51.324264Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_batch(train_dl)","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:51.329528Z","iopub.execute_input":"2021-07-26T12:10:51.330983Z","iopub.status.idle":"2021-07-26T12:10:52.475863Z","shell.execute_reply.started":"2021-07-26T12:10:51.330943Z","shell.execute_reply":"2021-07-26T12:10:52.475053Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.Using a GPU","metadata":{}},{"cell_type":"code","source":"def get_default_device():\n    \"\"\"Pick GPU if available, else CPU\"\"\"\n    if torch.cuda.is_available():\n        return torch.device('cuda')\n    else:\n        return torch.device('cpu')\n    \ndef to_device(data, device):\n    \"\"\"Move tensor(s) to chosen device\"\"\"\n    if isinstance(data, (list,tuple)):\n        return [to_device(x, device) for x in data]\n    return data.to(device, non_blocking=True)\n\nclass DeviceDataLoader():\n    \"\"\"Wrap a dataloader to move data to a device\"\"\"\n    def __init__(self, dl, device):\n        self.dl = dl\n        self.device = device\n        \n    def __iter__(self):\n        \"\"\"Yield a batch of data after moving it to device\"\"\"\n        for b in self.dl: \n            yield to_device(b, self.device)\n\n    def __len__(self):\n        \"\"\"Number of batches\"\"\"\n        return len(self.dl)","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:52.477174Z","iopub.execute_input":"2021-07-26T12:10:52.477655Z","iopub.status.idle":"2021-07-26T12:10:52.486534Z","shell.execute_reply.started":"2021-07-26T12:10:52.477612Z","shell.execute_reply":"2021-07-26T12:10:52.485785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = get_default_device()\ndevice","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:52.487773Z","iopub.execute_input":"2021-07-26T12:10:52.488226Z","iopub.status.idle":"2021-07-26T12:10:52.502346Z","shell.execute_reply.started":"2021-07-26T12:10:52.488191Z","shell.execute_reply":"2021-07-26T12:10:52.501288Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dl = DeviceDataLoader(train_dl,device)","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:52.503684Z","iopub.execute_input":"2021-07-26T12:10:52.504101Z","iopub.status.idle":"2021-07-26T12:10:52.511263Z","shell.execute_reply.started":"2021-07-26T12:10:52.504059Z","shell.execute_reply":"2021-07-26T12:10:52.509819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 4.Discriminator Network","metadata":{}},{"cell_type":"markdown","source":"### Discriminator Network\n\nThe discriminator takes an image as input, and tries to classify it as \"real\" or \"generated\". In this sense, it's like any other neural network. We'll use a convolutional neural networks (CNN) which outputs a single number output for every image. We'll use stride of 2 to progressively reduce the size of the output feature map.\n\n![](https://github.com/vdumoulin/conv_arithmetic/raw/master/gif/padding_strides_odd.gif)","metadata":{}},{"cell_type":"code","source":"import torch.nn as nn\nimport torch.nn.functional as F","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:52.512660Z","iopub.execute_input":"2021-07-26T12:10:52.513106Z","iopub.status.idle":"2021-07-26T12:10:52.520844Z","shell.execute_reply.started":"2021-07-26T12:10:52.513069Z","shell.execute_reply":"2021-07-26T12:10:52.519986Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"discriminator = nn.Sequential(\n    # in 3*64*64\n    nn.Conv2d(3,64, kernel_size = 4, stride = 2, padding = 1, bias = False),\n    nn.BatchNorm2d(64),\n    nn.LeakyReLU(0.2, inplace=True),\n    # out 64*32*32\n    \n    nn.Conv2d(64,128, kernel_size = 4, stride = 2, padding = 1, bias = False),\n    nn.BatchNorm2d(128),\n    nn.LeakyReLU(0.2, inplace=True),\n    # out 128*16*16\n    \n    nn.Conv2d(128,256, kernel_size = 4, stride = 2, padding = 1, bias = False),\n    nn.BatchNorm2d(256),\n    nn.LeakyReLU(0.2, inplace=True),\n    # out 256*8*8\n    \n    nn.Conv2d(256,512, kernel_size = 4, stride = 2, padding = 1, bias = False),\n    nn.BatchNorm2d(512),\n    nn.LeakyReLU(0.2, inplace=True),\n    # out 512*4*4\n    \n    nn.Conv2d(512, 1, kernel_size = 4, stride = 1, padding = 0, bias = False),\n    # 1*1*1\n    \n    nn.Flatten(),\n    nn.Sigmoid()\n)\n\ndiscriminator","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:52.521776Z","iopub.execute_input":"2021-07-26T12:10:52.523791Z","iopub.status.idle":"2021-07-26T12:10:52.559492Z","shell.execute_reply.started":"2021-07-26T12:10:52.523747Z","shell.execute_reply":"2021-07-26T12:10:52.558449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"discriminator = to_device(discriminator, device)","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:52.560902Z","iopub.execute_input":"2021-07-26T12:10:52.561297Z","iopub.status.idle":"2021-07-26T12:10:52.570296Z","shell.execute_reply.started":"2021-07-26T12:10:52.561257Z","shell.execute_reply":"2021-07-26T12:10:52.569378Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 5.Generator Network","metadata":{}},{"cell_type":"markdown","source":"### Generator Network\n\nThe input to the generator is typically a vector or a matrix of random numbers (referred to as a latent tensor) which is used as a seed for generating an image. The generator will convert a latent tensor of shape `(128, 1, 1)` into an image tensor of shape `3 x 28 x 28`. To achive this, we'll use the `ConvTranspose2d` layer from PyTorch, which is performs to as a *transposed convolution* (also referred to as a *deconvolution*). [Learn more](https://github.com/vdumoulin/conv_arithmetic/blob/master/README.md#transposed-convolution-animations)\n\n![](https://i.imgur.com/DRvK546.gif)","metadata":{}},{"cell_type":"code","source":"latent_size = 128\n\ngenerator = nn.Sequential(\n    # in latent_size*1*1\n    nn.ConvTranspose2d(latent_size, 512, kernel_size = 4, stride = 1, padding = 0, bias = False),\n    nn.BatchNorm2d(512),\n    nn.ReLU(True),\n    # 512*4*4\n    \n    nn.ConvTranspose2d(512, 256, kernel_size = 4, stride = 2, padding = 1, bias = False),\n    nn.BatchNorm2d(256),\n    nn.ReLU(True),\n    # 256*8*8\n    \n    nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1, bias=False),\n    nn.BatchNorm2d(128),\n    nn.ReLU(True),\n    # out: 128 x 16 x 16\n\n    nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1, bias=False),\n    nn.BatchNorm2d(64),\n    nn.ReLU(True),\n    # out: 64 x 32 x 32\n\n    nn.ConvTranspose2d(64, 3, kernel_size=4, stride=2, padding=1, bias=False),\n    nn.Tanh()\n    # out: 3 x 64 x 64\n)\n\ngenerator","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:52.571939Z","iopub.execute_input":"2021-07-26T12:10:52.572297Z","iopub.status.idle":"2021-07-26T12:10:52.610789Z","shell.execute_reply.started":"2021-07-26T12:10:52.572263Z","shell.execute_reply":"2021-07-26T12:10:52.609902Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"xb = torch.randn(batch_size, latent_size, 1, 1) # random latent tensors\nfake_images = generator(xb)\nprint(fake_images.shape)\nshow_images(fake_images)","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:52.611989Z","iopub.execute_input":"2021-07-26T12:10:52.612344Z","iopub.status.idle":"2021-07-26T12:10:53.662848Z","shell.execute_reply.started":"2021-07-26T12:10:52.612309Z","shell.execute_reply":"2021-07-26T12:10:53.661804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"generator = to_device(generator,device)","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:53.664307Z","iopub.execute_input":"2021-07-26T12:10:53.664658Z","iopub.status.idle":"2021-07-26T12:10:53.673762Z","shell.execute_reply.started":"2021-07-26T12:10:53.664621Z","shell.execute_reply":"2021-07-26T12:10:53.672794Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 6.Discriminator Training","metadata":{}},{"cell_type":"code","source":"def train_discriminator(real_images, opt_d):\n    # clear discrimimnator gradients\n    opt_d.zero_grad()\n    \n    # pass real images through discriminator\n    real_preds = discriminator(real_images)\n    real_targets = torch.ones(real_images.size(0), 1, device = device)\n    real_loss = F.binary_cross_entropy(real_preds, real_targets)\n    real_score = torch.mean(real_preds).item()\n    \n    # generate fake images\n    latent = torch.randn(batch_size, latent_size, 1, 1, device = device)\n    fake_images = generator(latent)\n    \n    # passing fake images through discriminator\n    fake_targets = torch.zeros(fake_images.size(0), 1, device = device)\n    fake_preds = discriminator(fake_images)\n    fake_loss = F.binary_cross_entropy(fake_preds,fake_targets)\n    fake_score = torch.mean(fake_preds).item()\n    \n    # update discriminator weights\n    loss = real_loss + fake_loss\n    loss.backward()\n    opt_d.step()\n    \n    return loss.item(), real_score, fake_score","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:53.675437Z","iopub.execute_input":"2021-07-26T12:10:53.675786Z","iopub.status.idle":"2021-07-26T12:10:53.685211Z","shell.execute_reply.started":"2021-07-26T12:10:53.675751Z","shell.execute_reply":"2021-07-26T12:10:53.683933Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 7.Generator Training","metadata":{}},{"cell_type":"code","source":"def train_generator(opt_g):\n    # clear generator gradients\n    opt_g.zero_grad()\n    \n    # generate fake images\n    latent = torch.randn(batch_size, latent_size, 1, 1, device = device)\n    fake_images = generator(latent)\n    \n    # try to fool the discriminator\n    preds = discriminator(fake_images)\n    targets = torch.ones(batch_size, 1, device = device)\n    loss = F.binary_cross_entropy(preds, targets)\n    \n    # update generator weights\n    loss.backward()\n    opt_g.step()\n    \n    return loss.item()","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:53.690026Z","iopub.execute_input":"2021-07-26T12:10:53.690455Z","iopub.status.idle":"2021-07-26T12:10:53.699649Z","shell.execute_reply.started":"2021-07-26T12:10:53.690419Z","shell.execute_reply":"2021-07-26T12:10:53.698569Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"- **Let's create a directory to store generated images.**","metadata":{}},{"cell_type":"code","source":"!mkdir Generated\nsample_dir = \"./Generated\"","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:53.701837Z","iopub.execute_input":"2021-07-26T12:10:53.702248Z","iopub.status.idle":"2021-07-26T12:10:54.417292Z","shell.execute_reply.started":"2021-07-26T12:10:53.702213Z","shell.execute_reply":"2021-07-26T12:10:54.416154Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torchvision.utils import save_image","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:54.420986Z","iopub.execute_input":"2021-07-26T12:10:54.421320Z","iopub.status.idle":"2021-07-26T12:10:54.428044Z","shell.execute_reply.started":"2021-07-26T12:10:54.421285Z","shell.execute_reply":"2021-07-26T12:10:54.427117Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def save_samples(index, latent_tensors, show = True):\n    fake_images = generator(latent_tensors)\n    fake_fname = \"gen-image-{0:0=4d}.jpg\".format(index)\n    save_image(denormalize(fake_images), os.path.join(sample_dir, fake_fname), nrow = 8)\n    print('Saving .. ', fake_fname)\n    \n    if show:\n        fig,ax = plt.subplots(figsize = (8,8))\n        ax.set_xticks([]); ax.set_yticks([])\n        ax.imshow(make_grid(fake_images.cpu().detach(), nrow = 8).permute(1,2,0))","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:54.431412Z","iopub.execute_input":"2021-07-26T12:10:54.431701Z","iopub.status.idle":"2021-07-26T12:10:54.440855Z","shell.execute_reply.started":"2021-07-26T12:10:54.431671Z","shell.execute_reply":"2021-07-26T12:10:54.439959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fixed_latent = torch.randn(64, latent_size, 1,1, device = device)","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:54.443685Z","iopub.execute_input":"2021-07-26T12:10:54.443932Z","iopub.status.idle":"2021-07-26T12:10:54.452417Z","shell.execute_reply.started":"2021-07-26T12:10:54.443909Z","shell.execute_reply":"2021-07-26T12:10:54.451588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"save_samples(0,fixed_latent)","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:54.453546Z","iopub.execute_input":"2021-07-26T12:10:54.453984Z","iopub.status.idle":"2021-07-26T12:10:54.764992Z","shell.execute_reply.started":"2021-07-26T12:10:54.453941Z","shell.execute_reply":"2021-07-26T12:10:54.760229Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 8.Full Training Loop","metadata":{}},{"cell_type":"markdown","source":"\n\n<img src=\"https://i.imgur.com/6NMdO9u.png\" style=\"max-width:420px; margin-bottom:32px\"/>\n\n","metadata":{}},{"cell_type":"code","source":"from tqdm.notebook import tqdm\nimport torch.nn.functional as F","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:54.766507Z","iopub.execute_input":"2021-07-26T12:10:54.767028Z","iopub.status.idle":"2021-07-26T12:10:54.771727Z","shell.execute_reply.started":"2021-07-26T12:10:54.766988Z","shell.execute_reply":"2021-07-26T12:10:54.770545Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def fit(epochs, lr, start_index = 1):\n    torch.cuda.empty_cache()\n    \n    # losses and scores\n    losses_g = []\n    losses_d = []\n    real_scores = []\n    fake_scores = []\n    \n    # create optimizers\n    opt_d = torch.optim.Adam(discriminator.parameters(), lr = lr, betas = (0.5, 0.999))\n    opt_g = torch.optim.Adam(generator.parameters(), lr = lr, betas = (0.5, 0.999))\n    \n    for epoch in range(epochs):\n        for real_images, _ in tqdm(train_dl):\n            \n            # train discriminator\n            loss_d, real_score, fake_score = train_discriminator(real_images, opt_d)\n            \n            # train generator\n            loss_g = train_generator(opt_g)\n            \n        # record losses and scores\n        losses_g.append(loss_g)\n        losses_d.append(loss_d)\n        real_scores.append(real_score)\n        fake_scores.append(fake_score)\n        \n        # log losses and score (last batch)\n        print(f\"Epoch [{epoch+1}/{epochs}], loss_g : {loss_g:.4f}, loss_d : {loss_d:.4f}, real_score : {real_score:.4f}, fake_score : {fake_score:.4f}\")\n        \n        # save generated images\n        save_samples(epoch+start_index, fixed_latent, show = False)\n        \n    return losses_g, losses_d, real_scores, fake_scores","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:54.773176Z","iopub.execute_input":"2021-07-26T12:10:54.773755Z","iopub.status.idle":"2021-07-26T12:10:54.785341Z","shell.execute_reply.started":"2021-07-26T12:10:54.773612Z","shell.execute_reply":"2021-07-26T12:10:54.784300Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Train the model.**","metadata":{}},{"cell_type":"code","source":"lr = 0.0002\nepochs = 25","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:54.786862Z","iopub.execute_input":"2021-07-26T12:10:54.787620Z","iopub.status.idle":"2021-07-26T12:10:54.793813Z","shell.execute_reply.started":"2021-07-26T12:10:54.787582Z","shell.execute_reply":"2021-07-26T12:10:54.793054Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"start = time.time()\n\nhistory = fit(epochs, lr)\n\nend = time.time()\n\nprint(f\"Finished in {(end-start):.4f} seconds.\")","metadata":{"execution":{"iopub.status.busy":"2021-07-26T12:10:54.795266Z","iopub.execute_input":"2021-07-26T12:10:54.795636Z","iopub.status.idle":"2021-07-26T13:23:32.794581Z","shell.execute_reply.started":"2021-07-26T12:10:54.795601Z","shell.execute_reply":"2021-07-26T13:23:32.793399Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"losses_g, losses_d, real_scores, fake_scores = history","metadata":{"execution":{"iopub.status.busy":"2021-07-26T13:26:52.064834Z","iopub.execute_input":"2021-07-26T13:26:52.065220Z","iopub.status.idle":"2021-07-26T13:26:52.070784Z","shell.execute_reply.started":"2021-07-26T13:26:52.065183Z","shell.execute_reply":"2021-07-26T13:26:52.069514Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Save the model checkpoints \ntorch.save(generator.state_dict(), 'G.pth')\ntorch.save(discriminator.state_dict(), 'D.pth')","metadata":{"execution":{"iopub.status.busy":"2021-07-26T13:26:54.524636Z","iopub.execute_input":"2021-07-26T13:26:54.524997Z","iopub.status.idle":"2021-07-26T13:26:54.608247Z","shell.execute_reply.started":"2021-07-26T13:26:54.524965Z","shell.execute_reply":"2021-07-26T13:26:54.607283Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 9.Result Visualizations","metadata":{}},{"cell_type":"code","source":"# Image 2\nImage(\"./Generated/gen-image-0002.jpg\")","metadata":{"execution":{"iopub.status.busy":"2021-07-26T13:26:57.082575Z","iopub.execute_input":"2021-07-26T13:26:57.082937Z","iopub.status.idle":"2021-07-26T13:26:57.095098Z","shell.execute_reply.started":"2021-07-26T13:26:57.082904Z","shell.execute_reply":"2021-07-26T13:26:57.093957Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Image 8\nImage(\"./Generated/gen-image-0015.jpg\")","metadata":{"execution":{"iopub.status.busy":"2021-07-26T13:26:58.282950Z","iopub.execute_input":"2021-07-26T13:26:58.283356Z","iopub.status.idle":"2021-07-26T13:26:58.296379Z","shell.execute_reply.started":"2021-07-26T13:26:58.283319Z","shell.execute_reply":"2021-07-26T13:26:58.295401Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Image 20\nImage(\"./Generated/gen-image-0020.jpg\")","metadata":{"execution":{"iopub.status.busy":"2021-07-26T13:26:59.962607Z","iopub.execute_input":"2021-07-26T13:26:59.962933Z","iopub.status.idle":"2021-07-26T13:26:59.973116Z","shell.execute_reply.started":"2021-07-26T13:26:59.962902Z","shell.execute_reply":"2021-07-26T13:26:59.972109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Image 25\nImage(\"./Generated/gen-image-0025.jpg\")\n","metadata":{"execution":{"iopub.status.busy":"2021-07-26T13:27:02.221649Z","iopub.execute_input":"2021-07-26T13:27:02.221970Z","iopub.status.idle":"2021-07-26T13:27:02.230890Z","shell.execute_reply.started":"2021-07-26T13:27:02.221940Z","shell.execute_reply":"2021-07-26T13:27:02.229875Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# saving the progress to a video\n\nvid_fname = 'gans_training.avi'\n\nfiles = [os.path.join(sample_dir, f) for f in os.listdir(sample_dir) if 'gen' in f]\nfiles.sort()\n\nout = cv.VideoWriter(vid_fname,cv.VideoWriter_fourcc(*'MP4V'), 1, (530,530))\n[out.write(cv.imread(fname)) for fname in files]\nout.release()","metadata":{"execution":{"iopub.status.busy":"2021-07-26T13:27:12.144487Z","iopub.execute_input":"2021-07-26T13:27:12.144825Z","iopub.status.idle":"2021-07-26T13:27:12.383591Z","shell.execute_reply.started":"2021-07-26T13:27:12.144794Z","shell.execute_reply":"2021-07-26T13:27:12.382722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(losses_d, '-')\nplt.plot(losses_g, '-')\nplt.xlabel('epoch')\nplt.ylabel('loss')\nplt.legend(['Discriminator', 'Generator'])\nplt.title('Losses');","metadata":{"execution":{"iopub.status.busy":"2021-07-26T13:27:13.883492Z","iopub.execute_input":"2021-07-26T13:27:13.883840Z","iopub.status.idle":"2021-07-26T13:27:14.043430Z","shell.execute_reply.started":"2021-07-26T13:27:13.883809Z","shell.execute_reply":"2021-07-26T13:27:14.042474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(real_scores, '-')\nplt.plot(fake_scores, '-')\nplt.xlabel('epoch')\nplt.ylabel('score')\nplt.legend(['Real', 'Fake'])\nplt.title('Scores');","metadata":{"execution":{"iopub.status.busy":"2021-07-26T13:27:16.784580Z","iopub.execute_input":"2021-07-26T13:27:16.784901Z","iopub.status.idle":"2021-07-26T13:27:16.946993Z","shell.execute_reply.started":"2021-07-26T13:27:16.784869Z","shell.execute_reply":"2021-07-26T13:27:16.945944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### References\n- Gif at https://www.kaggle.com/anshalsingh/gif-gan-anime-face-dataste?select=improvement.gif\n- https://jovian.ai/learn/deep-learning-with-pytorch-zero-to-gans","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}