{"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":"gpu","dataSources":[{"sourceId":21755,"databundleVersionId":1475600,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# I'm something of a painter myself","metadata":{}},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision\nimport torchvision.transforms as transforms\nimport torchvision.datasets as datasets\nimport torch.utils.data as data\nimport matplotlib.pyplot as plt","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:36:23.190506Z","iopub.execute_input":"2025-01-15T13:36:23.190996Z","iopub.status.idle":"2025-01-15T13:36:23.195211Z","shell.execute_reply.started":"2025-01-15T13:36:23.190962Z","shell.execute_reply":"2025-01-15T13:36:23.194346Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# MY WAY - OR THE HIGHWAY!\n!mkdir -p data/images\n!cp /kaggle/input/gan-getting-started/monet_jpg/* data/images\n!cp /kaggle/input/gan-getting-started/photo_jpg/* data/images","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:36:24.168207Z","iopub.execute_input":"2025-01-15T13:36:24.168507Z","iopub.status.idle":"2025-01-15T13:36:58.228624Z","shell.execute_reply.started":"2025-01-15T13:36:24.168483Z","shell.execute_reply":"2025-01-15T13:36:58.227339Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_directory = \"/kaggle/working/data\"\n\ntransform = transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))\n])\n\ndataset = datasets.ImageFolder(\n    root=data_directory,\n    transform=transform\n)\n\ndataset","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:36:58.230215Z","iopub.execute_input":"2025-01-15T13:36:58.230470Z","iopub.status.idle":"2025-01-15T13:36:58.257528Z","shell.execute_reply.started":"2025-01-15T13:36:58.230447Z","shell.execute_reply":"2025-01-15T13:36:58.256884Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataloader = data.DataLoader(\n    dataset=dataset,\n    batch_size=64,\n    shuffle=True,\n    num_workers=2\n)\n\nlen(dataloader)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:36:58.259185Z","iopub.execute_input":"2025-01-15T13:36:58.259397Z","iopub.status.idle":"2025-01-15T13:36:58.264811Z","shell.execute_reply.started":"2025-01-15T13:36:58.259378Z","shell.execute_reply":"2025-01-15T13:36:58.263982Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Woah, cool picture\n\nX_batch, y_batch = next(iter(dataloader))\n\nimage = X_batch[0].permute(1, 2, 0)\nimage = (image + 1) / 2\n\nplt.title(\"Sample from the dataset\")\nplt.imshow(image)\nplt.axis(False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:36:58.266275Z","iopub.execute_input":"2025-01-15T13:36:58.266511Z","iopub.status.idle":"2025-01-15T13:36:59.081947Z","shell.execute_reply.started":"2025-01-15T13:36:58.266491Z","shell.execute_reply":"2025-01-15T13:36:59.081019Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Knowing that the version number in the class name will remain the same\n# Regardless of how many changes are made...\n# Fills you with determination\n\nclass GeneratorV1(nn.Module):\n    def __init__(self):\n        super(GeneratorV1, self).__init__()\n        self.layers = nn.Sequential(\n            nn.ConvTranspose2d(100, 512, 4, 1, 0, bias=False),\n            nn.BatchNorm2d(512),\n            nn.ReLU(True),\n\n            nn.ConvTranspose2d(512, 256, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(256),\n            nn.ReLU(True),\n\n            nn.ConvTranspose2d(256, 128, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(128),\n            nn.ReLU(True),\n            \n            nn.ConvTranspose2d(128, 64, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(64),\n            nn.ReLU(True),\n            \n            nn.ConvTranspose2d(64, 32, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(32),\n            nn.ReLU(True),\n            \n            nn.ConvTranspose2d(32, 16, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(16),\n            nn.ReLU(True),\n\n            nn.ConvTranspose2d(16, 3, 4, 2, 1, bias=False),\n            nn.Tanh()\n        )\n    \n    def forward(self, X):\n        return self.layers.forward(X)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:36:59.083000Z","iopub.execute_input":"2025-01-15T13:36:59.083412Z","iopub.status.idle":"2025-01-15T13:36:59.090807Z","shell.execute_reply.started":"2025-01-15T13:36:59.083371Z","shell.execute_reply":"2025-01-15T13:36:59.089992Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class DiscriminatorV1(nn.Module):\n    def __init__(self):\n        super(DiscriminatorV1, self).__init__()\n        self.layers = nn.Sequential(\n            nn.Conv2d(3, 16, 4, 2, 1, bias=False),\n            nn.LeakyReLU(0.2, True),\n            \n            nn.Conv2d(16, 32, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(32),\n            nn.LeakyReLU(0.2, True),\n\n            nn.Conv2d(32, 64, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(64),\n            nn.LeakyReLU(0.2, True),\n            \n            nn.Conv2d(64, 128, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(128),\n            nn.LeakyReLU(0.2, True),\n            \n            nn.Conv2d(128, 256, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(256),\n            nn.LeakyReLU(0.2, True),\n            \n            nn.Conv2d(256, 512, 4, 2, 1, bias=False),\n            nn.BatchNorm2d(512),\n            nn.LeakyReLU(0.2, True),\n            \n            nn.Conv2d(512, 1, 4, 1, 0, bias=False),\n            nn.Sigmoid()\n        )\n\n    def forward(self, X):\n        return self.layers.forward(X).view(-1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:36:59.091556Z","iopub.execute_input":"2025-01-15T13:36:59.091946Z","iopub.status.idle":"2025-01-15T13:36:59.111036Z","shell.execute_reply.started":"2025-01-15T13:36:59.091913Z","shell.execute_reply":"2025-01-15T13:36:59.110360Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\ngenerator = GeneratorV1().to(device)\ndiscriminator = DiscriminatorV1().to(device)\n\ncriterion = nn.BCELoss()\n\noptimizer_G = torch.optim.Adam(\n    params=generator.parameters(),\n    lr=0.0002,\n    betas=(0.5, 0.999)\n)\noptimizer_D = torch.optim.Adam(\n    params=discriminator.parameters(),\n    lr=0.0002,\n    betas=(0.5, 0.999)\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:36:59.111879Z","iopub.execute_input":"2025-01-15T13:36:59.112090Z","iopub.status.idle":"2025-01-15T13:36:59.427486Z","shell.execute_reply.started":"2025-01-15T13:36:59.112072Z","shell.execute_reply":"2025-01-15T13:36:59.426559Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def plot_generator_images(generator):\n    noise = torch.randn(5*6, 100, 1, 1, device=device)\n    images = generator.forward(noise).cpu()\n    for i in range(5*6):\n        plt.subplot(5, 6, i+1)\n        plt.imshow(((images[i] + 1) / 2).detach().permute(1, 2, 0))\n        plt.axis(False)\n        \nplot_generator_images(GeneratorV1().to(device))\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:37:04.290934Z","iopub.execute_input":"2025-01-15T13:37:04.291283Z","iopub.status.idle":"2025-01-15T13:37:05.938467Z","shell.execute_reply.started":"2025-01-15T13:37:04.291251Z","shell.execute_reply":"2025-01-15T13:37:05.937575Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image = generator.forward(torch.randn(1, 100, 1, 1, device=device))\ndiscriminator.forward(image)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:37:05.939487Z","iopub.execute_input":"2025-01-15T13:37:05.939741Z","iopub.status.idle":"2025-01-15T13:37:06.329717Z","shell.execute_reply.started":"2025-01-15T13:37:05.939717Z","shell.execute_reply":"2025-01-15T13:37:06.328775Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Need at least 30 epochs for decent results\nnum_epochs = 100\n\ny_real = torch.ones(64, device=device)\ny_fake = torch.zeros(64, device=device)\n\nfor epoch in range(num_epochs):\n    noise = torch.randn(len(dataloader), 64, 100, 1, 1, device=device)\n    for batch, (X_real, _) in enumerate(dataloader):\n        optimizer_D.zero_grad()\n\n        y_pred = discriminator.forward(X_real.to(device))\n        loss_D_real = criterion(y_pred, y_real[:X_real.size(0)])\n\n        X_fake = generator.forward(noise[batch])\n        y_pred = discriminator.forward(X_fake.detach())\n        loss_D_fake = criterion(y_pred, y_fake)\n\n        loss_D = loss_D_real + loss_D_fake\n        loss_D.backward()\n        optimizer_D.step()\n\n        optimizer_G.zero_grad()\n\n        X_fake = generator.forward(noise[batch])\n        y_pred = discriminator.forward(X_fake)\n        loss_G = criterion(y_pred, y_real)\n\n        loss_G.backward()\n        optimizer_G.step()\n\n        print(f\"[{epoch+1}/{num_epochs}|{batch+1}/{len(dataloader)}] {loss_D:.6f} | {loss_G:.6f}\", end=\"\\r\")\n    print(end=\"\\n\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:37:09.523861Z","iopub.execute_input":"2025-01-15T13:37:09.524198Z","iopub.status.idle":"2025-01-15T13:47:05.214036Z","shell.execute_reply.started":"2025-01-15T13:37:09.524167Z","shell.execute_reply":"2025-01-15T13:47:05.212975Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plot_generator_images(generator)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:47:06.551333Z","iopub.execute_input":"2025-01-15T13:47:06.551662Z","iopub.status.idle":"2025-01-15T13:47:07.671384Z","shell.execute_reply.started":"2025-01-15T13:47:06.551633Z","shell.execute_reply":"2025-01-15T13:47:07.670503Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Helps a little sometimes\ntorch.cuda.empty_cache()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:47:15.832891Z","iopub.execute_input":"2025-01-15T13:47:15.833203Z","iopub.status.idle":"2025-01-15T13:47:15.864451Z","shell.execute_reply.started":"2025-01-15T13:47:15.833177Z","shell.execute_reply":"2025-01-15T13:47:15.863845Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def generate_best(generator, discriminator, min_rating, count):\n    best_images = []\n    rejected = 0\n    while len(best_images) < count:\n        noise = torch.randn(1, 100, 1, 1, device=device)\n        image = generator.forward(noise)\n        rating = discriminator.forward(image)\n        \n        if rating > min_rating:\n            image = (((image.squeeze().cpu().detach().permute(1, 2, 0).numpy() + 1) / 2) * 255).round().astype(int)\n            best_images.append(image)\n        else:\n            rejected += 1\n            \n        print(\"Generated images:\", len(best_images), rejected, end=\"\\r\")\n    return best_images\n\nbest_images = generate_best(generator, discriminator, min_rating=0.1, count=30)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:47:33.235332Z","iopub.execute_input":"2025-01-15T13:47:33.235648Z","iopub.status.idle":"2025-01-15T13:47:34.796048Z","shell.execute_reply.started":"2025-01-15T13:47:33.235622Z","shell.execute_reply":"2025-01-15T13:47:34.795084Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def generate_images(generator, batch_count, batch_size):\n    images = []\n    for batch in range(batch_count):\n        noise = torch.randn(batch_size, 100, 1, 1, device=device)\n        raw_images = generator.forward(noise).cpu().detach().permute(0, 2, 3, 1).numpy()\n        for image in raw_images:\n            image = (((image.squeeze() + 1) / 2) * 255).round().astype(int)\n            images.append(image)\n            print(\"Generated images:\", len(images), end=\"\\r\")\n    return images\n\nimages = generate_images(generator, batch_count=30, batch_size=256)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:50:27.953080Z","iopub.execute_input":"2025-01-15T13:50:27.953444Z","iopub.status.idle":"2025-01-15T13:50:52.437655Z","shell.execute_reply.started":"2025-01-15T13:50:27.953416Z","shell.execute_reply":"2025-01-15T13:50:52.436664Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Don't look very nice\nfor i in range(5*6):\n    plt.subplot(5, 6, i+1)\n    plt.imshow(best_images[i])\n    plt.axis(False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:50:54.494415Z","iopub.execute_input":"2025-01-15T13:50:54.494776Z","iopub.status.idle":"2025-01-15T13:50:55.440233Z","shell.execute_reply.started":"2025-01-15T13:50:54.494739Z","shell.execute_reply":"2025-01-15T13:50:55.439255Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# These images are generally better\nfor i in range(5*6):\n    plt.subplot(5, 6, i+1)\n    plt.imshow(images[i])\n    plt.axis(False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:50:57.442991Z","iopub.execute_input":"2025-01-15T13:50:57.443299Z","iopub.status.idle":"2025-01-15T13:50:58.559292Z","shell.execute_reply.started":"2025-01-15T13:50:57.443274Z","shell.execute_reply":"2025-01-15T13:50:58.558325Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import io\nimport zipfile\nimport numpy as np\nfrom PIL import Image\n\nwith zipfile.ZipFile(\"images.zip\", \"w\", zipfile.ZIP_DEFLATED) as zipf:\n    for i, img_array in enumerate(images):\n        img = Image.fromarray(img_array.astype(np.uint8))\n        \n        img_byte_arr = io.BytesIO()\n        img.save(img_byte_arr, format=\"JPEG\")\n        \n        img_byte_data = img_byte_arr.getvalue()\n        \n        zipf.writestr(f\"image_{i+1}.jpg\", img_byte_data)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:51:40.555376Z","iopub.execute_input":"2025-01-15T13:51:40.555774Z","iopub.status.idle":"2025-01-15T13:51:57.598868Z","shell.execute_reply.started":"2025-01-15T13:51:40.555740Z","shell.execute_reply":"2025-01-15T13:51:57.597942Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!rm -rf data","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:52:04.614672Z","iopub.execute_input":"2025-01-15T13:52:04.615049Z","iopub.status.idle":"2025-01-15T13:52:05.406198Z","shell.execute_reply.started":"2025-01-15T13:52:04.615019Z","shell.execute_reply":"2025-01-15T13:52:05.405166Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-15T13:52:06.182942Z","iopub.execute_input":"2025-01-15T13:52:06.183268Z","iopub.status.idle":"2025-01-15T13:52:06.797027Z","shell.execute_reply.started":"2025-01-15T13:52:06.183239Z","shell.execute_reply":"2025-01-15T13:52:06.795863Z"}},"outputs":[],"execution_count":null}]}