{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":30822,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"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, filename))\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","trusted":true,"execution":{"iopub.status.busy":"2024-12-21T01:23:19.231923Z","iopub.execute_input":"2024-12-21T01:23:19.232302Z","iopub.status.idle":"2024-12-21T01:23:22.348311Z","shell.execute_reply.started":"2024-12-21T01:23:19.232274Z","shell.execute_reply":"2024-12-21T01:23:22.347223Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport zipfile\nfrom random import sample\nimport torch\nimport torch.nn as nn\nimport torchvision.transforms as transforms\nfrom torchvision.utils import save_image\nfrom PIL import Image\nfrom torch.utils.data import Dataset, DataLoader\n\n# Check for GPU usage\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n\n# Dataset class to load Monet and photo images\nclass Images(Dataset):\n    def __init__(self, photo_path, monet_path, transform):\n        self.photo_path = photo_path\n        self.monet_path = monet_path\n        self.transform = transform\n        self.photos = os.listdir(photo_path)\n        self.monets = os.listdir(monet_path)\n\n        # Randomly sample 50 images if there are enough images, otherwise take as many as available\n        self.photos = sample(self.photos, min(50, len(self.photos)))\n        self.monets = sample(self.monets, min(50, len(self.monets)))\n\n        self.l_photo = len(self.photos)\n        self.l_monet = len(self.monets)\n\n    def __len__(self):\n        return max(len(self.photos), len(self.monets))\n\n    def __getitem__(self, idx):\n        # Load and transform images\n        photo = Image.open(os.path.join(self.photo_path, self.photos[idx % self.l_photo])).convert(\"RGB\")\n        monet = Image.open(os.path.join(self.monet_path, self.monets[idx % self.l_monet])).convert(\"RGB\")\n\n        photo = self.transform(photo)\n        monet = self.transform(monet)\n\n        return photo, monet\n\n# Image transformations\nimage_transform = transforms.Compose([\n    transforms.Resize((128, 128)),  # Rescale to 128x128 to reduce memory consumption\n    transforms.RandomHorizontalFlip(),  # Data augmentation\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),  # More augmentation\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])\n])\n\n# Define dataset and dataloader\nphoto_dataset_path = '/kaggle/input/gan-getting-started/photo_jpg/'\nmonet_dataset_path = '/kaggle/input/gan-getting-started/monet_jpg/'\n\ndataset = Images(photo_dataset_path, monet_dataset_path, image_transform)\ndataloader = DataLoader(dataset, batch_size=8, shuffle=True)\n\n# Define the Generator and Discriminator models with improvements\nclass Generator(nn.Module):\n    def __init__(self):\n        super(Generator, self).__init__()\n        self.model = nn.Sequential(\n            nn.Linear(100, 256 * 8 * 8),\n            nn.ReLU(True), nn.Unflatten(1, (256, 8, 8)),\n\n            nn.ConvTranspose2d(256, 128, kernel_size=4, stride=2, padding=1), nn.BatchNorm2d(128), nn.ReLU(True),\n\n            nn.ConvTranspose2d(128, 64, kernel_size=4, stride=2, padding=1), nn.BatchNorm2d(64), nn.ReLU(True),\n\n            nn.ConvTranspose2d(64, 32, kernel_size=4, stride=2, padding=1), nn.BatchNorm2d(32), nn.ReLU(True),\n\n            nn.ConvTranspose2d(32, 3, kernel_size=4, stride=2, padding=1), nn.Tanh()\n        )\n\n    def forward(self, x):\n        return self.model(x)\n\nclass Discriminator(nn.Module):\n    def __init__(self):\n        super(Discriminator, self).__init__()\n        self.model = nn.Sequential(\n            nn.Conv2d(3, 64, kernel_size=4, stride=2, padding=1), nn.LeakyReLU(0.2, inplace=True),\n\n            nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1), nn.BatchNorm2d(128), nn.LeakyReLU(0.2, inplace=True),\n\n            nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1), nn.BatchNorm2d(256), nn.LeakyReLU(0.2, inplace=True),\n\n            nn.Conv2d(256, 512, kernel_size=4, stride=2, padding=1), nn.BatchNorm2d(512), nn.LeakyReLU(0.2, inplace=True),\n\n            nn.Flatten(), nn.Linear(512 * 8 * 8, 1), nn.Sigmoid()\n        )\n\n    def forward(self, x):\n        return self.model(x)\n\n# Loss and optimizers\nadversarial_loss = nn.BCELoss()\n\ngenerator = Generator().to(device)\ndiscriminator = Discriminator().to(device)\n\noptimizer_G = torch.optim.Adam(generator.parameters(), lr=0.0001, betas=(0.5, 0.999))\noptimizer_D = torch.optim.Adam(discriminator.parameters(), lr=0.0001, betas=(0.5, 0.999))\n\noutput_dir = \"output/\"\nos.makedirs(output_dir, exist_ok=True)\n\n# Training the GAN with improvements\nepochs = 200\nfor epoch in range(epochs):\n    running_d_loss = 0.0\n    running_g_loss = 0.0\n    for i, (photos, _) in enumerate(dataloader):\n        # Adversarial ground truths\n        valid = torch.ones((photos.size(0), 1), requires_grad=False).to(device)\n        fake = torch.zeros((photos.size(0), 1), requires_grad=False).to(device)\n\n        # Real photos to be processed by the discriminator\n        real_photos = photos.to(device)\n\n        # Sample random noise for the generator\n        noise = torch.randn((photos.size(0), 100)).to(device)\n\n        # Train Generator\n        optimizer_G.zero_grad()\n        generated_photos = generator(noise)\n        g_loss = adversarial_loss(discriminator(generated_photos), valid)\n        running_g_loss += g_loss.item()\n        g_loss.backward()\n        optimizer_G.step()\n\n        # Train Discriminator\n        optimizer_D.zero_grad()\n        real_loss = adversarial_loss(discriminator(real_photos), valid)\n        fake_loss = adversarial_loss(discriminator(generated_photos.detach()), fake)\n        d_loss = (real_loss + fake_loss) / 2\n        running_d_loss += d_loss.item()\n        d_loss.backward()\n        optimizer_D.step()\n\n    print(f\"Epoch [{epoch + 1}/{epochs}] | Discriminator loss: {running_d_loss / len(dataloader):.4f} | Generator loss:\"\n          f\" {running_g_loss / len(dataloader):.4f}\")\n\n# Generate and save images\nnum_images = 7000\nbatch_size = 100\nimages_generated = 0\n\nfor batch_num in range(num_images // batch_size):\n    noise = torch.randn(batch_size, 100).to(device)\n    gen_imgs = generator(noise)\n    gen_imgs = gen_imgs.view(gen_imgs.size(0), 3, 128, 128)\n    gen_imgs = (gen_imgs + 1) / 2  # Rescale images to [0, 1]\n\n    for i in range(batch_size):\n        save_image(gen_imgs[i], f\"{output_dir}/image_{images_generated + i}.png\")\n\n    images_generated += batch_size\n    print(f\"Generated {images_generated} images.\")\n\n# Create zip file of generated images\nzip_filename = \"images.zip\"\nwith zipfile.ZipFile(zip_filename, 'w') as img_zip:\n    for foldername, subfolders, filenames in os.walk(output_dir):\n        for filename in filenames:\n            img_zip.write(os.path.join(foldername, filename), filename)\n\nprint(f\"All images have been generated and zipped into {zip_filename}.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-21T01:23:22.349613Z","iopub.execute_input":"2024-12-21T01:23:22.349940Z"}},"outputs":[],"execution_count":null}]}