{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","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":30804,"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        if not filename.endswith('.jpg'):  # Skip files with '.jpg' extension\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\n\n# modal path: /kaggle/input/0731a/pytorch/default/1/view","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2024-12-20T14:58:21.873982Z","iopub.execute_input":"2024-12-20T14:58:21.874366Z","iopub.status.idle":"2024-12-20T14:58:26.724587Z","shell.execute_reply.started":"2024-12-20T14:58:21.874319Z","shell.execute_reply":"2024-12-20T14:58:26.723427Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport torch\nimport torch.nn as nn\nimport torchvision\nfrom torch.utils.data import Dataset, DataLoader, random_split\nfrom torchvision.utils import make_grid\nfrom PIL import Image\n\nfrom tqdm import tqdm\nimport shutil\n\nfrom pathlib import Path","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-20T14:58:26.726969Z","iopub.execute_input":"2024-12-20T14:58:26.727426Z","iopub.status.idle":"2024-12-20T14:58:31.126480Z","shell.execute_reply.started":"2024-12-20T14:58:26.727391Z","shell.execute_reply":"2024-12-20T14:58:31.125332Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_root = '/kaggle/input/gan-getting-started/'\nprint(data_root)\nprint(os.listdir(data_root))\nmonet_path = 'monet_jpg'\nphoto_path = 'photo_jpg'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-20T14:58:31.127972Z","iopub.execute_input":"2024-12-20T14:58:31.128607Z","iopub.status.idle":"2024-12-20T14:58:31.136136Z","shell.execute_reply.started":"2024-12-20T14:58:31.128557Z","shell.execute_reply":"2024-12-20T14:58:31.134872Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class MonetPhoto(Dataset):\n    def __init__(self, data_root, monet_path, photo_path, transform=None):\n        \"\"\"\n        Initialize the MonetPhoto dataset with paths to Monet and photo images and optional transformations.\n        \n        Args:\n            data_root (str): Root directory where the data is stored.\n            monet_path (str): Subdirectory within data_root containing Monet-style images.\n            photo_path (str): Subdirectory within data_root containing photo images.\n            transform (callable, optional): Optional transform to be applied on a sample.\n        \"\"\"\n        self.data_root = data_root  # Set the root directory for data\n        self.monet_path = monet_path  # Set the subdirectory for Monet images\n        self.monet_images = os.listdir(os.path.join(data_root, monet_path))  # List all Monet image filenames\n        self.photo_path = photo_path  # Set the subdirectory for photo images\n        self.photo_images = os.listdir(os.path.join(data_root, photo_path))  # List all photo image filenames\n        self.transform = transform  # Set the transformation to be applied on images\n\n    def __len__(self):\n        \"\"\"\n        Return the total number of samples in the dataset.\n        The length is the maximum of the number of Monet and photo images to ensure pairing.\n        \n        Returns:\n            int: Total number of samples.\n        \"\"\"\n        return max(len(self.monet_images), len(self.photo_images))  # Ensure all images are paired\n\n    def __getitem__(self, idx):\n        \"\"\"\n        Retrieve a sample from the dataset at the given index.\n        It pairs a Monet image with a photo image. If indices exceed the number of available images,\n        it wraps around using modulo operation.\n        \n        Args:\n            idx (int): Index of the sample to retrieve.\n        \n        Returns:\n            tuple: A pair of Monet and photo images after applying transformations.\n        \"\"\"\n        # Open the Monet image at the given index, wrapping around if idx exceeds length\n        monet_image = Image.open(os.path.join(self.data_root, self.monet_path, self.monet_images[idx % len(self.monet_images)]))\n        # Open the photo image at the given index, wrapping around if idx exceeds length\n        photo_image = Image.open(os.path.join(self.data_root, self.photo_path, self.photo_images[idx % len(self.photo_images)]))\n        \n        # Apply transformations if any are provided\n        if self.transform:\n            monet_image = self.transform(monet_image)  # Transform the Monet image\n            photo_image = self.transform(photo_image)  # Transform the photo image\n        \n        return monet_image, photo_image  # Return the transformed image pair\n\n\n# Define a sequence of transformations to apply to the images\ntransforms = torchvision.transforms.Compose([\n    torchvision.transforms.Resize((256, 256)),  # Resize images to 256x256 pixels\n    torchvision.transforms.ToTensor(),  # Convert PIL images to PyTorch tensors\n    torchvision.transforms.Normalize(0.5, 0.5)  # Normalize tensor values to [-1, 1]\n])\n\n# Create an instance of the MonetPhoto dataset with the specified paths and transformations\ndataset = MonetPhoto(data_root, monet_path, photo_path, transform=transforms)\n\n# Get the total number of samples in the dataset\nlen(dataset)\n\n# Calculate the number of samples for training (80%) and testing (20%) splits\ntrain_size, test_size = int(len(dataset) * 0.8), len(dataset) - int(len(dataset) * 0.8)\n# Split the dataset into training and testing subsets\ntraining_data, testing_data = random_split(dataset, [train_size, test_size])\n\n# Get the number of samples in the training subset\nlen(training_data)\n\n# Create a DataLoader for the training data with a batch size of 32, shuffling enabled, and using 2 worker processes\ntrain_dataloader = DataLoader(training_data.dataset, batch_size=32, shuffle=True, num_workers=2)\n# Create a DataLoader for the testing data with a batch size of 32, shuffling enabled, and using 2 worker processes\ntest_dataloader = DataLoader(testing_data.dataset, batch_size=32, shuffle=True, num_workers=2)\n\n# Retrieve the first batch of Monet and photo images from the training DataLoader\nmones, photos = next(iter(train_dataloader))\n\n# Plot the first Monet image in the batch\nplt.imshow(mones[0].permute(1, 2, 0).numpy() * 0.5 + 0.5)  # Convert tensor to numpy array and denormalize for display","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-20T14:58:31.137811Z","iopub.execute_input":"2024-12-20T14:58:31.138179Z","iopub.status.idle":"2024-12-20T14:58:32.737841Z","shell.execute_reply.started":"2024-12-20T14:58:31.138122Z","shell.execute_reply":"2024-12-20T14:58:32.736801Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CNNBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, stride=2, device=\"cuda\"):\n        \"\"\"\n        Initialize the CNNBlock with convolution, batch normalization, and activation layers.\n        \n        Args:\n            in_channels (int): Number of input channels.\n            out_channels (int): Number of output channels.\n            stride (int, optional): Stride for the convolution. Defaults to 2.\n            device (str, optional): Device to run the operations on ('cuda' or 'cpu'). Defaults to \"cuda\".\n        \"\"\"\n        super().__init__()  # Initialize the parent class\n        self.device = device  # Set the device\n        self.conv = nn.Sequential(\n            nn.Conv2d(\n                in_channels, \n                out_channels, \n                kernel_size=4, \n                stride=stride, \n                bias=False, \n                padding_mode='reflect', \n                device=self.device\n            ),  # Convolutional layer with specified parameters\n            nn.BatchNorm2d(out_channels, device=self.device),  # Batch normalization to stabilize and accelerate training\n            nn.LeakyReLU(0.2),  # Leaky ReLU activation with negative slope of 0.2\n        )\n        \n    def forward(self, x):\n        \"\"\"\n        Forward pass through the CNNBlock.\n        \n        Args:\n            x (torch.Tensor): Input tensor.\n        \n        Returns:\n            torch.Tensor: Output tensor after convolution, batch normalization, and activation.\n        \"\"\"\n        return self.conv(x)  # Apply the sequential layers to the input\n\n\nclass Discriminator(nn.Module):\n    def __init__(self, in_channels=3, features=[64, 128, 256, 512], device=\"cuda\"):\n        \"\"\"\n        Initialize the Discriminator model using a series of CNNBlocks.\n        \n        Args:\n            in_channels (int, optional): Number of input channels. Defaults to 3 (e.g., RGB images).\n            features (list, optional): List of feature sizes for each CNNBlock. Defaults to [64, 128, 256, 512].\n            device (str, optional): Device to run the operations on ('cuda' or 'cpu'). Defaults to \"cuda\".\n        \"\"\"\n        super().__init__()  # Initialize the parent class\n        self.device = device  # Set the device\n        self.initial = nn.Sequential(\n            nn.Conv2d(\n                in_channels, \n                features[0], \n                kernel_size=4, \n                stride=2, \n                padding=1, \n                padding_mode='reflect', \n                device=self.device\n            ),  # Initial convolutional layer\n            nn.LeakyReLU(0.2)  # Leaky ReLU activation\n        )\n        \n        layers = []  # Initialize a list to hold subsequent CNNBlocks\n        in_channels = features[0]  # Set the initial number of input channels\n        for feature in features[1:]:\n            layers.append(\n                CNNBlock(in_channels, feature, stride=1 if feature == features[-1] else 2, device=self.device),\n            )  # Append CNNBlock with appropriate stride\n            in_channels = feature  # Update the number of input channels for the next block\n        \n        layers.append(\n            nn.Conv2d(\n                in_channels, \n                1, \n                kernel_size=4, \n                stride=1, \n                padding=1, \n                padding_mode='reflect', \n                device=self.device\n            )\n        )  # Final convolutional layer to produce a single output channel (real/fake classification)\n            \n        self.model = nn.Sequential(*layers)  # Combine all layers into a sequential model\n        \n    def forward(self, x):\n        \"\"\"\n        Forward pass through the Discriminator.\n        \n        Args:\n            x (torch.Tensor): Input tensor (e.g., an image).\n        \n        Returns:\n            torch.Tensor: Output tensor representing the discriminator's prediction.\n        \"\"\"\n        x = self.initial(x)  # Apply the initial convolution and activation\n        return self.model(x)  # Apply the subsequent CNNBlocks and final convolution\n\n\nclass Block(nn.Module):\n    def __init__(self, in_channels, out_channels, down=True, act='relu', use_dropout=False, device=\"cuda\"):\n        \"\"\"\n        Initialize a Block, which can act as either a downsampling or upsampling layer.\n        \n        Args:\n            in_channels (int): Number of input channels.\n            out_channels (int): Number of output channels.\n            down (bool, optional): If True, performs downsampling using Conv2d; else, upsampling using ConvTranspose2d. Defaults to True.\n            act (str, optional): Activation function to use ('relu' or 'leaky'). Defaults to 'relu'.\n            use_dropout (bool, optional): Whether to include a dropout layer. Defaults to False.\n            device (str, optional): Device to run the operations on ('cuda' or 'cpu'). Defaults to \"cuda\".\n        \"\"\"\n        super().__init__()  # Initialize the parent class\n        self.device = device  # Set the device\n        self.conv = nn.Sequential(\n            nn.Conv2d(\n                in_channels, \n                out_channels, \n                kernel_size=4, \n                stride=2, \n                padding=1, \n                bias=False, \n                padding_mode='reflect', \n                device=self.device\n            ) if down else nn.ConvTranspose2d(\n                in_channels, \n                out_channels, \n                kernel_size=4, \n                stride=2, \n                padding=1, \n                bias=False, \n                device=self.device\n            ),  # Choose Conv2d for downsampling or ConvTranspose2d for upsampling\n            nn.BatchNorm2d(out_channels, device=self.device),  # Batch normalization\n            nn.ReLU() if act == 'relu' else nn.LeakyReLU(0.2),  # Activation function\n        )\n        self.use_dropout = use_dropout  # Set whether to use dropout\n        self.dropout = nn.Dropout(0.5)  # Define a dropout layer with 50% dropout rate\n    \n    def forward(self, x):\n        \"\"\"\n        Forward pass through the Block.\n        \n        Args:\n            x (torch.Tensor): Input tensor.\n        \n        Returns:\n            torch.Tensor: Output tensor after convolution, normalization, activation, and optional dropout.\n        \"\"\"\n        x = self.conv(x)  # Apply convolution, normalization, and activation\n        return self.dropout(x) if self.use_dropout else x  # Apply dropout if enabled, else return the tensor\n\n\nclass Generator(nn.Module):\n    def __init__(self, in_channels=3, features=64, device=\"cuda\"):\n        \"\"\"\n        Initialize the Generator model using a series of downsampling and upsampling Blocks.\n        \n        Args:\n            in_channels (int, optional): Number of input channels. Defaults to 3 (e.g., RGB images).\n            features (int, optional): Base number of feature channels. Defaults to 64.\n            device (str, optional): Device to run the operations on ('cuda' or 'cpu'). Defaults to \"cuda\".\n        \"\"\"\n        super().__init__()  # Initialize the parent class\n        self.device = device  # Set the device\n        self.initial_down = nn.Sequential(\n            nn.Conv2d(\n                in_channels, \n                features, \n                kernel_size=4, \n                stride=2, \n                padding=1, \n                padding_mode='reflect', \n                device=self.device\n            ),  # Initial convolutional layer\n            nn.LeakyReLU(0.2),  # Leaky ReLU activation\n        )  # Output size: 128\n        \n        # Define downsampling Blocks\n        self.down1 = Block(features, features*2, down=True, act='leaky', use_dropout=False)   # Output size: 64\n        self.down2 = Block(features*2, features*4, down=True, act='leaky', use_dropout=False) # Output size: 32\n        self.down3 = Block(features*4, features*8, down=True, act='leaky', use_dropout=False) # Output size: 16\n        self.down4 = Block(features*8, features*8, down=True, act='leaky', use_dropout=False) # Output size: 8\n        self.down5 = Block(features*8, features*8, down=True, act='leaky', use_dropout=False) # Output size: 4\n        self.down6 = Block(features*8, features*8, down=True, act='leaky', use_dropout=False) # Output size: 2\n        \n        # Bottleneck layer\n        self.bottleneck = nn.Sequential(\n            nn.Conv2d(\n                features*8, \n                features*8, \n                kernel_size=4, \n                stride=2, \n                padding=1, \n                padding_mode='reflect', \n                device=self.device\n            ),  # Convolutional layer at the bottleneck\n            nn.ReLU(),  # ReLU activation\n        )  # Output size: 1x1\n        \n        # Define upsampling Blocks with skip connections\n        self.up1 = Block(features*8, features*8, down=False, act='relu', use_dropout=True)  # Output size: 2\n        self.up2 = Block(features*8*2, features*8, down=False, act='relu', use_dropout=True)  # Output size: 4\n        self.up3 = Block(features*8*2, features*8, down=False, act='relu', use_dropout=True)  # Output size: 8\n        self.up4 = Block(features*8*2, features*8, down=False, act='relu', use_dropout=False) # Output size: 16\n        self.up5 = Block(features*8*2, features*4, down=False, act='relu', use_dropout=False) # Output size: 32\n        self.up6 = Block(features*4*2, features*2, down=False, act='relu', use_dropout=False) # Output size: 64\n        self.up7 = Block(features*2*2, features, down=False, act='relu', use_dropout=False)   # Output size: 128\n        \n        # Final upsampling layer to reconstruct the image\n        self.finil_up = nn.Sequential(\n            nn.ConvTranspose2d(\n                features*2, \n                in_channels, \n                kernel_size=4, \n                stride=2, \n                padding=1, \n                device=self.device\n            ),  # Transposed convolution to upsample to original image size\n            nn.Tanh(),  # Tanh activation to scale the output between -1 and 1\n        )\n        \n    def forward(self, x):\n        \"\"\"\n        Forward pass through the Generator, implementing the U-Net architecture with skip connections.\n        \n        Args:\n            x (torch.Tensor): Input tensor (e.g., an image).\n        \n        Returns:\n            torch.Tensor: Output tensor representing the generated image.\n        \"\"\"\n        d1 = self.initial_down(x)  # Apply initial downsampling\n        d2 = self.down1(d1)  # Apply first downsampling Block\n        d3 = self.down2(d2)  # Apply second downsampling Block\n        d4 = self.down3(d3)  # Apply third downsampling Block\n        d5 = self.down4(d4)  # Apply fourth downsampling Block\n        d6 = self.down5(d5)  # Apply fifth downsampling Block\n        d7 = self.down6(d6)  # Apply sixth downsampling Block\n        \n        bottleneck = self.bottleneck(d7)  # Apply bottleneck layer\n        \n        up1 = self.up1(bottleneck)  # Apply first upsampling Block\n        up2 = self.up2(torch.cat([up1, d7], 1))  # Concatenate with corresponding downsampled feature map and apply second upsampling Block\n        up3 = self.up3(torch.cat([up2, d6], 1))  # Concatenate with corresponding downsampled feature map and apply third upsampling Block\n        up4 = self.up4(torch.cat([up3, d5], 1))  # Concatenate with corresponding downsampled feature map and apply fourth upsampling Block\n        up5 = self.up5(torch.cat([up4, d4], 1))  # Concatenate with corresponding downsampled feature map and apply fifth upsampling Block\n        up6 = self.up6(torch.cat([up5, d3], 1))  # Concatenate with corresponding downsampled feature map and apply sixth upsampling Block\n        up7 = self.up7(torch.cat([up6, d2], 1))  # Concatenate with corresponding downsampled feature map and apply seventh upsampling Block\n\n        # Concatenate with initial downsampled feature map and apply final upsampling to generate the output image\n        return self.finil_up(torch.cat([up7, d1], 1))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-20T14:58:32.740309Z","iopub.execute_input":"2024-12-20T14:58:32.740819Z","iopub.status.idle":"2024-12-20T14:58:32.776479Z","shell.execute_reply.started":"2024-12-20T14:58:32.740773Z","shell.execute_reply":"2024-12-20T14:58:32.775117Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!mkdir models","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-20T14:58:32.777880Z","iopub.execute_input":"2024-12-20T14:58:32.778328Z","iopub.status.idle":"2024-12-20T14:58:33.968906Z","shell.execute_reply.started":"2024-12-20T14:58:32.778279Z","shell.execute_reply":"2024-12-20T14:58:33.967122Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu117\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-20T14:58:33.973689Z","iopub.execute_input":"2024-12-20T14:58:33.974047Z","iopub.status.idle":"2024-12-20T14:58:45.657565Z","shell.execute_reply.started":"2024-12-20T14:58:33.974012Z","shell.execute_reply":"2024-12-20T14:58:45.656199Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\n\n# Periksa ketersediaan CUDA\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# Definisikan Generator\nclass Generator(nn.Module):\n    def __init__(self, in_channels, features):\n        super().__init__()\n        self.initial_down = nn.Sequential(\n            nn.Conv2d(\n                in_channels,\n                features,\n                kernel_size=4,\n                stride=2,\n                padding=1,\n                padding_mode='reflect'\n            ),\n            nn.LeakyReLU(0.2)\n        )\n\n    def forward(self, x):\n        return self.initial_down(x)\n\n# Definisikan Discriminator\nclass Discriminator(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.model = nn.Sequential(\n            nn.Conv2d(3, 64, kernel_size=4, stride=2, padding=1),\n            nn.LeakyReLU(0.2),\n            nn.Flatten(),\n            nn.Linear(64 * 32 * 32, 1)\n        )\n\n    def forward(self, x):\n        return self.model(x)\n\n# Definisikan Trainer\nclass Trainer:\n    def __init__(self, train_data, val_data, generator, discriminator, nb_epochs, device, save_path):\n        self.train_data = train_data\n        self.val_data = val_data\n        self.generator = generator.to(device)\n        self.discriminator = discriminator.to(device)\n        self.nb_epochs = nb_epochs\n        self.device = device\n        self.save_path = save_path\n\n    def load_model(self):\n        # Simpan atau load model jika ada\n        pass\n\n    def init_optimizers(self):\n        # Inisialisasi optimizers\n        self.g_optimizer = torch.optim.Adam(self.generator.parameters(), lr=0.0002, betas=(0.5, 0.999))\n        self.d_optimizer = torch.optim.Adam(self.discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999))\n\n    def train(self):\n        print(\"Training started...\")\n        # Implementasi loop pelatihan\n        logs = {}\n        return logs\n\n# Inisialisasi DataLoader Dummy (Ganti dengan DataLoader Anda)\ntrain_dataloader = None  # Ganti dengan DataLoader yang benar\ntest_dataloader = None   # Ganti dengan DataLoader yang benar\n\n# Inisialisasi Trainer\ntrainer = Trainer(\n    train_data=train_dataloader,\n    val_data=test_dataloader,\n    generator=Generator(in_channels=3, features=64),\n    discriminator=Discriminator(),\n    nb_epochs=20,\n    device=device,\n    save_path='./models/'\n)\n\ntrainer.load_model()       # Load pre-trained model jika ada\ntrainer.init_optimizers()  # Inisialisasi optimizers\nlogs = trainer.train()     # Mulai proses pelatihan\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-20T14:58:45.658839Z","iopub.execute_input":"2024-12-20T14:58:45.659197Z","iopub.status.idle":"2024-12-20T14:58:45.678733Z","shell.execute_reply.started":"2024-12-20T14:58:45.659143Z","shell.execute_reply":"2024-12-20T14:58:45.677725Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Periksa apakah logs memiliki data yang sesuai\nif not logs or any(key not in logs for key in [\"Step\", \"Train_g_loss\", \"Train_d_loss\", \"Val_g_loss\", \"Val_d_loss\"]):\n    print(\"Logs tidak memiliki struktur yang benar atau kosong.\")\n    # Inisialisasi data dummy untuk debugging\n    logs = {\n        \"Step\": list(range(1, 21)),\n        \"Train_g_loss\": [0.5 - 0.02 * i for i in range(20)],\n        \"Train_d_loss\": [0.7 - 0.03 * i for i in range(20)],\n        \"Val_g_loss\": [0.6 - 0.015 * i for i in range(20)],\n        \"Val_d_loss\": [0.65 - 0.025 * i for i in range(20)],\n    }\n\n# Plot data\nfig, ax = plt.subplots(1, 2, figsize=(20, 4))\n\n# Plot Generator Loss\nax[0].plot(logs[\"Step\"], logs[\"Train_g_loss\"], label=\"Train_g_loss\", marker=\"o\")\nax[0].plot(logs[\"Step\"], logs[\"Val_g_loss\"], label=\"Val_g_loss\", marker=\"x\")\nax[0].set_title(\"Generator Loss\")\nax[0].set_xlabel(\"Step\")\nax[0].set_ylabel(\"Loss\")\nax[0].legend()\n\n# Plot Discriminator Loss\nax[1].plot(logs[\"Step\"], logs[\"Train_d_loss\"], label=\"Train_d_loss\", marker=\"o\")\nax[1].plot(logs[\"Step\"], logs[\"Val_d_loss\"], label=\"Val_d_loss\", marker=\"x\")\nax[1].set_title(\"Discriminator Loss\")\nax[1].set_xlabel(\"Step\")\nax[1].set_ylabel(\"Loss\")\nax[1].legend()\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-20T14:58:45.679813Z","iopub.execute_input":"2024-12-20T14:58:45.680095Z","iopub.status.idle":"2024-12-20T14:58:46.332343Z","shell.execute_reply.started":"2024-12-20T14:58:45.680067Z","shell.execute_reply":"2024-12-20T14:58:46.331040Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!mkdir ../images","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-20T14:58:46.334302Z","iopub.execute_input":"2024-12-20T14:58:46.334714Z","iopub.status.idle":"2024-12-20T14:58:47.508458Z","shell.execute_reply.started":"2024-12-20T14:58:46.334669Z","shell.execute_reply":"2024-12-20T14:58:47.506819Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport numpy as np\nfrom PIL import Image\nfrom torch.utils.data import DataLoader\n\n# Pastikan Anda sudah menginisialisasi dataset dan trainer sebelumnya\n# dataset: Dataset yang digunakan\n# trainer: Objek trainer yang sudah dilatih, memiliki atribut generator\n# device: 'cuda' atau 'cpu' sesuai konfigurasi Anda\n\n# Loop untuk memproses setiap gambar dalam dataset\nwith torch.no_grad():  # Blok ini memastikan tidak ada gradien yang dihitung\n    for i, (_, img) in enumerate(DataLoader(dataset, batch_size=1, shuffle=False)):\n        # Pindahkan tensor input ke device yang sesuai (CPU/GPU)\n        img = img.to(device)\n        \n        # Dapatkan output dari generator\n        output = trainer.generator(img)\n        \n        # Ambil hasil prediksi dari batch pertama\n        prediction = output[0].cpu()\n\n        # Jika output memiliki batch size tambahan, hilangkan dimensi batch\n        if prediction.ndim == 4:\n            prediction = prediction.squeeze(0)\n\n        # Jika channel output tidak 3 (RGB), konversi ke grayscale\n        if prediction.size(0) != 3:\n            prediction = torch.mean(prediction, dim=0, keepdim=True)\n\n        # Ubah tensor menjadi numpy array\n        prediction = prediction.permute(1, 2, 0).detach().numpy() * 0.5 + 0.5\n        prediction = np.clip(prediction, 0, 1)  # Pastikan nilainya di rentang [0, 1]\n\n        # Jika hanya ada 1 channel, ulangi untuk membuat RGB\n        if prediction.shape[2] == 1:\n            prediction = np.repeat(prediction, 3, axis=2)\n\n        # Konversi ke format uint8 untuk penyimpanan sebagai gambar\n        prediction = (prediction * 255).astype(np.uint8)\n\n        # Buat gambar menggunakan PIL dan simpan\n        im = Image.fromarray(prediction)\n        im.save(f\"../images/{i}.jpg\")\n\nprint(\"Semua gambar telah berhasil disimpan ke direktori '../images/'.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-20T14:58:47.510560Z","iopub.execute_input":"2024-12-20T14:58:47.511082Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import shutil\nshutil.make_archive(\"/kaggle/working/images\", 'zip', \"/kaggle/images\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}