{"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":"# CycleGAN Tutorial from Scratch\ncyclegan is a pix2pix image generation model that generates images from datasets that do not require pairs.\n\nWe will implement this cyclegan directly from the ground up with pytorch, and practice converting monet pictures into pictures and pictures into monet pictures.\n","metadata":{}},{"cell_type":"markdown","source":"# CycleGAN : Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks\n\n[--> Paper](https://openaccess.thecvf.com/content_ICCV_2017/papers/Zhu_Unpaired_Image-To-Image_Translation_ICCV_2017_paper.pdf)\n\n![--> Paper](https://openaccess.thecvf.com/content_ICCV_2017/papers/Zhu_Unpaired_Image-To-Image_Translation_ICCV_2017_paper.pdf)","metadata":{}},{"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":"We will implement the following structure with `PyTorch`","metadata":{}},{"cell_type":"markdown","source":"![image](https://miro.medium.com/max/1838/0*S5gn5i6UhfyoRr9S.png)","metadata":{"execution":{"iopub.status.busy":"2021-06-23T16:22:40.014582Z","iopub.execute_input":"2021-06-23T16:22:40.014954Z","iopub.status.idle":"2021-06-23T16:22:40.654991Z","shell.execute_reply.started":"2021-06-23T16:22:40.014874Z","shell.execute_reply":"2021-06-23T16:22:40.654065Z"}}},{"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-06-17T14:51:25.201826Z","iopub.execute_input":"2021-06-17T14:51:25.202248Z","iopub.status.idle":"2021-06-17T14:51:26.404929Z","shell.execute_reply.started":"2021-06-17T14:51:25.202212Z","shell.execute_reply":"2021-06-17T14:51:26.40402Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 2. Initial Setting","metadata":{}},{"cell_type":"code","source":"# number of cpu (in kaggle server)\n!cat /proc/cpuinfo | grep processor","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:58:07.359408Z","iopub.execute_input":"2021-06-17T14:58:07.359731Z","iopub.status.idle":"2021-06-17T14:58:08.017679Z","shell.execute_reply.started":"2021-06-17T14:58:07.359701Z","shell.execute_reply":"2021-06-17T14:58:08.016768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_cpu = 2 # number of cpu threads to use during batch generation","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:51:39.920769Z","iopub.execute_input":"2021-06-17T14:51:39.921317Z","iopub.status.idle":"2021-06-17T14:51:39.925728Z","shell.execute_reply.started":"2021-06-17T14:51:39.921249Z","shell.execute_reply":"2021-06-17T14:51:39.924575Z"},"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 = 5 # 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-06-17T14:52:38.161088Z","iopub.execute_input":"2021-06-17T14:52:38.161475Z","iopub.status.idle":"2021-06-17T14:52:38.167352Z","shell.execute_reply.started":"2021-06-17T14:52:38.161433Z","shell.execute_reply":"2021-06-17T14:52:38.165799Z"},"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-06-17T14:52:38.48251Z","iopub.execute_input":"2021-06-17T14:52:38.482796Z","iopub.status.idle":"2021-06-17T14:52:38.49435Z","shell.execute_reply.started":"2021-06-17T14:52:38.48277Z","shell.execute_reply":"2021-06-17T14:52:38.493498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> TEST CODE : nn.Upsample","metadata":{}},{"cell_type":"code","source":"tensor = torch.from_numpy(np.random.randn(2,2))","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:39.348592Z","iopub.execute_input":"2021-06-17T14:52:39.348906Z","iopub.status.idle":"2021-06-17T14:52:39.359219Z","shell.execute_reply.started":"2021-06-17T14:52:39.348876Z","shell.execute_reply":"2021-06-17T14:52:39.358269Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tensor","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:40.200055Z","iopub.execute_input":"2021-06-17T14:52:40.200389Z","iopub.status.idle":"2021-06-17T14:52:40.288574Z","shell.execute_reply.started":"2021-06-17T14:52:40.20036Z","shell.execute_reply":"2021-06-17T14:52:40.287567Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tensor = tensor.view(1,1,2,2)\ntensor # nn.Upsample get only 3/4/5D tensor","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:40.400909Z","iopub.execute_input":"2021-06-17T14:52:40.401424Z","iopub.status.idle":"2021-06-17T14:52:40.408492Z","shell.execute_reply.started":"2021-06-17T14:52:40.401382Z","shell.execute_reply":"2021-06-17T14:52:40.407659Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_m = nn.Upsample(scale_factor=2)\ntest_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:40.600323Z","iopub.execute_input":"2021-06-17T14:52:40.601157Z","iopub.status.idle":"2021-06-17T14:52:40.621441Z","shell.execute_reply.started":"2021-06-17T14:52:40.601109Z","shell.execute_reply":"2021-06-17T14:52:40.62064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> Read More\n- [torch.nn.ReflectionPad2d(padding)](https://pytorch.org/docs/stable/generated/torch.nn.ReflectionPad2d.html)\n- [torch.nn.InstanceNorm2d(num_features, ...)](https://pytorch.org/docs/stable/generated/torch.nn.InstanceNorm2d.html)\n    - Example : Compare 4dim-Normalization methods,https://wdprogrammer.tistory.com/67\n\n![image](https://www.notion.so/image/https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2Fa23e53c6-47a1-4ae6-96b0-f4836b5d82a8%2FUntitled.png?table=block&id=2e5405fd-24c7-49e1-aa2e-69a80d8b4bf4&width=2800&cache=v2)\n- [torch.nn.Upsample(size=None, scale_factor=None, mode='nearest', align_corners=None)](https://pytorch.org/docs/stable/generated/torch.nn.Upsample.html)","metadata":{}},{"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-06-17T14:52:41.148111Z","iopub.execute_input":"2021-06-17T14:52:41.148447Z","iopub.status.idle":"2021-06-17T14:52:41.157216Z","shell.execute_reply.started":"2021-06-17T14:52:41.148418Z","shell.execute_reply":"2021-06-17T14:52:41.155925Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> TEST CODE : nn.ZeroPad2d","metadata":{}},{"cell_type":"code","source":"tensor = torch.from_numpy(np.random.randn(2,2))\ntensor","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:41.479541Z","iopub.execute_input":"2021-06-17T14:52:41.479815Z","iopub.status.idle":"2021-06-17T14:52:41.485676Z","shell.execute_reply.started":"2021-06-17T14:52:41.479788Z","shell.execute_reply":"2021-06-17T14:52:41.484854Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_m = nn.ZeroPad2d((1,0,0,0)) # Padding_left\ntest_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:41.651802Z","iopub.execute_input":"2021-06-17T14:52:41.652134Z","iopub.status.idle":"2021-06-17T14:52:41.660857Z","shell.execute_reply.started":"2021-06-17T14:52:41.652105Z","shell.execute_reply":"2021-06-17T14:52:41.659806Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_m = nn.ZeroPad2d((0,1,0,0)) # Padding_right\ntest_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:41.839507Z","iopub.execute_input":"2021-06-17T14:52:41.839748Z","iopub.status.idle":"2021-06-17T14:52:41.845802Z","shell.execute_reply.started":"2021-06-17T14:52:41.839723Z","shell.execute_reply":"2021-06-17T14:52:41.844897Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_m = nn.ZeroPad2d((0,0,1,0)) # Padding_top\ntest_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:41.992019Z","iopub.execute_input":"2021-06-17T14:52:41.992363Z","iopub.status.idle":"2021-06-17T14:52:41.998864Z","shell.execute_reply.started":"2021-06-17T14:52:41.99233Z","shell.execute_reply":"2021-06-17T14:52:41.997916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_m = nn.ZeroPad2d((0,0,0,1)) # Padding_bottom\ntest_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:42.179632Z","iopub.execute_input":"2021-06-17T14:52:42.179908Z","iopub.status.idle":"2021-06-17T14:52:42.187689Z","shell.execute_reply.started":"2021-06-17T14:52:42.179882Z","shell.execute_reply":"2021-06-17T14:52:42.185448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_m = nn.ZeroPad2d((1,0,1,0)) # Padding_left and Padding_top\ntest_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:42.351677Z","iopub.execute_input":"2021-06-17T14:52:42.351922Z","iopub.status.idle":"2021-06-17T14:52:42.359116Z","shell.execute_reply.started":"2021-06-17T14:52:42.351897Z","shell.execute_reply":"2021-06-17T14:52:42.35814Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Step 5. Define Loss","metadata":{}},{"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-06-17T14:52:42.699658Z","iopub.execute_input":"2021-06-17T14:52:42.69993Z","iopub.status.idle":"2021-06-17T14:52:42.70416Z","shell.execute_reply.started":"2021-06-17T14:52:42.699903Z","shell.execute_reply":"2021-06-17T14:52:42.703337Z"},"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\nG_AB = GeneratorResNet(input_shape, n_residual_blocks)\nG_BA = GeneratorResNet(input_shape, n_residual_blocks)\nD_A = Discriminator(input_shape)\nD_B = Discriminator(input_shape)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:43.039848Z","iopub.execute_input":"2021-06-17T14:52:43.040198Z","iopub.status.idle":"2021-06-17T14:52:43.277338Z","shell.execute_reply.started":"2021-06-17T14:52:43.040167Z","shell.execute_reply":"2021-06-17T14:52:43.276449Z"},"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    G_AB = G_AB.cuda()\n    G_BA = G_BA.cuda()\n    D_A = D_A.cuda()\n    D_B = D_B.cuda()\n    \n    criterion_GAN.cuda()\n    criterion_cycle.cuda()\n    criterion_identity.cuda()","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:43.39247Z","iopub.execute_input":"2021-06-17T14:52:43.392812Z","iopub.status.idle":"2021-06-17T14:52:47.896581Z","shell.execute_reply.started":"2021-06-17T14:52:43.39278Z","shell.execute_reply":"2021-06-17T14:52:47.895581Z"},"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-06-17T14:52:47.898265Z","iopub.execute_input":"2021-06-17T14:52:47.898638Z","iopub.status.idle":"2021-06-17T14:52:47.906837Z","shell.execute_reply.started":"2021-06-17T14:52:47.898597Z","shell.execute_reply":"2021-06-17T14:52:47.906088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"G_AB.apply(weights_init_normal)\nG_BA.apply(weights_init_normal)\nD_A.apply(weights_init_normal)\nD_B.apply(weights_init_normal)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:47.909884Z","iopub.execute_input":"2021-06-17T14:52:47.910148Z","iopub.status.idle":"2021-06-17T14:52:47.930737Z","shell.execute_reply.started":"2021-06-17T14:52:47.910124Z","shell.execute_reply":"2021-06-17T14:52:47.929772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> TEST CODE : `__class__.__name__`\n","metadata":{}},{"cell_type":"code","source":"def temp_weights_init_normal(m):\n    classname =  m.__class__.__name__\n    print(classname)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:47.932521Z","iopub.execute_input":"2021-06-17T14:52:47.932938Z","iopub.status.idle":"2021-06-17T14:52:47.939126Z","shell.execute_reply.started":"2021-06-17T14:52:47.932899Z","shell.execute_reply":"2021-06-17T14:52:47.938219Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"G_AB.apply(temp_weights_init_normal);","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:47.94023Z","iopub.execute_input":"2021-06-17T14:52:47.940496Z","iopub.status.idle":"2021-06-17T14:52:47.960636Z","shell.execute_reply.started":"2021-06-17T14:52:47.940473Z","shell.execute_reply":"2021-06-17T14:52:47.959986Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"`torch.nn.init.normal_(tensor, mean=0.0, std=1.0)`\n- Fills the input Tensor with values drawn from the normal distribution N(mean, std^2)","metadata":{}},{"cell_type":"code","source":"temp_w = torch.ones(2,5)\ntemp_w","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:47.963134Z","iopub.execute_input":"2021-06-17T14:52:47.963365Z","iopub.status.idle":"2021-06-17T14:52:47.974209Z","shell.execute_reply.started":"2021-06-17T14:52:47.963342Z","shell.execute_reply":"2021-06-17T14:52:47.973332Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"nn.init.normal_(temp_w)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:47.975318Z","iopub.execute_input":"2021-06-17T14:52:47.975777Z","iopub.status.idle":"2021-06-17T14:52:47.98543Z","shell.execute_reply.started":"2021-06-17T14:52:47.975752Z","shell.execute_reply":"2021-06-17T14:52:47.984522Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"`torch.nn.init.constant_(tensor, val)`\n- Fills the input Tensor with value `val`\n","metadata":{}},{"cell_type":"code","source":"temp_w2 = torch.empty(2,5)\ntemp_w2","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:51.847392Z","iopub.execute_input":"2021-06-17T14:52:51.847746Z","iopub.status.idle":"2021-06-17T14:52:51.856434Z","shell.execute_reply.started":"2021-06-17T14:52:51.847713Z","shell.execute_reply":"2021-06-17T14:52:51.855251Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"nn.init.constant_(temp_w2, 1)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:52.237669Z","iopub.execute_input":"2021-06-17T14:52:52.237994Z","iopub.status.idle":"2021-06-17T14:52:52.244832Z","shell.execute_reply.started":"2021-06-17T14:52:52.237946Z","shell.execute_reply":"2021-06-17T14:52:52.243982Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> Read More\n- [Torch.nn.init](https://pytorch.org/docs/stable/nn.init.html)","metadata":{}},{"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(G_AB.parameters(), G_BA.parameters()), lr=lr, betas=(b1,b2)\n)\n\noptimizer_D_A = torch.optim.Adam(\n    D_A.parameters(), lr=lr, betas=(b1,b2)\n)\noptimizer_D_B = torch.optim.Adam(\n    D_B.parameters(), lr=lr, betas=(b1,b2)\n)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:54.320286Z","iopub.execute_input":"2021-06-17T14:52:54.320628Z","iopub.status.idle":"2021-06-17T14:52:54.328607Z","shell.execute_reply.started":"2021-06-17T14:52:54.320596Z","shell.execute_reply":"2021-06-17T14:52:54.32751Z"},"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-06-17T14:52:56.008113Z","iopub.execute_input":"2021-06-17T14:52:56.008479Z","iopub.status.idle":"2021-06-17T14:52:56.014049Z","shell.execute_reply.started":"2021-06-17T14:52:56.00845Z","shell.execute_reply":"2021-06-17T14:52:56.01311Z"},"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_D_A = torch.optim.lr_scheduler.LambdaLR(\n    optimizer_D_A,\n    lr_lambda=LambdaLR(n_epochs, epoch, decay_epoch).step\n)\nlr_scheduler_D_B = torch.optim.lr_scheduler.LambdaLR(\n    optimizer_D_B,\n    lr_lambda=LambdaLR(n_epochs, epoch, decay_epoch).step\n)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:56.152383Z","iopub.execute_input":"2021-06-17T14:52:56.152681Z","iopub.status.idle":"2021-06-17T14:52:56.158916Z","shell.execute_reply.started":"2021-06-17T14:52:56.152634Z","shell.execute_reply":"2021-06-17T14:52:56.158062Z"},"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]","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:58.20839Z","iopub.execute_input":"2021-06-17T14:52:58.208718Z","iopub.status.idle":"2021-06-17T14:52:58.215941Z","shell.execute_reply.started":"2021-06-17T14:52:58.208686Z","shell.execute_reply":"2021-06-17T14:52:58.215Z"},"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-06-17T14:52:58.539523Z","iopub.execute_input":"2021-06-17T14:52:58.539799Z","iopub.status.idle":"2021-06-17T14:52:58.544497Z","shell.execute_reply.started":"2021-06-17T14:52:58.539771Z","shell.execute_reply":"2021-06-17T14:52:58.543551Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport glob","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:58.711625Z","iopub.execute_input":"2021-06-17T14:52:58.711873Z","iopub.status.idle":"2021-06-17T14:52:58.715588Z","shell.execute_reply.started":"2021-06-17T14:52:58.711848Z","shell.execute_reply":"2021-06-17T14:52:58.714802Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(root+'/monet_jpg')","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:58.891634Z","iopub.execute_input":"2021-06-17T14:52:58.891917Z","iopub.status.idle":"2021-06-17T14:52:58.896186Z","shell.execute_reply.started":"2021-06-17T14:52:58.891889Z","shell.execute_reply":"2021-06-17T14:52:58.89521Z"},"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-06-17T14:52:59.071765Z","iopub.execute_input":"2021-06-17T14:52:59.072096Z","iopub.status.idle":"2021-06-17T14:52:59.139263Z","shell.execute_reply.started":"2021-06-17T14:52:59.072064Z","shell.execute_reply":"2021-06-17T14:52:59.138442Z"},"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-06-17T14:52:59.25959Z","iopub.execute_input":"2021-06-17T14:52:59.259856Z","iopub.status.idle":"2021-06-17T14:52:59.524725Z","shell.execute_reply.started":"2021-06-17T14:52:59.25983Z","shell.execute_reply":"2021-06-17T14:52:59.523987Z"},"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_A = sorted(glob.glob(os.path.join(root+'/monet_jpg')+'/*.*')[:250])\n            self.files_B = sorted(glob.glob(os.path.join(root+'/photo_jpg')+'/*.*')[:250])\n        elif self.mode == 'test':\n            self.files_A = sorted(glob.glob(os.path.join(root+'/monet_jpg')+'/*.*')[250:])\n            self.files_B = sorted(glob.glob(os.path.join(root+'/photo_jpg')+'/*.*')[250:301])\n\n    def  __getitem__(self, index):\n        image_A = Image.open(self.files_A[index % len(self.files_A)])\n        \n        if self.unaligned:\n            image_B = Image.open(self.files_B[np.random.randint(0, len(self.files_B)-1)])\n        else:\n            image_B = Image.open(self.files_B[index % len(self.files_B)])\n        if image_A.mode != 'RGB':\n            image_A = to_rgb(image_A)\n        if image_B.mode != 'RGB':\n            image_B = to_rgb(image_B)\n            \n        item_A = self.transform(image_A)\n        item_B = self.transform(image_B)\n        return {'A':item_A, 'B':item_B}\n    \n    def __len__(self):\n        return max(len(self.files_A), len(self.files_B))\n            ","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:52:59.526107Z","iopub.execute_input":"2021-06-17T14:52:59.526439Z","iopub.status.idle":"2021-06-17T14:52:59.539249Z","shell.execute_reply.started":"2021-06-17T14:52:59.526403Z","shell.execute_reply":"2021-06-17T14:52:59.538331Z"},"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-06-17T14:52:59.671813Z","iopub.execute_input":"2021-06-17T14:52:59.672102Z","iopub.status.idle":"2021-06-17T14:52:59.725546Z","shell.execute_reply.started":"2021-06-17T14:52:59.672075Z","shell.execute_reply":"2021-06-17T14:52:59.724835Z"},"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-06-17T14:53:00.882123Z","iopub.execute_input":"2021-06-17T14:53:00.882452Z","iopub.status.idle":"2021-06-17T14:53:00.888871Z","shell.execute_reply.started":"2021-06-17T14:53:00.882424Z","shell.execute_reply":"2021-06-17T14:53:00.88801Z"},"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-06-17T14:53:01.039609Z","iopub.execute_input":"2021-06-17T14:53:01.039877Z","iopub.status.idle":"2021-06-17T14:53:01.043624Z","shell.execute_reply.started":"2021-06-17T14:53:01.039851Z","shell.execute_reply":"2021-06-17T14:53:01.042629Z"},"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    G_AB.eval()\n    G_BA.eval()\n    real_A = imgs['A'].type(Tensor) # A : monet\n    fake_B = G_AB(real_A).detach()\n    real_B = imgs['B'].type(Tensor) # B : photo\n    fake_A = G_BA(real_B).detach()\n    # Arange images along x-axis\n    real_A = make_grid(real_A, nrow=5, normalize=True)\n    fake_B = make_grid(fake_B, nrow=5, normalize=True)\n    real_B = make_grid(real_B, nrow=5, normalize=True)\n    fake_A = make_grid(fake_A, nrow=5, normalize=True)\n    # Arange images along y-axis    \n    image_grid = torch.cat((real_A, fake_B, real_B, fake_A), 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-06-17T14:53:01.220703Z","iopub.execute_input":"2021-06-17T14:53:01.220992Z","iopub.status.idle":"2021-06-17T14:53:01.227679Z","shell.execute_reply.started":"2021-06-17T14:53:01.220944Z","shell.execute_reply":"2021-06-17T14:53:01.226741Z"},"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-06-17T14:53:01.960011Z","iopub.execute_input":"2021-06-17T14:53:01.960362Z","iopub.status.idle":"2021-06-17T14:53:02.289779Z","shell.execute_reply.started":"2021-06-17T14:53:01.960331Z","shell.execute_reply":"2021-06-17T14:53:02.288731Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"G_AB.eval() # test mode \nG_BA.eval() # test mode\nprint(temp_imgs['A'].shape)\nprint(temp_imgs['B'].shape)\n","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:53:02.293216Z","iopub.execute_input":"2021-06-17T14:53:02.29349Z","iopub.status.idle":"2021-06-17T14:53:02.30225Z","shell.execute_reply.started":"2021-06-17T14:53:02.29346Z","shell.execute_reply":"2021-06-17T14:53:02.300668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_real_A = temp_imgs['A'].type(Tensor) # A : monet\ntemp_fake_B = G_AB(temp_real_A).detach()\ntemp_real_B = temp_imgs['B'].type(Tensor) # B : photo\ntemp_fake_A = G_BA(temp_real_B).detach()","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:53:02.819773Z","iopub.execute_input":"2021-06-17T14:53:02.820088Z","iopub.status.idle":"2021-06-17T14:53:03.773977Z","shell.execute_reply.started":"2021-06-17T14:53:02.820057Z","shell.execute_reply":"2021-06-17T14:53:03.773125Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(temp_real_A.shape)\nprint(temp_fake_B.shape)\nprint(temp_real_B.shape)\nprint(temp_fake_A.shape)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:53:03.775485Z","iopub.execute_input":"2021-06-17T14:53:03.775827Z","iopub.status.idle":"2021-06-17T14:53:03.782653Z","shell.execute_reply.started":"2021-06-17T14:53:03.77579Z","shell.execute_reply":"2021-06-17T14:53:03.78168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_real_A = make_grid(temp_real_A, nrow=5, normalize=True)\ntemp_real_B = make_grid(temp_real_B, nrow=5, normalize=True)\ntemp_fake_A = make_grid(temp_fake_A, nrow=5, normalize=True)\ntemp_fake_B = make_grid(temp_fake_B, nrow=5, normalize=True)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:53:03.784718Z","iopub.execute_input":"2021-06-17T14:53:03.785285Z","iopub.status.idle":"2021-06-17T14:53:03.893275Z","shell.execute_reply.started":"2021-06-17T14:53:03.785248Z","shell.execute_reply":"2021-06-17T14:53:03.892505Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"type(temp_real_A)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:53:03.895933Z","iopub.execute_input":"2021-06-17T14:53:03.896196Z","iopub.status.idle":"2021-06-17T14:53:03.901539Z","shell.execute_reply.started":"2021-06-17T14:53:03.896171Z","shell.execute_reply":"2021-06-17T14:53:03.900541Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(temp_real_A.cpu().permute(1,2,0))\nplt.title('Real A')\nplt.axis('off');","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:53:03.903029Z","iopub.execute_input":"2021-06-17T14:53:03.9038Z","iopub.status.idle":"2021-06-17T14:53:04.051987Z","shell.execute_reply.started":"2021-06-17T14:53:03.903762Z","shell.execute_reply":"2021-06-17T14:53:04.051121Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(temp_real_A.shape)\nprint(temp_fake_B.shape)\nprint(temp_real_B.shape)\nprint(temp_fake_A.shape)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:53:04.05303Z","iopub.execute_input":"2021-06-17T14:53:04.053345Z","iopub.status.idle":"2021-06-17T14:53:04.060784Z","shell.execute_reply.started":"2021-06-17T14:53:04.053313Z","shell.execute_reply":"2021-06-17T14:53:04.059684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_image_grid = torch.cat((temp_real_A, temp_fake_A, temp_real_B, temp_fake_B), 1)\nprint(temp_image_grid.shape)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:57:18.812848Z","iopub.execute_input":"2021-06-17T14:57:18.813282Z","iopub.status.idle":"2021-06-17T14:57:18.819579Z","shell.execute_reply.started":"2021-06-17T14:57:18.813237Z","shell.execute_reply":"2021-06-17T14:57:18.818542Z"},"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-06-17T14:57:19.072506Z","iopub.execute_input":"2021-06-17T14:57:19.072848Z","iopub.status.idle":"2021-06-17T14:57:19.092942Z","shell.execute_reply.started":"2021-06-17T14:57:19.072814Z","shell.execute_reply":"2021-06-17T14:57:19.091904Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.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-06-17T14:57:19.094838Z","iopub.execute_input":"2021-06-17T14:57:19.095221Z","iopub.status.idle":"2021-06-17T14:57:19.415622Z","shell.execute_reply.started":"2021-06-17T14:57:19.095179Z","shell.execute_reply":"2021-06-17T14:57:19.414631Z"},"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-06-17T14:57:25.181117Z","iopub.execute_input":"2021-06-17T14:57:25.181526Z","iopub.status.idle":"2021-06-17T14:57:25.188604Z","shell.execute_reply.started":"2021-06-17T14:57:25.181452Z","shell.execute_reply":"2021-06-17T14:57:25.187687Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for epoch in range(epoch, n_epochs):\n    for i, batch in enumerate(tqdm(dataloader)):\n        \n        # Set model input\n        real_A = batch['A'].type(Tensor)\n        real_B = batch['B'].type(Tensor)\n        \n        # Adversarial ground truths\n        valid = Tensor(np.ones((real_A.size(0), *D_A.output_shape))) # requires_grad = False. Default.\n        fake = Tensor(np.zeros((real_A.size(0), *D_A.output_shape))) # requires_grad = False. Default.\n        \n# -----------------\n# Train Generators\n# -----------------\n        G_AB.train() # train mode\n        G_BA.train() # train mode\n        \n        optimizer_G.zero_grad() # Integrated optimizer(G_AB, G_BA)\n        \n        # Identity Loss\n        loss_id_A = criterion_identity(G_BA(real_A), real_A) # If you put A into a generator that creates A with B,\n        loss_id_B = criterion_identity(G_AB(real_B), real_B) # 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_id_A + loss_id_B)/2\n        \n        # GAN Loss\n        fake_B = G_AB(real_A) # fake_B is fake-photo that generated by real monet-drawing\n        loss_GAN_AB = criterion_GAN(D_B(fake_B), valid) # tricking the 'fake-B' into 'real-B'\n        fake_A = G_BA(real_B)\n        loss_GAN_BA = criterion_GAN(D_A(fake_A), valid) # tricking the 'fake-A' into 'real-A'\n        \n        loss_GAN = (loss_GAN_AB + loss_GAN_BA)/2\n        \n        # Cycle Loss\n        recov_A = G_BA(fake_B) # recov_A is fake-monet-drawing that generated by fake-photo\n        loss_cycle_A = criterion_cycle(recov_A, real_A) # Reduces the difference between the restored image and the real image\n        recov_B = G_AB(fake_A)\n        loss_cycle_B = criterion_cycle(recov_B, real_B)\n        \n        loss_cycle = (loss_cycle_A + loss_cycle_B)/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        optimizer_G.step()\n        \n# -----------------\n# Train Discriminator A\n# -----------------\n        optimizer_D_A.zero_grad()\n    \n        loss_real = criterion_GAN(D_A(real_A), valid) # train to discriminate real images as real\n        loss_fake = criterion_GAN(D_A(fake_A.detach()), fake) # train to discriminate fake images as fake\n        \n        loss_D_A = (loss_real + loss_fake)/2\n        \n        loss_D_A.backward()\n        optimizer_D_A.step()\n\n# -----------------\n# Train Discriminator B\n# -----------------\n        optimizer_D_B.zero_grad()\n    \n        loss_real = criterion_GAN(D_B(real_B), valid) # train to discriminate real images as real\n        loss_fake = criterion_GAN(D_B(fake_B.detach()), fake) # train to discriminate fake images as fake\n        \n        loss_D_B = (loss_real + loss_fake)/2\n        \n        loss_D_B.backward()\n        optimizer_D_B.step()\n        \n# ------> Total Loss\n        loss_D = (loss_D_A + loss_D_B)/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\n","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:57:19.66193Z","iopub.execute_input":"2021-06-17T14:57:19.662231Z","iopub.status.idle":"2021-06-17T14:57:23.70221Z","shell.execute_reply.started":"2021-06-17T14:57:19.662202Z","shell.execute_reply":"2021-06-17T14:57:23.700132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> TEST CODE : check iteration and image shape","metadata":{}},{"cell_type":"code","source":"for i, batch in enumerate(dataloader):\n    print('iter : {}  A.size : {}'.format(i,batch['A'].size()))\n    print('iter : {}  B.size : {}'.format(i,batch['B'].size()))\n    if i == 10:\n        break","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:54:01.301211Z","iopub.execute_input":"2021-06-17T14:54:01.301547Z","iopub.status.idle":"2021-06-17T14:54:01.496306Z","shell.execute_reply.started":"2021-06-17T14:54:01.301514Z","shell.execute_reply":"2021-06-17T14:54:01.49525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> TEST CODE : Adversarial Ground Truths","metadata":{}},{"cell_type":"code","source":"temp_A = batch['A'].type(Tensor)","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:54:04.108636Z","iopub.execute_input":"2021-06-17T14:54:04.108997Z","iopub.status.idle":"2021-06-17T14:54:04.113275Z","shell.execute_reply.started":"2021-06-17T14:54:04.108942Z","shell.execute_reply":"2021-06-17T14:54:04.112337Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_A.shape","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:54:04.447947Z","iopub.execute_input":"2021-06-17T14:54:04.448299Z","iopub.status.idle":"2021-06-17T14:54:04.455213Z","shell.execute_reply.started":"2021-06-17T14:54:04.448266Z","shell.execute_reply":"2021-06-17T14:54:04.454326Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_img = temp_A.squeeze()\ntemp_img = temp_img.cpu().permute(1,2,0).numpy()","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:54:09.908116Z","iopub.execute_input":"2021-06-17T14:54:09.908448Z","iopub.status.idle":"2021-06-17T14:54:09.913793Z","shell.execute_reply.started":"2021-06-17T14:54:09.908419Z","shell.execute_reply":"2021-06-17T14:54:09.912497Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_img.shape","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:54:11.520321Z","iopub.execute_input":"2021-06-17T14:54:11.520651Z","iopub.status.idle":"2021-06-17T14:54:11.525884Z","shell.execute_reply.started":"2021-06-17T14:54:11.520619Z","shell.execute_reply":"2021-06-17T14:54:11.525078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(temp_img)\nplt.axis('off');","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:54:13.052151Z","iopub.execute_input":"2021-06-17T14:54:13.052474Z","iopub.status.idle":"2021-06-17T14:54:13.143603Z","shell.execute_reply.started":"2021-06-17T14:54:13.052443Z","shell.execute_reply":"2021-06-17T14:54:13.142667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"D_A.output_shape","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:54:16.519952Z","iopub.execute_input":"2021-06-17T14:54:16.520309Z","iopub.status.idle":"2021-06-17T14:54:16.526197Z","shell.execute_reply.started":"2021-06-17T14:54:16.520274Z","shell.execute_reply":"2021-06-17T14:54:16.52489Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_A.size()","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:54:16.731404Z","iopub.execute_input":"2021-06-17T14:54:16.731669Z","iopub.status.idle":"2021-06-17T14:54:16.737008Z","shell.execute_reply.started":"2021-06-17T14:54:16.731643Z","shell.execute_reply":"2021-06-17T14:54:16.736034Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_A.size(0) # batch_size","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:54:16.951563Z","iopub.execute_input":"2021-06-17T14:54:16.951828Z","iopub.status.idle":"2021-06-17T14:54:16.956894Z","shell.execute_reply.started":"2021-06-17T14:54:16.9518Z","shell.execute_reply":"2021-06-17T14:54:16.956005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Tensor(np.ones((temp_A.size(0), *D_A.output_shape)))","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:54:17.499765Z","iopub.execute_input":"2021-06-17T14:54:17.500093Z","iopub.status.idle":"2021-06-17T14:54:17.547305Z","shell.execute_reply.started":"2021-06-17T14:54:17.500062Z","shell.execute_reply":"2021-06-17T14:54:17.546345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Tensor(np.ones((temp_A.size(0), *D_A.output_shape))).shape","metadata":{"execution":{"iopub.status.busy":"2021-06-17T14:54:17.691704Z","iopub.execute_input":"2021-06-17T14:54:17.691989Z","iopub.status.idle":"2021-06-17T14:54:17.699497Z","shell.execute_reply.started":"2021-06-17T14:54:17.691943Z","shell.execute_reply":"2021-06-17T14:54:17.698682Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> Read More\n- [The Effect of the Identity Mapping Loss on Monet's painting](https://www.researchgate.net/figure/The-effect-of-the-identity-mapping-loss-on-Monets-painting-photos-From-left-to-right_fig3_322060135)","metadata":{}},{"cell_type":"markdown","source":"So far we have looked at the cyclegan model, which does not require pairs. \n\nIt is a very important model among various gan architectures, and will be the basis for stargan.\n\n\nIf you are satisfied with this cyclegan tutorial, I recommend that you continue learning the next [stargan tutorial](https://www.kaggle.com/songseungwon/stargan-tutorial-with-15-steps-make-fake-images)\n\nThank you!","metadata":{}}]}