{"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"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":30626,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"from torch.utils.data import DataLoader, Dataset\nfrom torchvision import transforms\nfrom tqdm.notebook import tqdm\nimport torch.optim as optim\nimport torch.nn as nn\nfrom PIL import Image\nimport torchvision\nimport shutil\nimport torch\nimport os","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class MonetDataset(Dataset):\n    def __init__(self, folder_path, transform=None):\n        self.folder_path = folder_path\n        self.transform = transform\n        self.images = [os.path.join(folder_path, f) for f in os.listdir(folder_path) if f.endswith(('.jpg', '.jpeg', '.png'))]\n\n    def __len__(self):\n        return len(self.images)\n\n    def __getitem__(self, idx):\n        image_path = self.images[idx]\n        image = Image.open(image_path).convert('RGB')\n        if self.transform:\n            image = self.transform(image)\n        return image\n\nclass PhotoDataset(Dataset):\n    def __init__(self, folder_path, transform=None):\n        self.folder_path = folder_path\n        self.transform = transform\n        self.images = [os.path.join(folder_path, f) for f in os.listdir(folder_path) if f.endswith(('.jpg', '.jpeg', '.png'))]\n\n    def __len__(self):\n        return len(self.images)\n\n    def __getitem__(self, idx):\n        image_path = self.images[idx]\n        image = Image.open(image_path).convert('RGB')\n        if self.transform:\n            image = self.transform(image)\n        return image","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Device configuration\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n# Hyperparameters\nIMAGE_DIM = 128\nnum_epochs = 512\nbatch_size = 16\nlearning_rate = 1e-4\nweigth_decay = 1e-3\n\n# Define transformations\ntransform = transforms.Compose([\n    transforms.Resize((256, 256)),\n\n    # Data augmentation\n    transforms.RandomHorizontalFlip(p=0.5),  # Randomly flip the image horizontally\n    transforms.RandomRotation(degrees=15),   # Random rotation of the image\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),  # Randomly change brightness, contrast, and saturation\n\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])\n])\n\n# Initialize datasets\nmonet_dataset = MonetDataset('/kaggle/input/gan-getting-started/monet_jpg', transform)\nphoto_dataset = PhotoDataset('/kaggle/input/gan-getting-started/photo_jpg', transform)\n\n# Initialize data loaders\nmonet_loader = DataLoader(monet_dataset, batch_size=batch_size, shuffle=True)\nphoto_loader = DataLoader(photo_dataset, batch_size=batch_size, shuffle=True)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class ResidualBlock(nn.Module):\n    def __init__(self, channels):\n        super().__init__()\n        self.block = nn.Sequential(\n            nn.Conv2d(channels, channels, kernel_size=3, stride=1, padding=1),\n            nn.BatchNorm2d(channels),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(channels, channels, kernel_size=3, stride=1, padding=1),\n            nn.BatchNorm2d(channels)\n        )\n\n    def forward(self, x):\n        return x + self.block(x)\n\nclass Discriminator(nn.Module):\n    def __init__(self):\n        super(Discriminator, self).__init__()\n\n        self.conv_layers = nn.Sequential(\n            nn.Conv2d(3, 64, kernel_size=3, stride=2, padding=1),\n            nn.LeakyReLU(0.2, inplace=True),\n            nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1),\n            nn.LeakyReLU(0.2, inplace=True),\n            nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1),\n            nn.LeakyReLU(0.2, inplace=True)\n        )\n\n        # Correct the input size of the linear layer to match the flattened output size\n        self.linear_layers = nn.Sequential(\n            nn.Flatten(),\n            nn.Linear(262144, 1024),  # Updated to match the output size of conv_layers\n            nn.LeakyReLU(0.2, inplace=True),\n            nn.Linear(1024, 1),\n            nn.Sigmoid()\n        )\n\n    def forward(self, img):\n        conv_out = self.conv_layers(img)\n        validity = self.linear_layers(conv_out)\n        return validity\n\nclass Generator(nn.Module):\n    def __init__(self):\n        super(Generator, self).__init__()\n\n        # Downsample\n        self.down = nn.Sequential(\n            nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(128, 256, kernel_size=3, stride=2, padding=1),\n            nn.ReLU(inplace=True)\n        )\n\n        # Residual blocks\n        self.res = nn.Sequential(\n            ResidualBlock(256),\n            ResidualBlock(256),\n            ResidualBlock(256),\n            ResidualBlock(256)\n        )\n\n        # Upsample\n        self.up = nn.Sequential(\n            nn.ConvTranspose2d(256, 128, kernel_size=3, stride=2, padding=1, output_padding=1),\n            nn.ReLU(inplace=True),\n            nn.ConvTranspose2d(128, 64, kernel_size=3, stride=2, padding=1, output_padding=1),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(64, 3, kernel_size=3, stride=1, padding=1),\n            nn.Tanh()\n        )\n\n    def forward(self, x):\n        x = self.down(x)\n        x = self.res(x)\n        x = self.up(x)\n        return x","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Instantiate models\nD = Discriminator().to(device)\nG = Generator().to(device)\n\n# Optimizers (No need for BCELoss)\nd_optimizer = optim.AdamW(D.parameters(), lr=learning_rate, weight_decay=weigth_decay)\ng_optimizer = optim.AdamW(G.parameters(), lr=learning_rate, weight_decay=weigth_decay)\n\ncriterion_GAN = nn.MSELoss()\ncriterion_cycle = nn.L1Loss()\ncriterion_identity = nn.L1Loss()\ncriterion_discriminator = nn.BCELoss()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Lambda factors for different components of the loss\nlambda_cycle = 10.0\nlambda_identity = 0.5 * lambda_cycle\n\ndef g_loss_function(real_monet, generated_photo, reconstructed_monet, real_photo, D):\n    valid = torch.ones(real_monet.size(0), 1, device=device)\n    g_loss_GAN = criterion_GAN(D(generated_photo), valid)\n    g_loss_cycle = criterion_cycle(reconstructed_monet, real_monet)\n    identity_photo = G(real_photo)\n    g_loss_identity = criterion_identity(identity_photo, real_photo)\n    g_loss = g_loss_GAN + lambda_cycle * g_loss_cycle + lambda_identity * g_loss_identity\n    return g_loss\n\ndef d_loss_function(real_outputs, fake_outputs):\n    real_labels = torch.ones(real_outputs.size(0), 1, device=device)\n    real_loss = criterion_discriminator(real_outputs, real_labels)\n    fake_labels = torch.zeros(fake_outputs.size(0), 1, device=device)\n    fake_loss = criterion_discriminator(fake_outputs, fake_labels)\n    d_loss = real_loss + fake_loss\n    return d_loss","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for epoch in range(num_epochs):\n    loader = zip(photo_loader, monet_loader)\n    epoch_g_loss = 0.0\n    epoch_d_loss = 0.0\n    for real_photos, real_monets in loader:\n        real_photos = real_photos.to(device)\n        real_monets = real_monets.to(device)\n\n        # Generator forward pass\n        G.zero_grad()\n        monet_style_imgs = G(real_photos)\n        reconstructed_photos = G(monet_style_imgs)\n\n        # For identity loss (optional)\n        real_monets = next(iter(monet_loader)).to(device)\n\n        # Calculate generator loss\n        g_loss = g_loss_function(real_photos, monet_style_imgs, reconstructed_photos, real_monets, D)\n        g_loss.backward()\n        g_optimizer.step()\n\n        # Discriminator Training\n        # Randomly sample real Monet images from monet_loader for discriminator training\n        D.zero_grad()\n\n        # Discriminator outputs for real and fake images\n        real_outputs = D(real_monets)\n        fake_outputs = D(monet_style_imgs.detach())\n\n        # Compute Discriminator loss\n        d_loss = d_loss_function(real_outputs, fake_outputs)\n        d_loss.backward()\n        d_optimizer.step()\n\n        # Accumulate losses for epoch-level logging\n        epoch_g_loss += g_loss.item()\n        epoch_d_loss += d_loss.item()\n\n    # Print epoch-level summaries\n    print(f\"Epoch {epoch+1}/{num_epochs} - Generator Loss: {epoch_g_loss / len(photo_loader):.4f}, Discriminator Loss: {epoch_d_loss / len(photo_loader):.4f}\")","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Configuration for style transfer\ntransformed_save_dir = '../images'\n\n# Ensure the save directory exists\nif not os.path.exists(transformed_save_dir):\n    os.makedirs(transformed_save_dir)\n    \nG.eval()\n\n# Process Monet images in batches and save transformed images\nfor i, real_photos in enumerate(photo_loader):\n    real_photos = real_photos.to(device)\n    with torch.no_grad():\n        monet_style_imgs = G(real_photos)\n\n    # Save each transformed image\n    for j, img in enumerate(monet_style_imgs):\n        save_path = os.path.join(transformed_save_dir, f'monet_style_image_{i * batch_size + j}.png')\n        torchvision.utils.save_image(img, save_path)\n\nprint(f\"Transformed images are saved in {transformed_save_dir}\")\n\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")","metadata":{},"execution_count":null,"outputs":[]}]}