class_docstr: Adversary training wrapper.
  
  Args:
      adversary (nn.Module): The adversary module will be used to estimate the logits given the fake and real samples.
          We assume here the adversary output is ``Tuple[List[torch.Tensor], List[List[torch.Tensor]]]``
          where the first item is a list of logits and the second item is a list of feature maps.
      optimizer (torch.optim.Optimizer): Optimizer used for training the given module.
      loss (AdvLossType): Loss function for generator training.
      loss_real (AdvLossType): Loss function for adversarial training on logits from real samples.
      loss_fake (AdvLossType): Loss function for adversarial training on logits from fake samples.
      loss_feat (FeatLossType): Feature matching loss function for generator training.
      normalize (bool): Whether to normalize by number of sub-discriminators.
  
  Example of usage:
      adv_loss = AdversarialLoss(adversaries, optimizer, loss, loss_real, loss_fake)
      for real in loader:
          noise = torch.randn(...)
          fake = model(noise)
          adv_loss.train_adv(fake, real)
          loss, _ = adv_loss(fake, real)
          loss.backward()
class_docstr_tok: ["Adversary","training","wrapper",".","Args",":","adversary","(","nn.Module",")",":","The","adversary","module","will","be","used","to","estimate","the","logits","given","the","fake","and","real","samples",".","We","assume","here","the","adversary","output","is","``","Tuple","[","List","[","torch.Tensor","]",",","List","[","List","[","torch.Tensor","]","]","]","``","where","the","first","item","is","a","list","of","logits","and","the","second","item","is","a","list","of","feature","maps",".","optimizer","(","torch.optim.Optimizer",")",":","Optimizer","used","for","training","the","given","module",".","loss","(","AdvLossType",")",":","Loss","function","for","generator","training",".","loss_real","(","AdvLossType",")",":","Loss","function","for","adversarial","training","on","logits","from","real","samples",".","loss_fake","(","AdvLossType",")",":","Loss","function","for","adversarial","training","on","logits","from","fake","samples",".","loss_feat","(","FeatLossType",")",":","Feature","matching","loss","function","for","generator","training",".","normalize","(","bool",")",":","Whether","to","normalize","by","number","of","sub-discriminators",".","Example","of","usage",":","adv_loss","=","AdversarialLoss","(","adversaries",",","optimizer",",","loss",",","loss_real",",","loss_fake",")","for","real","in","loader",":","noise","=","torch.randn","(","...",")","fake","=","model","(","noise",")","adv_loss.train_adv","(","fake",",","real",")","loss",",","_","=","adv_loss","(","fake",",","real",")","loss.backward","(",")"]
docstr: Train the adversary with the given fake and real example.
  
  We assume the adversary output is the following format: Tuple[List[torch.Tensor], List[List[torch.Tensor]]].
  The first item being the logits and second item being a list of feature maps for each sub-discriminator.
  
  This will automatically synchronize gradients (with `flashy.distrib.eager_sync_model`)
  and call the optimizer.
docstr_tok: ["Train","the","adversary","with","the","given","fake","and","real","example",".","We","assume","the","adversary","output","is","the","following","format",":","Tuple","[","List","[","torch.Tensor","]",",","List","[","List","[","torch.Tensor","]","]","]",".","The","first","item","being","the","logits","and","second","item","being","a","list","of","feature","maps","for","each","sub-discriminator",".","This","will","automatically","synchronize","gradients","(","with","`","flashy.distrib.eager_sync_model","`",")","and","call","the","optimizer","."]
code: def train_adv(
      self, fake: torch.Tensor, real: torch.Tensor
  ) -> torch.Tensor:
      """Train the adversary with the given fake and real example.
  
      We assume the adversary output is the following format: Tuple[List[torch.Tensor], List[List[torch.Tensor]]].
      The first item being the logits and second item being a list of feature maps for each sub-discriminator.
  
      This will automatically synchronize gradients (with `flashy.distrib.eager_sync_model`)
      and call the optimizer.
      """
      loss = torch.tensor(0.0, device=fake.device)
      all_logits_fake_is_fake, _ = self.get_adversary_pred(
          fake.detach()
      )
      all_logits_real_is_fake, _ = self.get_adversary_pred(
          real.detach()
      )
      n_sub_adversaries = len(all_logits_fake_is_fake)
      for logit_fake_is_fake, logit_real_is_fake in zip(
          all_logits_fake_is_fake, all_logits_real_is_fake
      ):
          loss += self.loss_fake(logit_fake_is_fake) + self.loss_real(
              logit_real_is_fake
          )
  
      if self.normalize:
          loss /= n_sub_adversaries
  
      self.optimizer.zero_grad()
      with flashy.distrib.eager_sync_model(self.adversary):
          loss.backward()
      self.optimizer.step()
  
      return loss
  
imports: import typing
  import flashy
  import torch
  import torch.nn
  import torch.nn.functional
label_desc: Use image node_id 5 for calling the AdversarialLoss obj's underlying member method code with example usage: obj.train_adv(fake, real) and returns: loss