{"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"},{"sourceId":3258442,"sourceType":"datasetVersion","datasetId":1974124}],"dockerImageVersionId":30097,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"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)","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\nimport random\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\n\nimport wandb","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:14.639677Z","iopub.execute_input":"2024-12-12T03:58:14.640139Z","iopub.status.idle":"2024-12-12T03:58:16.586051Z","shell.execute_reply.started":"2024-12-12T03:58:14.640058Z","shell.execute_reply":"2024-12-12T03:58:16.58523Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!nvidia-smi","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T03:58:16.587455Z","iopub.execute_input":"2024-12-12T03:58:16.58772Z","iopub.status.idle":"2024-12-12T03:58:17.644647Z","shell.execute_reply.started":"2024-12-12T03:58:16.58769Z","shell.execute_reply":"2024-12-12T03:58:17.643922Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 1+. WandB","metadata":{}},{"cell_type":"code","source":"!wandb login 'c46e89226ccd773f7fcb283fb6c2e784391a5c13'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T03:58:17.646277Z","iopub.execute_input":"2024-12-12T03:58:17.646514Z","iopub.status.idle":"2024-12-12T03:58:19.813211Z","shell.execute_reply.started":"2024-12-12T03:58:17.646487Z","shell.execute_reply":"2024-12-12T03:58:19.812206Z"}},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:19.814905Z","iopub.execute_input":"2024-12-12T03:58:19.815128Z","iopub.status.idle":"2024-12-12T03:58:20.822989Z","shell.execute_reply.started":"2024-12-12T03:58:19.815101Z","shell.execute_reply":"2024-12-12T03:58:20.82226Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"n_cpu = 4 # number of cpu threads to use during batch generation","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:20.824151Z","iopub.execute_input":"2024-12-12T03:58:20.824377Z","iopub.status.idle":"2024-12-12T03:58:20.828038Z","shell.execute_reply.started":"2024-12-12T03:58:20.82435Z","shell.execute_reply":"2024-12-12T03:58:20.827223Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# data (path)\nroot = \"../input/ukiyoe2photo/ukiyoe2photo\"\n\n# data (img)\nimg_height = 256\nimg_width = 256\nchannels = 3\n\n# training\nepoch = 0 # epoch to start training from\nn_epochs = 50 # number of epochs of training\nbatch_size = 5 # 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 = 25 # suggested default : 100 (suggested 'n_epochs' is 200)\n                 # epoch from which to start lr decay\n\nlambda_cycle = 10.0\nlambda_idt = 3.0\n\nbuffer_size = 100\nmax_time_dict = {\"h\": 11, \"m\": 55}\n","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:20.828975Z","iopub.execute_input":"2024-12-12T03:58:20.829252Z","iopub.status.idle":"2024-12-12T03:58:20.84021Z","shell.execute_reply.started":"2024-12-12T03:58:20.829228Z","shell.execute_reply":"2024-12-12T03:58:20.839298Z"},"trusted":true},"outputs":[],"execution_count":null},{"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=9):\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            model += [\n                nn.ConvTranspose2d(in_features, out_features, 3, stride=2, padding=1, output_padding=1),\n                nn.InstanceNorm2d(out_features),\n                nn.ReLU(inplace=True)\n            ]\n            in_features = out_features\n            \n        # Output Layer\n        model += [\n            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":"2024-12-12T03:58:20.841301Z","iopub.execute_input":"2024-12-12T03:58:20.841667Z","iopub.status.idle":"2024-12-12T03:58:20.855537Z","shell.execute_reply.started":"2024-12-12T03:58:20.841637Z","shell.execute_reply":"2024-12-12T03:58:20.854778Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:20.856704Z","iopub.execute_input":"2024-12-12T03:58:20.857027Z","iopub.status.idle":"2024-12-12T03:58:20.871014Z","shell.execute_reply.started":"2024-12-12T03:58:20.856996Z","shell.execute_reply":"2024-12-12T03:58:20.870392Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# tensor","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:20.873689Z","iopub.execute_input":"2024-12-12T03:58:20.873996Z","iopub.status.idle":"2024-12-12T03:58:20.882114Z","shell.execute_reply.started":"2024-12-12T03:58:20.873963Z","shell.execute_reply":"2024-12-12T03:58:20.881427Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# tensor = tensor.view(1,1,2,2)\n# tensor # nn.Upsample get only 3/4/5D tensor","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:20.883538Z","iopub.execute_input":"2024-12-12T03:58:20.8838Z","iopub.status.idle":"2024-12-12T03:58:20.894762Z","shell.execute_reply.started":"2024-12-12T03:58:20.883778Z","shell.execute_reply":"2024-12-12T03:58:20.893976Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test_m = nn.Upsample(scale_factor=2)\n# test_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:20.89576Z","iopub.execute_input":"2024-12-12T03:58:20.895968Z","iopub.status.idle":"2024-12-12T03:58:20.905778Z","shell.execute_reply.started":"2024-12-12T03:58:20.895948Z","shell.execute_reply":"2024-12-12T03:58:20.905048Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"## Step3+. UNet Generator","metadata":{}},{"cell_type":"code","source":"class Downsampling(nn.Module):\n    def __init__(self, in_channels, out_channels, kernel_size=4,\n                 stride=2, padding=1, norm=True, lrelu=True,):\n        super().__init__()\n        self.block = [\n            nn.Conv2d(in_channels, out_channels,\n                      kernel_size=kernel_size, stride=stride, padding=padding, bias=not norm),\n        ]\n        if norm:\n            self.block.append(nn.InstanceNorm2d(out_channels, affine=True))\n        if lrelu is not None:\n            self.block.append(nn.LeakyReLU(0.2, True) if lrelu else nn.ReLU(True))\n\n        self.block = nn.Sequential(*self.block)\n        \n    def forward(self, x):\n        return self.block(x)\n\n\nclass Upsampling(nn.Module):\n    def __init__(self, in_channels, out_channels, kernel_size=4,\n                 stride=2, padding=1, output_padding=0, dropout=False,):\n        super().__init__()\n        self.block = [\n            nn.ConvTranspose2d(in_channels, out_channels,\n                               kernel_size=kernel_size, stride=stride, \n                               padding=padding, output_padding=output_padding, bias=False),\n            nn.InstanceNorm2d(out_channels, affine=True),\n        ]\n        if dropout:\n            self.block.append(nn.Dropout(0.5))\n        self.block.append(nn.ReLU(True))\n\n        self.block = nn.Sequential(*self.block)\n        \n    def forward(self, x):\n        return self.block(x)\n\n\nclass GeneratorUNet(nn.Module):\n    def __init__(self, hid_channels=64, in_channels=3, out_channels=3):\n        super().__init__()\n        self.downsampling_path = nn.Sequential(\n            Downsampling(in_channels, hid_channels, norm=False), # 64x128x128\n            Downsampling(hid_channels, hid_channels*2), # 128x64x64\n            Downsampling(hid_channels*2, hid_channels*4), # 256x32x32\n            Downsampling(hid_channels*4, hid_channels*8), # 512x16x16\n            Downsampling(hid_channels*8, hid_channels*8), # 512x8x8\n            Downsampling(hid_channels*8, hid_channels*8), # 512x4x4\n            Downsampling(hid_channels*8, hid_channels*8), # 512x2x2\n            Downsampling(hid_channels*8, hid_channels*8, norm=False), # 512x1x1, instance norm does not work on 1x1\n        )\n        self.upsampling_path = nn.Sequential(\n            Upsampling(hid_channels*8, hid_channels*8, dropout=True), # (512+512)x2x2\n            Upsampling(hid_channels*16, hid_channels*8, dropout=True), # (512+512)x4x4\n            Upsampling(hid_channels*16, hid_channels*8, dropout=True), # (512+512)x8x8\n            Upsampling(hid_channels*16, hid_channels*8), # (512+512)x16x16\n            Upsampling(hid_channels*16, hid_channels*4), # (256+256)x32x32\n            Upsampling(hid_channels*8, hid_channels*2), # (128+128)x64x64\n            Upsampling(hid_channels*4, hid_channels), # (64+64)x128x128\n        )\n        self.feature_block = nn.Sequential(\n            nn.ConvTranspose2d(hid_channels*2, out_channels,\n                               kernel_size=4, stride=2, padding=1), # 3x256x256\n            nn.Tanh(),\n        )\n        \n    def forward(self, x):\n        skips = []\n        for down in self.downsampling_path:\n            x = down(x)\n            skips.append(x)\n        skips = reversed(skips[:-1])\n\n        for up, skip in zip(self.upsampling_path, skips):\n            x = up(x)\n            x = torch.cat([x, skip], dim=1)\n        return self.feature_block(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T03:58:20.906801Z","iopub.execute_input":"2024-12-12T03:58:20.907025Z","iopub.status.idle":"2024-12-12T03:58:20.921359Z","shell.execute_reply.started":"2024-12-12T03:58:20.907002Z","shell.execute_reply":"2024-12-12T03:58:20.920677Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 3++. Something something Transformer Generator","metadata":{}},{"cell_type":"code","source":"conv_initializer = lambda x: nn.init.normal_(x, mean=0.0, std=0.02)\ngamma_initializer = lambda x: nn.init.normal_(x, mean=0.0, std=0.02)\n\nclass EncoderBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, size=3, strides=2, apply_instancenorm=True, activation=nn.LeakyReLU(0.2), name='block_x'):\n        super(EncoderBlock, self).__init__()\n        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=size, stride=strides, padding=1, bias=False)\n        conv_initializer(self.conv.weight)\n        self.instancenorm = nn.InstanceNorm2d(out_channels, affine=False, track_running_stats=False) if apply_instancenorm else nn.Identity()\n        self.activation = activation\n\n    def forward(self, x):\n        x = self.conv(x)\n        x = self.instancenorm(x)\n        x = self.activation(x)\n        return x\n\nclass TransformerBlock(nn.Module):\n    def __init__(self, channels, size=3, strides=1, name='block_x'):\n        super(TransformerBlock, self).__init__()\n        self.conv1 = nn.Conv2d(channels, channels, kernel_size=size, stride=strides, padding=1, bias=False)\n        conv_initializer(self.conv1.weight)\n        self.conv2 = nn.Conv2d(channels, channels, kernel_size=size, stride=strides, padding=1, bias=False)\n        conv_initializer(self.conv2.weight)\n        self.relu = nn.ReLU()\n        # self.instancenorm = nn.InstanceNorm2d(channels, affine=False, track_running_stats=False)\n\n    def forward(self, x):\n        identity = x\n        out = self.conv1(x)\n        # out = self.instancenorm(out)\n        out = self.relu(out)\n        out = self.conv2(out)\n        # out = self.instancenorm(out)\n        out += identity\n        return out\n\nclass DecoderBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, size=3, strides=2, apply_instancenorm=True, name='block_x'):\n        super(DecoderBlock, self).__init__()\n        self.deconv = nn.ConvTranspose2d(in_channels, out_channels, kernel_size=size, stride=strides, padding=1, output_padding=1, bias=False)\n        conv_initializer(self.deconv.weight)\n        self.instancenorm = nn.InstanceNorm2d(out_channels, affine=False, track_running_stats=False) if apply_instancenorm else nn.Identity()\n        self.activation = nn.ReLU()\n\n    def forward(self, x):\n        x = self.deconv(x)\n        x = self.instancenorm(x)\n        x = self.activation(x)\n        return x","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T03:58:20.922221Z","iopub.execute_input":"2024-12-12T03:58:20.922426Z","iopub.status.idle":"2024-12-12T03:58:20.93844Z","shell.execute_reply.started":"2024-12-12T03:58:20.922407Z","shell.execute_reply":"2024-12-12T03:58:20.937779Z"}},"outputs":[],"execution_count":null},{"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, x):\n        x = self.model(x)\n        # x = F.avg_pool2d(x, x.size()[2:]).view(x.size()[0], -1)\n        return x","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:20.939399Z","iopub.execute_input":"2024-12-12T03:58:20.939732Z","iopub.status.idle":"2024-12-12T03:58:20.954626Z","shell.execute_reply.started":"2024-12-12T03:58:20.939698Z","shell.execute_reply":"2024-12-12T03:58:20.954066Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"> TEST CODE : nn.ZeroPad2d","metadata":{}},{"cell_type":"code","source":"# tensor = torch.from_numpy(np.random.randn(2,2))\n# tensor","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:20.955624Z","iopub.execute_input":"2024-12-12T03:58:20.955942Z","iopub.status.idle":"2024-12-12T03:58:20.969536Z","shell.execute_reply.started":"2024-12-12T03:58:20.955906Z","shell.execute_reply":"2024-12-12T03:58:20.968784Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test_m = nn.ZeroPad2d((1,0,0,0)) # Padding_left\n# test_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:20.970421Z","iopub.execute_input":"2024-12-12T03:58:20.970654Z","iopub.status.idle":"2024-12-12T03:58:20.979269Z","shell.execute_reply.started":"2024-12-12T03:58:20.970618Z","shell.execute_reply":"2024-12-12T03:58:20.978694Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test_m = nn.ZeroPad2d((0,1,0,0)) # Padding_right\n# test_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:20.98023Z","iopub.execute_input":"2024-12-12T03:58:20.980471Z","iopub.status.idle":"2024-12-12T03:58:20.989161Z","shell.execute_reply.started":"2024-12-12T03:58:20.980443Z","shell.execute_reply":"2024-12-12T03:58:20.988449Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test_m = nn.ZeroPad2d((0,0,1,0)) # Padding_top\n# test_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:20.990019Z","iopub.execute_input":"2024-12-12T03:58:20.990215Z","iopub.status.idle":"2024-12-12T03:58:20.998863Z","shell.execute_reply.started":"2024-12-12T03:58:20.990196Z","shell.execute_reply":"2024-12-12T03:58:20.998206Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test_m = nn.ZeroPad2d((0,0,0,1)) # Padding_bottom\n# test_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:20.999828Z","iopub.execute_input":"2024-12-12T03:58:21.000042Z","iopub.status.idle":"2024-12-12T03:58:21.00913Z","shell.execute_reply.started":"2024-12-12T03:58:21.000023Z","shell.execute_reply":"2024-12-12T03:58:21.008451Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test_m = nn.ZeroPad2d((1,0,1,0)) # Padding_left and Padding_top\n# test_m(tensor)","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:21.010147Z","iopub.execute_input":"2024-12-12T03:58:21.010468Z","iopub.status.idle":"2024-12-12T03:58:21.02092Z","shell.execute_reply.started":"2024-12-12T03:58:21.010436Z","shell.execute_reply":"2024-12-12T03:58:21.020202Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 4+. Buffer for Discriminator","metadata":{}},{"cell_type":"code","source":"class ImageBuffer():\n    def __init__(self, max_size=50):\n        assert (max_size > 0), 'Empty buffer or trying to create a black hole. Be careful.'\n        self.max_size = max_size\n        self.data = []\n\n    def push_and_pop(self, data):\n        to_return = []\n        for element in data.data:\n            element = torch.unsqueeze(element, 0)\n            if len(self.data) < self.max_size:\n                self.data.append(element)\n                to_return.append(element)\n            else:\n                if random.uniform(0,1) > 0.5:\n                    i = random.randint(0, self.max_size-1)\n                    to_return.append(self.data[i].clone())\n                    self.data[i] = element\n                else:\n                    to_return.append(element)\n        return Variable(torch.cat(to_return))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T03:58:21.021911Z","iopub.execute_input":"2024-12-12T03:58:21.022213Z","iopub.status.idle":"2024-12-12T03:58:21.034216Z","shell.execute_reply.started":"2024-12-12T03:58:21.022182Z","shell.execute_reply":"2024-12-12T03:58:21.033523Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fake_A_buffer = ImageBuffer(buffer_size)\nfake_B_buffer = ImageBuffer(buffer_size)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T03:58:21.035034Z","iopub.execute_input":"2024-12-12T03:58:21.035228Z","iopub.status.idle":"2024-12-12T03:58:21.048096Z","shell.execute_reply.started":"2024-12-12T03:58:21.035209Z","shell.execute_reply":"2024-12-12T03:58:21.04745Z"}},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:21.048927Z","iopub.execute_input":"2024-12-12T03:58:21.049117Z","iopub.status.idle":"2024-12-12T03:58:21.058357Z","shell.execute_reply.started":"2024-12-12T03:58:21.049099Z","shell.execute_reply":"2024-12-12T03:58:21.057699Z"},"trusted":true},"outputs":[],"execution_count":null},{"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\n# G_AB = GeneratorResNet(input_shape, n_residual_blocks)\n# G_BA = GeneratorResNet(input_shape, n_residual_blocks)\n\nG_AB = GeneratorUNet()\nG_BA = GeneratorUNet()\n\nD_A = Discriminator(input_shape)\nD_B = Discriminator(input_shape)","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:21.059316Z","iopub.execute_input":"2024-12-12T03:58:21.059657Z","iopub.status.idle":"2024-12-12T03:58:22.020287Z","shell.execute_reply.started":"2024-12-12T03:58:21.059623Z","shell.execute_reply":"2024-12-12T03:58:22.019641Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:22.021338Z","iopub.execute_input":"2024-12-12T03:58:22.021579Z","iopub.status.idle":"2024-12-12T03:58:26.587894Z","shell.execute_reply.started":"2024-12-12T03:58:22.021553Z","shell.execute_reply":"2024-12-12T03:58:26.58722Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:26.588872Z","iopub.execute_input":"2024-12-12T03:58:26.589094Z","iopub.status.idle":"2024-12-12T03:58:26.593873Z","shell.execute_reply.started":"2024-12-12T03:58:26.589072Z","shell.execute_reply":"2024-12-12T03:58:26.593086Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:26.598342Z","iopub.execute_input":"2024-12-12T03:58:26.59856Z","iopub.status.idle":"2024-12-12T03:58:26.619527Z","shell.execute_reply.started":"2024-12-12T03:58:26.598539Z","shell.execute_reply":"2024-12-12T03:58:26.618702Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:26.621197Z","iopub.execute_input":"2024-12-12T03:58:26.6215Z","iopub.status.idle":"2024-12-12T03:58:26.625683Z","shell.execute_reply.started":"2024-12-12T03:58:26.621473Z","shell.execute_reply":"2024-12-12T03:58:26.624855Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# G_AB.apply(temp_weights_init_normal);","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:26.626594Z","iopub.execute_input":"2024-12-12T03:58:26.626855Z","iopub.status.idle":"2024-12-12T03:58:26.635192Z","shell.execute_reply.started":"2024-12-12T03:58:26.626832Z","shell.execute_reply":"2024-12-12T03:58:26.634388Z"},"trusted":true},"outputs":[],"execution_count":null},{"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)\n# temp_w","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:26.636283Z","iopub.execute_input":"2024-12-12T03:58:26.636643Z","iopub.status.idle":"2024-12-12T03:58:26.644562Z","shell.execute_reply.started":"2024-12-12T03:58:26.63659Z","shell.execute_reply":"2024-12-12T03:58:26.64386Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# nn.init.normal_(temp_w)","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:26.645595Z","iopub.execute_input":"2024-12-12T03:58:26.645952Z","iopub.status.idle":"2024-12-12T03:58:26.655377Z","shell.execute_reply.started":"2024-12-12T03:58:26.645919Z","shell.execute_reply":"2024-12-12T03:58:26.654749Z"},"trusted":true},"outputs":[],"execution_count":null},{"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)\n# temp_w2","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:26.656161Z","iopub.execute_input":"2024-12-12T03:58:26.656387Z","iopub.status.idle":"2024-12-12T03:58:26.664749Z","shell.execute_reply.started":"2024-12-12T03:58:26.656365Z","shell.execute_reply":"2024-12-12T03:58:26.664062Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# nn.init.constant_(temp_w2, 1)","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:26.665533Z","iopub.execute_input":"2024-12-12T03:58:26.665816Z","iopub.status.idle":"2024-12-12T03:58:26.673956Z","shell.execute_reply.started":"2024-12-12T03:58:26.665779Z","shell.execute_reply":"2024-12-12T03:58:26.673361Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:26.674858Z","iopub.execute_input":"2024-12-12T03:58:26.675064Z","iopub.status.idle":"2024-12-12T03:58:26.68546Z","shell.execute_reply.started":"2024-12-12T03:58:26.675044Z","shell.execute_reply":"2024-12-12T03:58:26.684852Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:26.686277Z","iopub.execute_input":"2024-12-12T03:58:26.686525Z","iopub.status.idle":"2024-12-12T03:58:26.694982Z","shell.execute_reply.started":"2024-12-12T03:58:26.686503Z","shell.execute_reply":"2024-12-12T03:58:26.694361Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:26.695836Z","iopub.execute_input":"2024-12-12T03:58:26.696038Z","iopub.status.idle":"2024-12-12T03:58:26.703964Z","shell.execute_reply.started":"2024-12-12T03:58:26.696018Z","shell.execute_reply":"2024-12-12T03:58:26.703337Z"},"trusted":true},"outputs":[],"execution_count":null},{"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.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n]\n\n# transforms_val = [\n#     transforms.Resize(int(img_height*1.12), Image.BICUBIC),\n#     transforms.ToTensor(),\n#     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n# ]","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:26.704901Z","iopub.execute_input":"2024-12-12T03:58:26.705139Z","iopub.status.idle":"2024-12-12T03:58:26.716806Z","shell.execute_reply.started":"2024-12-12T03:58:26.705109Z","shell.execute_reply":"2024-12-12T03:58:26.716161Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:26.717886Z","iopub.execute_input":"2024-12-12T03:58:26.718099Z","iopub.status.idle":"2024-12-12T03:58:26.726967Z","shell.execute_reply.started":"2024-12-12T03:58:26.718079Z","shell.execute_reply":"2024-12-12T03:58:26.726372Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport glob\nfrom torch.utils.data import Dataset\n\nclass ImageDataset(Dataset):\n    def __init__(self, data_dir, transforms_=transforms_, unaligned=False, mode='train'):\n        self.transform = transforms.Compose(transforms_)\n        self.unaligned = unaligned\n        self.mode = mode\n\n        if self.mode == 'test':\n            dir_a = os.path.join(data_dir, \"testA\")\n            dir_b = os.path.join(data_dir, \"testB\")\n        elif self.mode == 'train':\n            dir_a = os.path.join(data_dir, \"trainA\")\n            dir_b = os.path.join(data_dir, \"trainB\")\n        \n        self.files_A = [os.path.join(dir_a, name) for name in sorted(os.listdir(dir_a))]\n        self.files_B = [os.path.join(dir_b, name) for name in sorted(os.listdir(dir_b))]\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":"2024-12-12T03:58:26.727882Z","iopub.execute_input":"2024-12-12T03:58:26.728081Z","iopub.status.idle":"2024-12-12T03:58:26.739139Z","shell.execute_reply.started":"2024-12-12T03:58:26.728062Z","shell.execute_reply":"2024-12-12T03:58:26.738406Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataloader = DataLoader(\n    ImageDataset(root, transforms_=transforms_, unaligned=True),\n    batch_size=batch_size,\n    shuffle=True,\n    num_workers=n_cpu\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":"2024-12-12T03:58:26.739956Z","iopub.execute_input":"2024-12-12T03:58:26.740153Z","iopub.status.idle":"2024-12-12T03:58:26.860163Z","shell.execute_reply.started":"2024-12-12T03:58:26.740134Z","shell.execute_reply":"2024-12-12T03:58:26.859664Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 13. Define function to get sample images","metadata":{}},{"cell_type":"markdown","source":"> TEST CODE : show image data","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nTensor = torch.cuda.FloatTensor if cuda else torch.Tensor\n\ndef sample_images(iter_loader):\n    \"\"\"show a generated sample from the test set\"\"\"\n    imgs = next(iter_loader)\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":"2024-12-12T03:58:26.861012Z","iopub.execute_input":"2024-12-12T03:58:26.86121Z","iopub.status.idle":"2024-12-12T03:58:26.866651Z","shell.execute_reply.started":"2024-12-12T03:58:26.86119Z","shell.execute_reply":"2024-12-12T03:58:26.865912Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"temp_imgs = next(iter(val_dataloader))","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:26.867597Z","iopub.execute_input":"2024-12-12T03:58:26.867866Z","iopub.status.idle":"2024-12-12T03:58:27.409711Z","shell.execute_reply.started":"2024-12-12T03:58:26.867831Z","shell.execute_reply":"2024-12-12T03:58:27.408729Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:27.411204Z","iopub.execute_input":"2024-12-12T03:58:27.411575Z","iopub.status.idle":"2024-12-12T03:58:27.41804Z","shell.execute_reply.started":"2024-12-12T03:58:27.41153Z","shell.execute_reply":"2024-12-12T03:58:27.417119Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:27.419284Z","iopub.execute_input":"2024-12-12T03:58:27.419686Z","iopub.status.idle":"2024-12-12T03:58:28.47099Z","shell.execute_reply.started":"2024-12-12T03:58:27.419649Z","shell.execute_reply":"2024-12-12T03:58:28.470322Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:28.47198Z","iopub.execute_input":"2024-12-12T03:58:28.47219Z","iopub.status.idle":"2024-12-12T03:58:28.476828Z","shell.execute_reply.started":"2024-12-12T03:58:28.47217Z","shell.execute_reply":"2024-12-12T03:58:28.476061Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:28.477769Z","iopub.execute_input":"2024-12-12T03:58:28.477994Z","iopub.status.idle":"2024-12-12T03:58:28.584385Z","shell.execute_reply.started":"2024-12-12T03:58:28.477971Z","shell.execute_reply":"2024-12-12T03:58:28.583669Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"type(temp_real_A)","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:28.585382Z","iopub.execute_input":"2024-12-12T03:58:28.58571Z","iopub.status.idle":"2024-12-12T03:58:28.590322Z","shell.execute_reply.started":"2024-12-12T03:58:28.585676Z","shell.execute_reply":"2024-12-12T03:58:28.58957Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:28.591256Z","iopub.execute_input":"2024-12-12T03:58:28.59148Z","iopub.status.idle":"2024-12-12T03:58:28.739661Z","shell.execute_reply.started":"2024-12-12T03:58:28.591458Z","shell.execute_reply":"2024-12-12T03:58:28.738913Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:28.740683Z","iopub.execute_input":"2024-12-12T03:58:28.740894Z","iopub.status.idle":"2024-12-12T03:58:28.745759Z","shell.execute_reply.started":"2024-12-12T03:58:28.740872Z","shell.execute_reply":"2024-12-12T03:58:28.74493Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:28.746745Z","iopub.execute_input":"2024-12-12T03:58:28.746967Z","iopub.status.idle":"2024-12-12T03:58:28.757052Z","shell.execute_reply.started":"2024-12-12T03:58:28.746945Z","shell.execute_reply":"2024-12-12T03:58:28.756156Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"temp_image_grid.cpu().permute(1,2,0).shape","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:28.757912Z","iopub.execute_input":"2024-12-12T03:58:28.758166Z","iopub.status.idle":"2024-12-12T03:58:28.775314Z","shell.execute_reply.started":"2024-12-12T03:58:28.758142Z","shell.execute_reply":"2024-12-12T03:58:28.774551Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2024-12-12T03:58:28.776372Z","iopub.execute_input":"2024-12-12T03:58:28.776714Z","iopub.status.idle":"2024-12-12T03:58:29.122181Z","shell.execute_reply.started":"2024-12-12T03:58:28.77668Z","shell.execute_reply":"2024-12-12T03:58:29.121424Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 14. Training","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport tqdm\nimport warnings\nimport time\n\niter_loader = iter(val_dataloader)","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:29.123199Z","iopub.execute_input":"2024-12-12T03:58:29.123422Z","iopub.status.idle":"2024-12-12T03:58:29.213641Z","shell.execute_reply.started":"2024-12-12T03:58:29.123399Z","shell.execute_reply":"2024-12-12T03:58:29.212211Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# WandB logging\nPROJECT = \"ukiyoe2photo-hanquoc\"\n\nwandb.init(\n    project=PROJECT,\n    config={\n        \"learning_rate\": lr,\n        \"epochs\": n_epochs,\n        \"batch_size\": batch_size,\n    },\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-12T03:58:29.215877Z","iopub.execute_input":"2024-12-12T03:58:29.216281Z","iopub.status.idle":"2024-12-12T03:58:36.243989Z","shell.execute_reply.started":"2024-12-12T03:58:29.216226Z","shell.execute_reply":"2024-12-12T03:58:36.242975Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"start_time_train = time.time()\nmax_time_train = 3600 * max_time_dict[\"h\"] + 60 * max_time_dict[\"m\"]\n\nfor epoch in tqdm.trange(epoch, n_epochs):\n    loss_D_cum = 0\n    loss_G_cum = 0\n    loss_GAN_cum = 0\n    loss_cycle_cum = 0\n    loss_identity_cum = 0\n\n    if time.time() - start_time_train > max_time_train:\n        print(\"EXCEEDED ALLOTTED TRAINING TIME. EXITING...\")\n        break\n    \n    for i, batch in enumerate(dataloader):\n        start_time_batch = time.time()\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 G_BA(A) vs. A\n        loss_id_A = criterion_identity(G_BA(real_A), real_A)\n        loss_id_B = criterion_identity(G_AB(real_B), real_B)\n        \n        loss_identity = (loss_id_A + loss_id_B)/2\n        \n        # GAN Loss\n        fake_B = G_AB(real_A)\n        loss_GAN_AB = criterion_GAN(D_B(fake_B), valid)\n        fake_A = G_BA(real_B)\n        loss_GAN_BA = criterion_GAN(D_A(fake_A), valid)\n        \n        loss_GAN = (loss_GAN_AB + loss_GAN_BA)/2\n        \n        # Cycle Loss\n        recov_A = G_BA(fake_B)\n        loss_cycle_A = criterion_cycle(recov_A, real_A)\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 Generators Loss\n        loss_G = loss_GAN + (lambda_cycle * loss_cycle) + (lambda_idt * loss_identity)\n        # 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)\n\n        fake_A = fake_A_buffer.push_and_pop(fake_A)\n        pred_fake = D_A(fake_A.detach())\n        loss_fake = criterion_GAN(pred_fake, 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)\n        \n        fake_B = fake_B_buffer.push_and_pop(fake_B)\n        pred_fake = D_B(fake_B.detach())\n        loss_fake = criterion_GAN(pred_fake, 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 Discriminators Loss\n        loss_D = (loss_D_A + loss_D_B)/2\n    \n        # -----------------\n        # Show Progress\n        # -----------------\n        if (i+1) % 200 == 0:\n            sample_images(iter_loader)\n            print('[Epoch %d/%d] [Batch %d/%d]\\n[D loss : %f]\\n[G loss : %f - (adv : %f, cycle : %f, identity : %f)]\\n[Epoch ETA : %d mins]'\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                      ((time.time() - start_time_batch) * (len(dataloader) - i+1)) // 60,\n                     ))\n        # -----------------\n        # Cum\n        # -----------------\n        loss_D_cum += loss_D.item()\n        loss_G_cum += loss_G.item()\n        loss_GAN_cum += loss_GAN.item()\n        loss_cycle_cum += loss_cycle.item()\n        loss_identity_cum += loss_identity.item()\n\n    # -----------------\n    # Save model checkpoint\n    # -----------------\n    print(f\"Saving to {os.getcwd()}\")\n    # torch.save(G_AB.state_dict(), 'G_AB.pth')\n    # torch.save(G_BA.state_dict(), 'G_BA.pth')\n    # torch.save(D_A.state_dict(), 'D_A.pth')\n    # torch.save(D_B.state_dict(), 'D_B.pth')\n\n    checkpoints = { \n        'epoch': epoch+1,\n        'G_BA': G_BA.state_dict(),\n        'G_AB': G_AB.state_dict(),\n        'D_A': D_A.state_dict(),\n        'D_B': D_B.state_dict(),\n        'optimizer_G': optimizer_G.state_dict(),\n        'optimizer_D_A': optimizer_D_A.state_dict(),\n        'optimizer_D_B': optimizer_D_B.state_dict(),\n        'lr_scheduler_D_A': lr_scheduler_D_A.state_dict(),\n        'lr_scheduler_D_B': lr_scheduler_D_B.state_dict(),\n    }\n    torch.save(checkpoints, 'later.pth')\n\n    # -----------------\n    # Loggin'\n    # -----------------\n    wandb.log({\n        \"loss D\": loss_D_cum / len(dataloader),\n        \"loss G\": loss_G_cum / len(dataloader),\n        \"loss adv\": loss_GAN_cum / len(dataloader),\n        \"loss cycle\": loss_cycle_cum / len(dataloader),\n        \"loss identity\": loss_identity_cum / len(dataloader),\n    })\n\n","metadata":{"execution":{"iopub.status.busy":"2024-12-12T03:58:36.24573Z","iopub.execute_input":"2024-12-12T03:58:36.246075Z"},"scrolled":true,"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"wandb.finish()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# checkpoints = { \n#     'epoch': epoch+1,\n#     'G_BA': G_BA.state_dict(),\n#     'G_AB': G_AB.state_dict(),\n#     'D_A': D_A.state_dict(),\n#     'D_B': D_B.state_dict(),\n#     'optimizer_G': optimizer_G.state_dict(),\n#     'optimizer_D_A': optimizer_D_A.state_dict(),\n#     'optimizer_D_B': optimizer_D_B.state_dict(),\n#     'lr_scheduler_D_A': lr_scheduler_D_A.state_dict(),\n#     'lr_scheduler_D_B': lr_scheduler_D_B.state_dict(),\n# }\n# torch.save(checkpoints, 'later.pth')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"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":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"> TEST CODE : Adversarial Ground Truths","metadata":{}},{"cell_type":"code","source":"# temp_A = batch['A'].type(Tensor)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# temp_A.shape","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# temp_img = temp_A.squeeze()\n# temp_img = temp_img.cpu().permute(1,2,0).numpy()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# temp_img.shape","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# plt.imshow(temp_img)\n# plt.axis('off');","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# D_A.output_shape","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# temp_A.size()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# temp_A.size(0) # batch_size","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tensor(np.ones((temp_A.size(0), *D_A.output_shape)))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Tensor(np.ones((temp_A.size(0), *D_A.output_shape))).shape","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"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":"## Step 15. Infer","metadata":{}},{"cell_type":"code","source":"# import random\n\n# # model = GeneratorResNet(input_shape=(3, 256, 256), num_residual_block=9)\n# model_BA = GeneratorUNet()\n# model_AB = GeneratorUNet()\n\n# # checkpoint = torch.load(\"/input/generator_b2a.pth\")\n# checkpoint_BA = torch.load(\"/kaggle/working/G_BA.pth\")\n# checkpoint_AB = torch.load(\"/kaggle/working/G_AB.pth\")\n\n# device = torch.device('cuda' if torch.cuda.is_available() else \"cpu\")\n\n# model_BA.load_state_dict(checkpoint_BA)\n# model_BA.to(device)\n# model_BA.eval()\n\n# model_AB.load_state_dict(checkpoint_AB)\n# model_AB.to(device)\n# model_AB.eval()\n\n# data_dir = \"../input/ukiyoe2photo/ukiyoe2photo\"\n# dir_b = os.path.join(data_dir, \"testB\")\n# files_B = [os.path.join(dir_b, name) for name in sorted(os.listdir(dir_b))]\n\n# transforms_temp = transforms.Compose([transforms.ToTensor(),])\n\n# NUM_TEST = 30\n\n# for filename in random.sample(files_B, NUM_TEST):\n#     image_B = Image.open(filename)\n\n#     if image_B.mode != 'RGB':\n#         image_B = to_rgb(image_B)\n            \n#     real_B = transforms_temp(image_B)\n#     real_B = real_B.type(Tensor)\n#     fake_A = model_BA(real_B[None, ...]).detach()\n#     cycled_B = model_AB(fake_A).detach()\n\n#     fig, ax = plt.subplots(1, 3, figsize=(10,5))\n\n#     plt.subplot(1, 3, 1)\n#     plt.imshow(real_B.cpu().permute(1,2,0))\n#     plt.title(\"Real Photo\")\n#     plt.axis('off')\n\n#     plt.subplot(1, 3, 2)\n#     fake_A = torch.squeeze(fake_A)\n#     plt.imshow(fake_A.cpu().permute(1,2,0))\n#     plt.title(\"Fake Ukiyo-e\")\n#     plt.axis('off')\n\n#     plt.subplot(1, 3, 3)\n#     cycled_B = torch.squeeze(cycled_B)\n#     plt.imshow(cycled_B.cpu().permute(1,2,0))\n#     plt.title(\"Cycled Photo\")\n#     plt.axis('off')\n    \n#     plt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}