{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"> # **⟲CycleGAN_Pytorch (Training)⟲**","metadata":{}},{"cell_type":"code","source":"# !zip -r file.zip directory_path\n# os.makedirs('../input/preview')\n# cv2.imwrite(\"filename.png\", img)","metadata":{"execution":{"iopub.status.busy":"2021-12-22T09:16:08.616583Z","iopub.execute_input":"2021-12-22T09:16:08.617203Z","iopub.status.idle":"2021-12-22T09:16:33.776929Z","shell.execute_reply.started":"2021-12-22T09:16:08.617103Z","shell.execute_reply":"2021-12-22T09:16:33.776091Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !pip install wandb\n","metadata":{"execution":{"iopub.status.busy":"2022-12-04T09:25:54.875445Z","iopub.execute_input":"2022-12-04T09:25:54.875746Z","iopub.status.idle":"2022-12-04T09:25:54.879988Z","shell.execute_reply.started":"2022-12-04T09:25:54.875712Z","shell.execute_reply":"2022-12-04T09:25:54.879310Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import wandb","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:31:52.394156Z","iopub.execute_input":"2022-12-05T08:31:52.394493Z","iopub.status.idle":"2022-12-05T08:31:53.071567Z","shell.execute_reply.started":"2022-12-05T08:31:52.394410Z","shell.execute_reply":"2022-12-05T08:31:53.070637Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open('/root/.netrc', 'w', encoding='utf-8') as f:\n    f.write('''machine api.wandb.ai\n        login user\n        password 22eff3c6a2aefa82e35e00f9c8e01b065c5e3ce0\n    ''')","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:31:55.257578Z","iopub.execute_input":"2022-12-05T08:31:55.258399Z","iopub.status.idle":"2022-12-05T08:31:55.265642Z","shell.execute_reply.started":"2022-12-05T08:31:55.258361Z","shell.execute_reply":"2022-12-05T08:31:55.264771Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"wandb.init(project = 'cycle-gan',entity=\"iuh\", name = 'model-gan')","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:31:56.971155Z","iopub.execute_input":"2022-12-05T08:31:56.971424Z","iopub.status.idle":"2022-12-05T08:32:04.617884Z","shell.execute_reply.started":"2022-12-05T08:31:56.971393Z","shell.execute_reply":"2022-12-05T08:32:04.616887Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport os\nfrom PIL import Image\nimport itertools\nfrom tqdm import tqdm\nimport cv2\n\n\nimport torch\nimport torchvision\n\nimport torch.optim.lr_scheduler as lr_scheduler\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as T\nimport torch.nn as nn","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:32:13.332436Z","iopub.execute_input":"2022-12-05T08:32:13.332724Z","iopub.status.idle":"2022-12-05T08:32:15.159416Z","shell.execute_reply.started":"2022-12-05T08:32:13.332686Z","shell.execute_reply":"2022-12-05T08:32:15.158540Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path = ['/kaggle/input/cuhk-dataset-256/sketches/sketches/','/kaggle/input/cuhk-dataset-256/photos/photos/']\nmonet = os.listdir('/kaggle/input/cuhk-dataset-256/sketches/sketches')\nphoto = os.listdir('/kaggle/input/cuhk-dataset-256/photos/photos')","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:33:05.216133Z","iopub.execute_input":"2022-12-05T08:33:05.216405Z","iopub.status.idle":"2022-12-05T08:33:05.489640Z","shell.execute_reply.started":"2022-12-05T08:33:05.216377Z","shell.execute_reply":"2022-12-05T08:33:05.488875Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# path = ['/kaggle/input/gan-getting-started/monet_jpg/','/kaggle/input/gan-getting-started/photo_jpg/']\n# monet = os.listdir('/kaggle/input/gan-getting-started/monet_jpg')\n# photo = os.listdir('/kaggle/input/gan-getting-started/photo_jpg')","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:33:06.525113Z","iopub.execute_input":"2022-12-05T08:33:06.525410Z","iopub.status.idle":"2022-12-05T08:33:06.532530Z","shell.execute_reply.started":"2022-12-05T08:33:06.525381Z","shell.execute_reply":"2022-12-05T08:33:06.531671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#visulization\n\ndef de_norm(input):\n    mean = 0.5 \n    std = 0.5\n    return input * std + mean\n\ndef visulization(x,y,z):\n    x = x.cpu().detach().numpy().transpose(1,2,0)\n    y = y.cpu().detach().numpy().transpose(1,2,0)\n    z = z.cpu().detach().numpy().transpose(1,2,0)\n    x = de_norm(x)\n    y = de_norm(y)\n    z = de_norm(z)\n    \n    print('photo Data Range', x.max(), x.min())\n    print('Fake monet Data Range',y.max(), y.min())\n    print('Cycle photo Data Range',z.max(), z.min())\n    plt.figure(figsize = (10,5))\n    plt.subplot(1,3,1)\n    plt.title('actual')\n    plt.imshow(x)\n    plt.tick_params(left = False, bottom = False, labelleft = False, labelbottom = False)\n    plt.subplot(1,3,2)\n    plt.title('fake')\n    plt.imshow(y)\n    plt.tick_params(left = False, bottom = False, labelleft = False, labelbottom = False)\n    plt.subplot(1,3,3)\n    plt.title('cycle')\n    plt.imshow(z)\n    plt.tick_params(left = False, bottom = False, labelleft = False, labelbottom = False)\n    plt.show()\n    \n# weight initialization \ndef weight_init(m : 'model'):\n    classname = m.__class__.__name__\n    if classname.find('Conv') != -1:\n        nn.init.normal_(m.weight.data, 0.0, 0.02)\n    elif classname.find('Instance') != -1:\n        nn.init.normal_(m.weight.data, 1.0, 0.02)\n        nn.init.constant_(m.bias.data, 0)\n\ndef update_req_grad(models, requires_grad=True):\n    for model in models:\n        for param in model.parameters():\n            param.requires_grad = requires_grad","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:33:08.148301Z","iopub.execute_input":"2022-12-05T08:33:08.149296Z","iopub.status.idle":"2022-12-05T08:33:08.162803Z","shell.execute_reply.started":"2022-12-05T08:33:08.149248Z","shell.execute_reply":"2022-12-05T08:33:08.161743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Defining Dataset\ntrain_transform = T.Compose([T.RandomHorizontalFlip(p = 0.5),\n                             T.RandomVerticalFlip(p = 0.5),\n                             T.RandomRotation(180),\n                             T.ToTensor(),\n                             T.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])\n\n\nclass CustomDataset(Dataset):\n    def __init__(self, path, monet, photo, transforms = None, seed = 777):\n        self.path = path\n        self.monet = monet\n        self.photo = photo\n        self.seed = seed\n        self.transforms = transforms\n        self.photo_len = len(self.monet)\n        self.monet_len = len(self.photo)\n        self.length_dataset = max(self.photo_len, self.monet_len)\n        \n        \n    def __len__(self):\n        return len(self.monet)\n    \n    def __getitem__(self, idx):\n       \n        #get path\n        monet_path = self.path[0] + self.monet[idx]\n        photo_idx = np.random.randint(0, len(self.photo))\n        photo_path = self.path[1] + self.photo[photo_idx]\n        #get image\n        monet = Image.open(monet_path).convert('RGB')\n        photo = Image.open(photo_path).convert('RGB')\n        #image Transform\n        if self.transforms:\n            torch.manual_seed(self.seed)\n            monet = self.transforms(monet)\n        if self.transforms:\n            torch.manual_seed(self.seed)\n            photo = self.transforms(photo)\n        return monet, photo","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:33:08.824050Z","iopub.execute_input":"2022-12-05T08:33:08.824334Z","iopub.status.idle":"2022-12-05T08:33:08.839322Z","shell.execute_reply.started":"2022-12-05T08:33:08.824301Z","shell.execute_reply":"2022-12-05T08:33:08.838436Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # **⟲CycleGAN Network⟲**","metadata":{}},{"cell_type":"markdown","source":"![](https://www.researchgate.net/profile/Irene-Gu-2/publication/343075688/figure/fig3/AS:916527951917056@1595528700573/Architecture-of-the-generator-and-discriminator-of-unpaired-CycleGAN-Conv-2D.ppm)\n","metadata":{}},{"cell_type":"code","source":"#Cycle GAN\n#Generator(Photo <--> Monet)\n#Defining layers\nclass Generator(nn.Module):\n    def __init__(self):\n        super(Generator, self).__init__()\n        \n        #1. Conv layers\n        \n        def CLayer(in_ch, out_ch, kernel_size = 3, stride = 1, padding = 1, bias = True, norm = 'bnorm', relu = 'relu'):\n            layers = []\n\n            layers += [nn.ReflectionPad2d(padding)]\n                         \n            layers += [nn.Conv2d(in_channels = in_ch,\n                                 out_channels = out_ch,\n                                 kernel_size = kernel_size,\n                                 stride = stride,\n                                 padding = 0,\n                                 bias = bias)]\n            if not norm is None:\n                if norm == 'bnorm':\n                    layers += [nn.BatchNorm2d(num_features = out_ch)]\n                elif norm =='inorm':\n                    layers += [nn.InstanceNorm2d(num_features = out_ch)]\n            \n            if relu == 'relu':\n                layers += [nn.ReLU()]\n            elif relu == 'leakyrelu':\n                layers += [nn.LeakyReLU()]\n                \n            return nn.Sequential(*layers)\n        \n        #2. Residual Blocks\n        \n        def Rblock(in_ch, out_ch, kernel_size = 3, stride = 1, padding = 1, bias = True, norm = 'bnorm', relu = 0.0):\n            layers = []\n            layers += [CLayer(in_ch = in_ch,\n                              out_ch = out_ch,\n                              kernel_size = kernel_size,\n                              stride = stride,\n                              padding = padding,\n                              bias = bias,\n                              norm = norm)]\n            \n            layers += [CLayer(in_ch = in_ch,\n                              out_ch = out_ch,\n                              kernel_size = kernel_size,\n                              stride = stride,\n                              padding = padding,\n                              bias = bias,\n                              norm = norm,\n                             relu = None)]\n            return nn.Sequential(*layers)\n        \n        #3. Transpose Conv layers\n        \n        def TCLayer(in_ch, out_ch, kernel_size = 3, stride = 2, padding = 1, output_padding = 1, bias = True, norm = 'bnorm', relu = 'relu', dropout = None):\n            layers = []\n            layers += [nn.ConvTranspose2d(in_channels = in_ch,\n                                         out_channels = out_ch,\n                                         kernel_size = kernel_size,\n                                         stride = stride,\n                                         padding = padding,\n                                         output_padding = output_padding,\n                                         bias = bias)]\n            if not dropout is None:\n              if dropout == True:\n                layers += [nn.Dropout(0.5)]\n\n            if not norm is None:\n                if norm == 'bnorm':\n                    layers += [nn.BatchNorm2d(num_features = out_ch)]\n                elif norm =='inorm':\n                    layers += [nn.InstanceNorm2d(num_features = out_ch)]\n            if not relu is None:        \n              if relu == 'relu':\n                  layers += [nn.ReLU()]\n              elif relu == 'leakyrelu':\n                  layers += [nn.LeakyReLU(0.2)]\n                \n            return nn.Sequential(*layers)\n\n        #Encoder\n        self.encoder1 = CLayer(in_ch = 3, out_ch = 64 , kernel_size = 7, stride = 1, padding = 3, norm = None, relu = 'relu')\n        self.encoder2 = CLayer(in_ch = 64, out_ch = 128 , kernel_size = 3, stride = 2, padding = 1, norm = 'inorm', relu = 'relu')\n        self.encoder3 = CLayer(in_ch = 128, out_ch = 256 , kernel_size = 3, stride = 2, padding = 1, norm = 'inorm', relu = 'relu')\n\n        #Transformer\n        res_layer = []\n        \n        for i in range(9):\n            res_layer += [Rblock(in_ch = 256, out_ch = 256, kernel_size = 3, stride = 1, padding = 1, norm = 'inorm', relu = 'relu')]\n            \n        self.trans = nn.Sequential(*res_layer)\n\n        #Decoder\n        self.decoder1 = TCLayer(in_ch = 256, out_ch = 128, kernel_size = 3, stride = 2, padding = 1, output_padding = 1, norm = 'inorm', relu = 'relu', dropout=True)\n        self.decoder2 = TCLayer(in_ch = 128, out_ch = 64, kernel_size = 3, stride = 2, padding = 1, output_padding = 1, norm = 'inorm', relu = 'relu', dropout=True)\n        self.decoder3 = CLayer(in_ch = 64, out_ch = 3 , kernel_size = 7, stride = 1, padding = 3, norm = 'inorm', relu = None) #No activation Function\n        \n    def forward(self, input):\n        \n        #Encoder\n        x = self.encoder1(input)\n        x = self.encoder2(x)\n        x = self.encoder3(x)\n        \n        #Transformer\n        x = self.trans(x)\n        \n        #Decoder\n        x = self.decoder1(x)\n        x = self.decoder2(x)\n        x = self.decoder3(x)\n        \n        output = torch.tanh(x)\n        \n        return output","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:33:10.554236Z","iopub.execute_input":"2022-12-05T08:33:10.554505Z","iopub.status.idle":"2022-12-05T08:33:10.579466Z","shell.execute_reply.started":"2022-12-05T08:33:10.554475Z","shell.execute_reply":"2022-12-05T08:33:10.578333Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Cycle GAN\n#Discriminator(Photo <--> Monet)\n#Defining layers\nclass Discriminator(nn.Module):\n    def __init__(self):\n        super(Discriminator, self).__init__()\n        \n        #1. Conv layers\n        \n        def CLayer(in_ch, out_ch, kernel_size = 3, stride = 1, padding = 1, bias = True, norm = 'bnorm', relu = 'relu'):\n            layers = []\n\n            layers += [nn.Conv2d(in_channels = in_ch,\n                                 out_channels = out_ch,\n                                 kernel_size = kernel_size,\n                                 stride = stride,\n                                 padding = 0,\n                                 bias = bias)]\n            if not norm is None:\n                if norm == 'bnorm':\n                    layers += [nn.BatchNorm2d(num_features = out_ch)]\n                elif norm =='inorm':\n                    layers += [nn.InstanceNorm2d(num_features = out_ch)]\n            \n            if relu == 'relu':\n                layers += [nn.ReLU()]\n            elif relu == 'leakyrelu':\n                layers += [nn.LeakyReLU(0.2, inplace = True)]\n                \n            return nn.Sequential(*layers)\n        \n        self.decoder1 = CLayer(in_ch = 3, out_ch = 64, kernel_size = 4, stride = 2, padding = 1, bias = False, norm = None, relu = 'leakyrelu')\n        self.decoder2 = CLayer(in_ch = 64, out_ch = 128, kernel_size = 4, stride = 2, padding = 1, bias = False, norm = None, relu = 'leakyrelu')\n        self.decoder3 = CLayer(in_ch = 128, out_ch = 256, kernel_size = 4, stride = 2, padding = 1, bias = False, norm = None, relu = 'leakyrelu')\n        self.decoder4 = CLayer(in_ch = 256, out_ch = 512, kernel_size = 4, stride = 1, padding = 1, bias = False, norm = None, relu = 'leakyrelu')\n        self.decoder5 = CLayer(in_ch = 512, out_ch = 1, kernel_size = 4, stride = 1, padding = 1, bias = False, norm = None, relu = None)\n        \n    def forward(self, input):\n        \n        x = self.decoder1(input)\n        x = self.decoder2(x)\n        x = self.decoder3(x)\n        x = self.decoder4(x)\n        output = self.decoder5(x)\n        \n        \n        return output","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:33:14.370147Z","iopub.execute_input":"2022-12-05T08:33:14.372682Z","iopub.status.idle":"2022-12-05T08:33:14.394665Z","shell.execute_reply.started":"2022-12-05T08:33:14.372625Z","shell.execute_reply":"2022-12-05T08:33:14.393302Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Training\n#configure\nlr = 0.0002\nn_epoch = 10\nbatch_size = 1\nsetting_patience = 7\n\n\n\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\n#Defineing Model\nGM2P = Generator().to(device) #Monet ---> Photo\nGP2M = Generator().to(device) #Photo ---> Monet\nDM2P = Discriminator().to(device) #Monet ---> Photo\nDP2M = Discriminator().to(device) #Photo ---> Monet\n\n#Weight Initialize\nweight_init(GM2P)\nweight_init(GP2M)\nweight_init(DM2P)\nweight_init(DP2M)\n\n#Load Model\n\n#GM2P_path = '/content/drive/MyDrive/kaggle/model/GM2P.pt'\n#GP2M_path = '/content/drive/MyDrive/kaggle/model/GP2M.pt'\n#DM2P_path = '/content/drive/MyDrive/kaggle/model/DM2P.pt'\n#DP2M_path = '/content/drive/MyDrive/kaggle/model/DP2M.pt'\n\n\n#GM2P.load_state_dict(torch.load(GM2P_path))\n#GP2M.load_state_dict(torch.load(GP2M_path))\n#DM2P.load_state_dict(torch.load(DM2P_path))\n#DP2M.load_state_dict(torch.load(DP2M_path))\n\n\n\n#Loss Functions\n#1. GAN loss - L2\ngan_loss = nn.MSELoss().to(device)\n#2. Cycle loss - L1\ncyc_loss = nn.L1Loss().to(device)\n#3. Identity loss - L1\niden_loss = nn.L1Loss().to(device)\n\n#Optimizer (Connet Monet <---> Photo)\nOptimG = torch.optim.Adam(itertools.chain(GM2P.parameters(), GP2M.parameters()), lr = lr, betas=(0.5, 0.999))\nOptimD = torch.optim.Adam(itertools.chain(DM2P.parameters(), DP2M.parameters()), lr = lr, betas=(0.5, 0.999))\n\nschedulerG = lr_scheduler.LambdaLR(optimizer=OptimG,\n                                        lr_lambda=lambda epoch: 0.95 ** epoch,\n                                        last_epoch=-1,\n                                        verbose=False)\nschedulerD = lr_scheduler.LambdaLR(optimizer=OptimD,\n                                        lr_lambda=lambda epoch: 0.95 ** epoch,\n                                        last_epoch=-1,\n                                        verbose=False)\n\n#Get Data from Dataloader\ntrain_dataset = CustomDataset(path, monet, photo, transforms = train_transform, seed = 26)\ntrain_dataloader = DataLoader(train_dataset, batch_size = batch_size, shuffle  = True, num_workers = 2)\ntrain_total_batch = len(train_dataloader)\nloss_G_list = []\nloss_D_list = []","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:33:22.552171Z","iopub.execute_input":"2022-12-05T08:33:22.552452Z","iopub.status.idle":"2022-12-05T08:33:26.003696Z","shell.execute_reply.started":"2022-12-05T08:33:22.552423Z","shell.execute_reply":"2022-12-05T08:33:26.002917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"> # **⟲CycleGAN Architecture⟲**","metadata":{}},{"cell_type":"markdown","source":"![](https://www.researchgate.net/profile/Mihir-Parmar/publication/335840935/figure/fig2/AS:883763248656384@1587716986091/Proposed-CycleGAN-architecture-Here-W-Whisper-and-S-Speech-After-35.jpg)\n\nProposed CycleGAN architecture. Here, W: Whisper, and S: Speech. After [35].","metadata":{}},{"cell_type":"code","source":"#Training & Evaluation\n\nbest_G_loss = 100\nbest_D_loss = 100\nbest_loss = 100\ntotal_patience = 0\nfor epoch in range(n_epoch):\n    \n    \n    GM2P.train()\n    GP2M.train()\n    DM2P.train()\n    DP2M.train()\n\n    loss_G_avg = 0.0\n    loss_D_avg = 0.0\n    \n    with tqdm(train_dataloader, unit = 'batch') as train_bar:\n        \n        for monets, photos in train_bar:  \n            \n            torch.cuda.empty_cache()\n            monets = monets.float().to(device)\n            photos = photos.float().to(device)\n            \n            #forward Generator\n            update_req_grad([DM2P, DP2M], False)\n            \n            \n            fake_photo = GM2P(monets)\n            fake_monet = GP2M(photos)\n\n            cycl_monet = GP2M(fake_photo)\n            cycl_photo = GM2P(fake_monet)\n            \n            ident_monet = GP2M(monets)\n            ident_photo = GM2P(photos)\n            \n            \n            #Caculating loss (Identity, Advrsarial, cycle consistency)\n            #identity loss\n            ident_loss_monet = iden_loss(ident_monet, monets) * 10 * 0.5\n            ident_loss_photo = iden_loss(ident_photo, photos) * 10 * 0.5\n            #Cycle loss\n            cycle_loss_monet = cyc_loss(cycl_monet, monets) * 10\n            cycle_loss_photo = cyc_loss(cycl_photo, photos) * 10\n            #Adversarial loss\n            pred_fake_monet = DM2P(fake_monet.detach())\n            pred_fake_photo = DP2M(fake_photo.detach())    \n            \n            adv_loss_monet = gan_loss(pred_fake_monet, torch.ones_like(pred_fake_monet))\n            adv_loss_photo = gan_loss(pred_fake_photo, torch.ones_like(pred_fake_photo))\n            \n            #Generater Loss\n            loss_G = (ident_loss_monet + ident_loss_photo ) + (cycle_loss_monet + cycle_loss_photo) + (adv_loss_monet + adv_loss_photo)\n            loss_G_avg += loss_G.item() / train_total_batch\n            #Generator Backward\n    \n            OptimG.zero_grad()\n            loss_G.backward(retain_graph=True)\n            OptimG.step()\n            \n            #forward Discriminator\n            update_req_grad([DM2P, DP2M], True)\n            OptimD.zero_grad()\n            \n            pred_real_monet = DP2M(photos)\n            pred_real_photo = DM2P(monets)\n            \n            #Discriminator loss\n            loss_D_monet = gan_loss(pred_real_monet, torch.ones_like(pred_real_monet)) + gan_loss(pred_fake_monet, torch.zeros_like(pred_fake_monet))\n            loss_D_photo = gan_loss(pred_real_photo, torch.ones_like(pred_real_photo)) + gan_loss(pred_fake_photo, torch.zeros_like(pred_fake_photo))\n    \n            loss_D = (loss_D_monet + loss_D_photo) / 2\n            loss_D_avg += loss_D.item() / train_total_batch\n            \n            #backward\n            loss_D.backward()\n            OptimD.step()\n\n            train_bar.set_postfix(epoch = epoch+1, loss_G = loss_G.item(),loss_D = loss_D.item())\n\n    schedulerG.step()\n    schedulerD.step()\n\n    wandb.log({'Epoch' : epoch+1, \"Generator loss\": loss_G_avg, \n               \"Discriminator loss\": loss_D_avg, \n               'G_lr' : OptimG.param_groups[0]['lr'],\n               'D_lr' : OptimD.param_groups[0]['lr']})\n    \n    if ((epoch + 1) == 1) | ((epoch + 1) % 10 == 0):\n        print('epoch : {} model save....'.format(epoch+1))\n\n        with torch.no_grad():\n          fake_monets = GP2M(photos)\n          cycle_monets = GM2P(fake_monets)\n\n    \n        photos_ = photos[0,:,:,:]\n        print(photos_.shape)\n        fake_monets = fake_monets[0,:,:,:]\n        print(fake_monets.shape)\n        cycle_monets = cycle_monets[0,:,:,:]\n        visulization(photos_, fake_monets, cycle_monets)\n                \n        print('🔨Model Save🔨')\n        torch.save(GM2P.state_dict(), '/kaggle/working/GM2P_epoch_{}.pt'.format(epoch+1))\n        torch.save(GP2M.state_dict(), '/kaggle/working/GP2M_epoch_{}.pt'.format(epoch+1))\n        torch.save(DM2P.state_dict(), '/kaggle/working/DM2P_epoch_{}.pt'.format(epoch+1))\n        torch.save(DP2M.state_dict(), '/kaggle/working/DP2M_epoch_{}.pt'.format(epoch+1))\n        \n","metadata":{"execution":{"iopub.status.busy":"2022-12-05T08:33:26.005411Z","iopub.execute_input":"2022-12-05T08:33:26.005666Z","iopub.status.idle":"2022-12-05T09:43:57.959842Z","shell.execute_reply.started":"2022-12-05T08:33:26.005633Z","shell.execute_reply":"2022-12-05T09:43:57.958777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}