class_docstr: Class that performs the main optimization.
  Keeps track of the current x and iterates through data to learn x given the penalty and order.
class_docstr_tok: ["Class","that","performs","the","main","optimization",".","Keeps","track","of","the","current","x","and","iterates","through","data","to","learn","x","given","the","penalty","and","order","."]
docstr: Trains the estimator to determine which features to include.
  
  Parameters
  ----------
  f_callback : function
      Function that performs a callback
  f_stop: function
      Function that tells you when to stop
docstr_tok: ["Trains","the","estimator","to","determine","which","features","to","include",".","Parameters","--","--","--","--","--","f_callback",":","function","Function","that","performs","a","callback","f_stop",":","function","Function","that","tells","you","when","to","stop"]
code: def train(self, f_callback=None, f_stop=None):
      """
      Trains the estimator to determine which features to include.
  
      Parameters
      ----------
      f_callback : function
          Function that performs a callback
      f_stop: function
          Function that tells you when to stop
      """
  
      t = time.time()
      h = torch.zeros([1, 1], dtype=torch.get_default_dtype())
      h = h.to(self.device)
      # h_complete is so when we divide by the number of classes
      # we only do that for that minibatch if accumulating
      h_complete = h.clone()
      flag_stop = False
      dataloader_iterator = iter(self.ds_train)
      self.x.grad = torch.zeros_like(self.x)
      while not flag_stop:
          try:
              xsub, ysub = next(dataloader_iterator)
          except StopIteration:
              dataloader_iterator = iter(self.ds_train)
              xsub, ysub = next(dataloader_iterator)
          try:
              s = self.ftransform(self.x)
              s = s.to(self.device)
              if self.multiclass:
                  # accumulate gradients over each class, classes range from
                  # 0 to n_classes - 1
                  # num_classes_batch = torch.unique(ysub).size()[0]
                  for target_class in range(self.n_classes):
                      ysub_binary = self.transform_y_into_binary(
                          ysub, target_class
                      )
                      if self._skip_y_forward(ysub_binary):
                          continue
                      # should should skip if target class is not included
                      # but that changes what we divide by
                      scaling_value = self._get_scaling_value(
                          ysub, target_class
                      )
                      f_train, pen, g1, g2 = self.forward_and_backward(
                          s, xsub, ysub_binary, retain_graph=True
                      )
                      self.x.grad += (
                          self.combine_gradient(g1, g2) * scaling_value
                      )
                      h += (
                          self.combine_loss(f_train, pen)
                          * scaling_value
                      )
              else:
                  if not self._skip_y_forward(ysub):
                      f_train, pen, g1, g2 = self.forward_and_backward(
                          s, xsub, ysub
                      )
                      self.x.grad += self.combine_gradient(g1, g2)
                      h += self.combine_loss(f_train, pen)
                  else:
                      continue
              h_complete += h
              self.it += 1
              if torch.isnan(h):
                  raise constants.NanError(
                      "Loss is nan, something may be misconfigured"
                  )
              if self.it % self.accum_steps == 0:
                  torch.nn.utils.clip_grad_norm_(
                      torch.nn.ParameterList([self.x]),
                      max_norm=self.max_norm,
                  )
                  self.opt_train.step()
  
                  t = time.time() - t
                  if f_stop is not None:
                      flag_stop = f_stop(self, h, self.it, t)
  
                  if f_callback is not None:
                      f_callback(self, h, self.it, t)
                  elif (
                      self.verbose
                      and (self.it // self.accum_steps) % self.verbose
                      == 0
                  ):
                      epoch = int(self.it / self.iters_per_epoch)
                      print(
                          "[Minibatch: %6d/ Epoch: %3d/ t: %3.3f s] Loss: %0.3f"
                          % (
                              self.it,
                              epoch,
                              t,
                              h_complete / self.accum_steps,
                          )
                      )
  
                  if flag_stop:
                      break
  
                  self.opt_train.zero_grad()
                  h = 0
                  h_complete = 0
                  t = time.time()
          except KeyboardInterrupt:
              flag_stop = True
              break
  
imports: import time
  import numpy
  import scipy.special
  import torch
  import torch.nn
  from .None import constants
  from .None import syssettings
  from .fginitialize import ChunkDataLoader
label_desc: Use image node_id 9 for calling the Solver obj's underlying member method code with example usage: obj.train(f_callback, f_stop) without return types