{"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":"2023-03-13T08:00:25.890901Z","iopub.execute_input":"2023-03-13T08:00:25.891182Z","iopub.status.idle":"2023-03-13T08:00:25.895138Z","shell.execute_reply.started":"2023-03-13T08:00:25.891154Z","shell.execute_reply":"2023-03-13T08:00:25.894133Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !pip install wandb\n","metadata":{"execution":{"iopub.status.busy":"2023-03-13T08:00:28.646548Z","iopub.execute_input":"2023-03-13T08:00:28.647232Z","iopub.status.idle":"2023-03-13T08:00:37.097351Z","shell.execute_reply.started":"2023-03-13T08:00:28.647196Z","shell.execute_reply":"2023-03-13T08:00:37.096409Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import wandb","metadata":{"execution":{"iopub.status.busy":"2023-03-13T08:00:37.100356Z","iopub.execute_input":"2023-03-13T08:00:37.100901Z","iopub.status.idle":"2023-03-13T08:00:37.758132Z","shell.execute_reply.started":"2023-03-13T08:00:37.100862Z","shell.execute_reply":"2023-03-13T08:00:37.757144Z"},"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 0f4414049a3825a7e2aee0fffc95f3843de2f566\n    ''')","metadata":{"execution":{"iopub.status.busy":"2023-03-13T08:04:36.782089Z","iopub.execute_input":"2023-03-13T08:04:36.782376Z","iopub.status.idle":"2023-03-13T08:04:36.789080Z","shell.execute_reply.started":"2023-03-13T08:04:36.782342Z","shell.execute_reply":"2023-03-13T08:04:36.788048Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"wandb.init(project = 'cycle-gan',entity=\"zhijiao\", name = 'model-gan')","metadata":{"execution":{"iopub.status.busy":"2023-03-13T08:04:39.294801Z","iopub.execute_input":"2023-03-13T08:04:39.295506Z","iopub.status.idle":"2023-03-13T08:04:46.005063Z","shell.execute_reply.started":"2023-03-13T08:04:39.295470Z","shell.execute_reply":"2023-03-13T08:04:46.004501Z"},"trusted":true},"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":"2023-03-13T08:05:22.954199Z","iopub.execute_input":"2023-03-13T08:05:22.954497Z","iopub.status.idle":"2023-03-13T08:05:24.928151Z","shell.execute_reply.started":"2023-03-13T08:05:22.954456Z","shell.execute_reply":"2023-03-13T08:05:24.927406Z"},"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":"2023-03-13T08:05:28.511094Z","iopub.execute_input":"2023-03-13T08:05:28.511366Z","iopub.status.idle":"2023-03-13T08:05:28.818485Z","shell.execute_reply.started":"2023-03-13T08:05:28.511337Z","shell.execute_reply":"2023-03-13T08:05:28.817532Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(monet[0:3])\nprint(photo[0:3])","metadata":{"execution":{"iopub.status.busy":"2023-03-13T08:06:06.587979Z","iopub.execute_input":"2023-03-13T08:06:06.588266Z","iopub.status.idle":"2023-03-13T08:06:06.593422Z","shell.execute_reply.started":"2023-03-13T08:06:06.588237Z","shell.execute_reply":"2023-03-13T08:06:06.592532Z"},"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":"2023-03-13T08:06:36.286567Z","iopub.execute_input":"2023-03-13T08:06:36.287073Z","iopub.status.idle":"2023-03-13T08:06:36.290831Z","shell.execute_reply.started":"2023-03-13T08:06:36.287037Z","shell.execute_reply":"2023-03-13T08:06:36.290116Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 可视化部分\ndef de_norm(input): # 竟然没有使用imagenet的标配(!)\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# 模型权重初始化\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        \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":"2023-03-13T08:08:26.449480Z","iopub.execute_input":"2023-03-13T08:08:26.450240Z","iopub.status.idle":"2023-03-13T08:08:26.461349Z","shell.execute_reply.started":"2023-03-13T08:08:26.450192Z","shell.execute_reply":"2023-03-13T08:08:26.460651Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 定义数据集\n# 数据增强部分\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\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        # get path\n        monet_path = self.path[0] + self.monet[idx] # 获取一张莫奈风格的图\n        photo_idx = np.random.randint(0, len(self.photo)) # 随机获取一张图片 这大概是有一个1:n的随机\n        photo_path = self.path[1] + self.photo[photo_idx]\n        #get image 转成RGB类型图\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":"2023-03-13T08:14:03.668853Z","iopub.execute_input":"2023-03-13T08:14:03.669707Z","iopub.status.idle":"2023-03-13T08:14:03.679391Z","shell.execute_reply.started":"2023-03-13T08:14:03.669667Z","shell.execute_reply":"2023-03-13T08:14:03.678327Z"},"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":"markdown","source":"### Generator","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        # 第一部分是卷积层 pading Conv2d BathcNorm Relu/LeakyReLU\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        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 转置卷积层（逐渐Unet化了）\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            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            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        # 接了9个残差块 \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 就是把Encoder的卷积层给翻过来\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":"2023-03-13T08:25:43.781314Z","iopub.execute_input":"2023-03-13T08:25:43.781578Z","iopub.status.idle":"2023-03-13T08:25:43.803273Z","shell.execute_reply.started":"2023-03-13T08:25:43.781549Z","shell.execute_reply":"2023-03-13T08:25:43.802487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Discriminator","metadata":{}},{"cell_type":"code","source":"#Cycle GAN\n#Discriminator(Photo <--> Monet)\n#Defining layers\n\n# 生成器相对来说比较简单，基本上就是一个没有池化层的卷积神经网络。\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":"2023-03-13T08:58:36.089687Z","iopub.execute_input":"2023-03-13T08:58:36.090275Z","iopub.status.idle":"2023-03-13T08:58:36.101633Z","shell.execute_reply.started":"2023-03-13T08:58:36.090238Z","shell.execute_reply":"2023-03-13T08:58:36.100787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 训练","metadata":{}},{"cell_type":"code","source":"# 先初始化一些实例，后面再开始训练\nlr = 0.0002\nn_epoch = 10\nbatch_size = 1\nsetting_patience = 7\n\n\n# 调用cuda\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\n# 定义模型，CycleGAN 这边\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# 权重初始化（这玩意必须要的吗）\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# 损失函数，这一块要好好理解的应该是\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) 优化算法，永远的Adma\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\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\n# 装载数据\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":"2023-03-13T08:58:36.919149Z","iopub.execute_input":"2023-03-13T08:58:36.919441Z","iopub.status.idle":"2023-03-13T08:58:37.306369Z","shell.execute_reply.started":"2023-03-13T08:58:36.919408Z","shell.execute_reply":"2023-03-13T08:58:37.305647Z"},"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":"# 训练与评估\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    # 读取一个batch\n    with tqdm(train_dataloader, unit = 'batch') as train_bar:\n        \n        for monets, photos in train_bar:  \n            \n            # 清下cuda\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            # 来回进行一次风格迁移，先由GM2P生成假的照片，再由GP2M生成假的莫奈画\n            # 在生成的假图片上再做一次风格迁移。，最好让他能够返回原来的效果\n            # 假图片是fake,循环得到的生成的原始图片是cycl\n            fake_photo = GM2P(monets)\n            cycl_monet = GP2M(fake_photo)\n            \n            fake_monet = GP2M(photos)\n            cycl_photo = GM2P(fake_monet)\n            \n            \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 对抗损失 (就是常规GAN的损失函数)\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            # 反向传播生成器，这个两个梯度好像是一起算的，哦其实也应该一起算，毕竟损失函数就是一起算的。\n            OptimG.zero_grad()\n            loss_G.backward(retain_graph=True)\n            OptimG.step()\n            \n            #forward Discriminator\n            # 判别器反向传播\n            update_req_grad([DM2P, DP2M], True) # 说实话这个我确实不太懂\n            OptimD.zero_grad()\n            \n            # 进行一个预测\n            pred_real_monet = DP2M(photos) # 生成真实的莫奈风格图片\n            pred_real_photo = DM2P(monets) # 生成真实的照片图片 \n            \n            # Discriminator loss\n            # 判别器损失函数\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    # 学习率更新\n    schedulerG.step()\n    schedulerD.step()\n\n    # wandb记录\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        # 保存权重输出\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":"2023-03-13T09:00:17.525954Z","iopub.execute_input":"2023-03-13T09:00:17.526229Z","iopub.status.idle":"2023-03-13T10:10:24.560554Z","shell.execute_reply.started":"2023-03-13T09:00:17.526201Z","shell.execute_reply":"2023-03-13T10:10:24.559682Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}