class_docstr: Callback function for early stopping
  
  .. versionadded:: 1.3.0
  
  Parameters
  ----------
  rounds :
      Early stopping rounds.
  metric_name :
      Name of metric that is used for early stopping.
  data_name :
      Name of dataset that is used for early stopping.
  maximize :
      Whether to maximize evaluation metric.  None means auto (discouraged).
  save_best :
      Whether training should return the best model or the last model.
  min_delta :
  
      .. versionadded:: 1.5.0
  
      Minimum absolute change in score to be qualified as an improvement.
  
  Examples
  --------
  
  .. code-block:: python
  
      es = xgboost.callback.EarlyStopping(
          rounds=2,
          min_delta=1e-3,
          save_best=True,
          maximize=False,
          data_name="validation_0",
          metric_name="mlogloss",
      )
      clf = xgboost.XGBClassifier(tree_method="hist", device="cuda", callbacks=[es])
  
      X, y = load_digits(return_X_y=True)
      clf.fit(X, y, eval_set=[(X, y)])
class_docstr_tok: ["Callback","function","for","early","stopping","..","versionadded",":",":","1.3.0","Parameters","--","--","--","--","--","rounds",":","Early","stopping","rounds",".","metric_name",":","Name","of","metric","that","is","used","for","early","stopping",".","data_name",":","Name","of","dataset","that","is","used","for","early","stopping",".","maximize",":","Whether","to","maximize","evaluation","metric",".","None","means","auto","(","discouraged",")",".","save_best",":","Whether","training","should","return","the","best","model","or","the","last","model",".","min_delta",":","..","versionadded",":",":","1.5.0","Minimum","absolute","change","in","score","to","be","qualified","as","an","improvement",".","Examples","--","--","--","--","..","code-block",":",":","python","es","=","xgboost.callback.EarlyStopping","(","rounds=2",",","min_delta=1e-3",",","save_best=True",",","maximize=False",",","data_name=","''","validation_0","''",",","metric_name=","''","mlogloss","''",",",")","clf","=","xgboost.XGBClassifier","(","tree_method=","''","hist","''",",","device=","''","cuda","''",",","callbacks=","[","es","]",")","X",",","y","=","load_digits","(","return_X_y=True",")","clf.fit","(","X",",","y",",","eval_set=","[","(","X",",","y",")","]",")"]
code: def _update_rounds(
      self,
      score: _Score,
      name: str,
      metric: str,
      model: _Model,
      epoch: int,
  ) -> bool:
      def get_s(value: _Score) -> float:
          """get score if it's cross validation history."""
          return value[0] if isinstance(value, tuple) else value
  
      def maximize(new: _Score, best: _Score) -> bool:
          """New score should be greater than the old one."""
          return numpy.greater(
              get_s(new) - self._min_delta, get_s(best)
          )
  
      def minimize(new: _Score, best: _Score) -> bool:
          """New score should be lesser than the old one."""
          return numpy.greater(
              get_s(best) - self._min_delta, get_s(new)
          )
  
      if self.maximize is None:
          # Just to be compatibility with old behavior before 1.3.  We should let
          # user to decide.
          maximize_metrics = (
              "auc",
              "aucpr",
              "pre",
              "pre@",
              "map",
              "ndcg",
              "auc@",
              "aucpr@",
              "map@",
              "ndcg@",
          )
          if metric != "mape" and any(
              metric.startswith(x) for x in maximize_metrics
          ):
              self.maximize = True
          else:
              self.maximize = False
  
      if self.maximize:
          improve_op = maximize
      else:
          improve_op = minimize
  
      if not self.stopping_history:  # First round
          self.current_rounds = 0
          self.stopping_history[name] = {}
          self.stopping_history[name][metric] = cast(
              _ScoreList, [score]
          )
          self.best_scores[name] = {}
          self.best_scores[name][metric] = [score]
          model.set_attr(
              best_score=str(score), best_iteration=str(epoch)
          )
      elif not improve_op(score, self.best_scores[name][metric][-1]):
          # Not improved
          self.stopping_history[name][metric].append(score)  # type: ignore
          self.current_rounds += 1
      else:  # Improved
          self.stopping_history[name][metric].append(score)  # type: ignore
          self.best_scores[name][metric].append(score)
          record = self.stopping_history[name][metric][-1]
          model.set_attr(
              best_score=str(record), best_iteration=str(epoch)
          )
          self.current_rounds = 0  # reset
  
      if self.current_rounds >= self.rounds:
          # Should stop
          return True
      return False
  
imports: import collections
  import os
  import pickle
  from abc import ABC
  from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, TypeVar, Union, cast
  import numpy
  from .None import collective
  from .core import Booster, DMatrix, XGBoostError, _parse_eval_str
label_desc: Use image node_id 3 for calling the EarlyStopping obj's underlying member method code with example usage: obj._update_rounds(score, name, metric, model, epoch) and returns: False, unknown, numpy, numpy, True