code: def _model_loop(
      args, loop_type, loader, model, opt, epoch, adv, writer
  ):
      """
      *Internal function* (refer to the train_model and eval_model functions for
      how to train and evaluate models).
  
      Runs a single epoch of either training or evaluating.
  
      Args:
          args (object) : an arguments object (see
              :meth:`~robustness.train.train_model` for list of arguments
          loop_type ('train' or 'val') : whether we are training or evaluating
          loader (iterable) : an iterable loader of the form
              `(image_batch, label_batch)`
          model (AttackerModel) : model to train/evaluate
          opt (ch.optim.Optimizer) : optimizer to use (ignored for evaluation)
          epoch (int) : which epoch we are currently on
          adv (bool) : whether to evaluate adversarially (otherwise standard)
          writer : tensorboardX writer (optional)
  
      Returns:
          The average top1 accuracy and the average loss across the epoch.
      """
      if not loop_type in ["train", "val"]:
          err_msg = "loop_type ({0}) must be 'train' or 'val'".format(
              loop_type
          )
          raise ValueError(err_msg)
      is_train = loop_type == "train"
  
      losses = AverageMeter()
      top1 = AverageMeter()
      top5 = AverageMeter()
  
      prec = "NatPrec" if not adv else "AdvPrec"
      loop_msg = "Train" if loop_type == "train" else "Val"
  
      # switch to train/eval mode depending
      model = model.train() if is_train else model.eval()
  
      # If adv training (or evaling), set eps and random_restarts appropriately
      if adv:
          eps = (
              args.custom_eps_multiplier(epoch) * args.eps
              if (is_train and args.custom_eps_multiplier)
              else args.eps
          )
          random_restarts = 0 if is_train else args.random_restarts
  
      # Custom training criterion
      has_custom_train_loss = has_attr(args, "custom_train_loss")
      train_criterion = (
          args.custom_train_loss
          if has_custom_train_loss
          else ch.nn.CrossEntropyLoss()
      )
  
      has_custom_adv_loss = has_attr(args, "custom_adv_loss")
      adv_criterion = (
          args.custom_adv_loss if has_custom_adv_loss else None
      )
  
      attack_kwargs = {}
      if adv:
          attack_kwargs = {
              "constraint": args.constraint,
              "eps": eps,
              "step_size": args.attack_lr,
              "iterations": args.attack_steps,
              "random_start": args.random_start,
              "custom_loss": adv_criterion,
              "random_restarts": random_restarts,
              "use_best": bool(args.use_best),
          }
  
      iterator = tqdm(enumerate(loader), total=len(loader))
      for i, (inp, target) in iterator:
          # measure data loading time
          target = target.cuda(non_blocking=True)
          output, final_inp = model(
              inp, target=target, make_adv=adv, **attack_kwargs
          )
          loss = train_criterion(output, target)
  
          if len(loss.shape) > 0:
              loss = loss.mean()
  
          model_logits = (
              output[0] if (type(output) is tuple) else output
          )
  
          # measure accuracy and record loss
          top1_acc = float("nan")
          top5_acc = float("nan")
          try:
              maxk = min(5, model_logits.shape[-1])
              if has_attr(args, "custom_accuracy"):
                  prec1, prec5 = args.custom_accuracy(
                      model_logits, target
                  )
              else:
                  prec1, prec5 = helpers.accuracy(
                      model_logits, target, topk=(1, maxk)
                  )
                  prec1, prec5 = prec1[0], prec5[0]
  
              losses.update(loss.item(), inp.size(0))
              top1.update(prec1, inp.size(0))
              top5.update(prec5, inp.size(0))
  
              top1_acc = top1.avg
              top5_acc = top5.avg
          except:
              warnings.warn("Failed to calculate the accuracy.")
  
          reg_term = 0.0
          if has_attr(args, "regularizer"):
              reg_term = args.regularizer(model, inp, target)
          loss = loss + reg_term
  
          # compute gradient and do SGD step
          if is_train:
              opt.zero_grad()
              if args.mixed_precision:
                  with amp.scale_loss(loss, opt) as sl:
                      sl.backward()
              else:
                  loss.backward()
              opt.step()
          elif adv and i == 0 and writer:
              # add some examples to the tensorboard
              nat_grid = make_grid(inp[:15, ...])
              adv_grid = make_grid(final_inp[:15, ...])
              writer.add_image("Nat input", nat_grid, epoch)
              writer.add_image("Adv input", adv_grid, epoch)
  
          # ITERATOR
          desc = (
              "{2} Epoch:{0} | Loss {loss.avg:.4f} | "
              "{1}1 {top1_acc:.3f} | {1}5 {top5_acc:.3f} | "
              "Reg term: {reg} ||".format(
                  epoch,
                  prec,
                  loop_msg,
                  loss=losses,
                  top1_acc=top1_acc,
                  top5_acc=top5_acc,
                  reg=reg_term,
              )
          )
  
          # USER-DEFINED HOOK
          if has_attr(args, "iteration_hook"):
              args.iteration_hook(model, i, loop_type, inp, target)
  
          iterator.set_description(desc)
          iterator.refresh()
  
      if writer is not None:
          prec_type = "adv" if adv else "nat"
          descs = ["loss", "top1", "top5"]
          vals = [losses, top1, top5]
          for d, v in zip(descs, vals):
              writer.add_scalar(
                  "_".join([prec_type, loop_type, d]), v.avg, epoch
              )
  
      return top1.avg, losses.avg
  
file_path: robustness/robustness/train.py
imports: import torch
  import numpy
  import torch.nn
  from torch.optim import SGD, lr_scheduler
  from torchvision.utils import make_grid
  from cox.utils import Parameters
  from .tools import helpers
  from .tools.helpers import AverageMeter, ckpt_at_epoch, has_attr
  from .tools import constants
  import dill
  import os
  import time
  import warnings
label_desc: Use image node_id 5 for calling a global function with example usage: _model_loop(args, loop_type, loader, model, opt, epoch, adv, writer) and returns: top1,  losses