class_docstr: Estimator implementation for Image Classification.
  
  Parameters
  ----------
  config : dict
      Config in nested dict.
  logger : logging.Logger
      Optional logger for this estimator, can be `None` when default setting is used.
  reporter : callable
      The reporter for metric checkpointing.
  net : mx.gluon.Block
      The custom network. If defined, the model name in config will be ignored so your
      custom network will be used for training rather than pulling it from model zoo.
class_docstr_tok: ["Estimator","implementation","for","Image","Classification",".","Parameters","--","--","--","--","--","config",":","dict","Config","in","nested","dict",".","logger",":","logging.Logger","Optional","logger","for","this","estimator",",","can","be","`","None","`","when","default","setting","is","used",".","reporter",":","callable","The","reporter","for","metric","checkpointing",".","net",":","mx.gluon.Block","The","custom","network",".","If","defined",",","the","model","name","in","config","will","be","ignored","so","your","custom","network","will","be","used","for","training","rather","than","pulling","it","from","model","zoo","."]
code: def _train_loop(self, train_data, val_data, time_limit=math.inf):
      start_tic = time.time()
      if self._cfg.train.no_wd:
          for k, v in self.net.collect_params(
              ".*beta|.*gamma|.*bias"
          ).items():
              v.wd_mult = 0.0
      if self._cfg.train.label_smoothing or self._cfg.train.mixup:
          sparse_label_loss = False
      else:
          sparse_label_loss = True
      if self.distillation:
          L = loss.DistillationSoftmaxCrossEntropyLoss(
              temperature=self._cfg.train.temperature,
              hard_weight=self._cfg.train.hard_weight,
              sparse_label=sparse_label_loss,
          )
      else:
          L = gluon.loss.SoftmaxCrossEntropyLoss(
              sparse_label=sparse_label_loss
          )
  
      if self._cfg.train.mixup:
          train_metric = mx.metric.RMSE()
      else:
          train_metric = mx.metric.Accuracy()
  
      if self._problem_type == REGRESSION:
          train_metric = mx.metric.RMSE()
          L = gluon.loss.L2Loss()
  
      if self._cfg.train.mode == "hybrid":
          self.net.hybridize(static_alloc=True, static_shape=True)
          if self.distillation:
              self.teacher.hybridize(
                  static_alloc=True, static_shape=True
              )
  
      self._logger.info(
          "Start training from [Epoch %d]",
          max(self._cfg.train.start_epoch, self.epoch),
      )
      early_stopper = EarlyStopperOnPlateau(
          patience=self._cfg.train.early_stop_patience,
          min_delta=self._cfg.train.early_stop_min_delta,
          baseline_value=self._cfg.train.early_stop_baseline,
          max_value=self._cfg.train.early_stop_max_value,
      )
      train_metric_name, train_metric_score = train_metric.get()
      train_metric_score = -float("inf")
      cp_name = ""
      self._time_elapsed += time.time() - start_tic
      for self.epoch in range(
          max(self._cfg.train.start_epoch, self.epoch),
          self._cfg.train.epochs,
      ):
          epoch = self.epoch
          if self._best_acc >= 1.0:
              self._logger.info(
                  "[Epoch {}] Early stopping as acc is reaching 1.0".format(
                      epoch
                  )
              )
              break
          (
              should_stop,
              stop_message,
          ) = early_stopper.get_early_stop_advice()
          if should_stop:
              self._logger.info(
                  "[Epoch {}] ".format(epoch) + stop_message
              )
              break
          tic = time.time()
          last_tic = time.time()
          mx.nd.waitall()
          if self._cfg.train.use_rec:
              train_data.reset()
          train_metric.reset()
  
          # pylint: disable=undefined-loop-variable
          for i, batch in enumerate(train_data):
              btic = time.time()
              if self._time_elapsed > time_limit:
                  self._logger.warning(
                      f"`time_limit={time_limit}` reached, exit early..."
                  )
                  return {
                      "train_acc": train_metric_score,
                      "valid_acc": self._best_acc,
                      "time": self._time_elapsed,
                      "checkpoint": cp_name,
                  }
              data, label = self.batch_fn(batch, self.ctx)
  
              if self._cfg.train.mixup:
                  lam = np.random.beta(
                      self._cfg.train.mixup_alpha,
                      self._cfg.train.mixup_alpha,
                  )
                  if (
                      epoch
                      >= self._cfg.train.epochs
                      - self._cfg.train.mixup_off_epoch
                  ):
                      lam = 1
                  data = [lam * X + (1 - lam) * X[::-1] for X in data]
  
                  if self._cfg.train.label_smoothing:
                      eta = 0.1
                  else:
                      eta = 0.0
                  label = mixup_transform(label, classes, lam, eta)
  
              elif self._cfg.train.label_smoothing:
                  hard_label = label
                  label = smooth(label, self.num_class)
  
              if self.distillation:
                  teacher_prob = [
                      nd.softmax(
                          self.teacher(
                              X.astype(
                                  self._cfg.train.dtype, copy=False
                              )
                          )
                          / self._cfg.train.temperature
                      )
                      for X in data
                  ]
  
              with ag.record():
                  outputs = [
                      self.net(
                          X.astype(self._cfg.train.dtype, copy=False)
                      )
                      for X in data
                  ]
                  if self.distillation:
                      losses = [
                          L(
                              yhat.astype("float32", copy=False),
                              y.astype("float32", copy=False),
                              p.astype("float32", copy=False),
                          )
                          for yhat, y, p in zip(
                              outputs, label, teacher_prob
                          )
                      ]
                  else:
                      losses = [
                          L(
                              yhat,
                              y.astype(
                                  self._cfg.train.dtype, copy=False
                              ),
                          )
                          for yhat, y in zip(outputs, label)
                      ]
              for l in losses:
                  l.backward()
              self.trainer.step(self.batch_size)
  
              if self._cfg.train.mixup:
                  output_softmax = [
                      nd.SoftmaxActivation(
                          out.astype("float32", copy=False)
                      )
                      for out in outputs
                  ]
                  train_metric.update(label, output_softmax)
              else:
                  if self._cfg.train.label_smoothing:
                      train_metric.update(hard_label, outputs)
                  else:
                      train_metric.update(label, outputs)
  
              if (
                  self._cfg.train.log_interval
                  and not (i + 1) % self._cfg.train.log_interval
              ):
                  (
                      train_metric_name,
                      train_metric_score,
                  ) = train_metric.get()
                  self._logger.info(
                      "Epoch[%d] Batch [%d]\tSpeed: %f samples/sec\t%s=%f\tlr=%f",
                      epoch,
                      i,
                      self._cfg.train.batch_size
                      * self._cfg.train.log_interval
                      / (time.time() - last_tic),
                      train_metric_name,
                      train_metric_score,
                      self.trainer.learning_rate,
                  )
                  last_tic = time.time()
              self._time_elapsed += time.time() - btic
  
          post_tic = time.time()
          train_metric_name, train_metric_score = train_metric.get()
          throughput = int(self.batch_size * i / (time.time() - tic))
  
          self._logger.info(
              "[Epoch %d] training: %s=%f",
              epoch,
              train_metric_name,
              train_metric_score,
          )
          self._logger.info(
              "[Epoch %d] speed: %d samples/sec\ttime cost: %f",
              epoch,
              throughput,
              time.time() - tic,
          )
  
          val_score = self._evaluate(
              val_data, metric_name=train_metric_name
          )
          if train_metric_name == "rmse":
              early_stopper.update(-val_score)
              self._logger.info(
                  "[Epoch %d] validation: rmse=%f", epoch, val_score
              )
              if -val_score > self._best_acc:
                  cp_name = os.path.join(
                      self._logdir, _BEST_CHECKPOINT_FILE
                  )
                  self._logger.info(
                      "[Epoch %d] Current best rmse: %f vs previous %f, saved to %s",
                      self.epoch,
                      val_score,
                      -self._best_acc,
                      cp_name,
                  )
                  self.save(cp_name)
                  self._best_acc = -val_score
              if self._reporter:
                  self._reporter(epoch=epoch, acc_reward=-val_score)
          else:
              top1_val, top5_val = val_score
              early_stopper.update(top1_val)
              self._logger.info(
                  "[Epoch %d] validation: top1=%f top5=%f",
                  epoch,
                  top1_val,
                  top5_val,
              )
  
              if top1_val > self._best_acc:
                  cp_name = os.path.join(
                      self._logdir, _BEST_CHECKPOINT_FILE
                  )
                  self._logger.info(
                      "[Epoch %d] Current best top-1: %f vs previous %f, saved to %s",
                      self.epoch,
                      top1_val,
                      self._best_acc,
                      cp_name,
                  )
                  self.save(cp_name)
                  self._best_acc = top1_val
              if self._reporter:
                  self._reporter(epoch=epoch, acc_reward=top1_val)
          self._time_elapsed += time.time() - post_tic
      if (
          train_metric_name == "rmse"
      ):  # TODO: fix ImageClassification(BaseTask)._fit_summary()
          return {
              "train_score": train_metric_score,
              "valid_score": -self._best_acc,
              "time": self._time_elapsed,
              "checkpoint": cp_name,
          }
      else:  # accuracy by default:
          return {
              "train_acc": train_metric_score,
              "valid_acc": self._best_acc,
              "time": self._time_elapsed,
              "checkpoint": cp_name,
          }
  
imports: import time
  import os
  import math
  import copy
  from PIL import Image
  import pandas
  import numpy
  import mxnet
  from mxnet import gluon, nd
  from mxnet.optimizer import Optimizer
  from mxnet import autograd
  from mxnet.gluon.data.vision import transforms
  from ....data.transforms.presets.imagenet import transform_eval
  from ....model_zoo import get_model
  from ....utils import LRSequential, LRScheduler
  from ....None import nn
  from ....None import loss
  from ..base_estimator import BaseEstimator, set_default
  from ..constants import BINARY, MULTICLASS, REGRESSION
  from .utils import get_data_loader, get_data_rec, smooth, mixup_transform
  from .default import ImageClassificationCfg
  from ...data.dataset import ImageClassificationDataset
  from ..conf import _BEST_CHECKPOINT_FILE
  from ..utils import EarlyStopperOnPlateau
label_desc: Use image node_id 4 for calling the ImageClassificationEstimator obj's underlying member method code with example usage: obj._train_loop(train_data, val_data, time_limit) and returns: dict, dict, dict