{"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":"## Main Reference\n1. [PyTorch-GAN | Github/eriklindernoren | Collection of PyTorch implementations of GAN](https://github.com/sw-song/PyTorch-GAN)\n2. [CycleGAN | Github/junyanz | Torch implementation for learning an image-to-image translation without input-output pairs](https://github.com/junyanz/CycleGAN)","metadata":{}},{"cell_type":"markdown","source":"## Index\n```\nStep 1. Import Libraries\nStep 2. Initial Setting\nStep 3. Define Generator\nStep 4. Define Discriminator\nStep 5. Define Loss Function\nStep 6. Initialize Generator and Discriminator\nStep 7. GPU Setting\nStep 8. Weight Setting\nStep 9. Configure Optimizer\nStep 10. Learning Rate Scheduler Setting\nStep 11. Image Transformation Setting\nStep 12. DataLoader Setting\nStep 13. Define function to get sample images\nStep 14. Training\n```\n---","metadata":{}},{"cell_type":"markdown","source":"### Step 1. Import Libraries","metadata":{}},{"cell_type":"code","source":"import numpy as np\n\nimport torchvision.transforms as transforms\nfrom torchvision.utils import make_grid\n\nfrom torch.utils.data import DataLoader\nfrom torchvision import datasets\nfrom torch.autograd import Variable\n\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:13:55.550406Z","iopub.execute_input":"2021-07-28T17:13:55.550712Z","iopub.status.idle":"2021-07-28T17:13:56.82302Z","shell.execute_reply.started":"2021-07-28T17:13:55.550639Z","shell.execute_reply":"2021-07-28T17:13:56.822217Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 2. Initial Setting","metadata":{}},{"cell_type":"code","source":"n_cpu = 2 # number of cpu threads to use during batch generation","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:13:56.825975Z","iopub.execute_input":"2021-07-28T17:13:56.8263Z","iopub.status.idle":"2021-07-28T17:13:56.83206Z","shell.execute_reply.started":"2021-07-28T17:13:56.826264Z","shell.execute_reply":"2021-07-28T17:13:56.831331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# data (path)\ndataset_name = 'gan-getting-started'\nroot = '../input/'+dataset_name\n\n# data (img)\nimg_height = 256\nimg_width = 256\nchannels = 3\n\n# training\nepoch = 0 # epoch to start training from\nn_epochs = 30 # number of epochs of training\nbatch_size = 1 # size of the batches\nlr = 0.0002 # adam : learning rate\nb1 = 0.5 # adam : decay of first order momentum of gradient\nb2 = 0.999 # adam : decay of first order momentum of gradient\ndecay_epoch = 3 # suggested default : 100 (suggested 'n_epochs' is 200)\n                 # epoch from which to start lr decay\n","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:13:56.835518Z","iopub.execute_input":"2021-07-28T17:13:56.835806Z","iopub.status.idle":"2021-07-28T17:13:56.840618Z","shell.execute_reply.started":"2021-07-28T17:13:56.835779Z","shell.execute_reply":"2021-07-28T17:13:56.839825Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 3. Define Generator","metadata":{"execution":{"iopub.status.busy":"2021-06-16T07:31:30.851239Z","iopub.execute_input":"2021-06-16T07:31:30.851561Z","iopub.status.idle":"2021-06-16T07:31:30.9469Z","shell.execute_reply.started":"2021-06-16T07:31:30.851531Z","shell.execute_reply":"2021-06-16T07:31:30.945422Z"}}},{"cell_type":"code","source":"class ResidualBlock(nn.Module):\n    def __init__(self, in_features):\n        super(ResidualBlock, self).__init__()\n        \n        self.block = nn.Sequential(\n            nn.ReflectionPad2d(1), # Pads the input tensor using the reflection of the input boundary\n            nn.Conv2d(in_features, in_features, 3),\n            nn.InstanceNorm2d(in_features), \n            nn.ReLU(inplace=True),\n            nn.ReflectionPad2d(1),\n            nn.Conv2d(in_features, in_features, 3),\n            nn.InstanceNorm2d(in_features)\n        )\n\n    def forward(self, x):\n        return x + self.block(x)\n\n\nclass GeneratorResNet(nn.Module):\n    def __init__(self, input_shape, num_residual_block):\n        super(GeneratorResNet, self).__init__()\n        \n        channels = input_shape[0]\n        \n        # Initial Convolution Block\n        out_features = 64\n        model = [\n            nn.ReflectionPad2d(channels),\n            nn.Conv2d(channels, out_features, 7),\n            nn.InstanceNorm2d(out_features),\n            nn.ReLU(inplace=True)\n        ]\n        in_features = out_features\n        \n        # Downsampling\n        for _ in range(2):\n            out_features *= 2\n            model += [\n                nn.Conv2d(in_features, out_features, 3, stride=2, padding=1),\n                nn.InstanceNorm2d(out_features),\n                nn.ReLU(inplace=True)\n            ]\n            in_features = out_features\n        \n        # Residual blocks\n        for _ in range(num_residual_block):\n            model += [ResidualBlock(out_features)]\n            \n        # Upsampling\n        for _ in range(2):\n            out_features //= 2\n            model += [\n                nn.Upsample(scale_factor=2), # --> width*2, heigh*2\n                nn.Conv2d(in_features, out_features, 3, stride=1, padding=1),\n                nn.ReLU(inplace=True)\n            ]\n            in_features = out_features\n            \n        # Output Layer\n        model += [nn.ReflectionPad2d(channels),\n                  nn.Conv2d(out_features, channels, 7),\n                  nn.Tanh()\n                 ]\n        \n        # Unpacking\n        self.model = nn.Sequential(*model) \n        \n    def forward(self, x):\n        return self.model(x)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:13:56.842406Z","iopub.execute_input":"2021-07-28T17:13:56.84288Z","iopub.status.idle":"2021-07-28T17:13:56.85644Z","shell.execute_reply.started":"2021-07-28T17:13:56.842845Z","shell.execute_reply":"2021-07-28T17:13:56.855685Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 4. Define Discriminator","metadata":{}},{"cell_type":"code","source":"class Discriminator(nn.Module):\n    def __init__(self, input_shape):\n        super(Discriminator, self).__init__()\n        \n        channels, height, width = input_shape\n        \n        # Calculate output shape of image discriminator (PatchGAN)\n        self.output_shape = (1, height//2**4, width//2**4)\n        \n        def discriminator_block(in_filters, out_filters, normalize=True):\n            \"\"\"Returns downsampling layers of each discriminator block\"\"\"\n            layers = [nn.Conv2d(in_filters, out_filters, 4, stride=2, padding=1)]\n            if normalize:\n                layers.append(nn.InstanceNorm2d(out_filters))\n            layers.append(nn.LeakyReLU(0.2, inplace=True))\n            return layers\n        \n        self.model = nn.Sequential(\n            *discriminator_block(channels, 64, normalize=False),\n            *discriminator_block(64, 128),\n            *discriminator_block(128,256),\n            *discriminator_block(256,512),\n            nn.ZeroPad2d((1,0,1,0)),\n            nn.Conv2d(512, 1, 4, padding=1)\n        )\n        \n    def forward(self, img):\n        return self.model(img)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:13:56.857755Z","iopub.execute_input":"2021-07-28T17:13:56.858109Z","iopub.status.idle":"2021-07-28T17:13:56.870001Z","shell.execute_reply.started":"2021-07-28T17:13:56.858074Z","shell.execute_reply":"2021-07-28T17:13:56.869162Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"criterion_GAN = torch.nn.MSELoss()\ncriterion_cycle = torch.nn.L1Loss()\ncriterion_identity = torch.nn.L1Loss()","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:13:56.871324Z","iopub.execute_input":"2021-07-28T17:13:56.871663Z","iopub.status.idle":"2021-07-28T17:13:56.880931Z","shell.execute_reply.started":"2021-07-28T17:13:56.871628Z","shell.execute_reply":"2021-07-28T17:13:56.880171Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 6. Initialize Generator and Discriminator","metadata":{}},{"cell_type":"code","source":"input_shape = (channels, img_height, img_width) # (3,256,256)\nn_residual_blocks = 9 # suggested default, number of residual blocks in generator\n\nGenerator_monet_to_photo = GeneratorResNet(input_shape, n_residual_blocks)\nGenerator_photo_to_monet = GeneratorResNet(input_shape, n_residual_blocks)\nDiscriminator_monet = Discriminator(input_shape)\nDiscriminator_photo = Discriminator(input_shape)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:13:56.881994Z","iopub.execute_input":"2021-07-28T17:13:56.882345Z","iopub.status.idle":"2021-07-28T17:13:57.13561Z","shell.execute_reply.started":"2021-07-28T17:13:56.882312Z","shell.execute_reply":"2021-07-28T17:13:57.134693Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 7. GPU Setting","metadata":{}},{"cell_type":"code","source":"cuda = torch.cuda.is_available()\n\nif cuda:\n    Generator_monet_to_photo = Generator_monet_to_photo.cuda()\n    Generator_photo_to_monet = Generator_photo_to_monet.cuda()\n    Discriminator_monet = Discriminator_monet.cuda()\n    Discriminator_photo = Discriminator_photo.cuda()\n    \n    criterion_GAN.cuda()\n    criterion_cycle.cuda()\n    criterion_identity.cuda()","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:13:57.13823Z","iopub.execute_input":"2021-07-28T17:13:57.138645Z","iopub.status.idle":"2021-07-28T17:14:01.684587Z","shell.execute_reply.started":"2021-07-28T17:13:57.138605Z","shell.execute_reply":"2021-07-28T17:14:01.683671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 8. Weight Setting","metadata":{}},{"cell_type":"code","source":"def weights_init_normal(m):\n    classname = m.__class__.__name__\n    if classname.find('Conv') != -1:\n        torch.nn.init.normal_(m.weight.data, 0.0, 0.02) # reset Conv2d's weight(tensor) with Gaussian Distribution\n        if hasattr(m, 'bias') and m.bias is not None:\n            torch.nn.init.constant_(m.bias.data, 0.0) # reset Conv2d's bias(tensor) with Constant(0)\n        elif classname.find('BatchNorm2d') != -1:\n            torch.nn.init.normal_(m.weight.data, 1.0, 0.02) # reset BatchNorm2d's weight(tensor) with Gaussian Distribution\n            torch.nn.init.constant_(m.bias.data, 0.0) # reset BatchNorm2d's bias(tensor) with Constant(0)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.686556Z","iopub.execute_input":"2021-07-28T17:14:01.686825Z","iopub.status.idle":"2021-07-28T17:14:01.696567Z","shell.execute_reply.started":"2021-07-28T17:14:01.6868Z","shell.execute_reply":"2021-07-28T17:14:01.695755Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Generator_monet_to_photo.apply(weights_init_normal)\nGenerator_photo_to_monet.apply(weights_init_normal)\nDiscriminator_monet.apply(weights_init_normal)\nDiscriminator_photo.apply(weights_init_normal)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.69782Z","iopub.execute_input":"2021-07-28T17:14:01.698301Z","iopub.status.idle":"2021-07-28T17:14:01.725267Z","shell.execute_reply.started":"2021-07-28T17:14:01.698265Z","shell.execute_reply":"2021-07-28T17:14:01.724505Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def temp_weights_init_normal(m):\n    classname =  m.__class__.__name__\n    print(classname)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.728112Z","iopub.execute_input":"2021-07-28T17:14:01.728373Z","iopub.status.idle":"2021-07-28T17:14:01.734118Z","shell.execute_reply.started":"2021-07-28T17:14:01.728348Z","shell.execute_reply":"2021-07-28T17:14:01.733291Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Generator_monet_to_photo.apply(temp_weights_init_normal);","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.737116Z","iopub.execute_input":"2021-07-28T17:14:01.737399Z","iopub.status.idle":"2021-07-28T17:14:01.759801Z","shell.execute_reply.started":"2021-07-28T17:14:01.737375Z","shell.execute_reply":"2021-07-28T17:14:01.759029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 9. Configure Optimizers","metadata":{}},{"cell_type":"code","source":"import itertools\n# lr = 0.0002\n# b1 = 0.5\n# b2 = 0.999\n\noptimizer_G = torch.optim.Adam(\n    itertools.chain(Generator_monet_to_photo.parameters(), Generator_photo_to_monet.parameters()), lr=lr, betas=(b1,b2)\n)\n\noptimizer_Discriminator_monet = torch.optim.Adam(\n    Discriminator_monet.parameters(), lr=lr, betas=(b1,b2)\n)\noptimizer_Discriminator_photo = torch.optim.Adam(\n    Discriminator_photo.parameters(), lr=lr, betas=(b1,b2)\n)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.760888Z","iopub.execute_input":"2021-07-28T17:14:01.761214Z","iopub.status.idle":"2021-07-28T17:14:01.76908Z","shell.execute_reply.started":"2021-07-28T17:14:01.761181Z","shell.execute_reply":"2021-07-28T17:14:01.768052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 10. Learning Rate Scheduler Setting","metadata":{}},{"cell_type":"code","source":"class LambdaLR:\n    def __init__(self, n_epochs, offset, decay_start_epoch):\n        assert (n_epochs - decay_start_epoch) > 0, \"Decay must start before the training session ends!\"\n        self.n_epochs = n_epochs\n        self.offset = offset\n        self.decay_start_epoch = decay_start_epoch\n        \n    def step(self, epoch):\n        return 1.0 - max(0, epoch+self.offset - self.decay_start_epoch)/(self.n_epochs - self.decay_start_epoch)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.770838Z","iopub.execute_input":"2021-07-28T17:14:01.771252Z","iopub.status.idle":"2021-07-28T17:14:01.777747Z","shell.execute_reply.started":"2021-07-28T17:14:01.771203Z","shell.execute_reply":"2021-07-28T17:14:01.776823Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# n_epochs = 10\n# epoch = 0\n# decay_epoch = 5\n\n\nlr_scheduler_G = torch.optim.lr_scheduler.LambdaLR(\n    optimizer_G,\n    lr_lambda=LambdaLR(n_epochs, epoch, decay_epoch).step\n)\n\nlr_scheduler_Discriminator_monet = torch.optim.lr_scheduler.LambdaLR(\n    optimizer_Discriminator_monet,\n    lr_lambda=LambdaLR(n_epochs, epoch, decay_epoch).step\n)\nlr_scheduler_Discriminator_photo = torch.optim.lr_scheduler.LambdaLR(\n    optimizer_Discriminator_photo,\n    lr_lambda=LambdaLR(n_epochs, epoch, decay_epoch).step\n)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.779169Z","iopub.execute_input":"2021-07-28T17:14:01.779946Z","iopub.status.idle":"2021-07-28T17:14:01.786482Z","shell.execute_reply.started":"2021-07-28T17:14:01.779873Z","shell.execute_reply":"2021-07-28T17:14:01.785601Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 11. Image Transformation Setting","metadata":{}},{"cell_type":"code","source":"from PIL import Image\nimport torchvision.transforms as transforms\n\ntransforms_ = [\n    transforms.Resize(int(img_height*1.12), Image.BICUBIC),\n    transforms.RandomCrop((img_height, img_width)),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n]\n\ntransforms_ = [\n    transforms.Resize(int(img_height*1.12), Image.BICUBIC),\n    transforms.RandomCrop((img_height, img_width)),\n    transforms.RandomHorizontalFlip(),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n]","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.787781Z","iopub.execute_input":"2021-07-28T17:14:01.788189Z","iopub.status.idle":"2021-07-28T17:14:01.798585Z","shell.execute_reply.started":"2021-07-28T17:14:01.788154Z","shell.execute_reply":"2021-07-28T17:14:01.797814Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 12. DataLoader Setting","metadata":{}},{"cell_type":"code","source":"def to_rgb(image):\n    rgb_image = Image.new(\"RGB\", image.size)\n    rgb_image.paste(image)\n    return rgb_image","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.799939Z","iopub.execute_input":"2021-07-28T17:14:01.800454Z","iopub.status.idle":"2021-07-28T17:14:01.807614Z","shell.execute_reply.started":"2021-07-28T17:14:01.800417Z","shell.execute_reply":"2021-07-28T17:14:01.806568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport glob","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.808756Z","iopub.execute_input":"2021-07-28T17:14:01.809198Z","iopub.status.idle":"2021-07-28T17:14:01.815973Z","shell.execute_reply.started":"2021-07-28T17:14:01.809165Z","shell.execute_reply":"2021-07-28T17:14:01.815157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(root+'/monet_jpg')","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.818721Z","iopub.execute_input":"2021-07-28T17:14:01.819404Z","iopub.status.idle":"2021-07-28T17:14:01.826373Z","shell.execute_reply.started":"2021-07-28T17:14:01.819007Z","shell.execute_reply":"2021-07-28T17:14:01.825296Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(glob.glob(os.path.join(root+'/monet_jpg')+'/*.*'))","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.827784Z","iopub.execute_input":"2021-07-28T17:14:01.828321Z","iopub.status.idle":"2021-07-28T17:14:01.960143Z","shell.execute_reply.started":"2021-07-28T17:14:01.828285Z","shell.execute_reply":"2021-07-28T17:14:01.959136Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(glob.glob(os.path.join(root+'/photo_jpg')+'/*.*'))","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:01.961349Z","iopub.execute_input":"2021-07-28T17:14:01.961762Z","iopub.status.idle":"2021-07-28T17:14:02.160906Z","shell.execute_reply.started":"2021-07-28T17:14:01.961726Z","shell.execute_reply":"2021-07-28T17:14:02.160222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import Dataset\n\nclass ImageDataset(Dataset):\n    def __init__(self, root, transforms_=None, unaligned=False, mode='train'):\n        self.transform = transforms.Compose(transforms_)\n        self.unaligned = unaligned\n        self.mode = mode\n        if self.mode == 'train':\n            self.files_Monet = sorted(glob.glob(os.path.join(root+'/monet_jpg')+'/*.*')[:25])\n            self.files_Photo = sorted(glob.glob(os.path.join(root+'/photo_jpg')+'/*.*')[:250])\n        elif self.mode == 'test':\n            self.files_Monet = sorted(glob.glob(os.path.join(root+'/monet_jpg')+'/*.*')[25:])\n            self.files_Photo = sorted(glob.glob(os.path.join(root+'/photo_jpg')+'/*.*')[250:301])\n        elif self.mode == 'all':\n            self.files_Monet = None\n            self.files_Photo = sorted(glob.glob(os.path.join(root+'/photo_jpg')+'/*.*'))\n\n    def  __getitem__(self, index):\n        if self.files_Monet is None:\n            image_Photo = Image.open(self.files_Photo[index % len(self.files_Photo)])\n            if image_Photo.mode != 'RGB':\n                image_Photo = to_rgb(image_Photo)\n            item_B = self.transform(image_Photo)\n            return {'B':item_B}\n        image_Monet = Image.open(self.files_Monet[index % len(self.files_Monet)])\n        \n        if self.unaligned:\n            image_Photo = Image.open(self.files_Photo[np.random.randint(0, len(self.files_Photo)-1)])\n        else:\n            image_Photo = Image.open(self.files_Photo[index % len(self.files_Photo)])\n        if image_Monet.mode != 'RGB':\n            image_Monet = to_rgb(image_Monet)\n        if image_Photo.mode != 'RGB':\n            image_Photo = to_rgb(image_Photo)\n            \n        item_A = self.transform(image_Monet)\n        item_B = self.transform(image_Photo)\n        return {'A':item_A, 'B':item_B}\n    \n    def __len__(self):\n        if self.mode == 'all':\n            return len(self.files_Photo)\n        return max(len(self.files_Monet), len(self.files_Photo))\n            ","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:02.162125Z","iopub.execute_input":"2021-07-28T17:14:02.162458Z","iopub.status.idle":"2021-07-28T17:14:02.178115Z","shell.execute_reply.started":"2021-07-28T17:14:02.162426Z","shell.execute_reply":"2021-07-28T17:14:02.177356Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataloader = DataLoader(\n    ImageDataset(root, transforms_=transforms_, unaligned=True),\n    batch_size=1, # 1\n    shuffle=True,\n    num_workers=n_cpu # 3\n)\n\nval_dataloader = DataLoader(\n    ImageDataset(root, transforms_=transforms_, unaligned=True, mode='test'),\n    batch_size=5,\n    shuffle=True,\n    num_workers=n_cpu\n)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:02.183789Z","iopub.execute_input":"2021-07-28T17:14:02.184039Z","iopub.status.idle":"2021-07-28T17:14:02.239926Z","shell.execute_reply.started":"2021-07-28T17:14:02.184016Z","shell.execute_reply":"2021-07-28T17:14:02.239206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 13. Define function to get sample images","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:02.24186Z","iopub.execute_input":"2021-07-28T17:14:02.242221Z","iopub.status.idle":"2021-07-28T17:14:02.246097Z","shell.execute_reply.started":"2021-07-28T17:14:02.242186Z","shell.execute_reply":"2021-07-28T17:14:02.245078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Tensor = torch.cuda.FloatTensor if cuda else torch.Tensor","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:02.247524Z","iopub.execute_input":"2021-07-28T17:14:02.247951Z","iopub.status.idle":"2021-07-28T17:14:02.254482Z","shell.execute_reply.started":"2021-07-28T17:14:02.247916Z","shell.execute_reply":"2021-07-28T17:14:02.253585Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def sample_images():\n    \"\"\"show a generated sample from the test set\"\"\"\n    imgs = next(iter(val_dataloader))\n    Generator_monet_to_photo.eval()\n    Generator_photo_to_monet.eval()\n    real_Monet = imgs['A'].type(Tensor) # A : monet\n    fake_Photo = Generator_monet_to_photo(real_Monet).detach()\n    real_Photo = imgs['B'].type(Tensor) # B : photo\n    fake_Monet = Generator_photo_to_monet(real_Photo).detach()\n    # Arange images along x-axis\n    real_Monet = make_grid(real_Monet, nrow=5, normalize=True)\n    fake_Photo = make_grid(fake_Photo, nrow=5, normalize=True)\n    real_Photo = make_grid(real_Photo, nrow=5, normalize=True)\n    fake_Monet = make_grid(fake_Monet, nrow=5, normalize=True)\n    # Arange images along y-axis    \n    image_grid = torch.cat((real_Monet, fake_Photo, real_Photo, fake_Monet), 1)\n    plt.imshow(image_grid.cpu().permute(1,2,0))\n    plt.title('Real A vs Fake B | Real B vs Fake A')\n    plt.axis('off')\n    plt.show();","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:02.255946Z","iopub.execute_input":"2021-07-28T17:14:02.256366Z","iopub.status.idle":"2021-07-28T17:14:02.264922Z","shell.execute_reply.started":"2021-07-28T17:14:02.256331Z","shell.execute_reply":"2021-07-28T17:14:02.264044Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> TEST CODE : show image data","metadata":{}},{"cell_type":"code","source":"temp_imgs = next(iter(val_dataloader))","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:02.266332Z","iopub.execute_input":"2021-07-28T17:14:02.26683Z","iopub.status.idle":"2021-07-28T17:14:02.686762Z","shell.execute_reply.started":"2021-07-28T17:14:02.266793Z","shell.execute_reply":"2021-07-28T17:14:02.685759Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Generator_monet_to_photo.eval() # test mode \nGenerator_photo_to_monet.eval() # test mode\nprint(temp_imgs['A'].shape)\nprint(temp_imgs['B'].shape)\n","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:02.690224Z","iopub.execute_input":"2021-07-28T17:14:02.690518Z","iopub.status.idle":"2021-07-28T17:14:02.698742Z","shell.execute_reply.started":"2021-07-28T17:14:02.690488Z","shell.execute_reply":"2021-07-28T17:14:02.697042Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_real_Monet = temp_imgs['A'].type(Tensor) # A : monet\ntemp_fake_Photo = Generator_monet_to_photo(temp_real_Monet).detach()\ntemp_real_Photo = temp_imgs['B'].type(Tensor) # B : photo\ntemp_fake_Monet = Generator_photo_to_monet(temp_real_Photo).detach()","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:02.700272Z","iopub.execute_input":"2021-07-28T17:14:02.700654Z","iopub.status.idle":"2021-07-28T17:14:03.63848Z","shell.execute_reply.started":"2021-07-28T17:14:02.700616Z","shell.execute_reply":"2021-07-28T17:14:03.637572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(temp_real_Monet.shape)\nprint(temp_fake_Photo.shape)\nprint(temp_real_Photo.shape)\nprint(temp_fake_Monet.shape)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:03.63983Z","iopub.execute_input":"2021-07-28T17:14:03.640157Z","iopub.status.idle":"2021-07-28T17:14:03.647323Z","shell.execute_reply.started":"2021-07-28T17:14:03.640122Z","shell.execute_reply":"2021-07-28T17:14:03.6463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_real_Monet = make_grid(temp_real_Monet, nrow=5, normalize=True)\ntemp_real_Photo = make_grid(temp_real_Photo, nrow=5, normalize=True)\ntemp_fake_Monet = make_grid(temp_fake_Monet, nrow=5, normalize=True)\ntemp_fake_Photo = make_grid(temp_fake_Photo, nrow=5, normalize=True)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:03.648987Z","iopub.execute_input":"2021-07-28T17:14:03.649519Z","iopub.status.idle":"2021-07-28T17:14:03.759024Z","shell.execute_reply.started":"2021-07-28T17:14:03.649423Z","shell.execute_reply":"2021-07-28T17:14:03.758309Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"type(temp_real_Monet)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:03.760437Z","iopub.execute_input":"2021-07-28T17:14:03.760772Z","iopub.status.idle":"2021-07-28T17:14:03.76655Z","shell.execute_reply.started":"2021-07-28T17:14:03.760738Z","shell.execute_reply":"2021-07-28T17:14:03.765553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=[100, 100])\nplt.imshow(temp_real_Monet.cpu().permute(1,2,0))\nplt.title('Real Monet')\nplt.axis('off');","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:03.76818Z","iopub.execute_input":"2021-07-28T17:14:03.768558Z","iopub.status.idle":"2021-07-28T17:14:04.909805Z","shell.execute_reply.started":"2021-07-28T17:14:03.768523Z","shell.execute_reply":"2021-07-28T17:14:04.908878Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(temp_real_Monet.shape)\nprint(temp_fake_Photo.shape)\nprint(temp_real_Photo.shape)\nprint(temp_fake_Monet.shape)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:04.911012Z","iopub.execute_input":"2021-07-28T17:14:04.9114Z","iopub.status.idle":"2021-07-28T17:14:04.916906Z","shell.execute_reply.started":"2021-07-28T17:14:04.911355Z","shell.execute_reply":"2021-07-28T17:14:04.916195Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_image_grid = torch.cat((temp_real_Monet, temp_fake_Monet, temp_real_Photo, temp_fake_Photo), 1)\nprint(temp_image_grid.shape)","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:04.918096Z","iopub.execute_input":"2021-07-28T17:14:04.918579Z","iopub.status.idle":"2021-07-28T17:14:04.931719Z","shell.execute_reply.started":"2021-07-28T17:14:04.918537Z","shell.execute_reply":"2021-07-28T17:14:04.930758Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_image_grid.cpu().permute(1,2,0).shape","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:04.932993Z","iopub.execute_input":"2021-07-28T17:14:04.933548Z","iopub.status.idle":"2021-07-28T17:14:04.943828Z","shell.execute_reply.started":"2021-07-28T17:14:04.933512Z","shell.execute_reply":"2021-07-28T17:14:04.943026Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=[100, 100])\nplt.imshow(temp_image_grid.cpu().permute(1,2,0))\nplt.title('Real A | Fake B | Real B | Fake A ')\nplt.axis('off');","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:04.944859Z","iopub.execute_input":"2021-07-28T17:14:04.945288Z","iopub.status.idle":"2021-07-28T17:14:10.330398Z","shell.execute_reply.started":"2021-07-28T17:14:04.945256Z","shell.execute_reply":"2021-07-28T17:14:10.327068Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 14. Training","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom tqdm.notebook import tqdm\nimport warnings","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:10.331788Z","iopub.execute_input":"2021-07-28T17:14:10.332747Z","iopub.status.idle":"2021-07-28T17:14:10.340605Z","shell.execute_reply.started":"2021-07-28T17:14:10.332699Z","shell.execute_reply":"2021-07-28T17:14:10.337343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss_vals=  []\nfor epoch in range(epoch, n_epochs):\n    epoch_loss= []\n    for i, batch in enumerate(tqdm(dataloader)):\n        \n        # Set model input\n        real_Monet = batch['A'].type(Tensor)\n        real_Photo = batch['B'].type(Tensor)\n        \n        # Adversarial ground truths\n        valid = Tensor(np.ones((real_Monet.size(0), *Discriminator_monet.output_shape))) # requires_grad = False. Default.\n        fake = Tensor(np.zeros((real_Monet.size(0), *Discriminator_monet.output_shape))) # requires_grad = False. Default.\n        \n# -----------------\n# Train Generators\n# -----------------\n        Generator_monet_to_photo.train() # train mode\n        Generator_photo_to_monet.train() # train mode\n        \n        optimizer_G.zero_grad() # Integrated optimizer(Generator_monet_to_photo, Generator_photo_to_monet)\n        \n        # Identity Loss\n        loss_Identity_Monet = criterion_identity(Generator_photo_to_monet(real_Monet), real_Monet) # If you put A into a generator that creates A with B,\n        loss_Identity_Photo = criterion_identity(Generator_monet_to_photo(real_Photo), real_Photo) # then of course A must come out as it is.\n                                                             # Taking this into consideration, add an identity loss that simply compares 'A and A' (or 'B and B').\n        loss_identity = (loss_Identity_Monet + loss_Identity_Photo)/2\n        \n        # GAN Loss\n        fake_Photo = Generator_monet_to_photo(real_Monet) # fake_Photo is fake-photo that generated by real monet-drawing\n        loss_GAN_M2P = criterion_GAN(Discriminator_photo(fake_Photo), valid) # tricking the 'fake-B' into 'real-B'\n        fake_Monet = Generator_photo_to_monet(real_Photo)\n        loss_GAN_P2M = criterion_GAN(Discriminator_monet(fake_Monet), valid) # tricking the 'fake-A' into 'real-A'\n        \n        loss_GAN = (loss_GAN_M2P + loss_GAN_P2M)/2\n        \n        # Cycle Loss\n        recov_A = Generator_photo_to_monet(fake_Photo) # recov_A is fake-monet-drawing that generated by fake-photo\n        loss_cycle_Monet = criterion_cycle(recov_A, real_Monet) # Reduces the difference between the restored image and the real image\n        recov_B = Generator_monet_to_photo(fake_Monet)\n        loss_cycle_Photo = criterion_cycle(recov_B, real_Photo)\n        \n        loss_cycle = (loss_cycle_Monet + loss_cycle_Photo)/2\n        \n# ------> Total Loss\n        loss_G = loss_GAN + (10.0*loss_cycle) + (5.0*loss_identity) # multiply suggested weight(default cycle loss weight : 10, default identity loss weight : 5)\n        \n        loss_G.backward()\n        epoch_loss.append(loss_G.item())\n        optimizer_G.step()\n        \n# -----------------\n# Train Discriminator Monet\n# -----------------\n        optimizer_Discriminator_monet.zero_grad()\n    \n        loss_real = criterion_GAN(Discriminator_monet(real_Monet), valid) # train to discriminate real images as real\n        loss_fake = criterion_GAN(Discriminator_monet(fake_Monet.detach()), fake) # train to discriminate fake images as fake\n        \n        loss_Discriminator_monet = (loss_real + loss_fake)/2\n        \n        loss_Discriminator_monet.backward()\n        optimizer_Discriminator_monet.step()\n\n# -----------------\n# Train Discriminator Photo\n# -----------------\n        optimizer_Discriminator_photo.zero_grad()\n    \n        loss_real = criterion_GAN(Discriminator_photo(real_Photo), valid) # train to discriminate real images as real\n        loss_fake = criterion_GAN(Discriminator_photo(fake_Photo.detach()), fake) # train to discriminate fake images as fake\n        \n        loss_Discriminator_photo = (loss_real + loss_fake)/2\n        \n        loss_Discriminator_photo.backward()\n        optimizer_Discriminator_photo.step()\n        \n# ------> Total Loss\n        loss_D = (loss_Discriminator_monet + loss_Discriminator_photo)/2\n    \n# -----------------\n# Show Progress\n# -----------------\n        if (i+1) % 50 == 0:\n            sample_images()\n            print('[Epoch %d/%d] [Batch %d/%d] [D loss : %f] [G loss : %f - (adv : %f, cycle : %f, identity : %f)]'\n                    %(epoch+1,n_epochs,       # [Epoch -]\n                      i+1,len(dataloader),   # [Batch -]\n                      loss_D.item(),       # [D loss -]\n                      loss_G.item(),       # [G loss -]\n                      loss_GAN.item(),     # [adv -]\n                      loss_cycle.item(),   # [cycle -]\n                      loss_identity.item(),# [identity -]\n                     ))\n    loss_vals.append(sum(epoch_loss)/len(epoch_loss))\n    print(loss_vals)\n","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:14:10.342252Z","iopub.execute_input":"2021-07-28T17:14:10.342608Z","iopub.status.idle":"2021-07-28T17:42:16.374492Z","shell.execute_reply.started":"2021-07-28T17:14:10.34257Z","shell.execute_reply":"2021-07-28T17:42:16.373584Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def my_plot(epochs, loss,title):\n    plt.title(title)\n    plt.plot(epochs, loss)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# show Generetors Loss\nmy_plot(np.linspace(1, n_epochs, n_epochs).astype(int), loss_vals,\"Generetors Loss\")","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Submission**","metadata":{}},{"cell_type":"code","source":"#Directory\n! mkdir ../images","metadata":{"execution":{"iopub.status.busy":"2021-07-28T17:42:16.842645Z","iopub.execute_input":"2021-07-28T17:42:16.843029Z","iopub.status.idle":"2021-07-28T17:42:17.51115Z","shell.execute_reply.started":"2021-07-28T17:42:16.842996Z","shell.execute_reply":"2021-07-28T17:42:17.510139Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pwd","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def reverse_normalize(image, mean_=0.5, std_=0.5):\n    if torch.is_tensor(image):\n        image = image.detach().numpy()\n    un_normalized_img = image * std_ + mean_\n    un_normalized_img = un_normalized_img * 255\n    return np.uint8(un_normalized_img)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Generator_photo_to_monet.eval() # test mode\n\nmean_=0.5 \nstd_=0.5\n\n#Get data loader for final transformation / submission\nsubmit_dataloader  = DataLoader(\n    ImageDataset(root, \n                 transforms_=transforms_, unaligned=False,mode='all'),\n    batch_size=1, # 1\n    shuffle=False,\n    num_workers=n_cpu # 3\n)\nprint(len(submit_dataloader))\ndataiter = iter(submit_dataloader)\n#Loop through each picture\nfor image_idx in range(0, len(submit_dataloader)):\n    #Get base picture\n    fixed_X = next(dataiter)\n    real_Photo = fixed_X['B'].type(Tensor) # B : photo\n    #Identify correct device\n    device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n    fake_Monet_monet = Generator_photo_to_monet(real_Photo)\n    image1_numpy = fake_Monet_monet.detach().cpu().numpy()\n    image1_numpy= np.squeeze(image1_numpy, axis=0)\n    image1_numpy = image1_numpy.transpose(1, 2, 0)\n    image1_numpy = reverse_normalize(image1_numpy, mean_, std_)\n    image1_numpy = np.uint8(image1_numpy)\n    image_i = Image.fromarray(image1_numpy)\n    print(image1_numpy.shape)\n    #Save picture\n    image_i.save(\"../images/\" + str(image_idx) + \".jpg\")\n\n    \n    ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}