{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\n\nimport torchvision.transforms as transforms\nfrom torchvision.utils import make_grid\n\nfrom torch.utils.data import DataLoader\nfrom torchvision import datasets\nfrom torch.autograd import Variable\n\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:32.666000Z","iopub.execute_input":"2023-10-07T07:39:32.666364Z","iopub.status.idle":"2023-10-07T07:39:32.671717Z","shell.execute_reply.started":"2023-10-07T07:39:32.666337Z","shell.execute_reply":"2023-10-07T07:39:32.670660Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# data directory \ndata_dir = '../input/gan-getting-started'\nn_cpu = 3\n# data (img)\nimg_height = 256\nimg_width = 256\nchannels = 3\n\n# training\nepoch = 0 # epoch to start training from\nn_epochs = 5 # number of epochs of training\nbatch_size = 1 # size of the batches\nlr = 0.0002 # adam : learning rate\nb1 = 0.5 # adam : decay of first order momentum of gradient\nb2 = 0.999 # adam : decay of first order momentum of gradient\ndecay_epoch = 3 # suggested default : 100 (suggested 'n_epochs' is 200)\n                 # epoch from which to start lr decay","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:32.675936Z","iopub.execute_input":"2023-10-07T07:39:32.676322Z","iopub.status.idle":"2023-10-07T07:39:32.686557Z","shell.execute_reply.started":"2023-10-07T07:39:32.676263Z","shell.execute_reply":"2023-10-07T07:39:32.685670Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport glob\nprint(data_dir+'/monet_jpg')\n\n","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:32.688717Z","iopub.execute_input":"2023-10-07T07:39:32.689383Z","iopub.status.idle":"2023-10-07T07:39:32.707062Z","shell.execute_reply.started":"2023-10-07T07:39:32.689260Z","shell.execute_reply":"2023-10-07T07:39:32.705998Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(glob.glob(os.path.join(data_dir+'/monet_jpg')+'/*.*'))","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:32.708423Z","iopub.execute_input":"2023-10-07T07:39:32.709343Z","iopub.status.idle":"2023-10-07T07:39:32.723925Z","shell.execute_reply.started":"2023-10-07T07:39:32.709315Z","shell.execute_reply":"2023-10-07T07:39:32.722878Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(glob.glob(os.path.join(data_dir+'/photo_jpg')+'/*.*'))","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:32.726397Z","iopub.execute_input":"2023-10-07T07:39:32.726949Z","iopub.status.idle":"2023-10-07T07:39:32.750394Z","shell.execute_reply.started":"2023-10-07T07:39:32.726921Z","shell.execute_reply":"2023-10-07T07:39:32.749483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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]\ndef 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-10-07T07:39:32.751602Z","iopub.execute_input":"2023-10-07T07:39:32.752162Z","iopub.status.idle":"2023-10-07T07:39:32.758093Z","shell.execute_reply.started":"2023-10-07T07:39:32.752134Z","shell.execute_reply":"2023-10-07T07:39:32.757252Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nfrom 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        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            \n","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:32.759211Z","iopub.execute_input":"2023-10-07T07:39:32.759956Z","iopub.status.idle":"2023-10-07T07:39:32.772004Z","shell.execute_reply.started":"2023-10-07T07:39:32.759927Z","shell.execute_reply":"2023-10-07T07:39:32.771107Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataloader = DataLoader(\n    ImageDataset(data_dir, transforms_=transforms_, unaligned=True),\n    batch_size=1, # 1\n    shuffle=True,\n    num_workers= n_cpu\n)\n\nval_dataloader = DataLoader(\n    ImageDataset(data_dir, 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-10-07T07:39:32.773031Z","iopub.execute_input":"2023-10-07T07:39:32.774035Z","iopub.status.idle":"2023-10-07T07:39:32.822659Z","shell.execute_reply.started":"2023-10-07T07:39:32.774005Z","shell.execute_reply":"2023-10-07T07:39:32.821777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Define Generator\n","metadata":{}},{"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)","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:32.823907Z","iopub.execute_input":"2023-10-07T07:39:32.824184Z","iopub.status.idle":"2023-10-07T07:39:32.829760Z","shell.execute_reply.started":"2023-10-07T07:39:32.824158Z","shell.execute_reply":"2023-10-07T07:39:32.828806Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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)","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:32.832014Z","iopub.execute_input":"2023-10-07T07:39:32.832606Z","iopub.status.idle":"2023-10-07T07:39:32.849787Z","shell.execute_reply.started":"2023-10-07T07:39:32.832576Z","shell.execute_reply":"2023-10-07T07:39:32.848713Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class 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        # 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-10-07T07:39:32.851676Z","iopub.execute_input":"2023-10-07T07:39:32.852222Z","iopub.status.idle":"2023-10-07T07:39:32.863095Z","shell.execute_reply.started":"2023-10-07T07:39:32.852190Z","shell.execute_reply":"2023-10-07T07:39:32.862334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"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-10-07T07:39:32.864361Z","iopub.execute_input":"2023-10-07T07:39:32.864844Z","iopub.status.idle":"2023-10-07T07:39:32.882589Z","shell.execute_reply.started":"2023-10-07T07:39:32.864816Z","shell.execute_reply":"2023-10-07T07:39:32.881828Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Difine 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-10-07T07:39:32.885082Z","iopub.execute_input":"2023-10-07T07:39:32.885595Z","iopub.status.idle":"2023-10-07T07:39:32.903180Z","shell.execute_reply.started":"2023-10-07T07:39:32.885565Z","shell.execute_reply":"2023-10-07T07:39:32.902409Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Initialize Generator and Discriminator\n","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-10-07T07:39:32.904556Z","iopub.execute_input":"2023-10-07T07:39:32.905293Z","iopub.status.idle":"2023-10-07T07:39:33.264078Z","shell.execute_reply.started":"2023-10-07T07:39:32.905241Z","shell.execute_reply":"2023-10-07T07:39:33.263149Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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-10-07T07:39:33.265233Z","iopub.execute_input":"2023-10-07T07:39:33.265762Z","iopub.status.idle":"2023-10-07T07:39:37.980336Z","shell.execute_reply.started":"2023-10-07T07:39:33.265728Z","shell.execute_reply":"2023-10-07T07:39:37.979407Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"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-10-07T07:39:37.981636Z","iopub.execute_input":"2023-10-07T07:39:37.981953Z","iopub.status.idle":"2023-10-07T07:39:37.988115Z","shell.execute_reply.started":"2023-10-07T07:39:37.981925Z","shell.execute_reply":"2023-10-07T07:39:37.987258Z"},"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-10-07T07:39:37.989497Z","iopub.execute_input":"2023-10-07T07:39:37.990666Z","iopub.status.idle":"2023-10-07T07:39:38.049634Z","shell.execute_reply.started":"2023-10-07T07:39:37.990631Z","shell.execute_reply":"2023-10-07T07:39:38.048723Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"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)\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-10-07T07:39:38.050729Z","iopub.execute_input":"2023-10-07T07:39:38.051484Z","iopub.status.idle":"2023-10-07T07:39:38.058198Z","shell.execute_reply.started":"2023-10-07T07:39:38.051456Z","shell.execute_reply":"2023-10-07T07:39:38.057072Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Learning rate Decay Scheduling","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)\n","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:38.062147Z","iopub.execute_input":"2023-10-07T07:39:38.062957Z","iopub.status.idle":"2023-10-07T07:39:38.072874Z","shell.execute_reply.started":"2023-10-07T07:39:38.062935Z","shell.execute_reply":"2023-10-07T07:39:38.072013Z"},"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-10-07T07:39:38.074110Z","iopub.execute_input":"2023-10-07T07:39:38.074479Z","iopub.status.idle":"2023-10-07T07:39:38.086144Z","shell.execute_reply.started":"2023-10-07T07:39:38.074447Z","shell.execute_reply":"2023-10-07T07:39:38.085419Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Step 13. Define function to get sample images¶\n","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:38.087175Z","iopub.execute_input":"2023-10-07T07:39:38.088008Z","iopub.status.idle":"2023-10-07T07:39:38.099514Z","shell.execute_reply.started":"2023-10-07T07:39:38.087973Z","shell.execute_reply":"2023-10-07T07:39:38.098630Z"},"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-10-07T07:39:38.100911Z","iopub.execute_input":"2023-10-07T07:39:38.101510Z","iopub.status.idle":"2023-10-07T07:39:38.119218Z","shell.execute_reply.started":"2023-10-07T07:39:38.101469Z","shell.execute_reply":"2023-10-07T07:39:38.118454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def sample_images():\n    \"\"\"show a generated sample from the test set\"\"\"\n    imgs = next(iter(val_dataloader))\n    G_AB.eval()\n    G_BA.eval()\n    real_A = imgs['A'].type(Tensor) # A : monet\n    fake_B = G_AB(real_A).detach()\n    real_B = imgs['B'].type(Tensor) # B : photo\n    fake_A = G_BA(real_B).detach()\n    # Arange images along x-axis\n    real_A = make_grid(real_A, nrow=5, normalize=True)\n    fake_B = make_grid(fake_B, nrow=5, normalize=True)\n    real_B = make_grid(real_B, nrow=5, normalize=True)\n    fake_A = make_grid(fake_A, nrow=5, normalize=True)\n    # Arange images along y-axis    \n    image_grid = torch.cat((real_A, fake_B, real_B, fake_A), 1)\n    plt.imshow(image_grid.cpu().permute(1,2,0))\n    plt.title('Real A vs Fake B | Real B vs Fake A')\n    plt.axis('off')\n    plt.show();","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:38.120538Z","iopub.execute_input":"2023-10-07T07:39:38.120824Z","iopub.status.idle":"2023-10-07T07:39:38.135099Z","shell.execute_reply.started":"2023-10-07T07:39:38.120798Z","shell.execute_reply":"2023-10-07T07:39:38.134331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Testing and checking","metadata":{}},{"cell_type":"code","source":"temp_imgs = next(iter(val_dataloader))\n","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:38.136362Z","iopub.execute_input":"2023-10-07T07:39:38.136651Z","iopub.status.idle":"2023-10-07T07:39:38.636692Z","shell.execute_reply.started":"2023-10-07T07:39:38.136624Z","shell.execute_reply":"2023-10-07T07:39:38.635468Z"},"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)","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:38.638315Z","iopub.execute_input":"2023-10-07T07:39:38.640252Z","iopub.status.idle":"2023-10-07T07:39:38.647195Z","shell.execute_reply.started":"2023-10-07T07:39:38.640218Z","shell.execute_reply":"2023-10-07T07:39:38.646238Z"},"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-10-07T07:39:38.648788Z","iopub.execute_input":"2023-10-07T07:39:38.650035Z","iopub.status.idle":"2023-10-07T07:39:47.416016Z","shell.execute_reply.started":"2023-10-07T07:39:38.650006Z","shell.execute_reply":"2023-10-07T07:39:47.415032Z"},"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-10-07T07:39:47.417459Z","iopub.execute_input":"2023-10-07T07:39:47.417978Z","iopub.status.idle":"2023-10-07T07:39:47.423308Z","shell.execute_reply.started":"2023-10-07T07:39:47.417946Z","shell.execute_reply":"2023-10-07T07:39:47.422458Z"},"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-10-07T07:39:47.424692Z","iopub.execute_input":"2023-10-07T07:39:47.425300Z","iopub.status.idle":"2023-10-07T07:39:47.543991Z","shell.execute_reply.started":"2023-10-07T07:39:47.425251Z","shell.execute_reply":"2023-10-07T07:39:47.543027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(temp_real_A.cpu().permute(1,2,0))\nplt.title('Real A')\nplt.axis('off');","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:47.545235Z","iopub.execute_input":"2023-10-07T07:39:47.546074Z","iopub.status.idle":"2023-10-07T07:39:47.861957Z","shell.execute_reply.started":"2023-10-07T07:39:47.546043Z","shell.execute_reply":"2023-10-07T07:39:47.861014Z"},"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-10-07T07:39:47.863009Z","iopub.execute_input":"2023-10-07T07:39:47.863330Z","iopub.status.idle":"2023-10-07T07:39:47.869600Z","shell.execute_reply.started":"2023-10-07T07:39:47.863301Z","shell.execute_reply":"2023-10-07T07:39:47.868692Z"},"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-10-07T07:39:47.871111Z","iopub.execute_input":"2023-10-07T07:39:47.871739Z","iopub.status.idle":"2023-10-07T07:39:47.883687Z","shell.execute_reply.started":"2023-10-07T07:39:47.871708Z","shell.execute_reply":"2023-10-07T07:39:47.882607Z"},"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-10-07T07:39:47.884866Z","iopub.execute_input":"2023-10-07T07:39:47.885424Z","iopub.status.idle":"2023-10-07T07:39:47.904144Z","shell.execute_reply.started":"2023-10-07T07:39:47.885396Z","shell.execute_reply":"2023-10-07T07:39:47.903222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.imshow(temp_image_grid.cpu().permute(1,2,0))\nplt.title('Real A | Fake B | Real B | Fake A ')\nplt.axis('off');","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:39:47.905479Z","iopub.execute_input":"2023-10-07T07:39:47.906395Z","iopub.status.idle":"2023-10-07T07:39:48.429217Z","shell.execute_reply.started":"2023-10-07T07:39:47.906366Z","shell.execute_reply":"2023-10-07T07:39:48.428204Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Training Step\n","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom tqdm.notebook import tqdm\nimport warnings\n","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:42:25.830927Z","iopub.execute_input":"2023-10-07T07:42:25.831476Z","iopub.status.idle":"2023-10-07T07:42:25.929365Z","shell.execute_reply.started":"2023-10-07T07:42:25.831435Z","shell.execute_reply":"2023-10-07T07:42:25.928352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for epoch in range(epoch, n_epochs):\n    for i, batch in enumerate(tqdm(dataloader)):\n        \n        # Set model input\n        real_A = batch['A'].type(Tensor)\n        real_B = batch['B'].type(Tensor)\n        \n        # Adversarial ground truths\n        valid = Tensor(np.ones((real_A.size(0), *D_A.output_shape))) # requires_grad = False. Default.\n        fake = Tensor(np.zeros((real_A.size(0), *D_A.output_shape))) # requires_grad = False. Default.\n        \n# -----------------\n# Train Generators\n# -----------------\n        G_AB.train() # train mode\n        G_BA.train() # train mode\n        \n        optimizer_G.zero_grad() # Integrated optimizer(G_AB, G_BA)\n        \n        # Identity Loss\n        loss_id_A = criterion_identity(G_BA(real_A), real_A) # If you put A into a generator that creates A with B,\n        loss_id_B = criterion_identity(G_AB(real_B), real_B) # then of course A must come out as it is.\n                                                             # Taking this into consideration, add an identity loss that simply compares 'A and A' (or 'B and B').\n        loss_identity = (loss_id_A + loss_id_B)/2\n        \n        # GAN Loss\n        fake_B = G_AB(real_A) # fake_B is fake-photo that generated by real monet-drawing\n        loss_GAN_AB = criterion_GAN(D_B(fake_B), valid) # tricking the 'fake-B' into 'real-B'\n        fake_A = G_BA(real_B)\n        loss_GAN_BA = criterion_GAN(D_A(fake_A), valid) # tricking the 'fake-A' into 'real-A'\n        \n        loss_GAN = (loss_GAN_AB + loss_GAN_BA)/2\n        \n        # Cycle Loss\n        recov_A = G_BA(fake_B) # recov_A is fake-monet-drawing that generated by fake-photo\n        loss_cycle_A = criterion_cycle(recov_A, real_A) # Reduces the difference between the restored image and the real image\n        recov_B = G_AB(fake_A)\n        loss_cycle_B = criterion_cycle(recov_B, real_B)\n        \n        loss_cycle = (loss_cycle_A + loss_cycle_B)/2\n        \n# ------> Total Loss\n        loss_G = loss_GAN + (10.0*loss_cycle) + (5.0*loss_identity) # multiply suggested weight(default cycle loss weight : 10, default identity loss weight : 5)\n        \n        loss_G.backward()\n        optimizer_G.step()\n        \n# -----------------\n# Train Discriminator A\n# -----------------\n        optimizer_D_A.zero_grad()\n    \n        loss_real = criterion_GAN(D_A(real_A), valid) # train to discriminate real images as real\n        loss_fake = criterion_GAN(D_A(fake_A.detach()), fake) # train to discriminate fake images as fake\n        \n        loss_D_A = (loss_real + loss_fake)/2\n        \n        loss_D_A.backward()\n        optimizer_D_A.step()\n\n# -----------------\n# Train Discriminator B\n# -----------------\n        optimizer_D_B.zero_grad()\n    \n        loss_real = criterion_GAN(D_B(real_B), valid) # train to discriminate real images as real\n        loss_fake = criterion_GAN(D_B(fake_B.detach()), fake) # train to discriminate fake images as fake\n        \n        loss_D_B = (loss_real + loss_fake)/2\n        \n        loss_D_B.backward()\n        optimizer_D_B.step()\n        \n# ------> Total Loss\n        loss_D = (loss_D_A + loss_D_B)/2\n    \n# -----------------\n# Show Progress\n# -----------------\n        if (i+1) % 50 == 0:\n            sample_images()\n            print('[Epoch %d/%d] [Batch %d/%d] [D loss : %f] [G loss : %f - (adv : %f, cycle : %f, identity : %f)]'\n                    %(epoch+1,n_epochs,       # [Epoch -]\n                      i+1,len(dataloader),   # [Batch -]\n                      loss_D.item(),       # [D loss -]\n                      loss_G.item(),       # [G loss -]\n                      loss_GAN.item(),     # [adv -]\n                      loss_cycle.item(),   # [cycle -]\n                      loss_identity.item(),# [identity -]\n                     ))","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:42:27.769315Z","iopub.execute_input":"2023-10-07T07:42:27.769641Z","iopub.status.idle":"2023-10-07T07:55:20.949247Z","shell.execute_reply.started":"2023-10-07T07:42:27.769614Z","shell.execute_reply":"2023-10-07T07:55:20.948003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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-10-07T07:55:20.951520Z","iopub.execute_input":"2023-10-07T07:55:20.952508Z","iopub.status.idle":"2023-10-07T07:55:21.303636Z","shell.execute_reply.started":"2023-10-07T07:55:20.952474Z","shell.execute_reply":"2023-10-07T07:55:21.302386Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Generate Image","metadata":{}},{"cell_type":"code","source":"photo_dir = os.path.join(data_dir, 'photo_jpg')\nfiles = [os.path.join(photo_dir, name) for name in os.listdir(photo_dir)]\nlen(files)","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:56:49.651978Z","iopub.execute_input":"2023-10-07T07:56:49.652376Z","iopub.status.idle":"2023-10-07T07:56:49.675970Z","shell.execute_reply.started":"2023-10-07T07:56:49.652348Z","shell.execute_reply":"2023-10-07T07:56:49.674701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"save_dir = '../images'\nif not os.path.exists(save_dir):\n    os.makedirs(save_dir)","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:56:51.489847Z","iopub.execute_input":"2023-10-07T07:56:51.490181Z","iopub.status.idle":"2023-10-07T07:56:51.495544Z","shell.execute_reply.started":"2023-10-07T07:56:51.490154Z","shell.execute_reply":"2023-10-07T07:56:51.494358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"generate_transforms = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n])\n\nto_image = transforms.ToPILImage()\n\nG_BA.eval()\nfor i in range(0, len(files), batch_size):\n    # read images\n    imgs = []\n    for j in range(i, min(len(files), i+batch_size)):\n        img = Image.open(files[j])\n        img = generate_transforms(img)\n        imgs.append(img)\n    imgs = torch.stack(imgs, 0).type(Tensor)\n    \n    # generate\n    fake_imgs = G_BA(imgs).detach().cpu()\n    \n    # save\n    for j in range(fake_imgs.size(0)):\n        img = fake_imgs[j].squeeze().permute(1, 2, 0)\n        img_arr = img.numpy()\n        img_arr = (img_arr - np.min(img_arr)) * 255 / (np.max(img_arr) - np.min(img_arr))\n        img_arr = img_arr.astype(np.uint8)\n        \n        img = to_image(img_arr)\n        _, name = os.path.split(files[i+j])\n        img.save(os.path.join(save_dir, name))\n","metadata":{"execution":{"iopub.status.busy":"2023-10-07T07:56:56.283500Z","iopub.execute_input":"2023-10-07T07:56:56.283840Z","iopub.status.idle":"2023-10-07T08:01:08.489147Z","shell.execute_reply.started":"2023-10-07T07:56:56.283813Z","shell.execute_reply":"2023-10-07T08:01:08.488182Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")","metadata":{"execution":{"iopub.status.busy":"2023-10-07T08:01:13.288128Z","iopub.execute_input":"2023-10-07T08:01:13.288705Z","iopub.status.idle":"2023-10-07T08:01:15.724696Z","shell.execute_reply.started":"2023-10-07T08:01:13.288672Z","shell.execute_reply":"2023-10-07T08:01:15.723711Z"},"trusted":true},"execution_count":null,"outputs":[]}]}