{"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":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport scipy\nimport pickle\nimport random\nimport os\n\n# loading in and transforming data\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision\nimport torchvision.datasets as datasets\nimport torchvision.transforms as transforms\nfrom torchvision.utils import make_grid\nimport PIL\nfrom PIL import Image\nimport imageio\nimport shutil\n# visualizing data 可视化数据\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\n\n\ndef copy_dirs(src_path,target_path):\n#copy all files of src_path to target_path\n    file_count=0\n    source_path = os.path.abspath(src_path)\n    target_path = os.path.abspath(target_path)\n    if not os.path.exists(target_path):\n        os.makedirs(target_path)\n    if os.path.exists(source_path):\n        for root, dirs, files in os.walk(source_path):\n            for file in files:\n                src_file = os.path.join(root, file)\n                shutil.copy(src_file, target_path)\n                file_count+=1\n    print(file_count)\n    return int(file_count) \n\n#加载数据集\n\npath_save_up_to_5gb = '/kaggle/working/'\npath_monet = '/kaggle/input/gan-getting-started/monet_jpg/'\npath_photo = '/kaggle/input/gan-getting-started/photo_jpg/'\nimg_size = 256\nnew_path_monet = '/kaggle/working/monet/jpg'\nnew_path_photo = '/kaggle/working/photo/jpg'\n\n#os.mkdir(new_path_monet)\n#os.mkdir(new_path_photo)\ncopy_dirs(path_monet, new_path_monet)\ncopy_dirs(path_photo, new_path_photo)\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n#for dirname, _, filenames in os.walk(new_path_monet):\n#    for filename in filenames:\n#        print(os.path.join(dirname, filename))\n\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-12-09T12:07:41.376577Z","iopub.execute_input":"2021-12-09T12:07:41.377444Z","iopub.status.idle":"2021-12-09T12:08:32.168069Z","shell.execute_reply.started":"2021-12-09T12:07:41.377339Z","shell.execute_reply":"2021-12-09T12:08:32.167123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#生成随机数 运行的结果不同\n\ndef set_seed(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    \nset_seed(42)","metadata":{"execution":{"iopub.status.busy":"2021-12-09T12:08:32.170524Z","iopub.execute_input":"2021-12-09T12:08:32.170897Z","iopub.status.idle":"2021-12-09T12:08:32.180292Z","shell.execute_reply.started":"2021-12-09T12:08:32.170861Z","shell.execute_reply":"2021-12-09T12:08:32.179583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_test(fixed_Y, fixed_X, G_YtoX, G_XtoY, mean_=0.5, std_=0.5):\n    \"\"\"\n    Shows results of generates based on test image input. \n    \"\"\"\n    #Identify correct device\n    device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n    \n    #Create fake pictures for both cycles\n    fake_X = G_YtoX(fixed_Y.to(device))\n    fake_Y = G_XtoY(fixed_X.to(device))\n    \n    #Generate grids 生成网格，将若干幅图像拼成一幅图像 展示一批数据\n    grid_x =  make_grid(fixed_X, nrow=4).permute(1, 2, 0).detach().cpu().numpy()\n    grid_y =  make_grid(fixed_Y, nrow=4).permute(1, 2, 0).detach().cpu().numpy()\n    grid_fake_x =  make_grid(fake_X, nrow=4).permute(1, 2, 0).detach().cpu().numpy()\n    grid_fake_y =  make_grid(fake_Y, nrow=4).permute(1, 2, 0).detach().cpu().numpy()\n    \n    #Normalize pictures to pixel range rom 0 to 255 将图片归一化到像素范围rom 0到255\n    X, fake_X = reverse_normalize(grid_x, mean_, std_), reverse_normalize(grid_fake_x, mean_, std_)\n    Y, fake_Y = reverse_normalize(grid_y, mean_, std_), reverse_normalize(grid_fake_y, mean_, std_)\n    \n    #Transformation from X -> Y\n    fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, sharey=True, figsize=(20, 10))\n    ax1.imshow(X)\n    ax1.axis('off')\n    ax1.set_title('X')\n    ax2.imshow(fake_Y)\n    ax2.axis('off')\n    ax2.set_title('Fake Y  (Monet-esque)')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-09T12:08:32.182057Z","iopub.execute_input":"2021-12-09T12:08:32.182623Z","iopub.status.idle":"2021-12-09T12:08:32.194023Z","shell.execute_reply.started":"2021-12-09T12:08:32.182585Z","shell.execute_reply":"2021-12-09T12:08:32.192951Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Create test loaders\nbatch_size_test = 8\nbatch_size=16\nfrom torchvision import transforms as T\nfrom torchvision.datasets import ImageFolder\n\ndef get_loader(path='/kaggle/working/monet', crop_size=178, image_size=256, #crop_size是对训练集图像进行裁剪，batch_size一次训练所选取的样本数\n               batch_size=16, mode='train', num_workers=1):\n    \"\"\"Build and return a data loader.\"\"\"\n    transform = []\n    if mode == 'train':\n        transform.append(T.RandomHorizontalFlip())\n    transform.append(T.CenterCrop(crop_size))\n    transform.append(T.Resize(image_size))\n    transform.append(T.ToTensor())\n    transform.append(T.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5)))\n    transform = T.Compose(transform)\n   \n    dataset = ImageFolder(path, transform)\n    #if dataset == 'RaFD':\n    #    dataset = ImageFolder(image_dir, transform)\n\n    data_loader = DataLoader(dataset=dataset,\n                                  batch_size=batch_size,\n                                  shuffle=(mode=='train'),\n                                  num_workers=num_workers)\n    return data_loader\ntest_dataloader_X = get_loader('/kaggle/working/photo', batch_size=batch_size_test)\ntest_dataloader_Y = get_loader('/kaggle/working/monet', batch_size=batch_size_test)\n#test_dataloader_Y = get_loader(dataset_monet, batch_size=batch_size_test, num_workers=1, pin_memory=True)\n#test_dataloader_X = DataLoader(dataset_photo, batch_size=batch_size_test, shuffle=False, num_workers=1, pin_memory=True)\n#dataloader_Y = DataLoader(dataset_monet, batch_size=batch_size, shuffle=True, num_workers=0, pin_memory=True)\n#dataloader_X = DataLoader(dataset_photo, batch_size=batch_size, shuffle=True, num_workers=0, pin_memory=True)","metadata":{"execution":{"iopub.status.busy":"2021-12-09T12:08:32.195567Z","iopub.execute_input":"2021-12-09T12:08:32.196104Z","iopub.status.idle":"2021-12-09T12:08:32.250733Z","shell.execute_reply.started":"2021-12-09T12:08:32.196066Z","shell.execute_reply":"2021-12-09T12:08:32.25009Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport numpy as np\n\n\nclass ResidualBlock(nn.Module):\n    \"\"\"Residual Block with instance normalization.\"\"\"\n    def __init__(self, dim_in, dim_out):\n        super(ResidualBlock, self).__init__()\n        self.main = nn.Sequential(\n            nn.Conv2d(dim_in, dim_out, kernel_size=3, stride=1, padding=1, bias=False), #二维卷积\n            nn.InstanceNorm2d(dim_out, affine=True, track_running_stats=True), #归一化\n            nn.ReLU(inplace=True),\n            nn.Conv2d(dim_out, dim_out, kernel_size=3, stride=1, padding=1, bias=False),\n            nn.InstanceNorm2d(dim_out, affine=True, track_running_stats=True))\n\n    def forward(self, x):\n        return x + self.main(x)\n\n#生成器\nclass Generator(nn.Module):\n    \"\"\"Generator network.\"\"\"\n    def __init__(self, conv_dim=64, c_dim=5, repeat_num=6):\n        super(Generator, self).__init__()\n\n        layers = []\n        layers.append(nn.Conv2d(3+c_dim, conv_dim, kernel_size=7, stride=1, padding=3, bias=False))\n        layers.append(nn.InstanceNorm2d(conv_dim, affine=True, track_running_stats=True))\n        layers.append(nn.ReLU(inplace=True))\n\n        # Down-sampling layers.\n        curr_dim = conv_dim\n        for i in range(2):\n            layers.append(nn.Conv2d(curr_dim, curr_dim*2, kernel_size=4, stride=2, padding=1, bias=False))\n            layers.append(nn.InstanceNorm2d(curr_dim*2, affine=True, track_running_stats=True))\n            layers.append(nn.ReLU(inplace=True))\n            curr_dim = curr_dim * 2\n\n        # Bottleneck layers.\n        for i in range(repeat_num):\n            layers.append(ResidualBlock(dim_in=curr_dim, dim_out=curr_dim))\n\n        # Up-sampling layers.\n        for i in range(2):\n            layers.append(nn.ConvTranspose2d(curr_dim, curr_dim//2, kernel_size=4, stride=2, padding=1, bias=False))\n            layers.append(nn.InstanceNorm2d(curr_dim//2, affine=True, track_running_stats=True))\n            layers.append(nn.ReLU(inplace=True))\n            curr_dim = curr_dim // 2\n\n        layers.append(nn.Conv2d(curr_dim, 3, kernel_size=7, stride=1, padding=3, bias=False))\n        layers.append(nn.Tanh())\n        self.main = nn.Sequential(*layers)\n\n    def forward(self, x, c):\n        # Replicate spatially and concatenate domain information.\n        # Note that this type of label conditioning does not work at all if we use reflection padding in Conv2d.\n        # This is because instance normalization ignores the shifting (or bias) effect.\n        c = c.view(c.size(0), c.size(1), 1, 1)\n        c = c.repeat(1, 1, x.size(2), x.size(3))\n        x = torch.cat([x, c], dim=1)\n        return self.main(x)\n\n#判别器\nclass Discriminator(nn.Module):\n    \"\"\"Discriminator network with PatchGAN.\"\"\"\n    def __init__(self, image_size=128, conv_dim=64, c_dim=5, repeat_num=6):\n        super(Discriminator, self).__init__()\n        layers = []\n        layers.append(nn.Conv2d(3, conv_dim, kernel_size=4, stride=2, padding=1))\n        layers.append(nn.LeakyReLU(0.01))\n\n        curr_dim = conv_dim\n        for i in range(1, repeat_num):\n            layers.append(nn.Conv2d(curr_dim, curr_dim*2, kernel_size=4, stride=2, padding=1))\n            layers.append(nn.LeakyReLU(0.01))\n            curr_dim = curr_dim * 2\n\n        kernel_size = int(image_size / np.power(2, repeat_num))\n        self.main = nn.Sequential(*layers)\n        self.conv1 = nn.Conv2d(curr_dim, 1, kernel_size=3, stride=1, padding=1, bias=False)\n        self.conv2 = nn.Conv2d(curr_dim, c_dim, kernel_size=kernel_size, bias=False)\n        \n    def forward(self, x):\n        h = self.main(x)\n        out_src = self.conv1(h)\n        out_cls = self.conv2(h)\n        return out_src, out_cls.view(out_cls.size(0), out_cls.size(1))","metadata":{"execution":{"iopub.status.busy":"2021-12-09T12:08:32.253755Z","iopub.execute_input":"2021-12-09T12:08:32.25411Z","iopub.status.idle":"2021-12-09T12:08:32.2751Z","shell.execute_reply.started":"2021-12-09T12:08:32.254075Z","shell.execute_reply":"2021-12-09T12:08:32.274247Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.autograd import Variable\nfrom torchvision.utils import save_image\nimport torch\nimport torch.nn.functional as F\nimport numpy as np\nimport os\nimport time\nimport datetime\n\n#Solver通过协调Net的前向判断计算和反向梯度计算(forward inference and backward gradients)，来对參数进行更新。\n#从而达到降低loss的目的。Caffe模型的学习被分为两个部分：由Solver进行优化、更新參数。由Net计算出loss和gradient。\nclass Solver(object):\n    \"\"\"Solver for training and testing StarGAN.\"\"\"\n\n    def __init__(self, celeba_loader, rafd_loader, config):\n        \"\"\"Initialize configurations.\"\"\"\n\n        # Data loader.\n        self.celeba_loader = celeba_loader\n        self.rafd_loader = rafd_loader\n\n        # Model configurations.\n        self.c_dim = config.c_dim\n        self.c2_dim = config.c2_dim\n        self.image_size = config.image_size\n        self.g_conv_dim = config.g_conv_dim\n        self.d_conv_dim = config.d_conv_dim\n        self.g_repeat_num = config.g_repeat_num\n        self.d_repeat_num = config.d_repeat_num\n        self.lambda_cls = config.lambda_cls\n        self.lambda_rec = config.lambda_rec\n        self.lambda_gp = config.lambda_gp\n\n        # Training configurations.\n        self.dataset = config.dataset\n        self.batch_size = config.batch_size\n        self.num_iters = config.num_iters\n        self.num_iters_decay = config.num_iters_decay\n        self.g_lr = config.g_lr\n        self.d_lr = config.d_lr\n        self.n_critic = config.n_critic\n        self.beta1 = config.beta1\n        self.beta2 = config.beta2\n        self.resume_iters = config.resume_iters\n\n        # Test configurations.\n        self.test_iters = config.test_iters\n        self.log_step = config.log_step\n        self.selected_attrs = config.selected_attrs\n\n        # Miscellaneous.\n        self.use_tensorboard = config.use_tensorboard\n        self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n        # Directories.\n        self.model_save_dir = config.model_save_dir\n        self.result_dir = config.result_dir\n\n        # Step size.\n        self.model_save_step = config.model_save_step\n        self.lr_update_step = config.lr_update_step\n\n        # Build the model and tensorboard.\n        self.build_model()\n        if self.use_tensorboard:\n            self.build_tensorboard()\n\n    def build_model(self):\n        \"\"\"Create a generator and a discriminator.\"\"\"\n        if self.dataset in ['CelebA', 'RaFD']:\n            self.G = Generator(self.g_conv_dim, self.c_dim, self.g_repeat_num)\n            self.D = Discriminator(self.image_size, self.d_conv_dim, self.c_dim, self.d_repeat_num) \n        elif self.dataset in ['Both']:\n            self.G = Generator(self.g_conv_dim, self.c_dim+self.c2_dim+2, self.g_repeat_num)   # 2 for mask vector.\n            self.D = Discriminator(self.image_size, self.d_conv_dim, self.c_dim+self.c2_dim, self.d_repeat_num)\n\n        self.g_optimizer = torch.optim.Adam(self.G.parameters(), self.g_lr, [self.beta1, self.beta2])\n        self.d_optimizer = torch.optim.Adam(self.D.parameters(), self.d_lr, [self.beta1, self.beta2])\n        #self.print_network(self.G, 'G')\n        #self.print_network(self.D, 'D')\n            \n        self.G.to(self.device)\n        self.D.to(self.device)\n\n    def print_network(self, model, name):\n        \"\"\"Print out the network information.\"\"\"\n        num_params = 0\n        for p in model.parameters():\n            num_params += p.numel()\n        print(model)\n        print(name)\n        print(\"The number of parameters: {}\".format(num_params))\n\n    def restore_model(self, resume_iters):\n        \"\"\"Restore the trained generator and discriminator.\"\"\"\n        print('Loading the trained models from step {}...'.format(resume_iters))\n        G_path = os.path.join(self.model_save_dir, '{}-G.ckpt'.format(resume_iters))\n        D_path = os.path.join(self.model_save_dir, '{}-D.ckpt'.format(resume_iters))\n        self.G.load_state_dict(torch.load(G_path, map_location=lambda storage, loc: storage))\n        self.D.load_state_dict(torch.load(D_path, map_location=lambda storage, loc: storage))\n\n\n    def update_lr(self, g_lr, d_lr):\n        \"\"\"Decay learning rates of the generator and discriminator.\"\"\"\n        for param_group in self.g_optimizer.param_groups:\n            param_group['lr'] = g_lr\n        for param_group in self.d_optimizer.param_groups:\n            param_group['lr'] = d_lr\n\n    def reset_grad(self):\n        \"\"\"Reset the gradient buffers.\"\"\"\n        self.g_optimizer.zero_grad()\n        self.d_optimizer.zero_grad()\n\n    def denorm(self, x):\n        \"\"\"Convert the range from [-1, 1] to [0, 1].\"\"\"\n        out = (x + 1) / 2\n        return out.clamp_(0, 1)\n\n    def gradient_penalty(self, y, x):\n        \"\"\"Compute gradient penalty: (L2_norm(dy/dx) - 1)**2.\"\"\"\n        weight = torch.ones(y.size()).to(self.device)\n        dydx = torch.autograd.grad(outputs=y,\n                                   inputs=x,\n                                   grad_outputs=weight,\n                                   retain_graph=True,\n                                   create_graph=True,\n                                   only_inputs=True)[0]\n\n        dydx = dydx.view(dydx.size(0), -1)\n        dydx_l2norm = torch.sqrt(torch.sum(dydx**2, dim=1))\n        return torch.mean((dydx_l2norm-1)**2)\n\n    def label2onehot(self, labels, dim):\n        \"\"\"Convert label indices to one-hot vectors.\"\"\"\n        batch_size = labels.size(0)\n        out = torch.zeros(batch_size, dim)\n        out[np.arange(batch_size), labels.long()] = 1\n        return out\n\n    def create_labels(self, c_org, c_dim=5, dataset='CelebA', selected_attrs=None):\n        \"\"\"Generate target domain labels for debugging and testing.\"\"\"\n        # Get hair color indices.\n        if dataset == 'CelebA':\n            hair_color_indices = []\n            for i, attr_name in enumerate(selected_attrs):\n                if attr_name in ['Black_Hair', 'Blond_Hair', 'Brown_Hair', 'Gray_Hair']:\n                    hair_color_indices.append(i)\n\n        c_trg_list = []\n        for i in range(c_dim):\n            if dataset == 'CelebA':\n                c_trg = c_org.clone()\n                if i in hair_color_indices:  # Set one hair color to 1 and the rest to 0.\n                    c_trg[:, i] = 1\n                    for j in hair_color_indices:\n                        if j != i:\n                            c_trg[:, j] = 0\n                else:\n                    c_trg[:, i] = (c_trg[:, i] == 0)  # Reverse attribute value.\n            elif dataset == 'RaFD':\n                c_trg = self.label2onehot(torch.ones(c_org.size(0))*i, c_dim)\n\n            c_trg_list.append(c_trg.to(self.device))\n        return c_trg_list\n\n    def classification_loss(self, logit, target, dataset='CelebA'):\n        \"\"\"Compute binary or softmax cross entropy loss.\"\"\"\n        if dataset == 'CelebA':\n            return F.binary_cross_entropy_with_logits(logit, target, size_average=False) / logit.size(0)\n        elif dataset == 'RaFD':\n            return F.cross_entropy(logit, target)\n\n    def train(self):\n        \"\"\"Train StarGAN within a single dataset.\"\"\"\n        # Set data loader.\n        if self.dataset == 'CelebA':\n            data_loader = self.celeba_loader\n        elif self.dataset == 'RaFD':\n            data_loader = self.rafd_loader\n\n        # Fetch fixed inputs for debugging.\n        data_iter = iter(data_loader)\n        tmp = next(data_iter)\n        #print(tmp)\n        print(len(tmp))\n        x_fixed, c_org = next(data_iter)\n        x_fixed = x_fixed.to(self.device)\n        c_fixed_list = self.create_labels(c_org, self.c_dim, self.dataset, self.selected_attrs)\n\n        # Learning rate cache for decaying.\n        g_lr = self.g_lr\n        d_lr = self.d_lr\n\n        # Start training from scratch or resume training.\n        start_iters = 0\n        if self.resume_iters:\n            start_iters = self.resume_iters\n            self.restore_model(self.resume_iters)\n\n        # Start training.\n        print('Start training...')\n        start_time = time.time()\n        print(start_iters, self.num_iters)\n        for i in range(start_iters, self.num_iters):\n            # =================================================================================== #\n            #                             1. Preprocess input data                                #\n            # =================================================================================== #\n\n            # Fetch real images and labels.\n            try:\n                x_real, label_org = next(data_iter)\n            except:\n                data_iter = iter(data_loader)\n                x_real, label_org = next(data_iter)\n\n            # Generate target domain labels randomly.\n            rand_idx = torch.randperm(label_org.size(0))\n            label_trg = label_org[rand_idx]\n\n            if self.dataset == 'CelebA':\n                c_org = label_org.clone()\n                c_trg = label_trg.clone()\n            elif self.dataset == 'RaFD':\n                c_org = self.label2onehot(label_org, self.c_dim)\n                c_trg = self.label2onehot(label_trg, self.c_dim)\n\n            x_real = x_real.to(self.device)           # Input images.\n            c_org = c_org.to(self.device)             # Original domain labels.\n            c_trg = c_trg.to(self.device)             # Target domain labels.\n            label_org = label_org.to(self.device)     # Labels for computing classification loss.\n            label_trg = label_trg.to(self.device)     # Labels for computing classification loss.\n\n            # =================================================================================== #\n            #                             2. Train the discriminator                              #\n            # =================================================================================== #\n\n            # Compute loss with real images.\n            out_src, out_cls = self.D(x_real)\n            d_loss_real = - torch.mean(out_src)\n            d_loss_cls = self.classification_loss(out_cls, label_org, self.dataset)\n\n            # Compute loss with fake images.\n            x_fake = self.G(x_real, c_trg)\n            out_src, out_cls = self.D(x_fake.detach())\n            d_loss_fake = torch.mean(out_src)\n\n            # Compute loss for gradient penalty.\n            alpha = torch.rand(x_real.size(0), 1, 1, 1).to(self.device)\n            x_hat = (alpha * x_real.data + (1 - alpha) * x_fake.data).requires_grad_(True)\n            out_src, _ = self.D(x_hat)\n            d_loss_gp = self.gradient_penalty(out_src, x_hat)\n\n            # Backward and optimize.\n            d_loss = d_loss_real + d_loss_fake + self.lambda_cls * d_loss_cls + self.lambda_gp * d_loss_gp\n            self.reset_grad()\n            d_loss.backward()\n            self.d_optimizer.step()\n\n            # Logging.\n            loss = {}\n            loss['D/loss_real'] = d_loss_real.item()\n            loss['D/loss_fake'] = d_loss_fake.item()\n            loss['D/loss_cls'] = d_loss_cls.item()\n            loss['D/loss_gp'] = d_loss_gp.item()\n            \n            # =================================================================================== #\n            #                               3. Train the generator                                #\n            # =================================================================================== #\n            \n            if (i+1) % self.n_critic == 0:\n                # Original-to-target domain.\n                x_fake = self.G(x_real, c_trg)\n                out_src, out_cls = self.D(x_fake)\n                g_loss_fake = - torch.mean(out_src)\n                g_loss_cls = self.classification_loss(out_cls, label_trg, self.dataset)\n\n                # Target-to-original domain.\n                x_reconst = self.G(x_fake, c_org)\n                g_loss_rec = torch.mean(torch.abs(x_real - x_reconst))\n\n                # Backward and optimize.\n                g_loss = g_loss_fake + self.lambda_rec * g_loss_rec + self.lambda_cls * g_loss_cls\n                self.reset_grad()\n                g_loss.backward()\n                self.g_optimizer.step()\n\n                # Logging.\n                loss['G/loss_fake'] = g_loss_fake.item()\n                loss['G/loss_rec'] = g_loss_rec.item()\n                loss['G/loss_cls'] = g_loss_cls.item()\n\n            # =================================================================================== #\n            #                                 4. Miscellaneous                                    #\n            # =================================================================================== #\n\n            # Print out training information.\n            if (i+1) % self.log_step == 0:\n                et = time.time() - start_time\n                et = str(datetime.timedelta(seconds=et))[:-7]\n                log = \"Elapsed [{}], Iteration [{}/{}]\".format(et, i+1, self.num_iters)\n                for tag, value in loss.items():\n                    log += \", {}: {:.4f}\".format(tag, value)\n                print(log)\n\n            # Save model checkpoints.\n            if (i+1) % self.model_save_step == 0:\n                G_path = os.path.join(self.model_save_dir, '{}-G.ckpt'.format(i+1))\n                D_path = os.path.join(self.model_save_dir, '{}-D.ckpt'.format(i+1))\n                torch.save(self.G.state_dict(), G_path)\n                torch.save(self.D.state_dict(), D_path)\n                print('Saved model checkpoints into {}...'.format(self.model_save_dir))\n\n            # Decay learning rates.\n            if (i+1) % self.lr_update_step == 0 and (i+1) > (self.num_iters - self.num_iters_decay):\n                g_lr -= (self.g_lr / float(self.num_iters_decay))\n                d_lr -= (self.d_lr / float(self.num_iters_decay))\n                self.update_lr(g_lr, d_lr)\n                print ('Decayed learning rates, g_lr: {}, d_lr: {}.'.format(g_lr, d_lr))\n        G_path = os.path.join(self.model_save_dir, '{}-G.ckpt'.format('final'))\n        D_path = os.path.join(self.model_save_dir, '{}-D.ckpt'.format('final'))\n        torch.save(self.G.state_dict(), G_path)\n        torch.save(self.D.state_dict(), D_path)\n        print('Saved model checkpoints into {}...'.format(self.model_save_dir))\n\n    def test(self):\n        \"\"\"Translate images using StarGAN trained on a single dataset.\"\"\"\n        # Load the trained generator.\n        self.restore_model(self.test_iters)\n        \n        # Set data loader.\n        if self.dataset == 'CelebA':\n            data_loader = self.celeba_loader\n        elif self.dataset == 'RaFD':\n            data_loader = self.rafd_loader\n        \n        with torch.no_grad():\n            for i, (x_real, c_org) in enumerate(data_loader):\n\n                # Prepare input images and target domain labels.\n                x_real = x_real.to(self.device)\n                c_trg_list = self.create_labels(c_org, self.c_dim, self.dataset, self.selected_attrs)\n\n                # Translate images.\n                x_fake_list = [x_real]\n                for c_trg in c_trg_list:\n                    x_fake_list.append(self.G(x_real, c_trg))\n\n                # Save the translated images.\n                x_concat = torch.cat(x_fake_list, dim=3)\n                result_path = os.path.join(self.result_dir, '{}-images.jpg'.format(i+1))\n                save_image(self.denorm(x_concat.data.cpu()), result_path, nrow=1, padding=0)\n                print('Saved real and fake images into {}...'.format(result_path))\n                \n    def generate(self):\n        \"\"\"Translate images using StarGAN trained on a single dataset.\"\"\"\n        # Load the trained generator.\n        self.restore_model(self.test_iters)\n        \n        # Set data loader.\n        if self.dataset == 'CelebA':\n            data_loader = self.celeba_loader\n        elif self.dataset == 'RaFD':\n            data_loader = self.rafd_loader\n        image_num=0\n        with torch.no_grad():\n            for i, (x_real, c_org) in enumerate(data_loader):\n                if image_num>1:\n                    break\n                # Prepare input images and target domain labels.\n                x_real = x_real.to(self.device)\n                c_trg_list = self.create_labels(c_org, self.c_dim, self.dataset, self.selected_attrs)\n                monet_trg = c_trg_list[0]\n                generated = self.G(x_real, monet_trg)\n                generated = generated[0]\n                result_path = os.path.join(self.result_dir, '{}-images.jpg'.format(image_num+1))\n                save_image(self.denorm(generated.data.cpu()), result_path, nrow=1, padding=0)\n                image_num += 1\n                print(result_path)\n    \n    def submit(self):\n        self.restore_model(self.test_iters)\n        \n        # Set data loader.\n        if self.dataset == 'CelebA':\n            data_loader = self.celeba_loader\n        elif self.dataset == 'RaFD':\n            data_loader = self.rafd_loader\n        image_num=0\n        with torch.no_grad():\n            for i, (x_real, c_org) in enumerate(data_loader):\n                if image_num>8000:\n                    break\n                # Prepare input images and target domain labels.\n                x_real = x_real.to(self.device)\n                c_trg_list = self.create_labels(c_org, self.c_dim, self.dataset, self.selected_attrs)\n                monet_trg = c_trg_list[0]\n                generated = self.G(x_real, monet_trg)\n                #print(generated.shape)\n                for j in range(generated.shape[0]):\n                    result_path = os.path.join(self.result_dir, '{}-images.jpg'.format(image_num+1))\n                    save_image(self.denorm(generated[j].data.cpu()), result_path, nrow=1, padding=0)\n                    image_num += 1\n                    if image_num % 100 == 0:\n                        print(image_num)\n        print(\"done, total generated:\")\n        print(image_num)\n        shutil.make_archive(\"/kaggle/working/images\", 'zip', self.result_dir)\n\n","metadata":{"execution":{"iopub.status.busy":"2021-12-09T12:08:32.276771Z","iopub.execute_input":"2021-12-09T12:08:32.277316Z","iopub.status.idle":"2021-12-09T12:08:32.343426Z","shell.execute_reply.started":"2021-12-09T12:08:32.277279Z","shell.execute_reply":"2021-12-09T12:08:32.342481Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -U easydict","metadata":{"execution":{"iopub.status.busy":"2021-12-09T12:08:32.344757Z","iopub.execute_input":"2021-12-09T12:08:32.345143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport argparse\nfrom torch.backends import cudnn\nimport easydict\n\ndef str2bool(v):\n    return v.lower() in ('true')\n\ndef main(config):\n    # For fast training.\n    cudnn.benchmark = True\n\n    # Create directories if not exist.\n    if not os.path.exists(config.model_save_dir):\n        os.makedirs(config.model_save_dir)\n    if not os.path.exists(config.result_dir):\n        os.makedirs(config.result_dir)\n\n    # Data loader.\n    celeba_loader = None\n    rafd_loader = None\n\n    if config.dataset in ['RaFD', 'Both']:\n        rafd_loader = get_loader(config.rafd_image_dir, image_size=config.image_size, batch_size=config.batch_size,\n                                 mode=config.mode, num_workers=config.num_workers)\n    \n\n    # Solver for training and testing StarGAN.\n    solver = Solver(celeba_loader, rafd_loader, config)\n\n    if config.mode == 'train':\n        if config.dataset in ['CelebA', 'RaFD']:\n            solver.train()\n        elif config.dataset in ['Both']:\n            solver.train_multi()\n    elif config.mode == 'test':\n        if config.dataset in ['CelebA', 'RaFD']:\n            solver.test()\n        elif config.dataset in ['Both']:\n            solver.test_multi()\n    elif config.mode == 'generate':\n        solver.generate()\n    elif config.mode == 'submit':\n        solver.submit()\n\n\ndef init_config():\n    config = easydict.EasyDict({\n        'c_dim': 5,\n        'c2_dim': 8,\n        'rafd_crop_size': 256,\n        'image_size': 128,\n        'g_conv_dim': 64,\n        'd_conv_dim': 64,\n        'g_repeat_num': 6,\n        'd_repeat_num': 6, \n        'lambda_cls': 1, \n        'lambda_rec': 10,\n        'lambda_gp': 10, \n        \n        'dataset': 'RaFD', \n        'batch_size': 16,\n        'num_iters': 200, \n        'num_iters_decay': 100, \n        'g_lr': 0.0001, \n        'd_lr': 0.0001, \n        'n_critic': 5, \n        'beta1': 0.5, \n        'beta2': 0.999, \n        'resume_iters': None, \n\n        'test_iters': 200, \n        'num_workers': 1,\n        'mode': 'train', \n        'use_tensorboard': False,\n        'log_step': 20,\n        'selected_attrs': None,\n        \n        'rafd_image_dir': '/kaggle/working/monet/jpg',\n        'model_save_dir': '/kaggle/working/models',\n        'result_dir': '/kaggle/working/submit',\n\n        'model_save_step': 100,\n        'lr_update_step': 100\n    })\n    return config","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"config = init_config()\nconfig.mode = 'train'\nconfig.dataset = 'RaFD' \nconfig.image_size = 256               \nconfig.c_dim = 1 \nconfig.rafd_image_dir = '/kaggle/working/monet'\nconfig.model_save_dir = '/kaggle/working/models'\n\npath = \"/kaggle/working/monet\" \nd = path\nprint([os.path.join(d, o) for o in os.listdir(d) \n                    if os.path.isdir(os.path.join(d,o))])\n\nmain(config)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#os.mkdir('/kaggle/working/example')\nconfig = init_config()\nconfig.mode = 'generate'\nconfig.dataset = 'RaFD' \nconfig.image_size = 256               \nconfig.c_dim = 1 \nconfig.rafd_image_dir = '/kaggle/working/photo'\nconfig.model_save_dir = '/kaggle/working/models'\nconfig.result_dir = '/kaggle/working/example'\nconfig.test_iters = 'final'\n\nmain(config)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_array = np.array(Image.open('/kaggle/working/example/2-images.jpg'))\nplt.imshow(img_array)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"config = init_config()\nconfig.mode = 'submit'\nconfig.dataset = 'RaFD' \nconfig.image_size = 256               \nconfig.c_dim = 1 \nconfig.rafd_image_dir = '/kaggle/working/photo'\nconfig.model_save_dir = '/kaggle/working/models'\nconfig.result_dir = '/kaggle/working/submit'\nconfig.test_iters = 'final'\n\nmain(config)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"shutil.make_archive(\"/kaggle/working/images\", 'zip', '/kaggle/working/submit')","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}