class_docstr: Callback function for xgboost.
  Support custom evaluation function and early-stopping.
class_docstr_tok: ["Callback","function","for","xgboost",".","Support","custom","evaluation","function","and","early-stopping","."]
docstr: Run after each iteration.  Return True when training should stop.
docstr_tok: ["Run","after","each","iteration",".","Return","True","when","training","should","stop","."]
code: def after_iteration(
      self, model: "xgb.Booster", epoch: int, evals_log: Dict
  ):
      """Run after each iteration.  Return True when training should stop."""
      # pylint:disable = import-outside-toplevel
      try:
          from xgboost.callback import _fmt_metric  # type: ignore
      except ImportError:
          # Compatibility with xgboost >= 1.6
          def _fmt_metric(value, show_stdv=True):
              """format metric string"""
              if len(value) == 2:
                  return f"{value[0]}:{value[1]:.5f}"
              if len(value) == 3:
                  if show_stdv:
                      return f"{value[0]}:{value[1]:.5f}+{value[2]:.5f}"
                  return f"{value[0]}:{value[1]:.5f}"
              raise ValueError("wrong metric value", value)
  
      ##### init state #####
      if not self.state:
          self.state["maximize_score"] = self.maximize
          self.state["best_iteration"] = 0
          if self.maximize:
              self.state["best_score"] = float("-inf")
          else:
              self.state["best_score"] = float("inf")
  
          assert model is not None
          if model.attr("best_score") is not None:
              self.state["best_score"] = float(model.attr("best_score"))
              self.state["best_iteration"] = int(
                  model.attr("best_iteration")
              )
              self.state["best_msg"] = model.attr("best_msg")
          else:
              model.set_attr(
                  best_iteration=str(self.state["best_iteration"])
              )
              model.set_attr(best_score=str(self.state["best_score"]))
      res_dict = {}
  
      if epoch % self.skip_every == 1:
          return False
  
      ##### evaluation #####
      mod_evals = self.evals
      if self.loss_type == "rank-binary":
          mod_evals = _binarize_evals(self.evals)
  
      if self.loss_type == "rank" and int(xgb.__version__[0]) >= 2:
          # since xgboost pr#8931
          raise RuntimeError(
              "Use 'rank-binary' instead of 'rank' loss_type with xgboost %s >= 2.0.0"
              % xgb.__version__
          )
  
      for feval in self.fevals:
          bst_eval = model.eval_set(mod_evals, epoch, feval)
          res = [x.split(":") for x in bst_eval.split()]
          for kv in res[1:]:
              res_dict[kv[0]] = [float(kv[1])]
  
      eval_res = []
      keys = list(res_dict.keys())
      keys.sort(
          key=lambda x: x if self.metric_shortname not in x else "a" + x
      )
      for key in keys:
          v = res_dict[key]
          eval_res.append([key] + v)
  
      ##### print eval result #####
      if (
          not isinstance(self.verbose_eval, bool)
          and self.verbose_eval
          and epoch % self.verbose_eval == 0
      ):
          infos = [f"XGB iter: {epoch:3d}"]
          for item in eval_res:
              if "null" in item[0]:
                  continue
              infos.append(f"{item[0]}: {item[1]:.6f}")
  
          logger.debug("\t".join(infos))
          if self.log_file:
              with open(self.log_file, "a") as fout:
                  fout.write("\t".join(infos) + "\n")
  
      ##### choose score and do early stopping #####
      score = None
      for item in eval_res:
          if item[0] == self.metric:
              score = item[1]
              break
      assert score is not None
  
      best_score = self.state["best_score"]
      best_iteration = self.state["best_iteration"]
      maximize_score = self.state["maximize_score"]
  
      if (maximize_score and score > best_score) or (
          not maximize_score and score < best_score
      ):
          msg = f"[{epoch}] " + "\t".join(
              [_fmt_metric(x) for x in eval_res]
          )
          self.state["best_msg"] = msg
          self.state["best_score"] = score
          self.state["best_iteration"] = epoch
          # save the property to attributes, so they will occur in checkpoint.
          if model is not None:
              model.set_attr(
                  best_score=str(self.state["best_score"]),
                  best_iteration=str(self.state["best_iteration"]),
                  best_msg=self.state["best_msg"],
              )
      elif epoch - best_iteration >= self.stopping_rounds:
          best_msg = self.state["best_msg"]
          if self.verbose_eval:
              logger.debug("XGB stopped. Best iteration: %s ", best_msg)
          return True
  
      return False
  
imports: import logging
  import time
  from typing import Dict
  import numpy
  from tvm.contrib.popen_pool import PopenPoolExecutor, StatusKind
  from ..None import feature
  from ..utils import get_rank
  from .metric import cover_curve, max_curve, recall_curve
  from .model_based_tuner import CostModel, FeatureCache
label_desc: Use image node_id 2 for calling the CustomCallback obj's underlying member method code with example usage: obj.after_iteration(model, epoch, evals_log) and returns: False, False, True, value, str, value, value, str, value, value, str, value, str, value