{"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":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"dockerImageVersionId":31236,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## __Create Generative Adversarial Networks (GANs)__\nDawud Ujamaa  \nJanuary 25, 2026","metadata":{}},{"cell_type":"markdown","source":"### __1. Load the dataset:__\nThe dataset selected for this assignment was the \"gan-getting-started\" dataset available from the kaggle.com at: https://www.kaggle.com/competitions/gan-getting-started/data","metadata":{}},{"cell_type":"code","source":"import time\nimport gc\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport itertools\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom PIL import Image\nimport PIL\nimport shutil\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import datasets, transforms\n\nstart_time = time.time()\nprint(f\"Notebook started at: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(start_time))}\")\n\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\n#for 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","execution":{"iopub.status.busy":"2026-01-20T04:01:07.164399Z","iopub.execute_input":"2026-01-20T04:01:07.164735Z","iopub.status.idle":"2026-01-20T04:01:21.861000Z","shell.execute_reply.started":"2026-01-20T04:01:07.164699Z","shell.execute_reply":"2026-01-20T04:01:21.860048Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# count files in each directory\n\nfrom pathlib import Path\n\ndef count_files_pathlib(directory_path):\n    path = Path(directory_path)\n    files = [p for p in path.iterdir() if p.is_file()]\n    return len(files)\n\nMONET_FILENAMES = r'/kaggle/input/gan-getting-started/monet_jpg'\nPHOTO_FILENAMES = r'/kaggle/input/gan-getting-started/photo_jpg'\n\n# Use '.' for the current directory, or provide an absolute/relative path\nmonet_files = count_files_pathlib(MONET_FILENAMES)\nphoto_files = count_files_pathlib(PHOTO_FILENAMES)\nprint(f'Number of Monet files: {monet_files}')\nprint(f'Number of Photo files: {photo_files}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:04:22.991039Z","iopub.execute_input":"2026-01-20T04:04:22.991629Z","iopub.status.idle":"2026-01-20T04:04:26.663131Z","shell.execute_reply.started":"2026-01-20T04:04:22.991597Z","shell.execute_reply":"2026-01-20T04:04:26.662334Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# list files in directory\n\ndef list_files_pathlib(directory_path='.'):\n    p = Path(directory_path)\n    files = [item for item in p.iterdir() if item.is_file()]\n    return files\n\nmonet_list = pd.DataFrame(list_files_pathlib(MONET_FILENAMES), columns=[\"filename\"])\nphoto_list = pd.DataFrame(list_files_pathlib(PHOTO_FILENAMES), columns=[\"filename\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:04:48.057782Z","iopub.execute_input":"2026-01-20T04:04:48.058305Z","iopub.status.idle":"2026-01-20T04:04:51.799287Z","shell.execute_reply.started":"2026-01-20T04:04:48.058276Z","shell.execute_reply":"2026-01-20T04:04:51.798500Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __2. Preprocess and resize images to the required input size for your GAN model:__ ","metadata":{}},{"cell_type":"code","source":"# build dataset from monet image files\n\nmonets = []\n\nimg_size=(256, 256)\n\nfor _, row in monet_list.iterrows():\n    img_path = row[\"filename\"]\n\n    # Load image\n    img = Image.open(img_path).convert(\"RGB\")\n    img = img.resize(img_size)\n\n    monets.append(np.array(img))\n\nX_MONET = np.array(monets, dtype=np.float32)\n\n# Check shapes\nprint(X_MONET.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:05:45.653717Z","iopub.execute_input":"2026-01-20T04:05:45.654393Z","iopub.status.idle":"2026-01-20T04:05:48.666600Z","shell.execute_reply.started":"2026-01-20T04:05:45.654367Z","shell.execute_reply":"2026-01-20T04:05:48.665937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# build dataset from photo image files\n\nphotos = []\n\nfor _, row in photo_list.iterrows():\n    img_path = row[\"filename\"]\n\n    # Load image\n    img = Image.open(img_path).convert(\"RGB\")\n    img = img.resize(img_size)\n\n    photos.append(np.array(img))\n\nX_PHOTOS = np.array(photos, dtype=np.float32)\n\n# Check shapes\nprint(X_PHOTOS.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:06:04.655605Z","iopub.execute_input":"2026-01-20T04:06:04.656152Z","iopub.status.idle":"2026-01-20T04:06:37.235555Z","shell.execute_reply.started":"2026-01-20T04:06:04.656126Z","shell.execute_reply":"2026-01-20T04:06:37.234821Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# First 20 images in Photo images dataset\n\nplt.figure(figsize=(12, 2))\n\nfor i in range(20):\n    plt.subplot(2, 10, i + 1)\n    plt.imshow(X_PHOTOS[i] / 255.0)\n    plt.axis('off')\n\nplt.tight_layout()\nplt.show();","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:07:36.303355Z","iopub.execute_input":"2026-01-20T04:07:36.304054Z","iopub.status.idle":"2026-01-20T04:07:36.715182Z","shell.execute_reply.started":"2026-01-20T04:07:36.304027Z","shell.execute_reply":"2026-01-20T04:07:36.714343Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# First 20 images in Monet images dataset\n\nplt.figure(figsize=(12, 2))\n\nfor i in range(20):\n    plt.subplot(2, 10, i + 1)\n    plt.imshow(X_MONET[i] / 255.0)\n    plt.axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:07:59.948558Z","iopub.execute_input":"2026-01-20T04:07:59.949191Z","iopub.status.idle":"2026-01-20T04:08:00.344022Z","shell.execute_reply.started":"2026-01-20T04:07:59.949164Z","shell.execute_reply":"2026-01-20T04:08:00.343247Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __3. Normalize pixel values to improve training stability:__","metadata":{}},{"cell_type":"code","source":"# resize images to 128x128 to improve processing speed\nfrom tqdm import tqdm\n\ndef resize_folder(src_dir, dest_dir, size=(128, 128)):\n    if not os.path.exists(dest_dir):\n        os.makedirs(dest_dir)\n\n    files = [f for f in os.listdir(src_dir) if f.lower().endswith(('.jpg', '.jpeg', '.png'))]\n    print(f\"Resizing {len(files)} images from {src_dir}...\")\n\n    for f in tqdm(files):\n        img = Image.open(os.path.join(src_dir, f)).convert('RGB')\n        img = img.resize(size, Image.Resampling.LANCZOS)\n        img.save(os.path.join(dest_dir, f), \"JPEG\", quality=95)\n\n# Execute for both folders\nresize_folder(r'/kaggle/input/gan-getting-started/monet_jpg', r'/kaggle/working/monet_128')\nresize_folder(r'/kaggle/input/gan-getting-started/photo_jpg', r'/kaggle/working/photo_128')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:10:48.262631Z","iopub.execute_input":"2026-01-20T04:10:48.263346Z","iopub.status.idle":"2026-01-20T04:11:08.485795Z","shell.execute_reply.started":"2026-01-20T04:10:48.263315Z","shell.execute_reply":"2026-01-20T04:11:08.485222Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#  Configuration\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nLR = 0.0002\nBATCH_SIZE = 1\nIMG_SIZE = 128\nFILTERS = 32\nEPOCHS = 100","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:11:38.979111Z","iopub.execute_input":"2026-01-20T04:11:38.979411Z","iopub.status.idle":"2026-01-20T04:11:38.983542Z","shell.execute_reply.started":"2026-01-20T04:11:38.979386Z","shell.execute_reply":"2026-01-20T04:11:38.982914Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class UnpairedImageDataset(Dataset):\n    def __init__(self, root_A, root_B):\n        self.root_A = root_A\n        self.root_B = root_B\n        self.files_A = sorted(os.listdir(root_A))\n        self.files_B = sorted(os.listdir(root_B))\n\n        self.transform = transforms.Compose([\n            transforms.RandomHorizontalFlip(),\n            transforms.ToTensor(),\n            transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),\n        ])\n\n    def __len__(self):\n        return min(1000, len(self.files_B))\n\n    def __getitem__(self, idx):\n        path_A = os.path.join(self.root_A, self.files_A[idx % len(self.files_A)])\n        path_B = os.path.join(self.root_B, self.files_B[idx % len(self.files_B)])\n\n        img_A = Image.open(path_A).convert(\"RGB\")\n        img_B = Image.open(path_B).convert(\"RGB\")\n\n        return self.transform(img_A), self.transform(img_B)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:12:08.120373Z","iopub.execute_input":"2026-01-20T04:12:08.121055Z","iopub.status.idle":"2026-01-20T04:12:08.127243Z","shell.execute_reply.started":"2026-01-20T04:12:08.121028Z","shell.execute_reply":"2026-01-20T04:12:08.126567Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# data loader\nif __name__ == \"__main__\":\n    dataset = UnpairedImageDataset(\n        root_A=r'/kaggle/working/monet_128',\n        root_B=r'/kaggle/working/photo_128'\n    )\n\n    loader = DataLoader(\n        dataset,\n        batch_size=BATCH_SIZE,\n        shuffle=True,\n        num_workers=4,       # Uses 4 CPU cores to feed the GPU\n        pin_memory=True,     # Speeds up CPU-to-GPU transfer\n        prefetch_factor=2    # Loads next batches while GPU is working\n    )\n\n    print(f\"Dataset loaded: {len(dataset)} pairs available.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:13:13.991569Z","iopub.execute_input":"2026-01-20T04:13:13.991897Z","iopub.status.idle":"2026-01-20T04:13:14.003212Z","shell.execute_reply.started":"2026-01-20T04:13:13.991872Z","shell.execute_reply":"2026-01-20T04:13:14.002664Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __4. Build a GAN architecture that includes the generator and discriminator.__","metadata":{}},{"cell_type":"markdown","source":"#### __4a. Build the Generator.__","metadata":{}},{"cell_type":"code","source":"#  U-Net Generator\ndef conv_block(in_ch, out_ch, stride=2, use_upsample=False):\n    if use_upsample:\n        return nn.Sequential(\n            nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),\n            nn.Conv2d(in_ch, out_ch, 3, 1, 1, padding_mode='reflect', bias=False),\n            nn.InstanceNorm2d(out_ch),\n            nn.ReLU(inplace=True)\n        )\n    return nn.Sequential(\n        nn.Conv2d(in_ch, out_ch, 3, stride, 1, padding_mode='reflect', bias=False),\n        nn.InstanceNorm2d(out_ch),\n        nn.LeakyReLU(0.2, inplace=True)\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:13:52.207287Z","iopub.execute_input":"2026-01-20T04:13:52.207846Z","iopub.status.idle":"2026-01-20T04:13:52.212977Z","shell.execute_reply.started":"2026-01-20T04:13:52.207816Z","shell.execute_reply":"2026-01-20T04:13:52.212343Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TinyGenerator(nn.Module):\n    def __init__(self):\n        super().__init__()\n        # 4 Levels of Downsampling\n        self.down1 = conv_block(3, FILTERS, stride=1)\n        self.down2 = conv_block(FILTERS, FILTERS*2)\n        self.down3 = conv_block(FILTERS*2, FILTERS*4)\n        self.down4 = conv_block(FILTERS*4, FILTERS*8)\n\n        # 4 Levels of Upsampling\n        self.up1 = conv_block(FILTERS*8, FILTERS*4, use_upsample=True)\n        self.up2 = conv_block(FILTERS*4, FILTERS*2, use_upsample=True)\n        self.up3 = conv_block(FILTERS*2, FILTERS, use_upsample=True)\n        self.final = nn.Sequential(\n            nn.Conv2d(FILTERS, 3, 3, 1, 1, padding_mode='reflect'),\n            nn.Tanh()\n        )\n\n    def forward(self, x):\n        d1 = self.down1(x)\n        d2 = self.down2(d1)\n        d3 = self.down3(d2)\n        d4 = self.down4(d3)\n        return self.final(self.up3(self.up2(self.up1(d4))))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:14:06.660520Z","iopub.execute_input":"2026-01-20T04:14:06.661414Z","iopub.status.idle":"2026-01-20T04:14:06.667872Z","shell.execute_reply.started":"2026-01-20T04:14:06.661378Z","shell.execute_reply":"2026-01-20T04:14:06.667209Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### __4b. Build the Discriminator.__","metadata":{}},{"cell_type":"code","source":"#  PatchGAN\nclass TinyDiscriminator(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.model = nn.Sequential(\n            conv_block(3, FILTERS*2, stride=2),\n            conv_block(FILTERS*2, FILTERS*4, stride=2),\n            conv_block(FILTERS*4, FILTERS*8, stride=1),\n            nn.Conv2d(FILTERS*8, 1, 4, padding=1) # PatchGAN output\n        )\n\n    def forward(self, x):\n        return self.model(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:14:31.247683Z","iopub.execute_input":"2026-01-20T04:14:31.248387Z","iopub.status.idle":"2026-01-20T04:14:31.253195Z","shell.execute_reply.started":"2026-01-20T04:14:31.248359Z","shell.execute_reply":"2026-01-20T04:14:31.252346Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### __4c. Initialize CycleGAN model.__","metadata":{}},{"cell_type":"code","source":"#  Initialize Models\nG_AB = TinyGenerator().to(DEVICE)\nG_BA = TinyGenerator().to(DEVICE)\nD_A = TinyDiscriminator().to(DEVICE)\nD_B = TinyDiscriminator().to(DEVICE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:15:00.806450Z","iopub.execute_input":"2026-01-20T04:15:00.806805Z","iopub.status.idle":"2026-01-20T04:15:01.019888Z","shell.execute_reply.started":"2026-01-20T04:15:00.806777Z","shell.execute_reply":"2026-01-20T04:15:01.019101Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define loss functions and optimizers\n\ncriterion_GAN = nn.MSELoss()\ncriterion_Cycle = nn.L1Loss()\n\nopt_G = optim.Adam(itertools.chain(G_AB.parameters(), G_BA.parameters()), lr=LR, betas=(0.5, 0.999))\nopt_D = optim.Adam(itertools.chain(D_A.parameters(), D_B.parameters()), lr=LR, betas=(0.5, 0.999))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:15:16.870097Z","iopub.execute_input":"2026-01-20T04:15:16.870820Z","iopub.status.idle":"2026-01-20T04:15:16.875508Z","shell.execute_reply.started":"2026-01-20T04:15:16.870790Z","shell.execute_reply":"2026-01-20T04:15:16.874890Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __5. Train the GAN model by alternately training the generator and discriminator.__","metadata":{}},{"cell_type":"code","source":"#  Training Loop\n\nlambda_identity = 5.0 # half of lambda_cycle (10.0)\n\nfor epoch in range(EPOCHS):\n    for i, (real_A, real_B) in enumerate(loader):\n        real_A, real_B = real_A.to(DEVICE), real_B.to(DEVICE)\n\n        # Train Generators \n        opt_G.zero_grad()\n\n        # Identity Loss (Helpful for style transfer)\n        # G_AB should not change B; G_BA should not change A\n        loss_id_A = criterion_Cycle(G_BA(real_A), real_A) * lambda_identity\n        loss_id_B = criterion_Cycle(G_AB(real_B), real_B) * lambda_identity\n\n        # GAN Loss\n        fake_B = G_AB(real_A)\n        loss_GAN_AB = criterion_GAN(D_B(fake_B), torch.ones_like(D_B(fake_B)))\n\n        fake_A = G_BA(real_B)\n        loss_GAN_BA = criterion_GAN(D_A(fake_A), torch.ones_like(D_A(fake_A)))\n\n        # Cycle Consistency Loss\n        rec_A = G_BA(fake_B)\n        loss_cycle_A = criterion_Cycle(rec_A, real_A) * 10.0\n\n        rec_B = G_AB(fake_A)\n        loss_cycle_B = criterion_Cycle(rec_B, real_B) * 10.0\n\n        # Total G Loss\n        total_G_loss = loss_GAN_AB + loss_GAN_BA + loss_cycle_A + loss_cycle_B + loss_id_A + loss_id_B\n        total_G_loss.backward()\n        opt_G.step()\n\n        # Train Discriminators \n        opt_D.zero_grad()\n\n        # D_A Loss\n        pred_real_A = D_A(real_A)\n        loss_D_real_A = criterion_GAN(pred_real_A, torch.ones_like(pred_real_A))\n        pred_fake_A = D_A(fake_A.detach())\n        loss_D_fake_A = criterion_GAN(pred_fake_A, torch.zeros_like(pred_fake_A))\n        loss_D_A = (loss_D_real_A + loss_D_fake_A) / 2\n\n        # D_B Loss\n        pred_real_B = D_B(real_B)\n        loss_D_real_B = criterion_GAN(pred_real_B, torch.ones_like(pred_real_B))\n        pred_fake_B = D_B(fake_B.detach())\n        loss_D_fake_B = criterion_GAN(pred_fake_B, torch.zeros_like(pred_fake_B))\n        loss_D_B = (loss_D_real_B + loss_D_fake_B) / 2\n\n        loss_D_A.backward()\n        loss_D_B.backward()\n        opt_D.step()\n\n    # Save a checkpoint every 10 epochs\n    if (epoch + 1) % 10 == 0:\n      torch.save({\n          'G_AB_state_dict': G_AB.state_dict(),\n          'G_BA_state_dict': G_BA.state_dict(),\n          'opt_G_state_dict': opt_G.state_dict(),\n          'epoch': epoch,\n          }, f\"/kaggle/working/cyclegan_checkpoint_{epoch+1}.pth\")\n      print(f\"Full checkpoint saved for epoch {epoch+1}\")\n\n    print(\n        f\"Epoch [{epoch+1}/{EPOCHS}] \"\n        f\"G: {total_G_loss.item():.4f} \"\n        f\"D_A: {loss_D_A.item():.4f} \"\n        f\"D_B: {loss_D_B.item():.4f}\"\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-20T04:24:45.281815Z","iopub.execute_input":"2026-01-20T04:24:45.282437Z","iopub.status.idle":"2026-01-20T05:29:15.656112Z","shell.execute_reply.started":"2026-01-20T04:24:45.282409Z","shell.execute_reply":"2026-01-20T05:29:15.655370Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#  Save Models\ntorch.save(G_AB.state_dict(), \"/kaggle/working/G_A_to_B.pth\")\ntorch.save(G_BA.state_dict(), \"/kaggle/working/G_B_to_A.pth\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __6. Generate 7 to 10K Monet-like images and submit to Kaggle.com:__","metadata":{}},{"cell_type":"code","source":"# load model\nmodel = TinyGenerator().to(DEVICE)\nmodel.load_state_dict(torch.load('/kaggle/working/G_A_to_B.pth', map_location=DEVICE))\nmodel.eval()\n\n# define transform for inference\ntransform = 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},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict(image_path):\n    # Load and Preprocess\n    img = Image.open(image_path).convert(\"RGB\")\n    img_tensor = transform(img).unsqueeze(0).to(DEVICE)\n\n    with torch.no_grad():\n        # Generate prediction\n        generated_tensor = model(img_tensor)\n\n    # Post-process: Move to CPU, denormalize, and convert to PIL\n    generated_tensor = generated_tensor.squeeze(0).cpu()\n    generated_tensor = generated_tensor * 0.5 + 0.5\n\n    # Convert to PIL Image\n    result_img = transforms.ToPILImage()(generated_tensor)\n    return result_img","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"! mkdir /kaggle/working/images","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# loop through the 7000+ photos and generate Monet images\ni = 1\nfor _, row in photo_list.iterrows():\n  output = predict(row[\"filename\"])\n  output.save(\"/kaggle/working/images/\"+ str(i) + \".jpg\")\n  i += 1","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# make a zip file containing the generated images\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/working/images\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### __7. Provide visualizations of your created artwork:__","metadata":{}},{"cell_type":"code","source":"GEN_FILENAMES = r\"/kaggle/working/images\"\nGEN_files = count_files_pathlib(GEN_FILENAMES)\nprint(f'Number of files: {GEN_files}')\nGEN_list = pd.DataFrame(list_files_pathlib(GEN_FILENAMES), columns=[\"filename\"])\n\n# build dataset of generated image files\n\ngens = []\n\nimg_size=(256, 256)\n\nfor _, row in GEN_list.iterrows():\n    img_path = row[\"filename\"]\n\n    # Load image\n    img = Image.open(img_path).convert(\"RGB\")\n    img = img.resize(img_size)\n\n    gens.append(np.array(img))\n\nX_GEN = np.array(gens, dtype=np.float32)\n\n# Check shapes\nprint(X_GEN.shape)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# First 20 images in Generated images dataset\n\nplt.figure(figsize=(12, 2))\n\nfor i in range(20):\n    plt.subplot(2, 10, i + 1)\n    plt.imshow(X_GEN[i] / 255.0)\n    plt.axis('off')\n\nplt.tight_layout()\nplt.show();","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}