{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torch.autograd import Variable\nfrom torch.utils.data import DataLoader\nfrom torchvision import transforms\nfrom torchvision import datasets\nfrom torchvision.utils import save_image\nimport os\nimport xml.etree.ElementTree as ET\nfrom PIL import Image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import argparse\nimport random\nimport torch.backends.cudnn as cudnn\nimport torchvision.utils as vutils\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport matplotlib.animation as animation\nfrom IPython.display import HTML\n\n# Set random seem for reproducibility\n#manualSeed = 999\nmanualSeed = random.randint(1, 10000) # use if you want new results\nprint(\"Random Seed: \", manualSeed)\nrandom.seed(manualSeed)\ntorch.manual_seed(manualSeed)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport PIL\nimport torchvision\nimport torchvision.datasets as dset\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nimport torchvision.utils as vutils\nfrom torch.autograd import Variable\nimport xml.etree.ElementTree as ET\nimport numpy as np\n\nimport imgaug as ia\nimport imgaug.augmenters as iaa\n\nimport matplotlib.pyplot as plt\n\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.parallel\nimport torch.optim as optim\nfrom torch.nn.init import xavier_uniform_\n\n\nimport time\nimport torch\nimport torch.nn as nn\n\nimport torch.nn.parallel\nimport torch.optim as optim\nfrom torch.nn.utils import spectral_norm\nimport torch.utils.data\nimport torchvision\nimport torchvision.datasets as dset\nimport torchvision.transforms as transforms\nimport torchvision.utils as vutils\nfrom torch.autograd import Variable\nfrom torch import nn, optim\nimport torch.nn.functional as F\nfrom torchvision import datasets, transforms\nfrom torchvision.utils import save_image\nimport matplotlib.image as mpimg\n\nimport torch.nn.functional as F\nfrom torch.nn import Parameter\n\n\nimport numpy as np\nimport os\nimport gzip, pickle\nimport tensorflow as tf\nfrom scipy import linalg\nimport pathlib\nimport urllib\nimport warnings\nfrom tqdm import tqdm\nfrom PIL import Image\nimport zipfile\n\nfrom tqdm import tqdm_notebook as tqdm","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size = 32\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 = 350\n\n# Learning rate for optimizers\nlr = 0.0001\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":"if not os.path.exists('./dc_img'):\n    os.mkdir('./dc_img')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def to_img(x):\n    out = 0.5 * (x + 1)\n    out = out.clamp(0, 1)\n    out = out.view(-1, 1, 28, 28)\n    return out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"! ls {'../input'}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"annotation_folders = os.listdir('../input/annotation/Annotation')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class DataGenerator(Dataset):\n    def __init__(self, directory, transform=None, n_samples=np.inf, crop_dogs=1):\n        self.directory = directory\n        self.transform = transform\n        self.n_samples = n_samples        \n        self.samples, self.labels = self.load_dogs_data(directory, crop_dogs)\n\n    def load_dogs_data(self, directory, crop_dogs):\n        required_transforms = torchvision.transforms.Compose([\n                torchvision.transforms.Resize(64),\n                torchvision.transforms.CenterCrop(64),\n        ])\n\n        imgs = []\n        labels = []\n        paths = []\n        for root, _, fnames in sorted(os.walk(directory)):\n            for fname in sorted(fnames)[:min(self.n_samples, 999999999999999)]:\n                path = os.path.join(root, fname)\n                paths.append(path)\n\n        for path in paths:\n            # Load image\n            try: img = dset.folder.default_loader(path)\n            except: continue\n            \n            # Get bounding boxes\n            annotation_basename = os.path.splitext(os.path.basename(path))[0]\n            annotation_dirname = next(\n                    dirname for dirname in os.listdir('../input/annotation/Annotation/') if\n                    dirname.startswith(annotation_basename.split('_')[0]))\n                \n            \n            if crop_dogs == 1 or crop_dogs == -1:\n                tree = ET.parse(os.path.join('../input/annotation/Annotation/',\n                                             annotation_dirname, annotation_basename))\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                    object_img = required_transforms(img.crop((xmin, ymin, xmax, ymax)))\n                    imgs.append(object_img)\n                    labels.append(annotation_dirname.split('-')[1].lower())\n\n            if crop_dogs == 0 or crop_dogs == -1:\n                object_img = required_transforms(img)\n                imgs.append(object_img)\n                labels.append(annotation_dirname.split('-')[1].lower())\n                \n        return imgs, labels\n    \n    \n    def __getitem__(self, index):\n        sample = self.samples[index]\n        label = self.labels[index]\n        \n        if self.transform is not None: \n            sample = self.transform(sample)\n        return np.asarray(sample), label\n\n    \n    def __len__(self):\n        return len(self.samples)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"database = '../input/all-dogs/all-dogs/'\ncrop_dogs = -1\nn_samples = np.inf\nBATCH_SIZE = 32\n\nbeta1 = 0.5\nepochs = 300\n\nuse_soft_noisy_labels=True\n\nnz = 128\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n\ntransform = transforms.Compose([transforms.RandomHorizontalFlip(p=0.5),\n                                transforms.ToTensor(),\n                                transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])\n\n\n\ntrain_data = DataGenerator(database, transform=transform, n_samples=n_samples, crop_dogs=crop_dogs)\n\ndecoded_dog_labels = {i:breed for i, breed in enumerate(sorted(set(train_data.labels)))}\nencoded_dog_labels = {breed:i for i, breed in enumerate(sorted(set(train_data.labels)))}\ntrain_data.labels = [encoded_dog_labels[l] for l in train_data.labels] # encode dog labels in the data generator\n\n\ndataloader = torch.utils.data.DataLoader(train_data, shuffle=True,\n                                           batch_size=BATCH_SIZE, num_workers=4)\n\n\nprint(\"Dog breeds loaded:  \", len(encoded_dog_labels))\nprint(\"Data samples loaded:\", len(train_data))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# random_transforms = [transforms.ColorJitter(), transforms.RandomRotation(degrees=20)]\n\n# transform = transforms.Compose([\n#                                 transforms.CenterCrop(64),\n#                                 transforms.RandomHorizontalFlip(p=0.5),\n#                                 transforms.RandomApply(random_transforms, p=0.3),\n#                                 transforms.ToTensor(),\n#                                 transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# rand_aff = random.uniform(3.0, 15.0)\n# rand_flip = random.uniform(0.3, 1.0)\n# rand_trans = random.uniform(0.3, 0.7)\n# rand_contr = random.uniform(0.2, 0.9)\n# random_transforms = [transforms.ColorJitter(contrast=rand_contr), transforms.RandomAffine(degrees=rand_aff)]\n# dataset = datasets.ImageFolder(root='../input/all-dogs',\n#                            transform=transforms.Compose([\n#                                transforms.Resize(image_size),\n#                                transforms.CenterCrop(image_size),\n#                                transforms.RandomHorizontalFlip(p=rand_flip),\n#                                transforms.RandomApply(random_transforms, p=rand_trans),\n#                                transforms.ToTensor(),\n#                                transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n#                            ]))\n# dataloader = torch.utils.data.DataLoader(dataset, batch_size=batch_size,\n#                                          shuffle=True, num_workers=2)\n# device = 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":"# dataset = datasets.ImageFolder(\n#     '../input/all-dogs',\n#     loader=ImageLoader,\n#     transform=transform\n# )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = 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":"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.05)\n    elif classname.find('BatchNorm') != -1:\n        nn.init.normal_(m.weight.data, 1.0, 0.05)\n        nn.init.constant_(m.bias.data, 0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class 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 * 8, 4, 1, 0, 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            # 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            # state size. (ngf*2) x 16 x 16\n            nn.ConvTranspose2d( ngf * 2, ngf, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(ngf),\n            nn.ReLU(True),\n            # state size. (ngf) x 32 x 32\n            nn.ConvTranspose2d( ngf, nc, 4, 2, 1, bias=False),\n            nn.Tanh()\n            # state size. (nc) x 64 x 64\n        )\n\n    def forward(self, input):\n        return self.main(input)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"netG = Generator(ngpu).to(device)\n\n# Handle multi-gpu if desired\nif (device.type == 'cuda') and (1 > 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)\n","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            # 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":"netD = 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)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"criterion = 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\n\n# Setup Adam optimizers for both G and D\noptimizerD = torch.optim.Adam(netD.parameters(), lr=lr, betas=(beta1, 0.999))\noptimizerG = torch.optim.Adam(netG.parameters(), lr=lr, betas=(beta1, 0.999))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from numpy.random import random\ndef smooth_positive_labels(y):\n    y = torch.add(y,-0.3)\n    r = (torch.from_numpy(random(y.shape[0])*0.5)).float().to(device)\n    return torch.add(y,r)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from numpy.random import choice\ndef noisy_labels(y, p_flip):\n    n_select = int(p_flip * y.shape[0])\n    flip_ix = choice([i for i in range(y.shape[0])], size=n_select)\n    # invert the labels in place\n    y[flip_ix] = 1 - y[flip_ix]\n    return y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"img_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, device=device)\n        # noise + one sided smoothening\n        \n        label = noisy_labels(label,0.05)\n        \n        label = smooth_positive_labels(label)\n        \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        \n        label = noisy_labels(label,0.1)\n        \n        label = smooth_positive_labels(label)\n        \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        # 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":"if not os.path.exists('../output_images'):\n    os.mkdir('../output_images')\nim_batch_size = 50\nn_images=10000\nfor i_batch in range(0, n_images, im_batch_size):\n    gen_z = torch.randn(im_batch_size, nz, 1, 1, device=device)\n    gen_images = netG(gen_z)\n    images = gen_images.to(\"cpu\").clone().detach()\n    images = images.numpy().transpose(0, 2, 3, 1)\n    for i_image in range(gen_images.size(0)):\n        save_image(gen_images[i_image, :, :, :], os.path.join('../output_images', f'image_{i_batch+i_image:05d}.png'))\n\n\nimport shutil\nshutil.make_archive('images', 'zip', '../output_images')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(25, 16))\n# display 10 images from each class\nfor i, j in enumerate(images[:32]):\n    ax = fig.add_subplot(4, 8, i + 1, xticks=[], yticks=[])\n    plt.imshow(j)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"real_batch = next(iter(dataloader))\n\n# Plot the real images\nplt.figure(figsize=(15,15))\nplt.subplot(1,2,1)\nplt.axis(\"off\")\nplt.title(\"Real Images\")\nplt.imshow(np.transpose(vutils.make_grid(real_batch[0].to(device)[:64], padding=5, normalize=True).cpu(),(1,2,0)))\n\n# Plot the fake images from the last epoch\nplt.subplot(1,2,2)\nplt.axis(\"off\")\nplt.title(\"Fake Images\")\nplt.imshow(np.transpose(img_list[-1],(1,2,0)))\nplt.show()","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.1"}},"nbformat":4,"nbformat_minor":1}