### Environment Setup: Install Dependencies Source: https://github.com/vita-group/enlightengan/blob/master/README.md Installs all necessary project dependencies listed in the 'requirement.txt' file. Make sure to run this command in your project's root directory. ```shell pip install -r requirement.txt ``` -------------------------------- ### Training: Start Training Process Source: https://github.com/vita-group/enlightengan/blob/master/README.md Initiates the training process for the EnlightenGAN model. This command should be run after setting up the environment and starting the visualization server. ```shell python scripts/script.py --train ``` -------------------------------- ### Environment Setup: Create Model Directory Source: https://github.com/vita-group/enlightengan/blob/master/README.md Creates the 'model' directory where pretrained models should be placed. This directory is essential for loading model weights. ```shell mkdir model ``` -------------------------------- ### Training: Start Visualization Server Source: https://github.com/vita-group/enlightengan/blob/master/README.md Launches the Visdom server for real-time visualization of training progress. Ensure this is running before starting the training process. The default port is 8097. ```shell nohup python -m visdom.server -port=8097 ``` -------------------------------- ### Execute EnlightenGAN via command line Source: https://context7.com/vita-group/enlightengan/llms.txt Convenience commands for starting the Visdom visualization server and running training or prediction tasks. ```bash # Start visdom server for visualization (run in background) nohup python -m visdom.server -port=8097 & # Train EnlightenGAN with recommended settings python scripts/script.py --train # Or run prediction on test images python scripts/script.py --predict ``` -------------------------------- ### Environment Setup: Python Version Source: https://github.com/vita-group/enlightengan/blob/master/README.md Specifies the required Python version for the project. Ensure you are using Python 3.5 or a compatible version. ```shell python3.5 ``` -------------------------------- ### Get Item for Unaligned Dataset Source: https://context7.com/vita-group/enlightengan/llms.txt Retrieves a pair of images (one from domain A, one from domain B) and applies transformations. It also computes an attention map from the grayscale version of image A. ```python def __getitem__(self, index): # Get images (randomly sampled from each domain) A_img = self.A_imgs[index % self.A_size] B_img = self.B_imgs[index % self.B_size] # Apply transforms A_img = self.transform(A_img) B_img = self.transform(B_img) # Compute attention map from grayscale r, g, b = A_img[0]+1, A_img[1]+1, A_img[2]+1 A_gray = 1. - (0.299*r + 0.587*g + 0.114*b) / 2. A_gray = torch.unsqueeze(A_gray, 0) return { 'A': A_img, # Low-light image 'B': B_img, # Normal-light image 'A_gray': A_gray, # Attention/illumination map 'input_img': A_img, # Input for generator 'A_paths': A_path, 'B_paths': B_path } ``` -------------------------------- ### Dataset Preparation: Create Test Directories Source: https://github.com/vita-group/enlightengan/blob/master/README.md Creates the necessary directories for storing test images. 'testA' should contain your input images, and 'testB' requires at least one image to ensure program execution. ```shell mkdir ../test_dataset/testA ``` ```shell mkdir ../test_dataset/testB ``` -------------------------------- ### Configure Training Options Source: https://context7.com/vita-group/enlightengan/llms.txt Defines command-line arguments for dataset paths, model architecture, loss weights, and training hyperparameters. ```python # options/base_options.py and options/train_options.py # Key training options: parser.add_argument('--dataroot', required=True, help='path to images') parser.add_argument('--name', type=str, default='experiment_name', help='experiment name') parser.add_argument('--model', type=str, default='single', help='model type') parser.add_argument('--dataset_mode', type=str, default='unaligned', help='dataset mode') # Generator options parser.add_argument('--which_model_netG', type=str, default='sid_unet_resize') parser.add_argument('--ngf', type=int, default=64, help='generator filters') parser.add_argument('--skip', type=float, default=1, help='skip connection weight') parser.add_argument('--self_attention', action='store_true', help='use attention') parser.add_argument('--times_residual', action='store_true', help='multiply residual by attention') # Discriminator options parser.add_argument('--which_model_netD', type=str, default='no_norm_4') parser.add_argument('--ndf', type=int, default=64, help='discriminator filters') parser.add_argument('--n_layers_D', type=int, default=5, help='D layers') parser.add_argument('--patchD', action='store_true', help='use patch discriminator') parser.add_argument('--patchD_3', type=int, default=5, help='number of patches') # Loss options parser.add_argument('--vgg', type=float, default=1, help='VGG loss weight') parser.add_argument('--vgg_choose', type=str, default='relu5_1', help='VGG layer') parser.add_argument('--use_ragan', action='store_true', help='use RaGAN loss') parser.add_argument('--hybrid_loss', action='store_true', help='hybrid loss') # Training options parser.add_argument('--batchSize', type=int, default=32) parser.add_argument('--fineSize', type=int, default=320, help='crop size') parser.add_argument('--lr', type=float, default=0.0001, help='learning rate') parser.add_argument('--niter', type=int, default=100, help='epochs at initial lr') parser.add_argument('--niter_decay', type=int, default=100, help='epochs to decay lr') parser.add_argument('--gpu_ids', type=str, default='0,1,2', help='GPU IDs') ``` -------------------------------- ### Visualize Training with Visdom Source: https://context7.com/vita-group/enlightengan/llms.txt Use the Visualizer class to display training results, plot loss curves, and log errors during the training process. ```python # util/visualizer.py - Training visualization from util.visualizer import Visualizer visualizer = Visualizer(opt) # Display current results in browser visuals = model.get_current_visuals() # OrderedDict of numpy images visualizer.display_current_results(visuals, epoch) # Plot loss curves errors = model.get_current_errors(epoch) # {'D_A': 0.5, 'G_A': 0.8, 'vgg': 0.1} visualizer.plot_current_errors(epoch, counter_ratio, opt, errors) # Print errors to console and log file visualizer.print_current_errors(epoch, epoch_iter, errors, time_per_batch) # Output: (epoch: 50, iters: 3200, time: 0.125) D_A: 0.456 G_A: 0.789 vgg: 0.123 # Save images during inference visualizer.save_images(webpage, visuals, img_path) ``` -------------------------------- ### Run Training or Prediction Script Source: https://context7.com/vita-group/enlightengan/llms.txt Use this script to initiate training or prediction. It parses command-line arguments to configure the process, including dataset paths and model parameters. Ensure the correct Python scripts (train.py, predict.py) are available in the project. ```python import os import argparse parser = argparse.ArgumentParser() parser.add_argument("--port", type=str, default="8097") parser.add_argument("--train", action='store_true') parser.add_argument("--predict", action='store_true') opt = parser.parse_args() if opt.train: os.system("python train.py \ --dataroot ../final_dataset \ --no_dropout \ --name enlightening \ --model single \ --dataset_mode unaligned \ --which_model_netG sid_unet_resize \ --which_model_netD no_norm_4 \ --patchD \ --patch_vgg \ --patchD_3 5 \ --n_layers_D 5 \ --n_layers_patchD 4 \ --fineSize 320 \ --patchSize 32 \ --skip 1 \ --batchSize 32 \ --self_attention \ --use_norm 1 \ --use_wgan 0 \ --use_ragan \ --hybrid_loss \ --times_residual \ --instance_norm 0 \ --vgg 1 \ --vgg_choose relu5_1 \ --gpu_ids 0,1,2 \ --display_port=" + opt.port) elif opt.predict: os.system("python predict.py \ --dataroot ../test_dataset \ --name enlightening \ --model single \ --which_direction AtoB \ --no_dropout \ --dataset_mode unaligned \ --which_model_netG sid_unet_resize \ --skip 1 \ --use_norm 1 \ --use_wgan 0 \ --self_attention \ --times_residual \ --instance_norm 0 \ --resize_or_crop='no' \ --which_epoch 200") ``` -------------------------------- ### Create Data Loader and Train Model Source: https://context7.com/vita-group/enlightengan/llms.txt Creates a data loader using the provided options and iterates through the dataset to train the model. Each batch of data is set as input to the model, and an optimization step is performed. ```python # Create data loader from data.data_loader import CreateDataLoader data_loader = CreateDataLoader(opt) dataset = data_loader.load_data() for i, data in enumerate(dataset): model.set_input(data) model.optimize_parameters(epoch) ``` -------------------------------- ### Utility Functions for Image and File Management Source: https://context7.com/vita-group/enlightengan/llms.txt Helper functions for tensor-to-image conversion, directory creation, and network diagnostics. ```python # util/util.py - Utility functions from util import util # Convert tensor to numpy image image_numpy = util.tensor2im(tensor) # [B,C,H,W] tensor -> [H,W,C] uint8 numpy # Convert attention map to displayable image attention_image = util.atten2im(attention_tensor) # Convert latent representation to image latent_image = util.latent2im(latent_tensor) # Save image to disk util.save_image(image_numpy, 'output.png') # Create directories util.mkdirs(['./checkpoints', './results']) # Network diagnostics util.diagnose_network(model.netG_A, name='Generator') # Get latest model checkpoint latest_model = util.get_model_list('./checkpoints/enlightening', key='G_A') ``` -------------------------------- ### Initialize VGG Perceptual Loss Source: https://context7.com/vita-group/enlightengan/llms.txt Loads a pretrained VGG16 model and defines a perceptual loss module using instance normalization for feature comparison. ```python # Load pretrained VGG16 vgg = networks.load_vgg16("./model", gpu_ids=[0]) vgg.eval() for param in vgg.parameters(): param.requires_grad = False # Create perceptual loss module class PerceptualLoss(nn.Module): def __init__(self, opt): super(PerceptualLoss, self).__init__() self.opt = opt self.instancenorm = nn.InstanceNorm2d(512, affine=False) def compute_vgg_loss(self, vgg, img, target): # Preprocess: RGB to BGR, scale to [0, 255] img_vgg = vgg_preprocess(img, self.opt) target_vgg = vgg_preprocess(target, self.opt) # Extract features at specified layer img_fea = vgg(img_vgg, self.opt) # e.g., relu5_1 target_fea = vgg(target_vgg, self.opt) # Compute loss with instance normalization return torch.mean( (self.instancenorm(img_fea) - self.instancenorm(target_fea)) ** 2 ) # Usage in training perceptual_loss = PerceptualLoss(opt) loss_vgg = perceptual_loss.compute_vgg_loss(vgg, fake_B, real_A) * opt.vgg ``` -------------------------------- ### Train EnlightenGAN models Source: https://context7.com/vita-group/enlightengan/llms.txt The main training loop script handles data loading, model optimization, periodic visualization, and checkpoint management. ```python # train.py - Main training script import time from options.train_options import TrainOptions from data.data_loader import CreateDataLoader from models.models import create_model from util.visualizer import Visualizer # Parse training options opt = TrainOptions().parse() # Create data loader for unpaired images data_loader = CreateDataLoader(opt) dataset = data_loader.load_data() dataset_size = len(data_loader) print('#training images = %d' % dataset_size) # Initialize the model model = create_model(opt) visualizer = Visualizer(opt) total_steps = 0 # Training loop for epoch in range(1, opt.niter + opt.niter_decay + 1): epoch_start_time = time.time() for i, data in enumerate(dataset): total_steps += opt.batchSize epoch_iter = total_steps - dataset_size * (epoch - 1) # Set input data and run optimization model.set_input(data) model.optimize_parameters(epoch) # Display results periodically if total_steps % opt.display_freq == 0: visualizer.display_current_results(model.get_current_visuals(), epoch) # Print and log errors if total_steps % opt.print_freq == 0: errors = model.get_current_errors(epoch) t = (time.time() - iter_start_time) / opt.batchSize visualizer.print_current_errors(epoch, epoch_iter, errors, t) # Save latest checkpoint if total_steps % opt.save_latest_freq == 0: model.save('latest') # Save epoch checkpoint if epoch % opt.save_epoch_freq == 0: model.save('latest') model.save(epoch) # Update learning rate after niter epochs if epoch > opt.niter: model.update_learning_rate() ``` -------------------------------- ### Initialize Unaligned Dataset Source: https://context7.com/vita-group/enlightengan/llms.txt Initializes the dataset for unpaired images by setting the root directory and loading all images from the specified training phase ('trainA' and 'trainB') into memory for faster access. ```python # data/unaligned_dataset.py - Dataset for unpaired images from data.unaligned_dataset import UnalignedDataset class UnalignedDataset(BaseDataset): def initialize(self, opt): self.opt = opt self.root = opt.dataroot # Expects directory structure: # dataroot/ # trainA/ - Low-light images # trainB/ - Normal-light images (unpaired) self.dir_A = os.path.join(opt.dataroot, opt.phase + 'A') self.dir_B = os.path.join(opt.dataroot, opt.phase + 'B') # Load and store all images in memory for faster training self.A_imgs, self.A_paths = store_dataset(self.dir_A) self.B_imgs, self.B_paths = store_dataset(self.dir_B) self.transform = get_transform(opt) ``` -------------------------------- ### Initialize EnlightenGAN Single Model Source: https://context7.com/vita-group/enlightengan/llms.txt Initializes the generator and discriminator networks, along with loss functions for GAN, cycle, and VGG perceptual loss. Training-specific discriminators are initialized only when in training mode. ```python from models.single_model import SingleModel class SingleModel(BaseModel): def initialize(self, opt): # Initialize generator with self-attention and skip connections self.netG_A = networks.define_G( opt.input_nc, opt.output_nc, opt.ngf, opt.which_model_netG, opt.norm, not opt.no_dropout, self.gpu_ids, skip=(opt.skip > 0), opt=opt ) # Initialize discriminators (training only) if self.isTrain: self.netD_A = networks.define_D(...) # Global discriminator if opt.patchD: self.netD_P = networks.define_D(...) # Patch discriminator # Loss functions self.criterionGAN = networks.GANLoss(use_lsgan=not opt.no_lsgan) self.criterionCycle = torch.nn.L1Loss() # VGG perceptual loss if opt.vgg > 0: self.vgg_loss = networks.PerceptualLoss(opt) self.vgg = networks.load_vgg16("./model", self.gpu_ids) ``` -------------------------------- ### Implement GAN Loss Functions Source: https://context7.com/vita-group/enlightengan/llms.txt Provides implementations for LSGAN, RaGAN, and WGAN-GP gradient penalty calculations. ```python # models/networks.py - GAN losses from models import networks # LSGAN loss (default) criterionGAN = networks.GANLoss( use_lsgan=True, # Use MSE loss (LSGAN) target_real_label=1.0, target_fake_label=0.0 ) # Compute discriminator loss pred_real = netD.forward(real_images) pred_fake = netD.forward(fake_images.detach()) loss_D_real = criterionGAN(pred_real, True) # Target: 1.0 loss_D_fake = criterionGAN(pred_fake, False) # Target: 0.0 loss_D = (loss_D_real + loss_D_fake) * 0.5 # Compute generator loss pred_fake = netD.forward(fake_images) loss_G = criterionGAN(pred_fake, True) # Generator wants D to output 1.0 # Relativistic average GAN (RaGAN) loss option if opt.use_ragan: pred_real = netD.forward(real_images) loss_G = ( criterionGAN(pred_real - torch.mean(pred_fake), False) + criterionGAN(pred_fake - torch.mean(pred_real), True) ) / 2 # WGAN-GP loss option class DiscLossWGANGP: def calc_gradient_penalty(self, netD, real_data, fake_data): alpha = torch.rand(1, 1).expand(real_data.size()).cuda() interpolates = alpha * real_data + ((1 - alpha) * fake_data) interpolates = Variable(interpolates, requires_grad=True) disc_interpolates = netD.forward(interpolates) gradients = torch.autograd.grad( outputs=disc_interpolates, inputs=interpolates, grad_outputs=torch.ones(disc_interpolates.size()).cuda(), create_graph=True, retain_graph=True )[0] gradient_penalty = ((gradients.norm(2, dim=1) - 1) ** 2).mean() * 10 return gradient_penalty ``` -------------------------------- ### Testing: Run Prediction Source: https://github.com/vita-group/enlightengan/blob/master/README.md Executes the prediction script to test the trained EnlightenGAN model. Ensure pretrained models are placed in './checkpoints/enlightening' and test datasets are prepared. ```shell python scripts/script.py --predict ``` -------------------------------- ### Create EnlightenGAN Model Source: https://context7.com/vita-group/enlightengan/llms.txt Instantiates the EnlightenGAN model using the `create_model` factory function. This function supports various model types, including 'single' for unpaired training. ```python from models.models import create_model # Create EnlightenGAN model (single model for unpaired training) # Supported models: 'cycle_gan', 'pix2pix', 'pair', 'single', 'temp', 'UNIT', 'test' model = create_model(opt) ``` -------------------------------- ### Model Factory API Source: https://context7.com/vita-group/enlightengan/llms.txt The create_model factory function instantiates the appropriate model architecture based on configuration options. ```APIDOC ## Model Creation API ### Description Instantiates the model architecture based on provided configuration options. ### Parameters #### Request Body - **opt** (object) - Required - Configuration object containing model parameters (e.g., model type, network architecture, normalization settings). ### Response - **model** (object) - The initialized model instance (e.g., SingleGANModel). ``` -------------------------------- ### Run EnlightenGAN inference Source: https://context7.com/vita-group/enlightengan/llms.txt The inference script processes test images and generates an HTML report with before/after comparisons. Note that nThreads and batchSize must be set to 1 for testing. ```python # predict.py - Inference script import os from options.test_options import TestOptions from data.data_loader import CreateDataLoader from models.models import create_model from util.visualizer import Visualizer from util import html # Parse test options opt = TestOptions().parse() opt.nThreads = 1 # test code only supports nThreads = 1 opt.batchSize = 1 # test code only supports batchSize = 1 opt.serial_batches = True # no shuffle opt.no_flip = True # no flip # Create data loader and model data_loader = CreateDataLoader(opt) dataset = data_loader.load_data() model = create_model(opt) visualizer = Visualizer(opt) # Create output webpage web_dir = os.path.join("./ablation/", opt.name, '%s_%s' % (opt.phase, opt.which_epoch)) webpage = html.HTML(web_dir, 'Experiment = %s, Phase = %s, Epoch = %s' % (opt.name, opt.phase, opt.which_epoch)) # Process all test images for i, data in enumerate(dataset): model.set_input(data) visuals = model.predict() # Returns OrderedDict with 'real_A' and 'fake_B' img_path = model.get_image_paths() print('process image... %s' % img_path) visualizer.save_images(webpage, visuals, img_path) webpage.save() ``` -------------------------------- ### Optimize Parameters for Single Model Source: https://context7.com/vita-group/enlightengan/llms.txt Performs a single optimization step for both the generator and discriminators. Gradients are zeroed, backward passes are computed, and optimizers are stepped. ```python def optimize_parameters(self, epoch): """Single optimization step""" self.forward() # Update Generator self.optimizer_G.zero_grad() self.backward_G(epoch) self.optimizer_G.step() # Update Discriminators self.optimizer_D_A.zero_grad() self.backward_D_A() if self.opt.patchD: self.optimizer_D_P.zero_grad() self.backward_D_P() self.optimizer_D_A.step() if self.opt.patchD: self.optimizer_D_P.step() ``` -------------------------------- ### VGG Perceptual Loss Network Definition Source: https://context7.com/vita-group/enlightengan/llms.txt Imports the networks module, which contains the implementation for VGG-based perceptual loss. This loss is used to preserve semantic content during image enhancement. ```python # models/networks.py - VGG perceptual loss from models import networks ``` -------------------------------- ### Set Input Data for Single Model Source: https://context7.com/vita-group/enlightengan/llms.txt Assigns input data from the dataloader to the model's internal variables. This includes low-light images, normal-light references, and attention maps. ```python def set_input(self, data): """Set input data from dataloader""" self.input_A = data['A'] # Low-light image self.input_B = data['B'] # Normal-light reference self.input_A_gray = data['A_gray'] # Attention map self.input_img = data['input_img'] ``` -------------------------------- ### Save Single Model Checkpoints Source: https://context7.com/vita-group/enlightengan/llms.txt Saves the generator and discriminator network weights to disk. Checkpoints are saved for both the global discriminator (D_A) and the patch discriminator (D_P) if enabled. ```python def save(self, label): """Save model checkpoints""" self.save_network(self.netG_A, 'G_A', label, self.gpu_ids) self.save_network(self.netD_A, 'D_A', label, self.gpu_ids) if self.opt.patchD: self.save_network(self.netD_P, 'D_P', label, self.gpu_ids) ``` -------------------------------- ### Define Generator Network Source: https://context7.com/vita-group/enlightengan/llms.txt Defines the generator network, specifying architecture, input/output channels, filters, normalization, and GPU usage. The 'sid_unet_resize' architecture is commonly used for EnlightenGAN. ```python from models import networks # Define generator network # Available architectures: # - 'resnet_9blocks', 'resnet_6blocks': ResNet-based generators # - 'unet_128', 'unet_256', 'unet_512': Standard U-Net generators # - 'sid_unet', 'sid_unet_shuffle', 'sid_unet_resize': SID-style U-Net variants # - 'DnCNN': Denoising CNN netG = networks.define_G( input_nc=3, # Number of input channels output_nc=3, # Number of output channels ngf=64, # Number of generator filters which_model_netG='sid_unet_resize', # Generator architecture norm='instance', # Normalization type: 'batch', 'instance', 'synBN' use_dropout=False, # Whether to use dropout gpu_ids=[0, 1, 2], # GPU IDs for DataParallel skip=True, # Enable skip connection (output = input + residual) opt=opt # Additional options ) ``` -------------------------------- ### Predict with Single Model Source: https://context7.com/vita-group/enlightengan/llms.txt Runs inference using the trained generator and returns the enhanced image along with the original input. The output is an OrderedDict containing tensor-to-image converted numpy arrays. ```python def predict(self): """Run inference and return results""" # Returns OrderedDict([('real_A', real_A), ('fake_B', fake_B)]) real_A = util.tensor2im(self.real_A.data) fake_B = util.tensor2im(self.fake_B.data) return OrderedDict([('real_A', real_A), ('fake_B', fake_B)]) ``` -------------------------------- ### Define Discriminator Networks Source: https://context7.com/vita-group/enlightengan/llms.txt Defines both global and patch discriminator networks. The `patch` parameter distinguishes between global (False) and patch (True) discriminators. Common architectures like 'no_norm_4' are supported. ```python from models import networks # Define global discriminator netD_A = networks.define_D( input_nc=3, # Number of input channels ndf=64, # Number of discriminator filters which_model_netD='no_norm_4', # Discriminator type n_layers_D=5, # Number of layers norm='instance', # Normalization type use_sigmoid=False, # Use sigmoid activation (False for LSGAN) gpu_ids=[0, 1, 2], patch=False # Global discriminator ) # Define patch discriminator for local texture netD_P = networks.define_D( input_nc=3, ndf=64, which_model_netD='no_norm_4', n_layers_D=4, # Typically fewer layers for patch D norm='instance', use_sigmoid=False, gpu_ids=[0, 1, 2], patch=True # Patch discriminator ) ``` -------------------------------- ### Discriminator Network API Source: https://context7.com/vita-group/enlightengan/llms.txt Defines the discriminator network architectures, supporting both global and patch-based discriminators. ```APIDOC ## Discriminator Network Definition ### Description Defines the discriminator network architecture for global or local patch-based texture discrimination. ### Parameters #### Request Body - **input_nc** (int) - Required - Number of input channels. - **ndf** (int) - Required - Number of discriminator filters. - **which_model_netD** (string) - Required - Discriminator type. - **n_layers_D** (int) - Required - Number of layers. - **norm** (string) - Required - Normalization type. - **use_sigmoid** (boolean) - Required - Use sigmoid activation. - **gpu_ids** (list) - Required - GPU IDs for DataParallel. - **patch** (boolean) - Required - Whether to use patch-based discrimination. ``` -------------------------------- ### Generator Network API Source: https://context7.com/vita-group/enlightengan/llms.txt Defines the generator network architecture, supporting various U-Net and ResNet variants. ```APIDOC ## Generator Network Definition ### Description Defines the generator network architecture used for image enhancement. ### Parameters #### Request Body - **input_nc** (int) - Required - Number of input channels. - **output_nc** (int) - Required - Number of output channels. - **ngf** (int) - Required - Number of generator filters. - **which_model_netG** (string) - Required - Generator architecture (e.g., 'sid_unet_resize'). - **norm** (string) - Required - Normalization type (e.g., 'instance'). - **use_dropout** (boolean) - Required - Whether to use dropout. - **gpu_ids** (list) - Required - GPU IDs for DataParallel. - **skip** (boolean) - Required - Enable skip connection. - **opt** (object) - Required - Additional configuration options. ``` -------------------------------- ### Forward Pass for Single Model Source: https://context7.com/vita-group/enlightengan/llms.txt Performs the forward pass through the generator network. It handles conditional generation based on the `skip` option, potentially returning latent representations. ```python def forward(self): """Forward pass through generator""" if self.opt.skip == 1: self.fake_B, self.latent_real_A = self.netG_A.forward( self.real_img, self.real_A_gray ) else: self.fake_B = self.netG_A.forward(self.real_img, self.real_A_gray) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.