{"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":"# Monet-ifying photos with WGAN in Pytorch","metadata":{}},{"cell_type":"markdown","source":"In this Notebook we will create a WGAN true to the original paper https://arxiv.org/abs/1701.07875 and with improvements from DCGAN and in the next, we'll add some tips and tricks from one of the authors as well as an improvement on the original papers 1-Lipschitz Continuity enforcement with gradient clipping.","metadata":{}},{"cell_type":"code","source":"#importing relevant packages\nimport numpy as np\nimport pandas as pd\nimport torch\nfrom torch import nn\nimport os\nfrom tqdm.auto import tqdm\nfrom torchvision import transforms\nfrom torchvision.utils import make_grid\nfrom torch import flatten\nfrom torch.utils.data import DataLoader, Dataset\nfrom PIL import Image","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-10-23T09:52:33.556438Z","iopub.execute_input":"2021-10-23T09:52:33.557079Z","iopub.status.idle":"2021-10-23T09:52:33.562755Z","shell.execute_reply.started":"2021-10-23T09:52:33.557041Z","shell.execute_reply":"2021-10-23T09:52:33.562042Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#choose gpu\ndevice = 'cuda'","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.564762Z","iopub.execute_input":"2021-10-23T09:52:33.565158Z","iopub.status.idle":"2021-10-23T09:52:33.57366Z","shell.execute_reply.started":"2021-10-23T09:52:33.565114Z","shell.execute_reply":"2021-10-23T09:52:33.573033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"## for TPU\n#!curl https://raw.githubusercontent.com/pytorch/xla/master/contrib/scripts/env-setup.py -o pytorch-xla-env-setup.py\n#!python pytorch-xla-env-setup.py --apt-packages libomp5 libopenblas-dev","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.574669Z","iopub.execute_input":"2021-10-23T09:52:33.575319Z","iopub.status.idle":"2021-10-23T09:52:33.584352Z","shell.execute_reply.started":"2021-10-23T09:52:33.575287Z","shell.execute_reply":"2021-10-23T09:52:33.583696Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_tensor_images(image_tensor, num_images=25, size=(3, 256, 256)):\n    '''\n    Function for visualizing images: Given a tensor of images, number of images, and\n    size per image, plots and prints the images in an uniform grid.\n    '''\n    image_tensor = (image_tensor + 1) / 2\n    image_unflat = image_tensor.detach().cpu()\n    image_grid = make_grid(image_unflat[:num_images], nrow=5)\n    plt.imshow(image_grid.permute(1, 2, 0).squeeze())\n    plt.show()\n\ndef make_grad_hook():\n    '''\n    Function to keep track of gradients for visualization purposes, \n    which fills the grads list when using model.apply(grad_hook).\n    '''\n    grads = []\n    def grad_hook(m):\n        if isinstance(m, nn.Conv2d) or isinstance(m, nn.ConvTranspose2d):\n            grads.append(m.weight.grad)\n    return grads, grad_hook","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.585822Z","iopub.execute_input":"2021-10-23T09:52:33.586343Z","iopub.status.idle":"2021-10-23T09:52:33.594617Z","shell.execute_reply.started":"2021-10-23T09:52:33.586299Z","shell.execute_reply":"2021-10-23T09:52:33.593957Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# *Critic* formerly known as the *Generator*\n","metadata":{}},{"cell_type":"markdown","source":"The critic tries to learn the distribution of Monet Paintings, i.e. given a photo x, it will try to output the most likely monet painting y.\nI.e. it tries to match the two distributions as closely as possible.\n\n![What the generator attempts](https://i.imgur.com/t9zb0Cn.png)\n","metadata":{}},{"cell_type":"code","source":"def get_conv_transpose(in_channels = 3, out_channels = 3, kernel_size = 3, stride = 2, padding = 0):\n    '''\n    Function for returning a block of the generator's neural network\n    given input and output dimensions.\n    Parameters:\n        input_dim: the dimension of the input vector, a scalar\n        output_dim: the dimension of the output vector, a scalar\n    Returns:\n        a generator neural network layer, with a linear transformation \n          followed by a batch normalization and then a relu activation\n    '''\n    return nn.Sequential(\n                nn.ConvTranspose2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding = padding),\n                nn.BatchNorm2d(out_channels),\n                nn.ReLU()\n            )","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.596497Z","iopub.execute_input":"2021-10-23T09:52:33.597173Z","iopub.status.idle":"2021-10-23T09:52:33.60564Z","shell.execute_reply.started":"2021-10-23T09:52:33.597136Z","shell.execute_reply":"2021-10-23T09:52:33.604781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_conv(in_channels = 3, out_channels = 3, kernel_size = 3, stride = 2, padding = 0, activation = True):\n    #use relu unless final\n    if activation:\n    \n        return nn.Sequential(\n                    nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding = padding),\n                    nn.BatchNorm2d(out_channels),\n                    nn.ReLU()\n                )\n    #dcgan suggests a gaussian latent space\n    else:\n        return nn.Sequential(\n                    nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding = padding),\n                    nn.BatchNorm2d(out_channels),\n                )\n        \n","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.607177Z","iopub.execute_input":"2021-10-23T09:52:33.607565Z","iopub.status.idle":"2021-10-23T09:52:33.619328Z","shell.execute_reply.started":"2021-10-23T09:52:33.607534Z","shell.execute_reply":"2021-10-23T09:52:33.618553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Generator(nn.Module):\n    '''\n    Generator Class\n    Values:\n        im_dim: the dimension of the images 256*256 acts as noise vector\n    '''\n    def __init__(self, hidden_dim=32):\n        super(Generator, self).__init__()\n        # Build the CNN\n        self.conv1 = nn.Sequential(\n            get_conv(in_channels = 3, out_channels = hidden_dim, padding = 1),\n            get_conv(in_channels = hidden_dim, out_channels = hidden_dim*2, padding = 0),\n            #leave me gaussian\n            get_conv(in_channels = hidden_dim*2, out_channels = hidden_dim*4, padding = 0, activation = False)\n        )\n        self.gen = nn.Sequential(\n            #in flattened image of dimension 3*(256**2) out 128\n            get_conv_transpose(hidden_dim*4, hidden_dim*2), \n            #in 128 out 256\n            get_conv_transpose(hidden_dim*2, hidden_dim, padding = 0), \n            #in 1024, out flattened image\n            nn.ConvTranspose2d(in_channels = hidden_dim, out_channels = 3, kernel_size = 3, stride = 2, output_padding = 1),\n            nn.Tanh()\n        )\n    def forward(self, image):\n        '''\n        Function for completing a forward pass of the generator: Given a noise tensor (photos), \n        returns generated images.\n        Parameters:\n            noise: a noise tensor with dimensions (n_samples, z_dim)\n        '''\n        image = self.conv1(image)\n        #image = image.view(len(image), 1024, 1, 1)\n        \n        return self.gen(image)\n    ","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.620765Z","iopub.execute_input":"2021-10-23T09:52:33.621145Z","iopub.status.idle":"2021-10-23T09:52:33.631724Z","shell.execute_reply.started":"2021-10-23T09:52:33.621103Z","shell.execute_reply":"2021-10-23T09:52:33.631009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# UNQ_C3 (UNIQUE CELL IDENTIFIER, DO NOT EDIT)\n# GRADED FUNCTION: Discriminator\nclass Critic(nn.Module):\n    '''\n    Discriminator Class\n    Values:\n        im_chan: the number of channels of the output image, a scalar\n              (MNIST is black-and-white, so 1 channel is your default)\n    hidden_dim: the inner dimension, a scalar\n    '''\n    def __init__(self, im_chan=3, hidden_dim=16):\n        super(Critic, self).__init__()\n        self.disc = nn.Sequential(\n            self.make_disc_block(im_chan, hidden_dim),\n            self.make_disc_block(hidden_dim, hidden_dim * 2),\n            self.make_disc_block(hidden_dim * 2, 1, final_layer=True),\n        )\n\n    def make_disc_block(self, input_channels = 3, output_channels = 3, kernel_size=3, stride=2, final_layer=False):\n        '''\n        Function to return a sequence of operations corresponding to a discriminator block of DCGAN, \n        corresponding to a convolution, a batchnorm (except for in the last layer), and an activation.\n        Parameters:\n            input_channels: how many channels the input feature representation has\n            output_channels: how many channels the output feature representation should have\n            kernel_size: the size of each convolutional filter, equivalent to (kernel_size, kernel_size)\n            stride: the stride of the convolution\n            final_layer: a boolean, true if it is the final layer and false otherwise \n                      (affects activation and batchnorm)\n        '''\n        if not final_layer:\n            return nn.Sequential(\n                nn.Conv2d(input_channels, output_channels, kernel_size, stride),\n                nn.BatchNorm2d(output_channels),\n                nn.LeakyReLU(0.2, inplace=True)\n            )\n        else: # Final Layer\n            return nn.Sequential(\n                nn.Conv2d(input_channels, output_channels, kernel_size, stride)\n            )\n\n    def forward(self, image):\n        '''\n        Function for completing a forward pass of the discriminator: Given an image tensor, \n        returns a 1-dimension tensor representing fake/real.\n        Parameters:\n            image: a flattened image tensor with dimension (im_dim)\n        '''\n        disc_pred = self.disc(image)\n        return disc_pred.view(len(disc_pred), -1)","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.633151Z","iopub.execute_input":"2021-10-23T09:52:33.634075Z","iopub.status.idle":"2021-10-23T09:52:33.646496Z","shell.execute_reply.started":"2021-10-23T09:52:33.63403Z","shell.execute_reply":"2021-10-23T09:52:33.645453Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"criterion = nn.BCEWithLogitsLoss()\ndisplay_step = 1500\nbatch_size = 32\n# A learning rate of 0.0002 works well on DCGAN\nlr = 0.00001\nn_epochs = 1000\n\nbeta_1 = 0.5 \nbeta_2 = 0.999","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.647917Z","iopub.execute_input":"2021-10-23T09:52:33.648398Z","iopub.status.idle":"2021-10-23T09:52:33.661585Z","shell.execute_reply.started":"2021-10-23T09:52:33.648358Z","shell.execute_reply":"2021-10-23T09:52:33.660994Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_gradient(crit, real, fake, epsilon):\n    '''\n    Return the gradient of the critic's scores with respect to mixes of real and fake images.\n    Parameters:\n        crit: the critic model\n        real: a batch of real images\n        fake: a batch of fake images\n        epsilon: a vector of the uniformly random proportions of real/fake per mixed image\n    Returns:\n        gradient: the gradient of the critic's scores, with respect to the mixed image\n    '''\n    # Mix the images together\n    mixed_images = real * epsilon + fake * (1 - epsilon)\n\n    # Calculate the critic's scores on the mixed images\n    mixed_scores = crit(mixed_images)\n    \n    # Take the gradient of the scores with respect to the images\n    gradient = torch.autograd.grad(\n\n        inputs=mixed_images,\n        outputs=mixed_scores,\n        # These other parameters have to do with the pytorch autograd engine works\n        grad_outputs=torch.ones_like(mixed_scores), \n        create_graph=True,\n        retain_graph=True,\n    )[0]\n    return gradient","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"l1_dist = nn.L1Loss()\ndef get_gen_loss(crit_fake_pred, photo, monet, lambda_value):\n    '''\n    Return the loss of a generator given the critic's scores of the generator's fake images.\n    Parameters:\n        crit_fake_pred: the critic's scores of the fake images\n    Returns:\n        gen_loss: a scalar loss value for the current batch of the generator\n    '''\n    #### START CODE HERE ####\n    fake = gen(photo)\n    gen_loss = -1. * torch.mean(crit_fake_pred)\n    gen_loss = gen_loss + l1_dist(fake, monet) *lambda_value\n    #### END CODE HERE ####\n    return gen_loss","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ndef get_crit_loss(crit_fake_pred, crit_real_pred, gp, c_lambda):\n    '''\n    Return the loss of a critic given the critic's scores for fake and real images,\n    the gradient penalty, and gradient penalty weight.\n    Parameters:\n        crit_fake_pred: the critic's scores of the fake images\n        crit_real_pred: the critic's scores of the real images\n        gp: the unweighted gradient penalty\n        c_lambda: the current weight of the gradient penalty \n    Returns:\n        crit_loss: a scalar for the critic's loss, accounting for the relevant factors\n    '''\n    crit_loss = torch.mean(crit_fake_pred) - torch.mean(crit_real_pred) + c_lambda * gp\n    return crit_loss","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#taken from https://www.kaggle.com/nachiket273/cyclegan-pytorch by @NACHIKET273\n#changed a little for understandability\n#creates dataset that feeds photo/monet noise, label\nclass ImageDataset(Dataset):\n    def __init__(self, monet_dir, photo_dir, normalize=True):\n        super().__init__()\n        #folder with monets\n        self.monet_dir = monet_dir\n        #folder with photos\n        self.photo_dir = photo_dir\n        self.monet_idx = dict()\n        self.photo_idx = dict()\n        if normalize:\n            self.transform = transforms.Compose([\n                transforms.ToTensor(),\n                transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))                                \n            ])\n        else:\n            self.transform = transforms.Compose([\n                transforms.ToTensor()                               \n            ])\n        #iterate over all monets and store them in dict by index\n        for i, monet in enumerate(os.listdir(self.monet_dir)):\n            self.monet_idx[i] = monet\n            \n        #iterate over all photos and store them in dict by index\n        for i, photo in enumerate(os.listdir(self.photo_dir)):\n            self.photo_idx[i] = photo\n\n    def __getitem__(self, idx):\n        rand_idx = int(np.random.uniform(0, len(self.monet_idx.keys())))\n        photo_path = os.path.join(self.photo_dir, self.photo_idx[rand_idx])\n        monet_path = os.path.join(self.monet_dir, self.monet_idx[idx])\n        photo_img = Image.open(photo_path)\n        photo_img = self.transform(photo_img)\n        monet_img = Image.open(monet_path)\n        monet_img = self.transform(monet_img)\n        return photo_img, monet_img\n\n    def __len__(self):\n        return min(len(self.monet_idx.keys()), len(self.photo_idx.keys()))\n    \n    \nclass PhotoDataset(Dataset):\n    def __init__(self, photo_dir, size=(256, 256), normalize=True):\n        super().__init__()\n        self.photo_dir = photo_dir\n        self.photo_idx = dict()\n        if normalize:\n            self.transform = transforms.Compose([\n                transforms.Resize(size),\n                transforms.ToTensor(),\n                transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))                                \n            ])\n        else:\n            self.transform = transforms.Compose([\n                transforms.Resize(size),\n                transforms.ToTensor()                               \n            ])\n        for i, fl in enumerate(os.listdir(self.photo_dir)):\n            self.photo_idx[i] = fl\n\n    def __getitem__(self, idx):\n        photo_path = os.path.join(self.photo_dir, self.photo_idx[idx])\n        photo_img = Image.open(photo_path)\n        photo_img = self.transform(photo_img)\n        return photo_img\n\n    def __len__(self):\n        return len(self.photo_idx.keys())","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.662877Z","iopub.execute_input":"2021-10-23T09:52:33.663392Z","iopub.status.idle":"2021-10-23T09:52:33.682998Z","shell.execute_reply.started":"2021-10-23T09:52:33.663355Z","shell.execute_reply":"2021-10-23T09:52:33.681875Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#create dataset and dataloader to feed to GAN\nimg_ds = ImageDataset('../input/gan-getting-started/monet_jpg/', '../input/gan-getting-started/photo_jpg/')\ndataloader = DataLoader(img_ds, batch_size=batch_size, pin_memory=True)","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:56:53.261991Z","iopub.execute_input":"2021-10-23T09:56:53.264333Z","iopub.status.idle":"2021-10-23T09:56:53.282506Z","shell.execute_reply.started":"2021-10-23T09:56:53.264241Z","shell.execute_reply":"2021-10-23T09:56:53.281343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#get the generator\ngen = Generator(hidden_dim = 32).to(device)\ngen_opt = torch.optim.Adam(gen.parameters(), lr=lr)\n\n#get the discriminator\ncrit = Critic().to(device) \ncrit_opt = torch.optim.Adam(crit.parameters(), lr=lr, betas=(beta_1, beta_2))\n\ndef weights_init(m):\n    if isinstance(m, nn.Conv2d) or isinstance(m, nn.ConvTranspose2d):\n        torch.nn.init.normal_(m.weight, 0.0, 0.02)\n    if isinstance(m, nn.BatchNorm2d):\n        torch.nn.init.normal_(m.weight, 0.0, 0.02)\n        torch.nn.init.constant_(m.bias, 0)\ngen = gen.apply(weights_init)\ncrit = crit.apply(weights_init)","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.707485Z","iopub.execute_input":"2021-10-23T09:52:33.707833Z","iopub.status.idle":"2021-10-23T09:52:33.770779Z","shell.execute_reply.started":"2021-10-23T09:52:33.707799Z","shell.execute_reply":"2021-10-23T09:52:33.770143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def gradient_penalty(gradient):\n    '''\n    Return the gradient penalty, given a gradient.\n    Given a batch of image gradients, you calculate the magnitude of each image's gradient\n    and penalize the mean quadratic distance of each magnitude to 1.\n    Parameters:\n        gradient: the gradient of the critic's scores, with respect to the mixed image\n    Returns:\n        penalty: the gradient penalty\n    '''\n    # Flatten the gradients so that each row captures one image\n    gradient = gradient.view(len(gradient), -1)\n\n    # Calculate the magnitude of every row\n    gradient_norm = gradient.norm(2, dim=1)\n    #gradient penalty from last slide of the presi\n    penalty = torch.mean((gradient_norm - 1)**2)\n    return penalty","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n#for photo, monet in tqdm(dataloader):\n#    plt.imshow(monet[0].numpy().transpose((1, 2, 0)))\n#    break","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:58:00.908748Z","iopub.execute_input":"2021-10-23T09:58:00.909949Z","iopub.status.idle":"2021-10-23T09:58:00.914257Z","shell.execute_reply.started":"2021-10-23T09:58:00.909891Z","shell.execute_reply":"2021-10-23T09:58:00.913133Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gen.cuda()\ncrit.cuda()","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:58:01.077823Z","iopub.execute_input":"2021-10-23T09:58:01.078159Z","iopub.status.idle":"2021-10-23T09:58:01.108202Z","shell.execute_reply.started":"2021-10-23T09:58:01.078125Z","shell.execute_reply":"2021-10-23T09:58:01.106926Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_epochs = 300\nz_dim = 64\ndisplay_step = 300\nbatch_size = 128\nlr = 0.00002\nbeta_1 = 0.5\nbeta_2 = 0.999\nc_lambda = 10\ncrit_repeats = 5\ndevice = 'cuda'\nlambda_value = 100","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cur_step = 0\nmean_generator_loss = 0\nmean_discriminator_loss = 0\ngen_loss = False\nerror = False\n \ncur_step = 0\ngenerator_losses = []\ncritic_losses = []\n\nfor epoch in range(n_epochs):\n  \n    # Dataloader returns the batches\n    for photo, monet in dataloader:\n        cur_batch_size = len(photo)\n        monet = monet.to(device)\n        photo = photo.to(device)\n        mean_iteration_critic_loss = 0\n        ### Update critic ###\n        crit_opt.zero_grad()\n        fake = gen(photo)\n        crit_fake_pred = crit(fake.detach())\n        crit_real_pred = crit(monet)\n\n        epsilon = torch.rand(len(monet), 1, 1, 1, device=device, requires_grad=True)\n        gradient = get_gradient(crit, monet, fake.detach(), epsilon)\n        gp = gradient_penalty(gradient)\n        crit_loss = get_crit_loss(crit_fake_pred, crit_real_pred, gp, c_lambda)\n\n        # Keep track of the average critic loss in this batch\n        mean_iteration_critic_loss += crit_loss.item()\n        # Update gradients\n        crit_loss.backward(retain_graph=True)\n        # Update optimizer\n        crit_opt.step()\n        \n        critic_losses += [mean_iteration_critic_loss]\n        \n        #backpropagation\n        gen_opt.zero_grad()\n        \n        fake_2 = gen(photo)\n        crit_fake_pred = crit(fake_2)\n        \n        gen_loss = get_gen_loss(crit_fake_pred, photo, monet, lambda_value)\n        gen_loss.backward()\n        gen_opt.step()\n\n        # Keep track of the average generator loss\n        generator_losses += [gen_loss.item()]\n\n\n        ### Visualization code ###\n        if cur_step % display_step == 0 and cur_step > 0:\n            gen_mean = sum(generator_losses[-display_step:]) / display_step\n            crit_mean = sum(critic_losses[-display_step:]) / display_step\n            print(f\"Step {cur_step}: Generator loss: {gen_mean}, critic loss: {crit_mean}\")\n            show_tensor_images(fake)\n            show_tensor_images(monet)\n            show_tensor_images(photo)\n            step_bins = 20\n            num_examples = (len(generator_losses) // step_bins) * step_bins\n            plt.plot(\n                range(num_examples // step_bins), \n                torch.Tensor(generator_losses[:num_examples]).view(-1, step_bins).mean(1),\n                label=\"Generator Loss\"\n            )\n            plt.plot(\n                range(num_examples // step_bins), \n                torch.Tensor(critic_losses[:num_examples]).view(-1, step_bins).mean(1),\n                label=\"Critic Loss\"\n            )\n            plt.legend()\n            plt.show()\n\n        cur_step += 1","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:58:01.253812Z","iopub.execute_input":"2021-10-23T09:58:01.254772Z","iopub.status.idle":"2021-10-23T09:58:18.961158Z","shell.execute_reply.started":"2021-10-23T09:58:01.254714Z","shell.execute_reply":"2021-10-23T09:58:18.959761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#np.random.uniform(0, 0.2, (3, 256, 256))","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:58:18.962771Z","iopub.status.idle":"2021-10-23T09:58:18.96332Z","shell.execute_reply.started":"2021-10-23T09:58:18.963048Z","shell.execute_reply":"2021-10-23T09:58:18.963076Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"photo_dataset = PhotoDataset('../input/gan-getting-started/photo_jpg/')\ndataloader = DataLoader(photo_dataset, batch_size=1, pin_memory=True)","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:56:21.042715Z","iopub.execute_input":"2021-10-23T09:56:21.043156Z","iopub.status.idle":"2021-10-23T09:56:21.051699Z","shell.execute_reply.started":"2021-10-23T09:56:21.043124Z","shell.execute_reply":"2021-10-23T09:56:21.050859Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir ../images","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:56:21.258621Z","iopub.execute_input":"2021-10-23T09:56:21.259211Z","iopub.status.idle":"2021-10-23T09:56:22.054652Z","shell.execute_reply.started":"2021-10-23T09:56:21.259166Z","shell.execute_reply":"2021-10-23T09:56:22.053435Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.listdir()","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:56:23.867114Z","iopub.execute_input":"2021-10-23T09:56:23.867517Z","iopub.status.idle":"2021-10-23T09:56:23.87358Z","shell.execute_reply.started":"2021-10-23T09:56:23.867463Z","shell.execute_reply":"2021-10-23T09:56:23.873048Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def unnorm(img, mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]):\n    for t, m, s in zip(img, mean, std):\n        t.mul_(s).add_(s)\n        \n    return img","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.796603Z","iopub.status.idle":"2021-10-23T09:52:33.797136Z","shell.execute_reply.started":"2021-10-23T09:52:33.796821Z","shell.execute_reply":"2021-10-23T09:52:33.796845Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"topil = transforms.ToPILImage()","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.798417Z","iopub.status.idle":"2021-10-23T09:52:33.798842Z","shell.execute_reply.started":"2021-10-23T09:52:33.798684Z","shell.execute_reply":"2021-10-23T09:52:33.798701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"t = tqdm(dataloader, leave=False, total=dataloader.__len__())\ngen.eval()\nfor i, photo in enumerate(t):\n    with torch.no_grad():\n        pred_monet = gen(photo.to(device)).detach()\n    pred_monet = unnorm(pred_monet) #I don't think this is necessary\n    pred_monet = torch.squeeze(pred_monet)\n    img = topil(pred_monet)\n    #print(type(img))\n    img = img.convert(\"RGB\")\n    img.save(\"../images/\" + str(i+1) + \".jpg\")","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.799654Z","iopub.status.idle":"2021-10-23T09:52:33.800094Z","shell.execute_reply.started":"2021-10-23T09:52:33.799895Z","shell.execute_reply":"2021-10-23T09:52:33.799911Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred_monet.shape","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.800872Z","iopub.status.idle":"2021-10-23T09:52:33.801319Z","shell.execute_reply.started":"2021-10-23T09:52:33.80116Z","shell.execute_reply":"2021-10-23T09:52:33.801176Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"b = topil(pred_monet)","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.8021Z","iopub.status.idle":"2021-10-23T09:52:33.802502Z","shell.execute_reply.started":"2021-10-23T09:52:33.802338Z","shell.execute_reply":"2021-10-23T09:52:33.802354Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.array(b).shape","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.803273Z","iopub.status.idle":"2021-10-23T09:52:33.803676Z","shell.execute_reply.started":"2021-10-23T09:52:33.803519Z","shell.execute_reply":"2021-10-23T09:52:33.803535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(b)","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.804488Z","iopub.status.idle":"2021-10-23T09:52:33.804886Z","shell.execute_reply.started":"2021-10-23T09:52:33.80473Z","shell.execute_reply":"2021-10-23T09:52:33.804746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.805678Z","iopub.status.idle":"2021-10-23T09:52:33.806086Z","shell.execute_reply.started":"2021-10-23T09:52:33.805917Z","shell.execute_reply":"2021-10-23T09:52:33.805944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#save your models\ntorch.save(gen.state_dict(), 'generator')\ntorch.save(crit.state_dict(), 'critic')","metadata":{"execution":{"iopub.status.busy":"2021-10-23T09:52:33.806884Z","iopub.status.idle":"2021-10-23T09:52:33.807293Z","shell.execute_reply.started":"2021-10-23T09:52:33.807138Z","shell.execute_reply":"2021-10-23T09:52:33.807153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}