code: def make_optimizer_and_schedule(args, model, checkpoint, params):
      """
      *Internal Function* (called directly from train_model)
  
      Creates an optimizer and a schedule for a given model, restoring from a
      checkpoint if it is non-null.
  
      Args:
          args (object) : an arguments object, see
              :meth:`~robustness.train.train_model` for details
          model (AttackerModel) : the model to create the optimizer for
          checkpoint (dict) : a loaded checkpoint saved by this library and loaded
              with `ch.load`
          params (list|None) : a list of parameters that should be updatable, all
              other params will not update. If ``None``, update all params
  
      Returns:
          An optimizer (ch.nn.optim.Optimizer) and a scheduler
              (ch.nn.optim.lr_schedulers module).
      """
      # Make optimizer
      param_list = model.parameters() if params is None else params
      optimizer = SGD(
          param_list,
          args.lr,
          momentum=args.momentum,
          weight_decay=args.weight_decay,
      )
  
      if args.mixed_precision:
          model.to("cuda")
          model, optimizer = amp.initialize(model, optimizer, "O1")
  
      # Make schedule
      schedule = None
      if args.custom_lr_multiplier == "cyclic":
          eps = args.epochs
          lr_func = lambda t: np.interp(
              [t], [0, eps * 4 // 15, eps], [0, 1, 0]
          )[0]
          schedule = lr_scheduler.LambdaLR(optimizer, lr_func)
      elif args.custom_lr_multiplier:
          cs = args.custom_lr_multiplier
          periods = eval(cs) if type(cs) is str else cs
          if args.lr_interpolation == "linear":
              lr_func = lambda t: np.interp([t], *zip(*periods))[0]
          else:
  
              def lr_func(ep):
                  for milestone, lr in reversed(periods):
                      if ep >= milestone:
                          return lr
                  return 1.0
  
          schedule = lr_scheduler.LambdaLR(optimizer, lr_func)
      elif args.step_lr:
          schedule = lr_scheduler.StepLR(
              optimizer,
              step_size=args.step_lr,
              gamma=args.step_lr_gamma,
          )
  
      # Fast-forward the optimizer and the scheduler if resuming
      if checkpoint:
          optimizer.load_state_dict(checkpoint["optimizer"])
          try:
              schedule.load_state_dict(checkpoint["schedule"])
          except:
              steps_to_take = checkpoint["epoch"]
              print(
                  "Could not load schedule (was probably LambdaLR)."
                  f" Stepping {steps_to_take} times instead..."
              )
              for i in range(steps_to_take):
                  schedule.step()
  
          if "amp" in checkpoint and checkpoint["amp"] not in [
              None,
              "N/A",
          ]:
              amp.load_state_dict(checkpoint["amp"])
  
          # TODO: see if there's a smarter way to do this
          # TODO: see what's up with loading fp32 weights and then MP training
          if args.mixed_precision:
              model.load_state_dict(checkpoint["model"])
  
      return optimizer, schedule
  
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 2 for calling a global function with example usage: make_optimizer_and_schedule(args, model, checkpoint, params) and returns: optimizer,  schedule, int, lr