class_docstr: First order optimier.
  
  Performs (stochastic) gradient descent, possibly using fancier methods like
  ADAM etc.
  
  Args:
      optimizer (tf.Optimizer): Optimizer to be used.
      learning_rate (dict): learning rate arguments.
          learning rates are our main interest parameters to tune optimizers.
      max_optimization_epochs (int): Maximum number of epochs for update.
      tolerance (float): Tolerance for difference in loss during update.
      batch_size (int): Batch size for optimization.
      callback (callable): Function to call during each epoch. Default is
          None.
      verbose (bool): If true, intermediate log message will be printed.
      name (str): Name scope of the optimizer.
class_docstr_tok: ["First","order","optimier",".","Performs","(","stochastic",")","gradient","descent",",","possibly","using","fancier","methods","like","ADAM","etc",".","Args",":","optimizer","(","tf.Optimizer",")",":","Optimizer","to","be","used",".","learning_rate","(","dict",")",":","learning","rate","arguments",".","learning","rates","are","our","main","interest","parameters","to","tune","optimizers",".","max_optimization_epochs","(","int",")",":","Maximum","number","of","epochs","for","update",".","tolerance","(","float",")",":","Tolerance","for","difference","in","loss","during","update",".","batch_size","(","int",")",":","Batch","size","for","optimization",".","callback","(","callable",")",":","Function","to","call","during","each","epoch",".","Default","is","None",".","verbose","(","bool",")",":","If","true",",","intermediate","log","message","will","be","printed",".","name","(","str",")",":","Name","scope","of","the","optimizer","."]
docstr: Perform optimization.
  
  Args:
      inputs (list[numpy.ndarray]): List of input values.
      extra_inputs (list[numpy.ndarray]): List of extra input values.
      callback (callable): Function to call during each epoch. Default
          is None.
  
  Raises:
      NotImplementedError: If inputs are invalid.
      Exception: If loss function is None, i.e. not defined.
docstr_tok: ["Perform","optimization",".","Args",":","inputs","(","list","[","numpy.ndarray","]",")",":","List","of","input","values",".","extra_inputs","(","list","[","numpy.ndarray","]",")",":","List","of","extra","input","values",".","callback","(","callable",")",":","Function","to","call","during","each","epoch",".","Default","is","None",".","Raises",":","NotImplementedError",":","If","inputs","are","invalid",".","Exception",":","If","loss","function","is","None",",","i.e",".","not","defined","."]
code: def optimize(self, inputs, extra_inputs=None, callback=None):
      """Perform optimization.
  
      Args:
          inputs (list[numpy.ndarray]): List of input values.
          extra_inputs (list[numpy.ndarray]): List of extra input values.
          callback (callable): Function to call during each epoch. Default
              is None.
  
      Raises:
          NotImplementedError: If inputs are invalid.
          Exception: If loss function is None, i.e. not defined.
  
      """
      if not inputs:
          # Assumes that we should always sample mini-batches
          raise NotImplementedError("No inputs are fed to optimizer.")
      if self._opt_fun is None:
          raise Exception(
              "Use update_opt() to setup the loss function first."
          )
  
      f_loss = self._opt_fun["f_loss"]
  
      if extra_inputs is None:
          extra_inputs = tuple()
  
      last_loss = f_loss(*(tuple(inputs) + extra_inputs))
  
      start_time = time.time()
  
      dataset = BatchDataset(
          inputs, self._batch_size, extra_inputs=extra_inputs
      )
  
      sess = tf.compat.v1.get_default_session()
  
      for epoch in range(self._max_optimization_epochs):
          if self._verbose:
              logger.log("Epoch {}".format(epoch))
  
          with click.progressbar(
              length=len(inputs[0]), label="Optimizing minibatches"
          ) as pbar:
              for batch in dataset.iterate(update=True):
                  sess.run(
                      self._train_op,
                      dict(list(zip(self._input_vars, batch))),
                  )
  
                  pbar.update(len(batch[0]))
  
          new_loss = f_loss(*(tuple(inputs) + extra_inputs))
  
          if self._verbose:
              logger.log("Epoch: {} | Loss: {}".format(epoch, new_loss))
          if self._callback or callback:
              elapsed = time.time() - start_time
              callback_args = dict(
                  loss=new_loss,
                  params=self._target.get_param_values()
                  if self._target
                  else None,
                  itr=epoch,
                  elapsed=elapsed,
              )
              if self._callback:
                  self._callback(callback_args)
              if callback:
                  callback(**callback_args)
  
          if abs(last_loss - new_loss) < self._tolerance:
              break
          last_loss = new_loss
  
file_path: garage/src/garage/tf/optimizers/first_order_optimizer.py
imports: import time
  import click
  from dowel import logger
  import tensorflow
  from garage import _Default, make_optimizer
  from garage.np.optimizers import BatchDataset
  from garage.tf import compile_function
  from garage.tf.optimizers._dtypes import LazyDict
label_desc: Use image node_id 4 for calling the FirstOrderOptimizer obj's underlying member method code with example usage: obj.optimize(inputs, extra_inputs, callback) without return types