code: def train_step(self, real_images):
      if isinstance(real_images, tuple):
          real_images = real_images[0]
      # Sample random points in the latent space
      batch_size = real_images.shape[0]
      random_latent_vectors = keras.random.normal(
          shape=(batch_size, self.latent_dim), seed=self.seed_generator
      )
  
      # Decode them to fake images
      generated_images = self.generator(random_latent_vectors)
  
      # Combine them with real images
      real_images = torch.tensor(real_images)
      combined_images = torch.concat(
          [generated_images, real_images], axis=0
      )
  
      # Assemble labels discriminating real from fake images
      labels = torch.concat(
          [torch.ones((batch_size, 1)), torch.zeros((batch_size, 1))],
          axis=0,
      )
      # Add random noise to the labels - important trick!
      labels += 0.05 * keras.random.uniform(
          labels.shape, seed=self.seed_generator
      )
  
      # Train the discriminator
      self.zero_grad()
      predictions = self.discriminator(combined_images)
      d_loss = self.loss_fn(labels, predictions)
      d_loss.backward()
      grads = [
          v.value.grad for v in self.discriminator.trainable_weights
      ]
      with torch.no_grad():
          self.d_optimizer.apply(
              grads, self.discriminator.trainable_weights
          )
  
      # Sample random points in the latent space
      random_latent_vectors = keras.random.normal(
          shape=(batch_size, self.latent_dim), seed=self.seed_generator
      )
  
      # Assemble labels that say "all real images"
      misleading_labels = torch.zeros((batch_size, 1))
  
      # Train the generator (note that we should *not* update the weights
      # of the discriminator)!
      self.zero_grad()
      predictions = self.discriminator(
          self.generator(random_latent_vectors)
      )
      g_loss = self.loss_fn(misleading_labels, predictions)
      grads = g_loss.backward()
      grads = [v.value.grad for v in self.generator.trainable_weights]
      with torch.no_grad():
          self.g_optimizer.apply(
              grads, self.generator.trainable_weights
          )
  
      # Update metrics and return their value.
      self.d_loss_tracker.update_state(d_loss)
      self.g_loss_tracker.update_state(g_loss)
      return {
          "d_loss": self.d_loss_tracker.result(),
          "g_loss": self.g_loss_tracker.result(),
      }
  
imports: import os
  import torch
  import keras
  from keras import layers
  import numpy
label_desc: Use image node_id 4 for calling the GAN obj's underlying member method code with example usage: obj.train_step(real_images) and returns: dict