{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":21755,"databundleVersionId":1475600},{"sourceType":"datasetVersion","sourceId":2940753,"datasetId":1802868,"databundleVersionId":2988242}],"dockerImageVersionId":31329,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\n\nprint(\"🔍 Checking the added dataset...\\n\")\n\n# \nmonet_path = None\nphoto_path = None\n\nfor root, dirs, files in os.walk('/kaggle/input'):\n    if 'monet_jpg' in dirs:\n        monet_path = os.path.join(root, 'monet_jpg')\n        print(f\"✅ Monet folder found: {monet_path}\")\n        print(f\"   Number of Monet images: {len(os.listdir(monet_path))}\")\n    if 'photo_jpg' in dirs:\n        photo_path = os.path.join(root, 'photo_jpg')\n        print(f\"✅ Photo folder found: {photo_path}\")\n        print(f\"   Number of Photo images: {len(os.listdir(photo_path))}\")\n\nif monet_path and photo_path:\n    print(\"\\n🎉 Success! Both folders are ready.\")\nelse:\n    print(\"\\n❌ Something wrong - try removing the dataset and adding it again.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:30:38.011471Z","iopub.execute_input":"2026-04-04T19:30:38.012235Z","iopub.status.idle":"2026-04-04T19:31:07.884356Z","shell.execute_reply.started":"2026-04-04T19:30:38.012186Z","shell.execute_reply":"2026-04-04T19:31:07.883575Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =============================================\n# I'm Something of a Painter Myself - Advanced CycleGAN (PyTorch)\n# Optimized for Kaggle GPU (T4 / P100)\n# =============================================\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nfrom torchvision.utils import save_image\nimport os\nfrom PIL import Image\nimport zipfile\nfrom tqdm import tqdm\nimport time\nprint(\"✅ All imports done\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:07.885668Z","iopub.execute_input":"2026-04-04T19:31:07.886050Z","iopub.status.idle":"2026-04-04T19:31:16.670660Z","shell.execute_reply.started":"2026-04-04T19:31:07.886024Z","shell.execute_reply":"2026-04-04T19:31:16.669992Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Device Configuration\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Using device: {device}\")\nif torch.cuda.is_available():\n    print(f\"GPU: {torch.cuda.get_device_name(0)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:16.671508Z","iopub.execute_input":"2026-04-04T19:31:16.671928Z","iopub.status.idle":"2026-04-04T19:31:16.975754Z","shell.execute_reply.started":"2026-04-04T19:31:16.671886Z","shell.execute_reply":"2026-04-04T19:31:16.974971Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================\n# Hyperparameters\n# ============================\nBATCH_SIZE = 4                    # Reduce to 2 if you get Out of Memory\nIMAGE_SIZE = 256\nEPOCHS = 8\nLR = 2e-4\nLAMBDA_CYCLE = 10.0\nLAMBDA_IDENTITY = 5.0\nNUM_WORKERS = 4\n\nscaler = torch.amp.GradScaler('cuda')\n\nprint(\"✅ Hyperparameters loaded successfully\")\nprint(f\"Batch Size: {BATCH_SIZE} | Epochs: {EPOCHS} | Using Mixed Precision\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:16.977248Z","iopub.execute_input":"2026-04-04T19:31:16.977549Z","iopub.status.idle":"2026-04-04T19:31:16.982493Z","shell.execute_reply.started":"2026-04-04T19:31:16.977526Z","shell.execute_reply":"2026-04-04T19:31:16.981765Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================\n# 1. Dataset\n# ============================\nclass MonetDataset(Dataset):\n    def _init_(self, root_dir, transform=None):\n        self.root_dir = root_dir\n        self.transform = transform\n        self.images = [f for f in os.listdir(root_dir) if f.endswith(('.jpg', '.png'))]\n    \n    def _len_(self):\n        return len(self.images)\n    \n    def _getitem_(self, idx):\n        img_path = os.path.join(self.root_dir, self.images[idx])\n        image = Image.open(img_path).convert(\"RGB\")\n        if self.transform:\n            image = self.transform(image)\n        return image\n\ntransform = transforms.Compose([\n    transforms.Resize((286, 286)),\n    transforms.RandomCrop(IMAGE_SIZE),\n    transforms.RandomHorizontalFlip(p=0.5),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:16.983531Z","iopub.execute_input":"2026-04-04T19:31:16.983984Z","iopub.status.idle":"2026-04-04T19:31:16.997289Z","shell.execute_reply.started":"2026-04-04T19:31:16.983960Z","shell.execute_reply":"2026-04-04T19:31:16.996578Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nfrom PIL import Image\nfrom torch.utils.data import Dataset\nimport torchvision.transforms as transforms\n\nclass MonetDataset(Dataset):\n    def __init__(self, root, transform=None):\n        self.root = root\n        self.transform = transform\n        self.images = os.listdir(root)\n        self.images = [img for img in self.images if img.endswith(('.jpg', '.jpeg', '.png'))]\n        \n    def __len__(self):\n        return len(self.images)\n    \n    def __getitem__(self, idx):\n        img_path = os.path.join(self.root, self.images[idx])\n        image = Image.open(img_path).convert('RGB')\n        \n        if self.transform:\n            image = self.transform(image)\n        \n        return image\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:16.998280Z","iopub.execute_input":"2026-04-04T19:31:16.998562Z","iopub.status.idle":"2026-04-04T19:31:17.014042Z","shell.execute_reply.started":"2026-04-04T19:31:16.998529Z","shell.execute_reply":"2026-04-04T19:31:17.013308Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.Resize((256, 256)),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:17.015002Z","iopub.execute_input":"2026-04-04T19:31:17.015503Z","iopub.status.idle":"2026-04-04T19:31:17.026207Z","shell.execute_reply.started":"2026-04-04T19:31:17.015481Z","shell.execute_reply":"2026-04-04T19:31:17.025495Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Correct Paths (from your successful check)\nmonet_path = \"/kaggle/input/competitions/gan-getting-started/monet_jpg\"\nphoto_path = \"/kaggle/input/competitions/gan-getting-started/photo_jpg\"\n\nprint(f\"Loading {len(os.listdir(monet_path))} Monet images and {len(os.listdir(photo_path))} Photo images...\")\n\nmonet_dataset = MonetDataset(monet_path, transform)\nphoto_dataset = MonetDataset(photo_path, transform)\n\nmonet_loader = DataLoader(monet_dataset, batch_size=BATCH_SIZE, shuffle=True, \n                         num_workers=NUM_WORKERS, pin_memory=True, drop_last=True)\nphoto_loader = DataLoader(photo_dataset, batch_size=BATCH_SIZE, shuffle=True, \n                         num_workers=NUM_WORKERS, pin_memory=True, drop_last=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:17.027212Z","iopub.execute_input":"2026-04-04T19:31:17.027521Z","iopub.status.idle":"2026-04-04T19:31:17.049672Z","shell.execute_reply.started":"2026-04-04T19:31:17.027499Z","shell.execute_reply":"2026-04-04T19:31:17.048924Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================\n# Custom Dataset\n# ============================\nclass MonetDataset(Dataset):\n    def __init__(self, root_dir, transform=None):\n        self.root_dir = root_dir\n        self.transform = transform\n        self.images = [f for f in os.listdir(root_dir) if f.endswith(('.jpg', '.png'))]\n    \n    def __len__(self):\n        return len(self.images)\n    \n    def __getitem__(self, idx):\n        img_path = os.path.join(self.root_dir, self.images[idx])\n        image = Image.open(img_path).convert(\"RGB\")\n        if self.transform:\n            image = self.transform(image)\n        return image\n\n# Data Augmentation\ntransform = transforms.Compose([\n    transforms.Resize((286, 286)),\n    transforms.RandomCrop(IMAGE_SIZE),\n    transforms.RandomHorizontalFlip(p=0.5),\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n])\n\n# Paths\nmonet_path = \"/kaggle/input/competitions/gan-getting-started/monet_jpg\"\nphoto_path = \"/kaggle/input/competitions/gan-getting-started/photo_jpg\"\n\n# Create Datasets and Loaders\nmonet_dataset = MonetDataset(monet_path, transform)\nphoto_dataset = MonetDataset(photo_path, transform)\n\nmonet_loader = DataLoader(monet_dataset, batch_size=BATCH_SIZE, shuffle=True,\n                         num_workers=NUM_WORKERS, pin_memory=True, drop_last=True)\nphoto_loader = DataLoader(photo_dataset, batch_size=BATCH_SIZE, shuffle=True,\n                         num_workers=NUM_WORKERS, pin_memory=True, drop_last=True)\n\nprint(f\"✅ Data loaded successfully!\")\nprint(f\"Monet images: {len(monet_dataset)} | Photo images: {len(photo_dataset)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:17.050698Z","iopub.execute_input":"2026-04-04T19:31:17.051004Z","iopub.status.idle":"2026-04-04T19:31:17.064094Z","shell.execute_reply.started":"2026-04-04T19:31:17.050972Z","shell.execute_reply":"2026-04-04T19:31:17.063234Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================\n# 2. Models\n# ============================\nclass ResidualBlock(nn.Module):\n    def _init_(self, channels):\n        super()._init_()\n        self.block = nn.Sequential(\n            nn.Conv2d(channels, channels, kernel_size=3, padding=1, bias=False),\n            nn.InstanceNorm2d(channels),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(channels, channels, kernel_size=3, padding=1, bias=False),\n            nn.InstanceNorm2d(channels)\n        )\n    \nclass Generator(nn.Module):\n    def __init__(self):\n        super().__init__()\n        # Initial convolution layer\n        self.initial = nn.Sequential(\n            nn.Conv2d(3, 64, kernel_size=7, padding=3, bias=False),\n            nn.InstanceNorm2d(64),\n            nn.ReLU(inplace=True)\n        )\n        \n        # Downsampling layers\n        self.down = nn.Sequential(\n            nn.Conv2d(64, 128, 3, 2, 1, bias=False),\n            nn.InstanceNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(128, 256, 3, 2, 1, bias=False),\n            nn.InstanceNorm2d(256),\n            nn.ReLU(inplace=True)\n        )\n        \n        # Residual blocks (the core of CycleGAN)\n        self.res_blocks = nn.Sequential(*[ResidualBlock(256) for _ in range(9)])\n        \n        # Upsampling layers\n        self.up = nn.Sequential(\n            nn.ConvTranspose2d(256, 128, 3, 2, 1, output_padding=1, bias=False),\n            nn.InstanceNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.ConvTranspose2d(128, 64, 3, 2, 1, output_padding=1, bias=False),\n            nn.InstanceNorm2d(64),\n            nn.ReLU(inplace=True)\n        )\n        \n        # Output layer\n        self.last = nn.Sequential(\n            nn.Conv2d(64, 3, kernel_size=7, padding=3),\n            nn.Tanh()\n        )\n\n    def forward(self, x):\n        x = self.initial(x)\n        x = self.down(x)\n        x = self.res_blocks(x)\n        x = self.up(x)\n        return self.last(x)          ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:17.066170Z","iopub.execute_input":"2026-04-04T19:31:17.066852Z","iopub.status.idle":"2026-04-04T19:31:17.075171Z","shell.execute_reply.started":"2026-04-04T19:31:17.066828Z","shell.execute_reply":"2026-04-04T19:31:17.074563Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================\n# 2. Models (Corrected Version)\n# ============================\n\nclass ResidualBlock(nn.Module):\n    def __init__(self, channels):\n        super(ResidualBlock, self).__init__()\n        self.block = nn.Sequential(\n            nn.Conv2d(channels, channels, kernel_size=3, padding=1, bias=False),\n            nn.InstanceNorm2d(channels),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(channels, channels, kernel_size=3, padding=1, bias=False),\n            nn.InstanceNorm2d(channels)\n        )\n    \n    def forward(self, x):\n        return x + self.block(x)\n\nclass Generator(nn.Module):\n    def __init__(self):\n        super(Generator, self).__init__()\n        \n        # Initial layer\n        self.initial = nn.Sequential(\n            nn.Conv2d(3, 64, kernel_size=7, padding=3, bias=False),\n            nn.InstanceNorm2d(64),\n            nn.ReLU(inplace=True)\n        )\n        \n        # Downsampling\n        self.down = nn.Sequential(\n            nn.Conv2d(64, 128, 3, 2, 1, bias=False),\n            nn.InstanceNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(128, 256, 3, 2, 1, bias=False),\n            nn.InstanceNorm2d(256),\n            nn.ReLU(inplace=True)\n        )\n        \n        # 9 Residual blocks\n        self.res_blocks = nn.Sequential(*[ResidualBlock(256) for _ in range(9)])\n        \n        # Upsampling\n        self.up = nn.Sequential(\n            nn.ConvTranspose2d(256, 128, 3, 2, 1, output_padding=1, bias=False),\n            nn.InstanceNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.ConvTranspose2d(128, 64, 3, 2, 1, output_padding=1, bias=False),\n            nn.InstanceNorm2d(64),\n            nn.ReLU(inplace=True)\n        )\n        \n        # Output layer\n        self.last = nn.Sequential(\n            nn.Conv2d(64, 3, kernel_size=7, padding=3),\n            nn.Tanh()\n        )\n\n    def forward(self, x):\n        x = self.initial(x)\n        x = self.down(x)\n        x = self.res_blocks(x)\n        x = self.up(x)\n        return self.last(x)\n\n# Initialize models\ngen_G = Generator().to(device) # Photo -> Monet\ngen_F = Generator().to(device) # Monet -> Photo\n\nprint(\"Models initialized successfully!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:17.076010Z","iopub.execute_input":"2026-04-04T19:31:17.076486Z","iopub.status.idle":"2026-04-04T19:31:17.584876Z","shell.execute_reply.started":"2026-04-04T19:31:17.076462Z","shell.execute_reply":"2026-04-04T19:31:17.584234Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Discriminator(nn.Module):\n    def __init__(self, in_channels=3):\n        super(Discriminator, self).__init__()\n\n        def discriminator_block(in_filters, out_filters, stride=2, normalize=True):\n            layers = [nn.Conv2d(in_filters, out_filters, 4, stride, 1)]\n            if normalize:\n                layers.append(nn.InstanceNorm2d(out_filters))\n            layers.append(nn.LeakyReLU(0.2, inplace=True))\n            return layers\n\n        self.model = nn.Sequential(\n            *discriminator_block(in_channels, 64, normalize=False), # (128x128)\n            *discriminator_block(64, 128),                         # (64x64)\n            *discriminator_block(128, 256),                        # (32x32)\n            *discriminator_block(256, 512, stride=1),              # (31x31)\n            nn.Conv2d(512, 1, 4, padding=1)                        # (30x30) Output Patch\n        )\n\n    def forward(self, img):\n        return self.model(img)\n\n# Initialize Discriminators\ndisc_M = Discriminator().to(device) # Checks if Monet is real\ndisc_P = Discriminator().to(device) # Checks if Photo is real","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:17.585771Z","iopub.execute_input":"2026-04-04T19:31:17.586133Z","iopub.status.idle":"2026-04-04T19:31:17.639114Z","shell.execute_reply.started":"2026-04-04T19:31:17.586094Z","shell.execute_reply":"2026-04-04T19:31:17.638504Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import itertools\n\n# Loss functions\ncriterion_GAN = nn.MSELoss()         # Standard for LSGAN\ncriterion_cycle = nn.L1Loss()        # Cycle consistency\ncriterion_identity = nn.L1Loss()     # Identity mapping\n\n# Optimizers\noptimizer_G = optim.Adam(\n    itertools.chain(gen_G.parameters(), gen_F.parameters()),\n    lr=LR, betas=(0.5, 0.999)\n)\noptimizer_D_M = optim.Adam(disc_M.parameters(), lr=LR, betas=(0.5, 0.999))\noptimizer_D_P = optim.Adam(disc_P.parameters(), lr=LR, betas=(0.5, 0.999))\n\n# Learning rate update schedulers (Linear decay after 30 epochs)\ndef lr_lambda(epoch):\n    return 1.0 - max(0, epoch - 30) / float(30)\n\nscheduler_G = optim.lr_scheduler.LambdaLR(optimizer_G, lr_lambda=lr_lambda)\nscheduler_D_M = optim.lr_scheduler.LambdaLR(optimizer_D_M, lr_lambda=lr_lambda)\nscheduler_D_P = optim.lr_scheduler.LambdaLR(optimizer_D_P, lr_lambda=lr_lambda)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:17.640024Z","iopub.execute_input":"2026-04-04T19:31:17.640319Z","iopub.status.idle":"2026-04-04T19:31:17.647400Z","shell.execute_reply.started":"2026-04-04T19:31:17.640287Z","shell.execute_reply":"2026-04-04T19:31:17.646855Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================================\n# TRAINING LOOP - CycleGAN\n# ================================================\n\nfor epoch in range(EPOCHS):\n    # We use len(photo_loader) because we want to cover all photo images\n    progress_bar = tqdm(\n        enumerate(zip(monet_loader, photo_loader)), \n        total=len(photo_loader), \n        desc=f\"Epoch {epoch+1}/{EPOCHS}\"\n    )\n\n    for i, (real_monet, real_photo) in progress_bar:\n        real_monet = real_monet.to(device)\n        real_photo = real_photo.to(device)\n\n        # -----------------------\n        #  Train Generators (G & F)\n        # -----------------------\n        optimizer_G.zero_grad()\n\n        with torch.cuda.amp.autocast():\n            # Identity Loss\n            id_monet = gen_G(real_monet)\n            loss_id_M = criterion_identity(id_monet, real_monet) * LAMBDA_IDENTITY\n            \n            id_photo = gen_F(real_photo)\n            loss_id_P = criterion_identity(id_photo, real_photo) * LAMBDA_IDENTITY\n\n            # GAN Loss (Adversarial)\n            fake_monet = gen_G(real_photo)\n            loss_GAN_G = criterion_GAN(disc_M(fake_monet), torch.ones_like(disc_M(fake_monet)))\n            \n            fake_photo = gen_F(real_monet)\n            loss_GAN_F = criterion_GAN(disc_P(fake_photo), torch.ones_like(disc_P(fake_photo)))\n\n            # Cycle Consistency Loss\n            recovered_photo = gen_F(fake_monet)\n            loss_cycle_P = criterion_cycle(recovered_photo, real_photo) * LAMBDA_CYCLE\n            \n            recovered_monet = gen_G(fake_photo)\n            loss_cycle_M = criterion_cycle(recovered_monet, real_monet) * LAMBDA_CYCLE\n\n            # Total Generator Loss\n            loss_G = (loss_GAN_G + loss_GAN_F + \n                      loss_cycle_P + loss_cycle_M + \n                      loss_id_M + loss_id_P)\n\n        scaler.scale(loss_G).backward()\n        scaler.step(optimizer_G)\n        scaler.update()\n\n        # -----------------------\n        #  Train Discriminators\n        # -----------------------\n        # Discriminator for Monet images\n        optimizer_D_M.zero_grad()\n        with torch.cuda.amp.autocast():\n            loss_real_M = criterion_GAN(disc_M(real_monet), torch.ones_like(disc_M(real_monet)))\n            loss_fake_M = criterion_GAN(disc_M(fake_monet.detach()), torch.zeros_like(disc_M(fake_monet.detach())))\n            loss_D_M = (loss_real_M + loss_fake_M) * 0.5\n        \n        scaler.scale(loss_D_M).backward()\n        scaler.step(optimizer_D_M)\n        scaler.update()\n\n        # Discriminator for Photo images\n        optimizer_D_P.zero_grad()\n        with torch.cuda.amp.autocast():\n            loss_real_P = criterion_GAN(disc_P(real_photo), torch.ones_like(disc_P(real_photo)))\n            loss_fake_P = criterion_GAN(disc_P(fake_photo.detach()), torch.zeros_like(disc_P(fake_photo.detach())))\n            loss_D_P = (loss_real_P + loss_fake_P) * 0.5\n            \n        scaler.scale(loss_D_P).backward()\n        scaler.step(optimizer_D_P)\n        scaler.update()\n\n        # Update Progress Bar\n        progress_bar.set_description(\n            f\"Epoch {epoch+1}/{EPOCHS} | Loss_G: {loss_G.item():.4f} | Loss_D: {(loss_D_M + loss_D_P).item():.4f}\"\n        )\n\n    # Update Learning Rates after each epoch\n    scheduler_G.step()\n    scheduler_D_M.step()\n    scheduler_D_P.step()\n\n    # Print epoch summary\n    print(f\"✅ Epoch {epoch+1}/{EPOCHS} completed | Loss_G: {loss_G.item():.4f} | Loss_D: {(loss_D_M + loss_D_P).item():.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:31:17.648456Z","iopub.execute_input":"2026-04-04T19:31:17.648764Z","iopub.status.idle":"2026-04-04T19:38:49.889617Z","shell.execute_reply.started":"2026-04-04T19:31:17.648725Z","shell.execute_reply":"2026-04-04T19:38:49.888701Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================================================\n# FINAL STEP: GENERATE IMAGES & CREATE SUBMISSION ZIP\n# ================================================\n\nimport os\nimport shutil\nfrom torchvision.utils import save_image\nfrom tqdm import tqdm\nimport torch\n\n# 1. Create output directory\noutput_dir = \"/kaggle/working/images\"\nos.makedirs(output_dir, exist_ok=True)\n\n# 2. Set generator to evaluation mode\ngen_G.eval()\n\nprint(\"Starting final image generation for submission...\")\n\nimage_count = 0\n\nwith torch.no_grad():\n    for photos in tqdm(photo_loader, desc=\"Generating Images\"):\n        photos = photos.to(device)\n        \n        # Generate fake Monet images\n        fake_monets = gen_G(photos)\n        \n        # De-normalize: from [-1,1] → [0,1]\n        fake_monets = (fake_monets * 0.5 + 0.5).clamp(0, 1)\n        \n        # Save each image with 4-digit naming (best practice)\n        for i in range(fake_monets.size(0)):\n            image_count += 1\n            img_path = os.path.join(output_dir, f\"{image_count:04d}.jpg\")\n            save_image(fake_monets[i], img_path, normalize=False)\n            \n        # Stop at \\~7500 images (competition limit)\n        if image_count >= 7500:\n            break\n\nprint(f\"\\nTotal images generated: {image_count}\")\n\n# 3. Create the ZIP file (this is the most important part)\nzip_path = \"/kaggle/working/images\"\nshutil.make_archive(zip_path, 'zip', output_dir)\n\nprint(f\"\\nSUCCESS: 'images.zip' has been created successfully!\")\nprint(f\"Number of images in zip: {image_count}\")\nprint(\"You can now submit to the competition!\")\n\n# 4. Optional: Show the first few images to check quality (for debugging)\nprint(\"\\nFirst 5 generated images saved as:\")\nfor i in range(1, 6):\n    print(f\"   {i:04d}.jpg\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:38:49.891662Z","iopub.execute_input":"2026-04-04T19:38:49.892159Z","iopub.status.idle":"2026-04-04T19:42:05.977809Z","shell.execute_reply.started":"2026-04-04T19:38:49.892114Z","shell.execute_reply":"2026-04-04T19:42:05.976760Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from PIL import Image\nimport matplotlib.pyplot as plt\n\n# Show the first 5 generated images to check quality\nprint(\"First 5 generated Monet-style images:\\n\")\n\nfig, axes = plt.subplots(1, 5, figsize=(15, 3))\n\nfor i in range(5):\n    img_path = f\"/kaggle/working/images/{i+1:04d}.jpg\"\n    try:\n        img = Image.open(img_path)\n        axes[i].imshow(img)\n        axes[i].set_title(f\"Image {i+1:04d}.jpg\")\n        axes[i].axis('off')\n    except FileNotFoundError:\n        axes[i].text(0.5, 0.5, f\"Image {i+1:04d}.jpg\\nNot Found\", \n                    ha='center', va='center')\n        axes[i].axis('off')\n\nplt.tight_layout()\nplt.show()\n\n# Also print how many images were generated in total\nimport os\nnum_images = len([f for f in os.listdir(\"/kaggle/working/images\") if f.endswith('.jpg')])\nprint(f\"✅ Total images generated: {num_images}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:42:05.979306Z","iopub.execute_input":"2026-04-04T19:42:05.979732Z","iopub.status.idle":"2026-04-04T19:42:06.476323Z","shell.execute_reply.started":"2026-04-04T19:42:05.979663Z","shell.execute_reply":"2026-04-04T19:42:06.475414Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(len(os.listdir('/kaggle/working/images')))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:51:31.455434Z","iopub.execute_input":"2026-04-04T19:51:31.455921Z","iopub.status.idle":"2026-04-04T19:51:31.465473Z","shell.execute_reply.started":"2026-04-04T19:51:31.455888Z","shell.execute_reply":"2026-04-04T19:51:31.464428Z"}},"outputs":[],"execution_count":null}]}