{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":30747,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"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)\n\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\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n#     for filename in filenames:\n    print(os.path.join(dirname))\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":"2024-08-02T12:24:47.613415Z","iopub.execute_input":"2024-08-02T12:24:47.614343Z","iopub.status.idle":"2024-08-02T12:24:53.604686Z","shell.execute_reply.started":"2024-08-02T12:24:47.614309Z","shell.execute_reply":"2024-08-02T12:24:53.603703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision\nimport matplotlib.pyplot as plt\nfrom PIL import Image","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:24:53.606145Z","iopub.execute_input":"2024-08-02T12:24:53.606558Z","iopub.status.idle":"2024-08-02T12:24:58.861755Z","shell.execute_reply.started":"2024-08-02T12:24:53.606520Z","shell.execute_reply":"2024-08-02T12:24:58.860748Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Extraction","metadata":{}},{"cell_type":"code","source":"class TorchDataset(Dataset):\n    def __init__(self, data_path, transform=None):\n        self.data_path = data_path\n        self.transform = transform\n        self.image_paths = [os.path.join(data_path, file) for file in os.listdir(data_path) if file.endswith('.jpg')]\n        \n    def __len__(self):\n        return len(self.image_paths)\n    \n    def __getitem__(self, idx):\n        img_path = self.image_paths[idx]\n        image = Image.open(img_path).convert('RGB')\n        if self.transform:\n            image = self.transform(image)\n        return image","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:24:58.862898Z","iopub.execute_input":"2024-08-02T12:24:58.863501Z","iopub.status.idle":"2024-08-02T12:24:58.870525Z","shell.execute_reply.started":"2024-08-02T12:24:58.863471Z","shell.execute_reply":"2024-08-02T12:24:58.869588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transforms = torchvision.transforms.Compose([\n    torchvision.transforms.Resize((256,256)),\n    torchvision.transforms.ToTensor(),\n    torchvision.transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n])","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:24:58.872643Z","iopub.execute_input":"2024-08-02T12:24:58.872959Z","iopub.status.idle":"2024-08-02T12:24:58.885312Z","shell.execute_reply.started":"2024-08-02T12:24:58.872936Z","shell.execute_reply":"2024-08-02T12:24:58.884358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MonetDataset = TorchDataset(data_path='/kaggle/input/gan-getting-started/monet_jpg', transform=transforms)\nPhotoDataset = TorchDataset(data_path='/kaggle/input/gan-getting-started/photo_jpg', transform=transforms)\n\nMonetLoader = DataLoader(MonetDataset, batch_size=16, shuffle=True, num_workers=2)\nPhotoLoader = DataLoader(PhotoDataset, batch_size=16, shuffle=True, num_workers=2)","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:24:58.886325Z","iopub.execute_input":"2024-08-02T12:24:58.886600Z","iopub.status.idle":"2024-08-02T12:24:58.914711Z","shell.execute_reply.started":"2024-08-02T12:24:58.886577Z","shell.execute_reply":"2024-08-02T12:24:58.913911Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# EDA","metadata":{}},{"cell_type":"code","source":"print(len(PhotoDataset), len(MonetDataset))","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:24:58.915744Z","iopub.execute_input":"2024-08-02T12:24:58.916036Z","iopub.status.idle":"2024-08-02T12:24:58.920907Z","shell.execute_reply.started":"2024-08-02T12:24:58.916013Z","shell.execute_reply":"2024-08-02T12:24:58.920044Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"monets = next(iter(MonetLoader))\nphotos = next(iter(PhotoLoader))\nprint(monets.shape, photos.shape)","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:24:58.922164Z","iopub.execute_input":"2024-08-02T12:24:58.922636Z","iopub.status.idle":"2024-08-02T12:24:59.567951Z","shell.execute_reply.started":"2024-08-02T12:24:58.922605Z","shell.execute_reply":"2024-08-02T12:24:59.566746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# tansform data to be readable by plt.imshow\nmonets_imshow = []\nfor monet in monets:\n    monet = monet.permute(1, 2, 0) \n    monet = monet.numpy() \n    monet = monet * 0.5 + 0.5 \n    monets_imshow.append(monet)\n\nphotos_imshow = []    \nfor photo in photos:\n    photo = photo.permute(1, 2, 0) \n    photo = photo.numpy()\n    photo = photo * 0.5 + 0.5\n    photos_imshow.append(photo)","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:24:59.569571Z","iopub.execute_input":"2024-08-02T12:24:59.569885Z","iopub.status.idle":"2024-08-02T12:24:59.601609Z","shell.execute_reply.started":"2024-08-02T12:24:59.569857Z","shell.execute_reply":"2024-08-02T12:24:59.600656Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(monets_imshow[3].shape) \nprint(monets_imshow[3].dtype) ","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:24:59.602739Z","iopub.execute_input":"2024-08-02T12:24:59.602999Z","iopub.status.idle":"2024-08-02T12:24:59.607501Z","shell.execute_reply.started":"2024-08-02T12:24:59.602977Z","shell.execute_reply":"2024-08-02T12:24:59.606663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('Monet')\nplt.figure(figsize=(15, 5)) \nfor i in range(4):\n    plt.subplot(1, 4, i+1)  \n    plt.imshow(monets_imshow[i])\nplt.show()\n\nprint('Photos')\nplt.figure(figsize=(15, 5)) \nfor i in range(4):\n    plt.subplot(1, 4, i+1)  \n    plt.imshow(photos_imshow[i])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:24:59.612047Z","iopub.execute_input":"2024-08-02T12:24:59.612491Z","iopub.status.idle":"2024-08-02T12:25:01.209777Z","shell.execute_reply.started":"2024-08-02T12:24:59.612457Z","shell.execute_reply":"2024-08-02T12:25:01.208904Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Discriminator","metadata":{}},{"cell_type":"code","source":"import torch.nn as nn\n\nclass Block(nn.Module):\n    def __init__(self, in_channels, out_channels, stride):\n        super().__init__()\n        self.cnn = nn.Sequential(\n            # Convolution layer\n            nn.Conv2d(\n                in_channels,\n                out_channels,\n                kernel_size=4,\n                stride=stride,\n                padding=1,\n                bias=True,\n                padding_mode=\"reflect\",\n            ), \n            nn.InstanceNorm2d(out_channels), \n            nn.LeakyReLU(0.2, inplace=True), \n        )\n    \n    def forward(self, x):\n        return self.cnn(x)","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:29:10.318715Z","iopub.execute_input":"2024-08-02T12:29:10.319091Z","iopub.status.idle":"2024-08-02T12:29:10.326321Z","shell.execute_reply.started":"2024-08-02T12:29:10.319059Z","shell.execute_reply":"2024-08-02T12:29:10.325378Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Discriminator(nn.Module):\n    def __init__(self, in_channels=3, features=[64, 128, 256, 512]):\n        super().__init__()\n        self.initial = nn.Sequential(\n            nn.Conv2d(\n                in_channels,\n                features[0],\n                kernel_size=4,\n                stride=2,\n                padding=1,\n                padding_mode=\"reflect\",\n            ),\n            nn.LeakyReLU(0.2, inplace=True),\n        )\n\n        layers = []\n        in_channels = features[0]\n        for feature in features[1:]:\n            layers.append(\n                Block(in_channels, feature, stride=1 if feature == features[-1] else 2)\n            )\n            in_channels = feature\n        layers.append(\n            nn.Conv2d(\n                in_channels,\n                1,\n                kernel_size=4,\n                stride=1,\n                padding=1,\n                padding_mode=\"reflect\",\n            )\n        )\n        self.model = nn.Sequential(*layers)\n\n    def forward(self, x):\n        x = self.initial(x)\n        return torch.sigmoid(self.model(x))","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:29:11.641383Z","iopub.execute_input":"2024-08-02T12:29:11.642104Z","iopub.status.idle":"2024-08-02T12:29:11.650910Z","shell.execute_reply.started":"2024-08-02T12:29:11.642073Z","shell.execute_reply":"2024-08-02T12:29:11.649925Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_dis_test = Discriminator()\n\ntest_input = torch.randn((2, 3, 256, 256))\n\nprint(model_dis_test(test_input).shape)","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:29:14.299274Z","iopub.execute_input":"2024-08-02T12:29:14.299901Z","iopub.status.idle":"2024-08-02T12:29:14.458550Z","shell.execute_reply.started":"2024-08-02T12:29:14.299870Z","shell.execute_reply":"2024-08-02T12:29:14.457584Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Generator","metadata":{}},{"cell_type":"code","source":"class CNNBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, down=True, use_act=True, **kwargs):\n        super().__init__()\n        \n        if down:\n            conv_layer = nn.Conv2d(in_channels, out_channels, padding_mode=\"reflect\", **kwargs)\n        else:\n            conv_layer = nn.ConvTranspose2d(in_channels, out_channels, **kwargs)\n        \n        if use_act:\n            act_layer = nn.ReLU(inplace=True)\n        else:\n            act_layer = nn.Identity()\n        \n        self.cnn = nn.Sequential(\n            conv_layer,\n            nn.InstanceNorm2d(out_channels),\n            act_layer,\n        )\n\n    def forward(self, x):\n        return self.cnn(x)\n\n\nclass ResidualBlock(nn.Module):\n    def __init__(self, channels):\n        super().__init__()\n        self.block = nn.Sequential(\n            CNNBlock(channels, channels, kernel_size=3, padding=1),\n            CNNBlock(channels, channels, use_act=False, kernel_size=3, padding=1),\n        )\n\n    def forward(self, x):\n        return x + self.block(x)","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:29:28.584344Z","iopub.execute_input":"2024-08-02T12:29:28.585049Z","iopub.status.idle":"2024-08-02T12:29:28.594644Z","shell.execute_reply.started":"2024-08-02T12:29:28.585016Z","shell.execute_reply":"2024-08-02T12:29:28.593600Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Generator(nn.Module):\n    def __init__(self, img_channels, num_features=64, num_residuals=9):\n        super().__init__()\n        self.initial = nn.Sequential(\n            nn.Conv2d(\n                img_channels,\n                num_features,\n                kernel_size=7,\n                stride=1,\n                padding=3,\n                padding_mode=\"reflect\",\n            ),\n            nn.InstanceNorm2d(num_features),\n            nn.ReLU(inplace=True),\n        )\n        self.down_blocks = nn.ModuleList(\n            [\n                CNNBlock(\n                    num_features, \n                    num_features * 2, \n                    kernel_size=3, \n                    stride=2, \n                    padding=1\n                ),\n                CNNBlock(\n                    num_features * 2,\n                    num_features * 4,\n                    kernel_size=3,\n                    stride=2,\n                    padding=1,\n                ),\n            ]\n        )\n        self.res_blocks = nn.Sequential(\n            *[ResidualBlock(num_features * 4) for _ in range(num_residuals)]\n        )\n        self.up_blocks = nn.ModuleList(\n            [\n                CNNBlock(\n                    num_features * 4,\n                    num_features * 2,\n                    down=False,\n                    kernel_size=3,\n                    stride=2,\n                    padding=1,\n                    output_padding=1,\n                ),\n                CNNBlock(\n                    num_features * 2,\n                    num_features * 1,\n                    down=False,\n                    kernel_size=3,\n                    stride=2,\n                    padding=1,\n                    output_padding=1,\n                ),\n            ]\n        )\n\n        self.last = nn.Conv2d(\n            num_features * 1,\n            img_channels,\n            kernel_size=7,\n            stride=1,\n            padding=3,\n            padding_mode=\"reflect\",\n        )\n\n    def forward(self, x):\n        x = self.initial(x)\n        for layer in self.down_blocks:\n            x = layer(x)\n        x = self.res_blocks(x)\n        for layer in self.up_blocks:\n            x = layer(x)\n        return torch.tanh(self.last(x))","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:29:35.389483Z","iopub.execute_input":"2024-08-02T12:29:35.390136Z","iopub.status.idle":"2024-08-02T12:29:35.401363Z","shell.execute_reply.started":"2024-08-02T12:29:35.390106Z","shell.execute_reply":"2024-08-02T12:29:35.400390Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_channels = 3\nimg_size = 256\n\ntest_input = torch.randn((2, img_channels, img_size, img_size))\n\nmodel_gen_test = Generator(img_channels, 9)\n\nprint(model_gen_test(test_input).shape)","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:29:37.920331Z","iopub.execute_input":"2024-08-02T12:29:37.920693Z","iopub.status.idle":"2024-08-02T12:29:38.126376Z","shell.execute_reply.started":"2024-08-02T12:29:37.920662Z","shell.execute_reply":"2024-08-02T12:29:38.125444Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Training","metadata":{}},{"cell_type":"code","source":"device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(f\"Using device: {device}\")","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:29:40.060407Z","iopub.execute_input":"2024-08-02T12:29:40.061254Z","iopub.status.idle":"2024-08-02T12:29:40.089268Z","shell.execute_reply.started":"2024-08-02T12:29:40.061222Z","shell.execute_reply":"2024-08-02T12:29:40.088334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import random_split\n\nval_size_monet = int(0.2 * len(MonetDataset))\ntrain_size_monet = len(MonetDataset) - val_size_monet\n\nval_size_photo = int(0.2 * len(PhotoDataset))\ntrain_size_photo = len(PhotoDataset) - val_size_photo\n\n\ntrain_MonetDataset, val_MonetDataset = random_split(MonetDataset, [train_size_monet, val_size_monet])\ntrain_PhotoDataset, val_PhotoDataset = random_split(PhotoDataset, [train_size_photo, val_size_photo])\n\ntrain_MonetLoader = DataLoader(train_MonetDataset, batch_size=16, shuffle=True, num_workers=2)\nval_MonetLoader = DataLoader(val_MonetDataset, batch_size=16, shuffle=False, num_workers=2)\n\ntrain_PhotoLoader = DataLoader(train_PhotoDataset, batch_size=16, shuffle=True, num_workers=2)\nval_PhotoLoader = DataLoader(val_PhotoDataset, batch_size=16, shuffle=False, num_workers=2)","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:29:42.187587Z","iopub.execute_input":"2024-08-02T12:29:42.187922Z","iopub.status.idle":"2024-08-02T12:29:42.196504Z","shell.execute_reply.started":"2024-08-02T12:29:42.187897Z","shell.execute_reply":"2024-08-02T12:29:42.195594Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.optim as optim\nfrom torch.cuda.amp import GradScaler, autocast\nfrom tqdm import tqdm\n\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nG_Photo2Monet = Generator(img_channels=3).to(device)\nG_Monet2Photo = Generator(img_channels=3).to(device)\nD_Photo = Discriminator(in_channels=3).to(device)\nD_Monet = Discriminator(in_channels=3).to(device)\n\noptimizer_G_Photo2Monet = optim.Adam(G_Photo2Monet.parameters(), lr=1e-4, betas=(0.5, 0.5))\noptimizer_G_Monet2Photo = optim.Adam(G_Monet2Photo.parameters(), lr=1e-4, betas=(0.5, 0.5))\noptimizer_D_Photo = optim.Adam(D_Photo.parameters(), lr=1e-4, betas=(0.5, 0.5))\noptimizer_D_Monet = optim.Adam(D_Monet.parameters(), lr=1e-4, betas=(0.5, 0.5))\n\ncriterion_GAN = nn.MSELoss()\ncriterion_cycle = nn.L1Loss()\n\nscaler = GradScaler()\n\nlambda_cycle = 5\nnum_epochs = 100\nbatch_size = 16\n\nfor epoch in range(num_epochs):\n    epoch_loss_G_Photo2Monet = 0\n    epoch_loss_G_Monet2Photo = 0\n    epoch_loss_D_Photo = 0\n    epoch_loss_D_Monet = 0\n    \n    for i, (real_photo, real_monet) in enumerate(zip(train_PhotoLoader, train_MonetLoader)):\n        real_photo = real_photo.to(device)\n        real_monet = real_monet.to(device)\n        batch_size = real_photo.size(0)\n\n        fake_monet = G_Photo2Monet(real_photo).detach()\n        fake_photo = G_Monet2Photo(real_monet).detach()\n\n        D_Photo_real = D_Photo(real_photo)\n        D_Monet_real = D_Monet(real_monet)\n        D_Photo_output_shape = D_Photo_real.shape\n        D_Monet_output_shape = D_Monet_real.shape\n\n        real_label_Photo = torch.ones(D_Photo_output_shape, dtype=torch.float, device=device)\n        fake_label_Photo = torch.zeros(D_Photo_output_shape, dtype=torch.float, device=device)\n        real_label_Monet = torch.ones(D_Monet_output_shape, dtype=torch.float, device=device)\n        fake_label_Monet = torch.zeros(D_Monet_output_shape, dtype=torch.float, device=device)\n\n        with autocast():\n            D_Photo_real = D_Photo(real_photo)\n            D_Photo_fake = D_Photo(fake_photo)\n            loss_D_Photo_real = criterion_GAN(D_Photo_real, real_label_Photo)\n            loss_D_Photo_fake = criterion_GAN(D_Photo_fake, fake_label_Photo)\n            loss_D_Photo = (loss_D_Photo_real + loss_D_Photo_fake) * 0.5\n\n            D_Monet_real = D_Monet(real_monet)\n            D_Monet_fake = D_Monet(fake_monet)\n            loss_D_Monet_real = criterion_GAN(D_Monet_real, real_label_Monet)\n            loss_D_Monet_fake = criterion_GAN(D_Monet_fake, fake_label_Monet)\n            loss_D_Monet = (loss_D_Monet_real + loss_D_Monet_fake) * 0.5\n\n        optimizer_D_Photo.zero_grad()\n        scaler.scale(loss_D_Photo).backward()\n        scaler.step(optimizer_D_Photo)\n\n        optimizer_D_Monet.zero_grad()\n        scaler.scale(loss_D_Monet).backward()\n        scaler.step(optimizer_D_Monet)\n\n        epoch_loss_D_Photo += loss_D_Photo.item()\n        epoch_loss_D_Monet += loss_D_Monet.item()\n\n        with autocast():\n            fake_monet = G_Photo2Monet(real_photo)\n            fake_photo = G_Monet2Photo(real_monet)\n            loss_GAN_Photo2Monet = criterion_GAN(D_Monet(fake_monet), real_label_Monet)\n            loss_GAN_Monet2Photo = criterion_GAN(D_Photo(fake_photo), real_label_Photo)\n\n            cycle_photo = G_Monet2Photo(fake_monet)\n            cycle_monet = G_Photo2Monet(fake_photo)\n            loss_cycle_photo = criterion_cycle(cycle_photo, real_photo)\n            loss_cycle_monet = criterion_cycle(cycle_monet, real_monet)\n\n            loss_G_Photo2Monet = loss_GAN_Photo2Monet + lambda_cycle * loss_cycle_photo\n            loss_G_Monet2Photo = loss_GAN_Monet2Photo + lambda_cycle * loss_cycle_monet\n\n        optimizer_G_Photo2Monet.zero_grad()\n        scaler.scale(loss_G_Photo2Monet).backward()\n        scaler.step(optimizer_G_Photo2Monet)\n\n        optimizer_G_Monet2Photo.zero_grad()\n        scaler.scale(loss_G_Monet2Photo).backward()\n        scaler.step(optimizer_G_Monet2Photo)\n\n        scaler.update()\n\n        epoch_loss_G_Photo2Monet += loss_G_Photo2Monet.item()\n        epoch_loss_G_Monet2Photo += loss_G_Monet2Photo.item()\n\n    epoch_loss_G_Photo2Monet /= len(train_PhotoLoader)\n    epoch_loss_G_Monet2Photo /= len(train_MonetLoader)\n    epoch_loss_D_Photo /= len(train_PhotoLoader)\n    epoch_loss_D_Monet /= len(train_MonetLoader)\n\n    print(f\"Epoch [{epoch+1}/{num_epochs}] - \"\n          f\"loss_G_Photo2Monet: {epoch_loss_G_Photo2Monet:.4f}, \"\n          f\"loss_G_Monet2Photo: {epoch_loss_G_Monet2Photo:.4f}, \"\n          f\"loss_D_Photo: {epoch_loss_D_Photo:.4f}, \"\n          f\"loss_D_Monet: {epoch_loss_D_Monet:.4f}\")\n\n    if (epoch + 1) % 10 == 0:\n        with torch.no_grad():\n            G_Photo2Monet.eval()\n            example_photo = next(iter(val_PhotoLoader)).to(device)\n            fake_monet = G_Photo2Monet(example_photo)\n\n            plt.figure(figsize=(12, 6))\n            for i in range(4):\n                plt.subplot(2, 4, i + 1)\n                plt.imshow(((example_photo[i].cpu().numpy().transpose(1, 2, 0) + 1) / 2))\n                plt.axis('off')\n                plt.subplot(2, 4, i + 5)\n                plt.imshow(((fake_monet[i].cpu().numpy().transpose(1, 2, 0) + 1) / 2))\n                plt.axis('off')\n            plt.show()\n\n            G_Photo2Monet.train()\n\nfinal_model_path = 'final_model.pth'\ntorch.save({\n    'G_Photo2Monet': G_Photo2Monet.state_dict(),\n    'G_Monet2Photo': G_Monet2Photo.state_dict(),\n    'D_Photo': D_Photo.state_dict(),\n    'D_Monet': D_Monet.state_dict(),\n    'optimizer_G_Photo2Monet': optimizer_G_Photo2Monet.state_dict(),\n    'optimizer_G_Monet2Photo': optimizer_G_Monet2Photo.state_dict(),\n    'optimizer_D_Photo': optimizer_D_Photo.state_dict(),\n    'optimizer_D_Monet': optimizer_D_Monet.state_dict(),\n}, final_model_path)","metadata":{"execution":{"iopub.status.busy":"2024-08-02T12:29:47.552154Z","iopub.execute_input":"2024-08-02T12:29:47.552486Z","iopub.status.idle":"2024-08-02T13:36:30.192646Z","shell.execute_reply.started":"2024-08-02T12:29:47.552460Z","shell.execute_reply":"2024-08-02T13:36:30.191587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nfrom zipfile import ZipFile\n\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nmodel_path = '/kaggle/working/final_model.pth'\ncheckpoint = torch.load(model_path)\n\n\nG_Photo2Monet = Generator(img_channels=3).to(device)\nG_Photo2Monet.load_state_dict(checkpoint['G_Photo2Monet'])\nG_Photo2Monet.eval()\n\ntest_loader = DataLoader(PhotoDataset, batch_size=1, shuffle=False)\n\n\nos.makedirs('../tmp/images', exist_ok=True)\n\nwith torch.no_grad():\n    for i, img in enumerate(test_loader):\n        img = img.to(device)\n        fake_monet = G_Photo2Monet(img)[0].cpu().permute(1, 2, 0).numpy() * 0.5 + 0.5\n        im = Image.fromarray((fake_monet * 255).astype(np.uint8))\n        im.save(f\"../tmp/images/{i}.jpg\")\n\noutput_zip_path = \"/kaggle/working/images.zip\"\nwith ZipFile(output_zip_path, 'w') as zipf:\n    for root, _, files in os.walk('../tmp/images'):\n        for file in files:\n            zipf.write(os.path.join(root, file), os.path.relpath(os.path.join(root, file), '../tmp/images'))\n","metadata":{"execution":{"iopub.status.busy":"2024-08-02T13:40:33.107916Z","iopub.execute_input":"2024-08-02T13:40:33.108875Z","iopub.status.idle":"2024-08-02T13:43:08.183426Z","shell.execute_reply.started":"2024-08-02T13:40:33.108835Z","shell.execute_reply":"2024-08-02T13:43:08.182400Z"},"trusted":true},"execution_count":null,"outputs":[]}]}