{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.10","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":30097,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# CycleGAN - Ankur Shukla\npix2pix image generation model that generates images from datasets that do not require pairs.\n\nimplemented  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":"We will implement the following structure with `PyTorch`","metadata":{}},{"cell_type":"markdown","source":"","metadata":{"jupyter":{"source_hidden":true}}},{"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\nimport matplotlib.pyplot as plt\nfrom IPython.display import clear_output","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:20.124068Z","iopub.execute_input":"2023-12-15T07:28:20.124465Z","iopub.status.idle":"2023-12-15T07:28:20.130173Z","shell.execute_reply.started":"2023-12-15T07:28:20.124423Z","shell.execute_reply":"2023-12-15T07:28:20.129270Z"},"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":"2023-12-15T07:28:20.156397Z","iopub.execute_input":"2023-12-15T07:28:20.156690Z","iopub.status.idle":"2023-12-15T07:28:21.138955Z","shell.execute_reply.started":"2023-12-15T07:28:20.156661Z","shell.execute_reply":"2023-12-15T07:28:21.138040Z"},"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":"2023-12-15T07:28:21.140933Z","iopub.execute_input":"2023-12-15T07:28:21.141358Z","iopub.status.idle":"2023-12-15T07:28:21.145494Z","shell.execute_reply.started":"2023-12-15T07:28:21.141309Z","shell.execute_reply":"2023-12-15T07:28:21.144696Z"},"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\nsample_interval = 1\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    \n# Lists to store losses for visualization\nG_losses = []\nD_losses = []\n","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:21.147400Z","iopub.execute_input":"2023-12-15T07:28:21.147685Z","iopub.status.idle":"2023-12-15T07:28:21.156822Z","shell.execute_reply.started":"2023-12-15T07:28:21.147659Z","shell.execute_reply":"2023-12-15T07:28:21.156058Z"},"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":"2023-12-15T07:28:21.158354Z","iopub.execute_input":"2023-12-15T07:28:21.158624Z","iopub.status.idle":"2023-12-15T07:28:21.172843Z","shell.execute_reply.started":"2023-12-15T07:28:21.158594Z","shell.execute_reply":"2023-12-15T07:28:21.172000Z"},"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":"2023-12-15T07:28:21.174064Z","iopub.execute_input":"2023-12-15T07:28:21.174424Z","iopub.status.idle":"2023-12-15T07:28:21.185690Z","shell.execute_reply.started":"2023-12-15T07:28:21.174388Z","shell.execute_reply":"2023-12-15T07:28:21.184767Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tensor","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:21.186684Z","iopub.execute_input":"2023-12-15T07:28:21.186941Z","iopub.status.idle":"2023-12-15T07:28:21.198060Z","shell.execute_reply.started":"2023-12-15T07:28:21.186917Z","shell.execute_reply":"2023-12-15T07:28:21.197222Z"},"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":"2023-12-15T07:28:21.199189Z","iopub.execute_input":"2023-12-15T07:28:21.199545Z","iopub.status.idle":"2023-12-15T07:28:21.207265Z","shell.execute_reply.started":"2023-12-15T07:28:21.199509Z","shell.execute_reply":"2023-12-15T07:28:21.206481Z"},"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":"2023-12-15T07:28:21.208262Z","iopub.execute_input":"2023-12-15T07:28:21.208509Z","iopub.status.idle":"2023-12-15T07:28:21.217490Z","shell.execute_reply.started":"2023-12-15T07:28:21.208486Z","shell.execute_reply":"2023-12-15T07:28:21.216722Z"},"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":"2023-12-15T07:28:21.220101Z","iopub.execute_input":"2023-12-15T07:28:21.220440Z","iopub.status.idle":"2023-12-15T07:28:21.229495Z","shell.execute_reply.started":"2023-12-15T07:28:21.220399Z","shell.execute_reply":"2023-12-15T07:28:21.228614Z"},"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":"2023-12-15T07:28:21.231330Z","iopub.execute_input":"2023-12-15T07:28:21.231666Z","iopub.status.idle":"2023-12-15T07:28:21.242805Z","shell.execute_reply.started":"2023-12-15T07:28:21.231631Z","shell.execute_reply":"2023-12-15T07:28:21.242049Z"},"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":"2023-12-15T07:28:21.243756Z","iopub.execute_input":"2023-12-15T07:28:21.244055Z","iopub.status.idle":"2023-12-15T07:28:21.252491Z","shell.execute_reply.started":"2023-12-15T07:28:21.244016Z","shell.execute_reply":"2023-12-15T07:28:21.251568Z"},"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":"2023-12-15T07:28:21.253657Z","iopub.execute_input":"2023-12-15T07:28:21.253926Z","iopub.status.idle":"2023-12-15T07:28:21.261908Z","shell.execute_reply.started":"2023-12-15T07:28:21.253900Z","shell.execute_reply":"2023-12-15T07:28:21.261067Z"},"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":"2023-12-15T07:28:21.263054Z","iopub.execute_input":"2023-12-15T07:28:21.263415Z","iopub.status.idle":"2023-12-15T07:28:21.271836Z","shell.execute_reply.started":"2023-12-15T07:28:21.263388Z","shell.execute_reply":"2023-12-15T07:28:21.271016Z"},"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":"2023-12-15T07:28:21.273013Z","iopub.execute_input":"2023-12-15T07:28:21.273374Z","iopub.status.idle":"2023-12-15T07:28:21.282101Z","shell.execute_reply.started":"2023-12-15T07:28:21.273338Z","shell.execute_reply":"2023-12-15T07:28:21.281203Z"},"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":"2023-12-15T07:28:21.283363Z","iopub.execute_input":"2023-12-15T07:28:21.283709Z","iopub.status.idle":"2023-12-15T07:28:21.291615Z","shell.execute_reply.started":"2023-12-15T07:28:21.283674Z","shell.execute_reply":"2023-12-15T07:28:21.290844Z"},"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":"2023-12-15T07:28:21.293109Z","iopub.execute_input":"2023-12-15T07:28:21.293600Z","iopub.status.idle":"2023-12-15T07:28:21.299912Z","shell.execute_reply.started":"2023-12-15T07:28:21.293549Z","shell.execute_reply":"2023-12-15T07:28:21.299079Z"},"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":"2023-12-15T07:28:21.301118Z","iopub.execute_input":"2023-12-15T07:28:21.301475Z","iopub.status.idle":"2023-12-15T07:28:21.542837Z","shell.execute_reply.started":"2023-12-15T07:28:21.301440Z","shell.execute_reply":"2023-12-15T07:28:21.541921Z"},"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":"2023-12-15T07:28:21.543926Z","iopub.execute_input":"2023-12-15T07:28:21.544231Z","iopub.status.idle":"2023-12-15T07:28:21.584749Z","shell.execute_reply.started":"2023-12-15T07:28:21.544202Z","shell.execute_reply":"2023-12-15T07:28:21.584023Z"},"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":"2023-12-15T07:28:21.585831Z","iopub.execute_input":"2023-12-15T07:28:21.586110Z","iopub.status.idle":"2023-12-15T07:28:21.592466Z","shell.execute_reply.started":"2023-12-15T07:28:21.586076Z","shell.execute_reply":"2023-12-15T07:28:21.591646Z"},"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":"2023-12-15T07:28:21.593630Z","iopub.execute_input":"2023-12-15T07:28:21.593902Z","iopub.status.idle":"2023-12-15T07:28:21.607095Z","shell.execute_reply.started":"2023-12-15T07:28:21.593875Z","shell.execute_reply":"2023-12-15T07:28:21.606242Z"},"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":"2023-12-15T07:28:21.608240Z","iopub.execute_input":"2023-12-15T07:28:21.608514Z","iopub.status.idle":"2023-12-15T07:28:21.612496Z","shell.execute_reply.started":"2023-12-15T07:28:21.608488Z","shell.execute_reply":"2023-12-15T07:28:21.611627Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"G_AB.apply(temp_weights_init_normal);","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:21.613634Z","iopub.execute_input":"2023-12-15T07:28:21.613999Z","iopub.status.idle":"2023-12-15T07:28:21.635380Z","shell.execute_reply.started":"2023-12-15T07:28:21.613947Z","shell.execute_reply":"2023-12-15T07:28:21.634714Z"},"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":"2023-12-15T07:28:21.636335Z","iopub.execute_input":"2023-12-15T07:28:21.636599Z","iopub.status.idle":"2023-12-15T07:28:21.642886Z","shell.execute_reply.started":"2023-12-15T07:28:21.636573Z","shell.execute_reply":"2023-12-15T07:28:21.641965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"nn.init.normal_(temp_w)","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:21.644016Z","iopub.execute_input":"2023-12-15T07:28:21.644295Z","iopub.status.idle":"2023-12-15T07:28:21.652240Z","shell.execute_reply.started":"2023-12-15T07:28:21.644269Z","shell.execute_reply":"2023-12-15T07:28:21.651391Z"},"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":"2023-12-15T07:28:21.653197Z","iopub.execute_input":"2023-12-15T07:28:21.653516Z","iopub.status.idle":"2023-12-15T07:28:21.661586Z","shell.execute_reply.started":"2023-12-15T07:28:21.653490Z","shell.execute_reply":"2023-12-15T07:28:21.660700Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"nn.init.constant_(temp_w2, 1)","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:21.662776Z","iopub.execute_input":"2023-12-15T07:28:21.663149Z","iopub.status.idle":"2023-12-15T07:28:21.670843Z","shell.execute_reply.started":"2023-12-15T07:28:21.663111Z","shell.execute_reply":"2023-12-15T07:28:21.669956Z"},"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":"2023-12-15T07:28:21.675510Z","iopub.execute_input":"2023-12-15T07:28:21.675783Z","iopub.status.idle":"2023-12-15T07:28:21.683922Z","shell.execute_reply.started":"2023-12-15T07:28:21.675747Z","shell.execute_reply":"2023-12-15T07:28:21.683052Z"},"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":"2023-12-15T07:28:21.685911Z","iopub.execute_input":"2023-12-15T07:28:21.686188Z","iopub.status.idle":"2023-12-15T07:28:21.693609Z","shell.execute_reply.started":"2023-12-15T07:28:21.686163Z","shell.execute_reply":"2023-12-15T07:28:21.692897Z"},"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":"2023-12-15T07:28:21.694562Z","iopub.execute_input":"2023-12-15T07:28:21.694830Z","iopub.status.idle":"2023-12-15T07:28:21.707581Z","shell.execute_reply.started":"2023-12-15T07:28:21.694805Z","shell.execute_reply":"2023-12-15T07:28:21.706716Z"},"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":"2023-12-15T07:28:21.708656Z","iopub.execute_input":"2023-12-15T07:28:21.709016Z","iopub.status.idle":"2023-12-15T07:28:21.718873Z","shell.execute_reply.started":"2023-12-15T07:28:21.708958Z","shell.execute_reply":"2023-12-15T07:28:21.718067Z"},"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":"2023-12-15T07:28:21.719830Z","iopub.execute_input":"2023-12-15T07:28:21.720134Z","iopub.status.idle":"2023-12-15T07:28:21.728744Z","shell.execute_reply.started":"2023-12-15T07:28:21.720098Z","shell.execute_reply":"2023-12-15T07:28:21.727858Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport glob","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:21.729823Z","iopub.execute_input":"2023-12-15T07:28:21.730195Z","iopub.status.idle":"2023-12-15T07:28:21.738198Z","shell.execute_reply.started":"2023-12-15T07:28:21.730158Z","shell.execute_reply":"2023-12-15T07:28:21.737488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(root+'/monet_jpg')","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:21.739074Z","iopub.execute_input":"2023-12-15T07:28:21.739368Z","iopub.status.idle":"2023-12-15T07:28:21.748652Z","shell.execute_reply.started":"2023-12-15T07:28:21.739341Z","shell.execute_reply":"2023-12-15T07:28:21.747553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(glob.glob(os.path.join(root+'/monet_jpg')+'/*.*'))","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:21.749715Z","iopub.execute_input":"2023-12-15T07:28:21.750028Z","iopub.status.idle":"2023-12-15T07:28:21.763472Z","shell.execute_reply.started":"2023-12-15T07:28:21.749991Z","shell.execute_reply":"2023-12-15T07:28:21.762695Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(glob.glob(os.path.join(root+'/photo_jpg')+'/*.*'))","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:21.764546Z","iopub.execute_input":"2023-12-15T07:28:21.764951Z","iopub.status.idle":"2023-12-15T07:28:21.796372Z","shell.execute_reply.started":"2023-12-15T07:28:21.764923Z","shell.execute_reply":"2023-12-15T07:28:21.795655Z"},"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":"2023-12-15T07:28:21.797385Z","iopub.execute_input":"2023-12-15T07:28:21.797638Z","iopub.status.idle":"2023-12-15T07:28:21.809692Z","shell.execute_reply.started":"2023-12-15T07:28:21.797614Z","shell.execute_reply":"2023-12-15T07:28:21.808811Z"},"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":"2023-12-15T07:28:21.811011Z","iopub.execute_input":"2023-12-15T07:28:21.811372Z","iopub.status.idle":"2023-12-15T07:28:21.878597Z","shell.execute_reply.started":"2023-12-15T07:28:21.811337Z","shell.execute_reply":"2023-12-15T07:28:21.877892Z"},"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":"2023-12-15T07:28:21.879733Z","iopub.execute_input":"2023-12-15T07:28:21.880108Z","iopub.status.idle":"2023-12-15T07:28:21.883994Z","shell.execute_reply.started":"2023-12-15T07:28:21.880069Z","shell.execute_reply":"2023-12-15T07:28:21.883065Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Tensor = torch.cuda.FloatTensor if cuda else torch.Tensor","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:21.885211Z","iopub.execute_input":"2023-12-15T07:28:21.885559Z","iopub.status.idle":"2023-12-15T07:28:21.893526Z","shell.execute_reply.started":"2023-12-15T07:28:21.885524Z","shell.execute_reply":"2023-12-15T07:28:21.892752Z"},"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.figure(figsize=(15, 15))\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();\n    \n    \n# 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\n#     # Arrange 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\n#     # Arrange images along y-axis\n#     image_grid = torch.cat((real_A, fake_B, real_B, fake_A), 0)\n\n#     plt.figure(figsize=(15, 15))\n#     plt.imshow(image_grid.permute(1, 2, 0).cpu().numpy())  # Permute dimensions for proper display\n#     plt.title('Real A vs Fake B | Real B vs Fake A')\n#     plt.axis('off')\n#     plt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:21.894607Z","iopub.execute_input":"2023-12-15T07:28:21.894866Z","iopub.status.idle":"2023-12-15T07:28:21.903567Z","shell.execute_reply.started":"2023-12-15T07:28:21.894842Z","shell.execute_reply":"2023-12-15T07:28:21.902876Z"},"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":"2023-12-15T07:28:21.904580Z","iopub.execute_input":"2023-12-15T07:28:21.904857Z","iopub.status.idle":"2023-12-15T07:28:22.157744Z","shell.execute_reply.started":"2023-12-15T07:28:21.904821Z","shell.execute_reply":"2023-12-15T07:28:22.156586Z"},"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":"2023-12-15T07:28:22.159316Z","iopub.execute_input":"2023-12-15T07:28:22.159595Z","iopub.status.idle":"2023-12-15T07:28:22.166788Z","shell.execute_reply.started":"2023-12-15T07:28:22.159564Z","shell.execute_reply":"2023-12-15T07:28:22.165926Z"},"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":"2023-12-15T07:28:22.167923Z","iopub.execute_input":"2023-12-15T07:28:22.168240Z","iopub.status.idle":"2023-12-15T07:28:22.321149Z","shell.execute_reply.started":"2023-12-15T07:28:22.168212Z","shell.execute_reply":"2023-12-15T07:28:22.320341Z"},"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":"2023-12-15T07:28:22.322415Z","iopub.execute_input":"2023-12-15T07:28:22.322697Z","iopub.status.idle":"2023-12-15T07:28:22.327575Z","shell.execute_reply.started":"2023-12-15T07:28:22.322671Z","shell.execute_reply":"2023-12-15T07:28:22.326719Z"},"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":"2023-12-15T07:28:22.328703Z","iopub.execute_input":"2023-12-15T07:28:22.329011Z","iopub.status.idle":"2023-12-15T07:28:22.435706Z","shell.execute_reply.started":"2023-12-15T07:28:22.328957Z","shell.execute_reply":"2023-12-15T07:28:22.434965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"type(temp_real_A)","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:22.436947Z","iopub.execute_input":"2023-12-15T07:28:22.437335Z","iopub.status.idle":"2023-12-15T07:28:22.442510Z","shell.execute_reply.started":"2023-12-15T07:28:22.437295Z","shell.execute_reply":"2023-12-15T07:28:22.441666Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(15, 15))\nplt.imshow(temp_real_A.cpu().permute(1,2,0))\nplt.title('Real A')\nplt.axis('off');","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:22.443641Z","iopub.execute_input":"2023-12-15T07:28:22.444000Z","iopub.status.idle":"2023-12-15T07:28:22.684582Z","shell.execute_reply.started":"2023-12-15T07:28:22.443945Z","shell.execute_reply":"2023-12-15T07:28:22.683665Z"},"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":"2023-12-15T07:28:22.685898Z","iopub.execute_input":"2023-12-15T07:28:22.686246Z","iopub.status.idle":"2023-12-15T07:28:22.692202Z","shell.execute_reply.started":"2023-12-15T07:28:22.686212Z","shell.execute_reply":"2023-12-15T07:28:22.691365Z"},"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":"2023-12-15T07:28:22.693316Z","iopub.execute_input":"2023-12-15T07:28:22.693648Z","iopub.status.idle":"2023-12-15T07:28:22.702620Z","shell.execute_reply.started":"2023-12-15T07:28:22.693608Z","shell.execute_reply":"2023-12-15T07:28:22.701788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_image_grid.cpu().permute(1,2,0).shape","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:22.703832Z","iopub.execute_input":"2023-12-15T07:28:22.704199Z","iopub.status.idle":"2023-12-15T07:28:22.720329Z","shell.execute_reply.started":"2023-12-15T07:28:22.704163Z","shell.execute_reply":"2023-12-15T07:28:22.719598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(15, 15))\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":"2023-12-15T07:28:22.721213Z","iopub.execute_input":"2023-12-15T07:28:22.721454Z","iopub.status.idle":"2023-12-15T07:28:23.379438Z","shell.execute_reply.started":"2023-12-15T07:28:22.721431Z","shell.execute_reply":"2023-12-15T07:28:23.378285Z"},"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":"2023-12-15T07:28:23.380744Z","iopub.execute_input":"2023-12-15T07:28:23.381108Z","iopub.status.idle":"2023-12-15T07:28:23.385341Z","shell.execute_reply.started":"2023-12-15T07:28:23.381071Z","shell.execute_reply":"2023-12-15T07:28:23.384483Z"},"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         # Append losses to the lists\n        G_losses.append(loss_G.item())\n        D_losses.append(loss_D.item())\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             # Visualize generated samples\n            sample_images()\n\n            # Plot losses over training\n            plt.figure(figsize=(10, 5))\n            plt.title(\"Generator and Discriminator Loss During Training\")\n            plt.plot(G_losses, label=\"Generator\")\n            plt.plot(D_losses, label=\"Discriminator\")\n            plt.xlabel(\"Iterations\")\n            plt.ylabel(\"Loss\")\n            plt.legend()\n            plt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:28:23.386618Z","iopub.execute_input":"2023-12-15T07:28:23.386949Z","iopub.status.idle":"2023-12-15T07:43:21.074874Z","shell.execute_reply.started":"2023-12-15T07:28:23.386914Z","shell.execute_reply":"2023-12-15T07:43:21.074015Z"},"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":"2023-12-15T07:43:21.076282Z","iopub.execute_input":"2023-12-15T07:43:21.076570Z","iopub.status.idle":"2023-12-15T07:43:21.278605Z","shell.execute_reply.started":"2023-12-15T07:43:21.076537Z","shell.execute_reply":"2023-12-15T07:43:21.277523Z"},"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":"2023-12-15T07:43:21.280258Z","iopub.execute_input":"2023-12-15T07:43:21.280633Z","iopub.status.idle":"2023-12-15T07:43:21.285633Z","shell.execute_reply.started":"2023-12-15T07:43:21.280593Z","shell.execute_reply":"2023-12-15T07:43:21.284715Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_A.shape","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:43:21.286779Z","iopub.execute_input":"2023-12-15T07:43:21.287094Z","iopub.status.idle":"2023-12-15T07:43:21.297335Z","shell.execute_reply.started":"2023-12-15T07:43:21.287060Z","shell.execute_reply":"2023-12-15T07:43:21.296446Z"},"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":"2023-12-15T07:43:21.298445Z","iopub.execute_input":"2023-12-15T07:43:21.298761Z","iopub.status.idle":"2023-12-15T07:43:21.306146Z","shell.execute_reply.started":"2023-12-15T07:43:21.298733Z","shell.execute_reply":"2023-12-15T07:43:21.305302Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_img.shape","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:43:21.307182Z","iopub.execute_input":"2023-12-15T07:43:21.307507Z","iopub.status.idle":"2023-12-15T07:43:21.315861Z","shell.execute_reply.started":"2023-12-15T07:43:21.307474Z","shell.execute_reply":"2023-12-15T07:43:21.315050Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(temp_img)\nplt.axis('off');","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:43:21.317019Z","iopub.execute_input":"2023-12-15T07:43:21.317269Z","iopub.status.idle":"2023-12-15T07:43:21.426892Z","shell.execute_reply.started":"2023-12-15T07:43:21.317245Z","shell.execute_reply":"2023-12-15T07:43:21.426070Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"D_A.output_shape","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:43:21.428084Z","iopub.execute_input":"2023-12-15T07:43:21.428357Z","iopub.status.idle":"2023-12-15T07:43:21.433547Z","shell.execute_reply.started":"2023-12-15T07:43:21.428331Z","shell.execute_reply":"2023-12-15T07:43:21.432704Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_A.size()","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:43:21.434752Z","iopub.execute_input":"2023-12-15T07:43:21.435063Z","iopub.status.idle":"2023-12-15T07:43:21.445392Z","shell.execute_reply.started":"2023-12-15T07:43:21.435033Z","shell.execute_reply":"2023-12-15T07:43:21.444488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_A.size(0) # batch_size","metadata":{"execution":{"iopub.status.busy":"2023-12-15T07:43:21.446544Z","iopub.execute_input":"2023-12-15T07:43:21.446797Z","iopub.status.idle":"2023-12-15T07:43:21.457012Z","shell.execute_reply.started":"2023-12-15T07:43:21.446771Z","shell.execute_reply":"2023-12-15T07:43:21.456072Z"},"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":"2023-12-15T07:43:21.458344Z","iopub.execute_input":"2023-12-15T07:43:21.458646Z","iopub.status.idle":"2023-12-15T07:43:21.506547Z","shell.execute_reply.started":"2023-12-15T07:43:21.458618Z","shell.execute_reply":"2023-12-15T07:43:21.505750Z"},"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":"2023-12-15T07:43:21.507716Z","iopub.execute_input":"2023-12-15T07:43:21.508017Z","iopub.status.idle":"2023-12-15T07:43:21.513754Z","shell.execute_reply.started":"2023-12-15T07:43:21.507963Z","shell.execute_reply":"2023-12-15T07:43:21.512952Z"},"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":{}},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"","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":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}