{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"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 in \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 \"../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\n\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n#         print(os.path.join(dirname, filename))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"from __future__ import print_function\n#%matplotlib inline\nimport argparse\nimport os\nimport random\nimport torch\nimport torch.nn as nn\nimport torch.nn.parallel\nimport torch.backends.cudnn as cudnn\nimport torch.optim as optim\nimport torch.utils.data\nimport torchvision.datasets as dset\nimport torchvision.transforms as transforms\nimport torchvision.utils as vutils\nimport numpy as np\nimport matplotlib.pyplot as plt\n# import matplotlib.animation as animation\n# from IPython.display import HTML\n\nmanualSeed = 807\nrandom.seed(manualSeed)\ntorch.manual_seed(manualSeed)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Root directory for dataset\ndataroot = \"../input/all-dogs/\"\n\n# Number of workers for dataloader\nworkers = 0\n\n# Batch size during training\nbatch_size = 64\n\n# Spatial size of training images. All images will be resized to this\n#   size using a transformer.\nimage_size = 64\n\n# Number of channels in the training images. For color images this is 3\nnc = 3\n\n# Size of z latent vector (i.e. size of generator input)\nnz = 100\n\n# Size of feature maps in generator\nngf = 64\n\n# Size of feature maps in discriminator\nndf = 64\n\n# Number of training epochs\nnum_epochs = 300\n\n# Learning rate for optimizers\nlr = 0.0002\n\n# Beta1 hyperparam for Adam optimizers\nbeta1 = 0.5\n\n# Number of GPUs available. Use 0 for CPU mode.\nngpu = 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from glob import glob","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# CROP THE DATA WITH BOUNDING BOX\nimport xml.etree.ElementTree as ET \nfrom PIL import Image \n\nROOT = '../input/'\nIMAGES = os.listdir(ROOT + 'all-dogs/all-dogs/')\nbreeds = os.listdir(ROOT + 'annotation/Annotation/')  \n\nprint(len(breeds))\n\ndata = []\n\nfor breed in breeds:\n    for dog in os.listdir(ROOT+'annotation/Annotation/'+breed):\n        try: img = Image.open(ROOT+'all-dogs/all-dogs/'+dog+'.jpg') \n        except: continue           \n        tree = ET.parse(ROOT+'annotation/Annotation/'+breed+'/'+dog)\n        root = tree.getroot()\n        objects = root.findall('object')\n        for o in objects:\n            bndbox = o.find('bndbox') \n            xmin = int(bndbox.find('xmin').text)\n            ymin = int(bndbox.find('ymin').text)\n            xmax = int(bndbox.find('xmax').text)\n            ymax = int(bndbox.find('ymax').text)\n            w = np.min((xmax - xmin, ymax - ymin))\n            img = img.crop((xmin, ymin, xmin+w, ymin+w))\n            img = img.resize((64,64), Image.ANTIALIAS)\n            data.append(img)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(len(data))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# DETECT WHOLE BLACK (BROKEN) IMAGES\nfor i, img in enumerate(data):\n    extrema = img.convert(\"L\").getextrema()\n    if extrema == (0, 0):\n        data.remove(img)\n        \nprint(len(data))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data = [transforms.ToTensor()(x) for x in data]\ndata = torch.stack([x for x in data])\nprint(data.size())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataset = torch.utils.data.TensorDataset(data)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# We can use an image folder dataset the way we have it setup.\n# Create the dataset\n# dataset = dset.ImageFolder(root=dataroot,\n#                            transform=transforms.Compose([\n#                                transforms.Resize(image_size),\n#                                transforms.CenterCrop(image_size),\n#                                transforms.ToTensor(),\n#                            ]))\n# Create the dataloader\ndataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size,\n                                         shuffle=True, num_workers=workers)\n\n# Decide which device we want to run on\ndevice = torch.device(\"cuda:0\" if (torch.cuda.is_available() and ngpu > 0) else \"cpu\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"real_batch = next(iter(dataloader))\nplt.figure(figsize=(8,8))\nplt.axis(\"off\")\nplt.title(\"Training Images\")\nplt.imshow(np.transpose(vutils.make_grid(real_batch[0].to(device)[:64], padding=2, normalize=True).cpu(),(1,2,0)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def weights_init(m):\n    classname = m.__class__.__name__\n    if classname.find('Conv') != -1:\n        nn.init.normal_(m.weight.data, 0.0, 0.02)\n    elif classname.find('BatchNorm') != -1:\n        nn.init.normal_(m.weight.data, 1.0, 0.02)\n        nn.init.constant_(m.bias.data, 0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Generator Code\n\nclass Generator(nn.Module):\n    def __init__(self, ngpu):\n        super(Generator, self).__init__()\n        self.ngpu = ngpu\n        self.main = nn.Sequential(\n            # input is Z, going into a convolution\n            nn.ConvTranspose2d( nz, ngf * 16, 4, 1, 0, bias=False),\n            nn.BatchNorm2d(ngf * 16),\n            nn.ReLU(True),\n            # state size. (ngf*16) x 2 x 2\n            nn.ConvTranspose2d(ngf * 16, ngf * 8, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(ngf * 8),\n            nn.ReLU(True),\n            # TRY TO EXTRACT FEATURES FROM THE CONVTRANSPOSE FEATURE MAPS\n            nn.Conv2d(ngf * 8, ngf * 8, 3, 1, 1, bias=False),\n            nn.BatchNorm2d(ngf * 8),\n            nn.ReLU(True),\n            # state size. (ngf*8) x 4 x 4\n            nn.ConvTranspose2d( ngf * 8, ngf * 4, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(ngf * 4),\n            nn.ReLU(True),\n            \n            \n            # state size. (ngf*4) x 8 x 8\n            nn.ConvTranspose2d( ngf * 4, ngf * 2, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(ngf * 2),\n            nn.ReLU(True),\n            # TRY TO EXTRACT FEATURES FROM THE CONVTRANSPOSE FEATURE MAPS\n            nn.Conv2d( ngf * 2, ngf * 2, 3, 1, 1, bias=False),\n            nn.BatchNorm2d(ngf * 2),\n            nn.ReLU(True),\n            \n            nn.Conv2d( ngf * 2, ngf * 4, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(ngf * 4),\n            nn.ReLU(True),\n            nn.ConvTranspose2d( ngf * 4, ngf * 2, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(ngf * 2),\n            nn.ReLU(True),\n            \n            # state size. (ngf) x 64 x 64\n            nn.ConvTranspose2d( ngf * 2, nc, 4, 2, 1, bias=False),\n            nn.Tanh()\n        )\n\n    def forward(self, input):\n        return self.main(input)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create the generator\nnetG = Generator(ngpu).to(device)\n\n# Handle multi-gpu if desired\nif (device.type == 'cuda') and (ngpu > 1):\n    netG = nn.DataParallel(netG, list(range(ngpu)))\n\n# Apply the weights_init function to randomly initialize all weights\n#  to mean=0, stdev=0.2.\nnetG.apply(weights_init)\n\n# Print the model\nprint(netG)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class Discriminator(nn.Module):\n    def __init__(self, ngpu):\n        super(Discriminator, self).__init__()\n        self.ngpu = ngpu\n        self.main = nn.Sequential(\n            # input is (nc) x 64 x 64\n            nn.Conv2d(nc, ndf, 4, 2, 1, bias=False),\n            nn.LeakyReLU(0.2, inplace=True),\n            # state size. (ndf) x 32 x 32\n            nn.Conv2d(ndf, ndf * 2, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(ndf * 2),\n            nn.LeakyReLU(0.2, inplace=True),\n            # state size. (ndf*2) x 16 x 16\n            nn.Conv2d(ndf * 2, ndf * 4, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(ndf * 4),\n            nn.LeakyReLU(0.2, inplace=True),\n            \n            \n            # state size. (ndf*4) x 8 x 8\n            nn.Conv2d(ndf * 4, ndf * 8, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(ndf * 8),\n            nn.LeakyReLU(0.2, inplace=True),\n            # state size. (ndf*8) x 4 x 4\n            nn.Conv2d(ndf * 8, 1, 4, 1, 0, bias=False),\n            nn.Sigmoid()\n        )\n\n    def forward(self, input):\n        return self.main(input)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create the Discriminator\nnetD = Discriminator(ngpu).to(device)\n\n# Handle multi-gpu if desired\nif (device.type == 'cuda') and (ngpu > 1):\n    netD = nn.DataParallel(netD, list(range(ngpu)))\n\n# Apply the weights_init function to randomly initialize all weights\n#  to mean=0, stdev=0.2.\nnetD.apply(weights_init)\n\n# Print the model\nprint(netD)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Initialize BCELoss function\ncriterion = nn.BCELoss()\n\n# Create batch of latent vectors that we will use to visualize\n#  the progression of the generator\nfixed_noise = torch.randn(64, nz, 1, 1, device=device)\n\n# Establish convention for real and fake labels during training\nreal_label = 1\nfake_label = 0\nlabel_smooth = 0\n\n# Setup Adam optimizers for both G and D\noptimizerD = optim.Adam(netD.parameters(), lr=lr, betas=(beta1, 0.999))\noptimizerG = optim.Adam(netG.parameters(), lr=lr, betas=(beta1, 0.999))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Training Loop\n\n# Lists to keep track of progress\nimg_list = []\nG_losses = []\nD_losses = []\niters = 0\n\nprint(\"Starting Training Loop...\")\n# For each epoch\nfor epoch in range(num_epochs):\n    # For each batch in the dataloader\n    for i, data in enumerate(dataloader, 0):\n\n        ############################\n        # (1) Update D network: maximize log(D(x)) + log(1 - D(G(z)))\n        ###########################\n        ## Train with all-real batch\n        netD.zero_grad()\n        # Format batch\n        real_cpu = data[0].to(device)\n        b_size = real_cpu.size(0)\n        label = torch.full((b_size,), real_label - label_smooth, device=device)\n        # Forward pass real batch through D\n        output = netD(real_cpu).view(-1)\n        # Calculate loss on all-real batch\n        errD_real = criterion(output, label)\n        # Calculate gradients for D in backward pass\n        errD_real.backward()\n        D_x = output.mean().item()\n\n        ## Train with all-fake batch\n        # Generate batch of latent vectors\n        noise = torch.randn(b_size, nz, 1, 1, device=device)\n        # Generate fake image batch with G\n        fake = netG(noise)\n        label.fill_(fake_label)\n        # Classify all fake batch with D\n        output = netD(fake.detach()).view(-1)\n        # Calculate D's loss on the all-fake batch\n        errD_fake = criterion(output, label)\n        # Calculate the gradients for this batch\n        errD_fake.backward()\n        D_G_z1 = output.mean().item()\n        # Add the gradients from the all-real and all-fake batches\n        errD = errD_real + errD_fake\n        # Update D\n        optimizerD.step()\n\n        ############################\n        # (2) Update G network: maximize log(D(G(z)))\n        ###########################\n        netG.zero_grad()\n        label.fill_(real_label)  # fake labels are real for generator cost\n        # Since we just updated D, perform another forward pass of all-fake batch through D\n        output = netD(fake).view(-1)\n        # Calculate G's loss based on this output\n        errG = criterion(output, label)\n        # Calculate gradients for G\n        errG.backward()\n        D_G_z2 = output.mean().item()\n        # Update G\n        optimizerG.step()\n\n        # Output training stats\n        if i % 50 == 0:\n            print('[%d/%d][%d/%d]\\tLoss_D: %.4f\\tLoss_G: %.4f\\tD(x): %.4f\\tD(G(z)): %.4f / %.4f'\n                  % (epoch, num_epochs, i, len(dataloader),\n                     errD.item(), errG.item(), D_x, D_G_z1, D_G_z2))\n\n        # Save Losses for plotting later\n        G_losses.append(errG.item())\n        D_losses.append(errD.item())\n\n        # THIS PART STORE THE IMAGES TO BE DISPLAY AS ANIMATION, BUT MAYBE TAKE UP TOO MUCH STORAGE\n        # THE KERNEL COMMIT WILL FAIL IF UNBLOCK THEM\n        #Check how the generator is doing by saving G's output on fixed_noise\n#         if (iters % 500 == 0) or ((epoch == num_epochs-1) and (i == len(dataloader)-1)):\n#             with torch.no_grad():\n#                 fake = netG(fixed_noise).detach().cpu()\n#             img_list.append(vutils.make_grid(fake, padding=2, normalize=True))\n\n#         iters += 1","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(10,5))\nplt.title(\"Generator and Discriminator Loss During Training\")\nplt.plot(G_losses,label=\"G\")\nplt.plot(D_losses,label=\"D\")\nplt.xlabel(\"iterations\")\nplt.ylabel(\"Loss\")\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# DO NOT DISPLAY IMAGE - KERNEL MAY FAIL\n# fig = plt.figure(figsize=(8,8))\n# plt.axis(\"off\")\n# ims = [[plt.imshow(np.transpose(i,(1,2,0)), animated=True)] for i in img_list]\n# ani = animation.ArtistAnimation(fig, ims, interval=1000, repeat_delay=1000, blit=True)\n\n# HTML(ani.to_jshtml())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import shutil\nfrom torchvision.utils import save_image\n\nprint(\"Creating submit\")\nos.makedirs('../output_images', exist_ok=True)\nim_batch_size = 100\nn_images = 10000\n\nfor i_batch in range(0, n_images, im_batch_size):\n    noise = torch.randn(im_batch_size, nz, 1, 1, device=device)\n    gen_images = netG(noise)\n    gen_images = (gen_images.to(\"cpu\").clone().detach() + 1) / 2\n    for ii, img in enumerate(gen_images):\n        save_image(gen_images[ii, :, :, :], os.path.join('../output_images', f'image_{i_batch + ii:05d}.png'))\n\nshutil.make_archive('images', 'zip', '../output_images')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":1}