{"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 glob\nimport os\nimport shutil\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pytorch_lightning as L\nimport torch\nimport torch.nn.functional as F\nimport torchvision.transforms as T\nfrom pytorch_lightning.trainer.supporters import CombinedLoader\nfrom torch import nn\nfrom torch.utils.data import DataLoader, Dataset\nfrom torchvision.io import read_image\nfrom torchvision.utils import make_grid, save_image\n\n_ = L.seed_everything(0, workers=True)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-04-13T07:10:20.829249Z","iopub.execute_input":"2023-04-13T07:10:20.82988Z","iopub.status.idle":"2023-04-13T07:10:26.788867Z","shell.execute_reply.started":"2023-04-13T07:10:20.829837Z","shell.execute_reply":"2023-04-13T07:10:26.787592Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_img(img_tensor, nrow, title=\"\"):\n    img_tensor = img_tensor.detach().cpu()*0.5 + 0.5\n    img_grid = make_grid(img_tensor, nrow=nrow).permute(1, 2, 0)\n    plt.figure(figsize=(18, 8))\n    plt.imshow(img_grid)\n    plt.axis(\"off\")\n    plt.title(title)\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:26.79147Z","iopub.execute_input":"2023-04-13T07:10:26.79188Z","iopub.status.idle":"2023-04-13T07:10:26.799895Z","shell.execute_reply.started":"2023-04-13T07:10:26.791838Z","shell.execute_reply":"2023-04-13T07:10:26.798831Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomTransform(object):\n    def __init__(self, img_dim=256):\n        self.transform = T.Compose([\n            T.RandomResizedCrop((img_dim, img_dim),\n                                scale=(0.8, 1.0), ratio=(0.9, 1.1)),\n            T.RandomHorizontalFlip(p=0.5),\n        ])\n        \n    def __call__(self, img, stage=\"fit\"):\n        if stage == \"fit\":\n            img = self.transform(img)\n        if stage == \"test\":\n            img = self.transform(img)\n        return img/127.5 - 1\n","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:26.801588Z","iopub.execute_input":"2023-04-13T07:10:26.80216Z","iopub.status.idle":"2023-04-13T07:10:26.810766Z","shell.execute_reply.started":"2023-04-13T07:10:26.802117Z","shell.execute_reply":"2023-04-13T07:10:26.808631Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torchvision\nfrom torchvision import transforms\nclass CustomDataset(Dataset):\n    def __init__(self, filenames, transform, stage):\n        self.filenames = filenames\n        self.transform = transform\n        self.stage = stage\n        \n    def __len__(self):\n        return len(self.filenames)\n    \n    def __getitem__(self, idx):\n        img_name = self.filenames[idx]\n        img = read_image(img_name)\n        return self.transform(img, stage=self.stage)","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:26.814113Z","iopub.execute_input":"2023-04-13T07:10:26.814946Z","iopub.status.idle":"2023-04-13T07:10:26.821735Z","shell.execute_reply.started":"2023-04-13T07:10:26.814899Z","shell.execute_reply":"2023-04-13T07:10:26.820681Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MONET_DIR = \"/kaggle/input/gan-getting-started/monet_jpg/*.jpg\"\nPHOTO_DIR = \"/kaggle/input/gan-getting-started/photo_jpg/*.jpg\"\nMONET_TEST_DIR = \"/kaggle/input/ceg-deep-learning/Part 2-4/*.jpg\"\nPHOTO_TEST_DIR = \"/kaggle/input/ceg-deep-learning/Part 2-5/*.jpg\"\nLOADER_CONFIG = {\n    \"batch_size\": 8,\n    \"num_workers\": os.cpu_count(),\n    \"pin_memory\": torch.cuda.is_available(),\n}\ntransform = CustomTransform()","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:26.823458Z","iopub.execute_input":"2023-04-13T07:10:26.824673Z","iopub.status.idle":"2023-04-13T07:10:26.880087Z","shell.execute_reply.started":"2023-04-13T07:10:26.824643Z","shell.execute_reply":"2023-04-13T07:10:26.87897Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image\nimport os\n\n# 定义目录路径和输出目录路径\ninput_dir = \"/kaggle/input/ceg-deep-learning/Part 2-5\"  \noutput_dir = \"/kaggle/input/ceg-deep-learning/Part 2-5\"  \n\n# 遍历输入目录下的所有文件\nfor filename in os.listdir(input_dir):\n    # 构建输入文件的完整路径和输出文件的完整路径\n    input_path = os.path.join(input_dir, filename)\n    output_path = os.path.join(output_dir, filename)\n\n    # 打开图片并进行大小变换\n    with Image.open(input_path) as image:\n        # 将图像大小调整为 256x256\n        image = image.resize((256, 256))\n\nprint(\"图片大小变换完成！\")\n","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:26.881676Z","iopub.execute_input":"2023-04-13T07:10:26.883681Z","iopub.status.idle":"2023-04-13T07:10:26.988439Z","shell.execute_reply.started":"2023-04-13T07:10:26.883551Z","shell.execute_reply":"2023-04-13T07:10:26.987427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CustomDataModule(L.LightningDataModule):\n    def __init__(\n        self, \n        monet_dir=MONET_DIR,\n        photo_dir=PHOTO_DIR,\n        test_monet_dir=MONET_TEST_DIR,\n        test_photo_dir=PHOTO_TEST_DIR,\n        loader_config=LOADER_CONFIG,\n        transform=transform,\n        mode=\"max_size_cycle\",\n    ):\n        super().__init__()\n        self.monet_filenames = sorted(glob.glob(monet_dir))\n        self.photo_filenames = sorted(glob.glob(photo_dir))\n        self.test_monet_filenames = sorted(glob.glob(test_monet_dir))\n        self.test_photo_filenames = sorted(glob.glob(test_photo_dir))\n        self.loader_config = loader_config\n        self.transform = transform\n        self.mode = mode\n        \n    def setup(self, stage):\n        if stage == \"fit\":\n            self.train_monet = CustomDataset(self.monet_filenames, self.transform, stage)\n            self.train_photo = CustomDataset(self.photo_filenames, self.transform, stage)\n        \n        elif stage == \"predict\":\n            self.predict = CustomDataset(self.photo_filenames, self.transform, stage)\n            \n        elif stage == \"test\":\n            self.test_monet = CustomDataset(self.test_monet_filenames, self.transform, stage)\n            self.test_photo = CustomDataset(self.test_photo_filenames, self.transform, stage)\n            \n    def train_dataloader(self):\n        loader_monet = DataLoader(\n            self.train_monet, \n            shuffle=True, \n            drop_last=True, \n            **self.loader_config,\n        )\n        loader_photo = DataLoader(\n            self.train_photo, \n            shuffle=True,\n            drop_last=True,\n            **self.loader_config,\n        )\n        loaders = {\"monet\": loader_monet, \"photo\": loader_photo}\n        return CombinedLoader(loaders, mode=self.mode)\n    \n    def predict_dataloader(self):\n        return DataLoader(self.predict, shuffle=False, **self.loader_config)\n    \n    def test_dataloader(self):\n        return DataLoader(self.test_monet, shuffle=False, **self.loader_config)\n    def test_step(self, batch, batch_idx):\n        x, y = batch  # Example input/output batch structure, modify as per your data\n        \n        # Forward pass\n        y_pred = self(x)\n        \n        # Compute loss or other metrics\n        loss = self.loss_function(y_pred, y)\n        \n        # Return output or loss\n        return {\"loss\": loss}\n    def test_dataloader2(self):\n        return DataLoader(self.test_photo, shuffle=False, **self.loader_config)","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:26.9918Z","iopub.execute_input":"2023-04-13T07:10:26.99236Z","iopub.status.idle":"2023-04-13T07:10:27.005428Z","shell.execute_reply.started":"2023-04-13T07:10:26.992329Z","shell.execute_reply":"2023-04-13T07:10:27.004201Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SAMPLE_SIZE=5\ndm_sample = CustomDataModule(loader_config={\"batch_size\": SAMPLE_SIZE})\n\ndm_sample.setup(\"fit\")\ntrain_loader = dm_sample.train_dataloader()\nmonet_samples = next(iter(train_loader))[\"monet\"]\n\ndm_sample.setup(\"predict\")\npredict_loader = dm_sample.predict_dataloader()\nphoto_samples = next(iter(predict_loader))\n\ndm_sample.setup(\"test\")\ntest_loader1 = dm_sample.test_dataloader()\nmonet_sampless = next(iter(test_loader1))\n\ndm_sample.setup(\"test\")\ntest_loader2 = dm_sample.test_dataloader2()\nmonet_samplesss= next(iter(test_loader2))\n\nshow_img(monet_samples, nrow=SAMPLE_SIZE, title=\"Samples of Monet Paintings\")\nshow_img(photo_samples, nrow=SAMPLE_SIZE, title=\"Samples of Photos\")\nshow_img(monet_sampless, nrow=SAMPLE_SIZE, title=\"Part 2-4 pictures\")\nshow_img(monet_samplesss, nrow=SAMPLE_SIZE, title=\"Part 2-5 pictures\")","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:27.007355Z","iopub.execute_input":"2023-04-13T07:10:27.007916Z","iopub.status.idle":"2023-04-13T07:10:29.917245Z","shell.execute_reply.started":"2023-04-13T07:10:27.007876Z","shell.execute_reply":"2023-04-13T07:10:29.914992Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Downsampling(nn.Module):\n    def __init__(\n        self,\n        in_channels,\n        out_channels,\n        norm=True,\n        kernel_size=4,\n        stride=2,\n        padding=1,\n    ):\n        super().__init__()\n        self.block = nn.Sequential(\n            nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size,\n                      stride=stride, padding=padding, bias=False)\n        )\n        if norm:\n            self.block.append(nn.InstanceNorm2d(out_channels, affine=True))\n        self.block.append(nn.LeakyReLU(0.2))\n        \n    def forward(self, x):\n        return self.block(x)","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:29.918912Z","iopub.execute_input":"2023-04-13T07:10:29.919586Z","iopub.status.idle":"2023-04-13T07:10:29.928295Z","shell.execute_reply.started":"2023-04-13T07:10:29.919546Z","shell.execute_reply":"2023-04-13T07:10:29.926736Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Upsampling(nn.Module):\n    def __init__(\n        self,\n        in_channels,\n        out_channels,\n        dropout=False,\n        kernel_size=4,\n        stride=2,\n        padding=1,\n        output_padding=0,\n    ):\n        super().__init__()\n        self.block = nn.Sequential(\n            nn.ConvTranspose2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, \n                               padding=padding, output_padding=output_padding, bias=False),\n            nn.InstanceNorm2d(out_channels, affine=True),\n        )\n        if dropout:\n            self.block.append(nn.Dropout(0.5))\n        self.block.append(nn.ReLU())\n        \n    def forward(self, x):\n        return self.block(x)","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:29.932713Z","iopub.execute_input":"2023-04-13T07:10:29.93342Z","iopub.status.idle":"2023-04-13T07:10:29.941972Z","shell.execute_reply.started":"2023-04-13T07:10:29.933381Z","shell.execute_reply":"2023-04-13T07:10:29.940936Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ResidualBlock(nn.Module):\n    def __init__(self, channels):\n        super(ResidualBlock, self).__init__()\n        self.conv1 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)\n        self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)\n        self.relu = nn.ReLU(inplace=True)\n        \n    def forward(self, x):\n        residual = x\n        out = self.relu(self.conv1(x))\n        out = self.conv2(out)\n        out += residual\n        out = self.relu(out)\n        return out\n\nclass Generator(nn.Module):\n    def __init__(self, in_channels, out_channels, hid_channels):\n        super(Generator, self).__init__()\n        self.downsampling_blocks = nn.Sequential(\n            Downsampling(in_channels, hid_channels, norm=False), # 64x128x128\n            Downsampling(hid_channels, hid_channels*2), # 128x64x64\n            Downsampling(hid_channels*2, hid_channels*4), # 256x32x32\n            Downsampling(hid_channels*4, hid_channels*8), # 512x16x16\n            Downsampling(hid_channels*8, hid_channels*8), # 512x8x8\n            Downsampling(hid_channels*8, hid_channels*8), # 512x4x4\n            Downsampling(hid_channels*8, hid_channels*8), # 512x2x2\n            Downsampling(hid_channels*8, hid_channels*8, norm=False), # 512x1x1\n        )\n        self.upsampling_blocks = nn.Sequential(\n            Upsampling(hid_channels*8, hid_channels*8, dropout=True), # (512+512)x2x2\n            Upsampling(hid_channels*16, hid_channels*8, dropout=True), # (512+512)x4x4\n            Upsampling(hid_channels*16, hid_channels*8, dropout=True), # (512+512)x8x8\n            Upsampling(hid_channels*16, hid_channels*8), # (512+512)x16x16\n            Upsampling(hid_channels*16, hid_channels*4), # (256+256)x32x32\n            Upsampling(hid_channels*8, hid_channels*2), # (128+128)x64x64\n            Upsampling(hid_channels*4, hid_channels), # (64+64)x128x128\n        )\n        self.feature_block = nn.Sequential(\n            nn.ConvTranspose2d(hid_channels*2, out_channels,\n                               kernel_size=4, stride=2, padding=1), # 3x256x256\n            nn.Tanh(),\n        )\n        self.residual_blocks = nn.Sequential(\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8)\n        )\n        \n    def forward(self, x):\n        skips = []\n        for down in self.downsampling_blocks:\n            x = down(x)\n            skips.append(x)\n        skips = reversed(skips[:-1])\n        \n        for up, skip in zip(self.upsampling_blocks, skips):\n            x = up(x)\n            x = torch.cat([x, skip], dim=1)\n        return self.feature_block(x)","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:29.943731Z","iopub.execute_input":"2023-04-13T07:10:29.944471Z","iopub.status.idle":"2023-04-13T07:10:29.96561Z","shell.execute_reply.started":"2023-04-13T07:10:29.944429Z","shell.execute_reply":"2023-04-13T07:10:29.964525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nclass Discriminator(nn.Module):\n    def __init__(self, in_channels, hid_channels):\n        super(Discriminator, self).__init__()\n        self.downsampling_blocks = nn.Sequential(\n            Downsampling(in_channels, hid_channels, norm=False), # 64x128x128\n            Downsampling(hid_channels, hid_channels*2), # 128x64x64\n            Downsampling(hid_channels*2, hid_channels*4), # 256x32x32\n            Downsampling(hid_channels*4, hid_channels*8, stride=1), # 512x31x31\n        )\n        self.residual_blocks = nn.Sequential(\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8),\n            ResidualBlock(hid_channels*8)\n        )\n        self.conv = nn.Conv2d(hid_channels*8, 1, kernel_size=4, padding=1) # 1x30x30\n        \n    def forward(self, x):\n        x = self.downsampling_blocks(x)\n        x = self.residual_blocks(x)\n        x = self.conv(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:29.967515Z","iopub.execute_input":"2023-04-13T07:10:29.968233Z","iopub.status.idle":"2023-04-13T07:10:29.9784Z","shell.execute_reply.started":"2023-04-13T07:10:29.968197Z","shell.execute_reply":"2023-04-13T07:10:29.977405Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IN_CHANNELS = 3\nOUT_CHANNELS = 3\nHID_CHANNELS = 64\nLR = 2e-4\n#LR=0.9\nBETAS = (0.5, 0.999)\nLAMBDA = 10\nDISPLAY_EPOCHS = 5","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:29.979901Z","iopub.execute_input":"2023-04-13T07:10:29.980253Z","iopub.status.idle":"2023-04-13T07:10:29.989418Z","shell.execute_reply.started":"2023-04-13T07:10:29.980217Z","shell.execute_reply":"2023-04-13T07:10:29.988477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CycleGAN(L.LightningModule):\n    def __init__(\n        self, \n        in_channels=IN_CHANNELS,\n        out_channels=OUT_CHANNELS, \n        hid_channels=HID_CHANNELS,\n        lr=LR,\n        betas=BETAS,\n        lambda_w=LAMBDA,\n        display_epochs=DISPLAY_EPOCHS,\n        photo_samples=photo_samples,\n        monet_sampless=monet_sampless\n        \n    ):\n        super().__init__()\n        self.lr = lr\n        self.betas = betas\n        self.lambda_w = lambda_w\n        self.display_epochs = display_epochs\n        self.photo_samples = photo_samples\n        self.monet_sampless = monet_sampless\n        self.monet_samplesss= monet_samplesss\n        self.loss_history = []\n        self.epoch_count = 0\n        \n        self.gen_PM = Generator(in_channels, out_channels, hid_channels)\n        self.gen_MP = Generator(in_channels, out_channels, hid_channels)\n        self.disc_M = Discriminator(in_channels, hid_channels)\n        self.disc_P = Discriminator(in_channels, hid_channels)\n        self.reset_parameters()\n        \n    def forward(self, z):\n        return self.gen_PM(z)\n    \n    def weights_init(self, m):\n        if isinstance(m, (nn.Conv2d, nn.ConvTranspose2d, nn.InstanceNorm2d)):\n            nn.init.normal_(m.weight, 0., 0.02)\n            if m.bias is not None:\n                nn.init.constant_(m.bias, 0.)\n                \n    def reset_parameters(self):\n        self.gen_PM = self.gen_PM.apply(self.weights_init)\n        self.gen_MP = self.gen_MP.apply(self.weights_init)\n        self.disc_M = self.disc_M.apply(self.weights_init)\n        self.disc_P = self.disc_P.apply(self.weights_init)\n        \n    def adv_criterion(self, y_hat, y):\n        return F.binary_cross_entropy_with_logits(y_hat, y)\n    \n    def recon_criterion(self, y_hat, y):\n        return F.l1_loss(y_hat, y)\n    \n    def adv_loss(self, fake_Y, disc_Y):\n        fake_Y_hat = disc_Y(fake_Y)\n        valid = torch.ones_like(fake_Y_hat)\n        adv_loss_XY = self.adv_criterion(fake_Y_hat, valid)\n        return adv_loss_XY\n    \n    def id_loss(self, real_Y, gen_XY):\n        id_Y = gen_XY(real_Y)\n        id_loss_Y = self.recon_criterion(id_Y, real_Y)\n        return 0.5 * self.lambda_w * id_loss_Y\n    \n    def cycle_loss(self, real_Y, fake_X, gen_XY):\n        cycle_Y = gen_XY(fake_X)\n        cycle_loss_Y = self.recon_criterion(cycle_Y, real_Y)\n        return self.lambda_w * cycle_loss_Y\n        \n    def gen_loss(self, real_X, real_Y, gen_XY, gen_YX, disc_Y):\n        adv_loss_XY = self.adv_loss(gen_XY(real_X), disc_Y)\n\n        id_loss_Y = self.id_loss(real_Y, gen_XY)\n        \n        cycle_loss_Y = self.cycle_loss(real_Y, gen_YX(real_Y), gen_XY)\n        cycle_loss_X = self.cycle_loss(real_X, gen_XY(real_X), gen_YX)\n        total_cycle_loss = cycle_loss_X + cycle_loss_Y\n        \n        gen_loss_XY = adv_loss_XY + id_loss_Y + total_cycle_loss\n        return gen_loss_XY\n    \n    def disc_loss(self, real_Y, fake_Y, disc_Y, smooth=0.9):\n        real_Y_hat = disc_Y(real_Y)\n        valid = torch.full_like(real_Y_hat, fill_value=smooth)\n        real_loss_Y = self.adv_criterion(real_Y_hat, valid)\n        \n        fake_Y_hat = disc_Y(fake_Y.detach())\n        fake = torch.zeros_like(fake_Y_hat)\n        fake_loss_Y = self.adv_criterion(fake_Y_hat, fake)\n        \n        disc_loss_Y = (fake_loss_Y+real_loss_Y) * 0.5\n        return disc_loss_Y\n    \n    def configure_optimizers(self):\n        params = {\n            \"lr\": self.lr,\n            \"betas\": self.betas,\n        }\n        opt_gen_PM = torch.optim.Adam(self.gen_PM.parameters(), **params)\n        opt_gen_MP = torch.optim.Adam(self.gen_MP.parameters(), **params)\n        opt_disc_M = torch.optim.Adam(self.disc_M.parameters(), **params)\n        opt_disc_P = torch.optim.Adam(self.disc_P.parameters(), **params)\n        \n        return [opt_gen_PM, opt_gen_MP, opt_disc_M, opt_disc_P], []\n    \n    def training_step(self, batch, batch_idx, optimizer_idx):\n        real_M = batch[\"monet\"]\n        real_P = batch[\"photo\"]\n        if optimizer_idx == 0:\n            gen_loss_PM = self.gen_loss(real_P, real_M, \n                                        self.gen_PM, self.gen_MP, self.disc_M)\n            return gen_loss_PM\n        \n        if optimizer_idx == 1:\n            gen_loss_MP = self.gen_loss(real_M, real_P,\n                                        self.gen_MP, self.gen_PM, self.disc_P)\n            return gen_loss_MP\n        \n        if optimizer_idx == 2:\n            disc_loss_M = self.disc_loss(real_M, self.gen_PM(real_P), self.disc_M)\n            return disc_loss_M\n        \n        if optimizer_idx == 3:\n            disc_loss_P = self.disc_loss(real_P, self.gen_MP(real_M), self.disc_P)\n            return disc_loss_P\n    \n    def training_epoch_end(self, outputs):\n        self.epoch_count += 1\n        \n        losses = []\n        for j in range(4):\n            loss = np.mean([out[j][\"loss\"].item() for out in outputs])\n            losses.append(loss)\n        self.loss_history.append(losses)\n        print(\n            f\"Epoch {self.epoch_count} -\",\n            f\"gen_loss_PM: {losses[0]:.5f} -\",\n            f\"gen_loss_MP: {losses[1]:.5f} -\",\n            f\"disc_loss_M: {losses[2]:.5f} -\",\n            f\"disc_loss_P: {losses[3]:.5f}\",\n        )\n        \n        if self.epoch_count%self.display_epochs==0 or self.epoch_count==1:\n            gen_monets = self(self.photo_samples.to(self.device)).detach().cpu()\n            show_img(\n                torch.cat([self.photo_samples, gen_monets]),\n                nrow=len(self.photo_samples),\n                title=f\"Epoch {self.epoch_count}: Photo-to-Monet Translation\",\n            )\n            \n            gen_monets2 = self(self.monet_sampless.to(self.device)).detach().cpu()\n            show_img(\n                torch.cat([self.monet_sampless, gen_monets2]),\n                nrow=len(self.monet_sampless),\n                title=f\"Epoch {self.epoch_count}: test for Part 2-4\",\n            )\n            gen_monets3 = self(self.monet_samplesss.to(self.device)).detach().cpu()\n            show_img(\n                torch.cat([self.monet_samplesss, gen_monets3]),\n                nrow=len(self.monet_samplesss),\n                title=f\"Epoch {self.epoch_count}: test for Part 2-5\",\n            )\n            \n    def predict_step(self, batch, batch_idx):\n        return self(batch)\n    \n    def loss_curves(self):\n        labels = [\"gen_loss_PM\", \"gen_loss_MP\", \"disc_loss_M\", \"disc_loss_P\"]\n        titles = [\"Generator Loss Curves\", \"Discriminator Loss Curves\"]\n        num_epochs = len(self.loss_history)\n        plt.figure(figsize=(18, 4.5))\n        for j in range(4):\n            if j%2 == 0:\n                plt.subplot(1, 2, (j//2)+1)\n                plt.title(titles[j//2])\n                plt.ylabel(\"Loss\")\n                plt.xlabel(\"Epoch\")\n            plt.plot(\n                np.arange(1, num_epochs+1),\n                [losses[j] for losses in self.loss_history],\n                label=labels[j],\n            )\n            plt.legend(loc=\"upper right\")","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:29.991297Z","iopub.execute_input":"2023-04-13T07:10:29.991726Z","iopub.status.idle":"2023-04-13T07:10:30.023633Z","shell.execute_reply.started":"2023-04-13T07:10:29.991665Z","shell.execute_reply":"2023-04-13T07:10:30.022534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TRAIN_CONFIG = {\n    \"accelerator\": \"gpu\" if torch.cuda.is_available() else \"cpu\",\n    \"devices\": 1,\n    \"logger\": False,\n    \"enable_checkpointing\": torch.cuda.is_available(),\n    \"max_epochs\": 8,\n}","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:30.02721Z","iopub.execute_input":"2023-04-13T07:10:30.027481Z","iopub.status.idle":"2023-04-13T07:10:30.035462Z","shell.execute_reply.started":"2023-04-13T07:10:30.027456Z","shell.execute_reply":"2023-04-13T07:10:30.034288Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dm = CustomDataModule()\nmodel = CycleGAN()\ncheckpoint = {\n    'state_dict': model.state_dict(),\n    # 其他相关信息，例如优化器状态、训练配置等\n}\ntorch.save(checkpoint, 'model_checkpoint.pth')\ntrainer = L.Trainer(\n    **TRAIN_CONFIG\n)","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:30.037284Z","iopub.execute_input":"2023-04-13T07:10:30.037757Z","iopub.status.idle":"2023-04-13T07:10:35.800822Z","shell.execute_reply.started":"2023-04-13T07:10:30.037684Z","shell.execute_reply":"2023-04-13T07:10:35.799837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainer.fit(model, datamodule=dm)","metadata":{"execution":{"iopub.status.busy":"2023-04-13T07:10:35.802508Z","iopub.execute_input":"2023-04-13T07:10:35.802893Z","iopub.status.idle":"2023-04-13T10:13:26.941932Z","shell.execute_reply.started":"2023-04-13T07:10:35.802855Z","shell.execute_reply":"2023-04-13T10:13:26.940744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MONET_TEST_DIR = \"/kaggle/input/ceg-deep-learning/*.jpg\"\nPHOTO_TEST_DIR = \"/kaggle/input/ceg-deep-learning/*.jpg\"","metadata":{"execution":{"iopub.status.busy":"2023-04-13T10:13:26.944931Z","iopub.execute_input":"2023-04-13T10:13:26.945831Z","iopub.status.idle":"2023-04-13T10:13:26.95192Z","shell.execute_reply.started":"2023-04-13T10:13:26.945783Z","shell.execute_reply":"2023-04-13T10:13:26.950787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.loss_curves()","metadata":{"execution":{"iopub.status.busy":"2023-04-13T10:13:26.953644Z","iopub.execute_input":"2023-04-13T10:13:26.954402Z","iopub.status.idle":"2023-04-13T10:13:27.374389Z","shell.execute_reply.started":"2023-04-13T10:13:26.954364Z","shell.execute_reply":"2023-04-13T10:13:27.373403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions=trainer.predict(model, datamodule=dm)","metadata":{"execution":{"iopub.status.busy":"2023-04-13T10:13:27.375676Z","iopub.execute_input":"2023-04-13T10:13:27.377036Z","iopub.status.idle":"2023-04-13T10:14:01.472931Z","shell.execute_reply.started":"2023-04-13T10:13:27.376995Z","shell.execute_reply":"2023-04-13T10:14:01.471475Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.makedirs(\"../images\", exist_ok=True)\n\nidx = 0\nfor tensor in predictions:\n    for monet in tensor:\n        save_image((monet.squeeze()*0.5+0.5), fp=f\"../images/{idx}.jpg\")\n        idx += 1\n\nshutil.make_archive(\"/kaggle/working/images\", \"zip\", \"/kaggle/images\")","metadata":{"execution":{"iopub.status.busy":"2023-04-13T10:14:01.475376Z","iopub.execute_input":"2023-04-13T10:14:01.476181Z","iopub.status.idle":"2023-04-13T10:14:35.71627Z","shell.execute_reply.started":"2023-04-13T10:14:01.476133Z","shell.execute_reply":"2023-04-13T10:14:35.715282Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#from PIL import Image\n#import numpy as np\n\n#device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n# 加载模型权重或检查点\n#checkpoint_path = '/kaggle/working/model_checkpoint.pth'  # 替换为实际的检查点文件路径\n#checkpoint = torch.load(checkpoint_path)\n#model.load_state_dict(checkpoint['state_dict'])\n# 切换模型为评估模式\n#model.eval()\n\n#trainer.test(model, datamodule=dm)\n\n\n","metadata":{"execution":{"iopub.status.busy":"2023-04-13T10:14:35.719451Z","iopub.execute_input":"2023-04-13T10:14:35.720356Z","iopub.status.idle":"2023-04-13T10:14:35.724972Z","shell.execute_reply.started":"2023-04-13T10:14:35.720314Z","shell.execute_reply":"2023-04-13T10:14:35.723888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image\nimport numpy as np\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n# 加载模型权重或检查点\ncheckpoint_path = '/kaggle/working/model_checkpoint.pth'  # 替换为实际的检查点文件路径\ncheckpoint = torch.load(checkpoint_path)\nmodel.load_state_dict(checkpoint['state_dict'])\n# 切换模型为评估模式\nmodel.eval()\n    \n\n# 加载测试图片\ntest_image1_path = '/kaggle/input/ceg-deep-learning/Part 2-4/0a1d1b9f8e.jpg'  # 替换为实际的测试图片路径\ntest_image2_path = '/kaggle/input/ceg-deep-learning/Part 2-4/0a49020ae5.jpg'\ntest_image3_path = '/kaggle/input/ceg-deep-learning/Part 2-4/0a497f768d.jpg'\ntest_image1 = Image.open(test_image1_path)\ntest_image2 = Image.open(test_image2_path)\ntest_image3 = Image.open(test_image3_path)\n\n\n\n","metadata":{"execution":{"iopub.status.busy":"2023-04-13T10:14:35.727125Z","iopub.execute_input":"2023-04-13T10:14:35.72846Z"},"trusted":true},"execution_count":null,"outputs":[]}]}