code: """
      FD-MobileNet for ImageNet-1K, implemented in Gluon.
      Original paper: 'FD-MobileNet: Improved MobileNet with A Fast Downsampling Strategy,'
      https://arxiv.org/abs/1802.03750.
  """
  
  __all__ = ['fdmobilenet_w1', 'fdmobilenet_w3d4', 'fdmobilenet_wd2', 'fdmobilenet_wd4', 'get_fdmobilenet']
  
  import os
  from mxnet import cpu
  from .mobilenet import MobileNet
  
  
  def get_fdmobilenet(width_scale,
                      model_name=None,
                      pretrained=False,
                      ctx=cpu(),
                      root=os.path.join("~", ".mxnet", "models"),
                      **kwargs):
      """
      Create FD-MobileNet model with specific parameters.
  
      Parameters:
      ----------
      width_scale : float
          Scale factor for width of layers.
      model_name : str or None, default None
          Model name for loading pretrained model.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      ctx : Context, default CPU
          The context in which to load the pretrained weights.
      root : str, default '~/.mxnet/models'
          Location for keeping the model parameters.
      """
      channels = [[32], [64], [128, 128], [256, 256], [512, 512, 512, 512, 512, 1024]]
      first_stage_stride = True
  
      if width_scale != 1.0:
          channels = [[int(cij * width_scale) for cij in ci] for ci in channels]
  
      net = MobileNet(
          channels=channels,
          first_stage_stride=first_stage_stride,
          **kwargs)
  
      if pretrained:
          if (model_name is None) or (not model_name):
              raise ValueError("Parameter `model_name` should be properly initialized for loading pretrained model.")
          from .model_store import get_model_file
          net.load_parameters(
              filename=get_model_file(
                  model_name=model_name,
                  local_model_store_dir_path=root),
              ctx=ctx)
  
      return net
  
  
  def fdmobilenet_w1(**kwargs):
      """
      FD-MobileNet 1.0x model from 'FD-MobileNet: Improved MobileNet with A Fast Downsampling Strategy,'
      https://arxiv.org/abs/1802.03750.
  
      Parameters:
      ----------
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      ctx : Context, default CPU
          The context in which to load the pretrained weights.
      root : str, default '~/.mxnet/models'
          Location for keeping the model parameters.
      """
      return get_fdmobilenet(width_scale=1.0, model_name="fdmobilenet_w1", **kwargs)
  
  
  def fdmobilenet_w3d4(**kwargs):
      """
      FD-MobileNet 0.75x model from 'FD-MobileNet: Improved MobileNet with A Fast Downsampling Strategy,'
      https://arxiv.org/abs/1802.03750.
  
      Parameters:
      ----------
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      ctx : Context, default CPU
          The context in which to load the pretrained weights.
      root : str, default '~/.mxnet/models'
          Location for keeping the model parameters.
      """
      return get_fdmobilenet(width_scale=0.75, model_name="fdmobilenet_w3d4", **kwargs)
  
  
  def fdmobilenet_wd2(**kwargs):
      """
      FD-MobileNet 0.5x model from 'FD-MobileNet: Improved MobileNet with A Fast Downsampling Strategy,'
      https://arxiv.org/abs/1802.03750.
  
      Parameters:
      ----------
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      ctx : Context, default CPU
          The context in which to load the pretrained weights.
      root : str, default '~/.mxnet/models'
          Location for keeping the model parameters.
      """
      return get_fdmobilenet(width_scale=0.5, model_name="fdmobilenet_wd2", **kwargs)
  
  
  def fdmobilenet_wd4(**kwargs):
      """
      FD-MobileNet 0.25x model from 'FD-MobileNet: Improved MobileNet with A Fast Downsampling Strategy,'
      https://arxiv.org/abs/1802.03750.
  
      Parameters:
      ----------
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      ctx : Context, default CPU
          The context in which to load the pretrained weights.
      root : str, default '~/.mxnet/models'
          Location for keeping the model parameters.
      """
      return get_fdmobilenet(width_scale=0.25, model_name="fdmobilenet_wd4", **kwargs)
  
  
  def _test():
      import numpy as np
      import mxnet as mx
  
      pretrained = False
  
      models = [
          fdmobilenet_w1,
          fdmobilenet_w3d4,
          fdmobilenet_wd2,
          fdmobilenet_wd4,
      ]
  
      for model in models:
  
          net = model(pretrained=pretrained)
  
          ctx = mx.cpu()
          if not pretrained:
              net.initialize(ctx=ctx)
  
          net_params = net.collect_params()
          weight_count = 0
          for param in net_params.values():
              if (param.shape is None) or (not param._differentiable):
                  continue
              weight_count += np.prod(param.shape)
          print("m={}, {}".format(model.__name__, weight_count))
          assert (model != fdmobilenet_w1 or weight_count == 2901288)
          assert (model != fdmobilenet_w3d4 or weight_count == 1833304)
          assert (model != fdmobilenet_wd2 or weight_count == 993928)
          assert (model != fdmobilenet_wd4 or weight_count == 383160)
  
          x = mx.nd.zeros((1, 3, 224, 224), ctx=ctx)
          y = net(x)
          assert (y.shape == (1, 1000))
  
  
  if __name__ == "__main__":
      _test()
   """
      Script for training model on PyTorch.
  """
  
  import os
  import time
  import logging
  import argparse
  import random
  import numpy as np
  
  import torch.nn as nn
  import torch.backends.cudnn as cudnn
  import torch.utils.data
  
  from common.logger_utils import initialize_logging
  from common.train_log_param_saver import TrainLogParamSaver
  from pytorch.utils import prepare_pt_context, prepare_model, validate
  from pytorch.utils import report_accuracy, get_composite_metric, get_metric_name
  
  from pytorch.dataset_utils import get_dataset_metainfo
  from pytorch.dataset_utils import get_train_data_source, get_val_data_source
  
  
  def add_train_cls_parser_arguments(parser):
      """
      Create python script parameters (for training/classification specific subpart).
  
      Parameters:
      ----------
      parser : ArgumentParser
          ArgumentParser instance.
      """
      parser.add_argument(
          "--model",
          type=str,
          required=True,
          help="type of model to use. see model_provider for options")
      parser.add_argument(
          "--use-pretrained",
          action="store_true",
          help="enable using pretrained model from github repo")
      parser.add_argument(
          "--resume",
          type=str,
          default="",
          help="resume from previously saved parameters if not None")
      parser.add_argument(
          "--resume-state",
          type=str,
          default="",
          help="resume from previously saved optimizer state if not None")
  
      parser.add_argument(
          "--num-gpus",
          type=int,
          default=0,
          help="number of gpus to use")
      parser.add_argument(
          "-j",
          "--num-data-workers",
          dest="num_workers",
          default=4,
          type=int,
          help="number of preprocessing workers")
  
      parser.add_argument(
          "--batch-size",
          type=int,
          default=512,
          help="training batch size per device (CPU/GPU)")
      parser.add_argument(
          "--batch-size-scale",
          type=int,
          default=1,
          help="manual batch-size increasing factor")
      parser.add_argument(
          "--num-epochs",
          type=int,
          default=120,
          help="number of training epochs")
      parser.add_argument(
          "--start-epoch",
          type=int,
          default=1,
          help="starting epoch for resuming, default is 1 for new training")
      parser.add_argument(
          "--attempt",
          type=int,
          default=1,
          help="current attempt number for training")
  
      parser.add_argument(
          "--optimizer-name",
          type=str,
          default="nag",
          help="optimizer name")
      parser.add_argument(
          "--lr",
          type=float,
          default=0.1,
          help="learning rate")
      parser.add_argument(
          "--lr-mode",
          type=str,
          default="cosine",
          help="learning rate scheduler mode. options are step, poly and cosine")
      parser.add_argument(
          "--lr-decay",
          type=float,
          default=0.1,
          help="decay rate of learning rate")
      parser.add_argument(
          "--lr-decay-period",
          type=int,
          default=0,
          help="interval for periodic learning rate decays. default is 0 to disable")
      parser.add_argument(
          "--lr-decay-epoch",
          type=str,
          default="40,60",
          help="epoches at which learning rate decays")
      parser.add_argument(
          "--target-lr",
          type=float,
          default=1e-8,
          help="ending learning rate")
      parser.add_argument(
          "--poly-power",
          type=float,
          default=2,
          help="power value for poly LR scheduler")
      parser.add_argument(
          "--warmup-epochs",
          type=int,
          default=0,
          help="number of warmup epochs")
      parser.add_argument(
          "--warmup-lr",
          type=float,
          default=1e-8,
          help="starting warmup learning rate")
      parser.add_argument(
          "--warmup-mode",
          type=str,
          default="linear",
          help="learning rate scheduler warmup mode. options are linear, poly and constant")
      parser.add_argument(
          "--momentum",
          type=float,
          default=0.9,
          help="momentum value for optimizer")
      parser.add_argument(
          "--wd",
          type=float,
          default=0.0001,
          help="weight decay rate")
      parser.add_argument(
          "--gamma-wd-mult",
          type=float,
          default=1.0,
          help="weight decay multiplier for batchnorm gamma")
      parser.add_argument(
          "--beta-wd-mult",
          type=float,
          default=1.0,
          help="weight decay multiplier for batchnorm beta")
      parser.add_argument(
          "--bias-wd-mult",
          type=float,
          default=1.0,
          help="weight decay multiplier for bias")
      parser.add_argument(
          "--grad-clip",
          type=float,
          default=None,
          help="max_norm for gradient clipping")
      parser.add_argument(
          "--label-smoothing",
          action="store_true",
          help="use label smoothing")
  
      parser.add_argument(
          "--mixup",
          action="store_true",
          help="use mixup strategy")
      parser.add_argument(
          "--mixup-epoch-tail",
          type=int,
          default=15,
          help="number of epochs without mixup at the end of training")
  
      parser.add_argument(
          "--log-interval",
          type=int,
          default=50,
          help="number of batches to wait before logging")
      parser.add_argument(
          "--save-interval",
          type=int,
          default=4,
          help="saving parameters epoch interval, best model will always be saved")
      parser.add_argument(
          "--save-dir",
          type=str,
          default="",
          help="directory of saved models and log-files")
      parser.add_argument(
          "--logging-file-name",
          type=str,
          default="train.log",
          help="filename of training log")
  
      parser.add_argument(
          "--seed",
          type=int,
          default=-1,
          help="Random seed to be fixed")
      parser.add_argument(
          "--log-packages",
          type=str,
          default="torch, torchvision",
          help="list of python packages for logging")
      parser.add_argument(
          "--log-pip-packages",
          type=str,
          default="",
          help="list of pip packages for logging")
  
      parser.add_argument(
          "--tune-layers",
          type=str,
          default="",
          help="regexp for selecting layers for fine tuning")
  
  
  def parse_args():
      """
      Parse python script parameters (common part).
  
      Returns:
      -------
      ArgumentParser
          Resulted args.
      """
      parser = argparse.ArgumentParser(
          description="Train a model for image classification (PyTorch)",
          formatter_class=argparse.ArgumentDefaultsHelpFormatter)
      parser.add_argument(
          "--dataset",
          type=str,
          default="ImageNet1K",
          help="dataset name. options are ImageNet1K, CUB200_2011, CIFAR10, CIFAR100, SVHN")
      parser.add_argument(
          "--work-dir",
          type=str,
          default=os.path.join("..", "imgclsmob_data"),
          help="path to working directory only for dataset root path preset")
  
      args, _ = parser.parse_known_args()
      dataset_metainfo = get_dataset_metainfo(dataset_name=args.dataset)
      dataset_metainfo.add_dataset_parser_arguments(
          parser=parser,
          work_dir_path=args.work_dir)
  
      add_train_cls_parser_arguments(parser)
  
      args = parser.parse_args()
      return args
  
  
  def init_rand(seed):
      """
      Initialize all random generators by seed.
  
      Parameters:
      ----------
      seed : int
          Seed value.
  
      Returns:
      -------
      int
          Generated seed value.
      """
      if seed <= 0:
          seed = np.random.randint(10000)
      else:
          cudnn.deterministic = True
          logging.warning(
              "You have chosen to seed training. This will turn on the CUDNN deterministic setting, which can slow down "
              "your training considerably! You may see unexpected behavior when restarting from checkpoints.")
      random.seed(seed)
      np.random.seed(seed)
      torch.manual_seed(seed)
      return seed
  
  
  def prepare_trainer(net,
                      optimizer_name,
                      wd,
                      momentum,
                      lr_mode,
                      lr,
                      lr_decay_period,
                      lr_decay_epoch,
                      lr_decay,
                      num_epochs,
                      state_file_path):
      """
      Prepare trainer.
  
      Parameters:
      ----------
      net : Module
          Model.
      optimizer_name : str
          Name of optimizer.
      wd : float
          Weight decay rate.
      momentum : float
          Momentum value.
      lr_mode : str
          Learning rate scheduler mode.
      lr : float
          Learning rate.
      lr_decay_period : int
          Interval for periodic learning rate decays.
      lr_decay_epoch : str
          Epoches at which learning rate decays.
      lr_decay : float
          Decay rate of learning rate.
      num_epochs : int
          Number of training epochs.
      state_file_path : str
          Path for file with trainer state.
  
      Returns:
      -------
      Optimizer
          Optimizer.
      LRScheduler
          Learning rate scheduler.
      int
          Start epoch.
      """
      optimizer_name = optimizer_name.lower()
      if (optimizer_name == "sgd") or (optimizer_name == "nag"):
          optimizer = torch.optim.SGD(
              params=net.parameters(),
              lr=lr,
              momentum=momentum,
              weight_decay=wd,
              nesterov=(optimizer_name == "nag"))
      else:
          raise ValueError("Usupported optimizer: {}".format(optimizer_name))
  
      if state_file_path:
          checkpoint = torch.load(state_file_path)
          if type(checkpoint) == dict:
              optimizer.load_state_dict(checkpoint["optimizer"])
              start_epoch = checkpoint["epoch"]
          else:
              start_epoch = None
      else:
          start_epoch = None
  
      cudnn.benchmark = True
  
      lr_mode = lr_mode.lower()
      if lr_decay_period > 0:
          lr_decay_epoch = list(range(lr_decay_period, num_epochs, lr_decay_period))
      else:
          lr_decay_epoch = [int(i) for i in lr_decay_epoch.split(",")]
      if (lr_mode == "step") and (lr_decay_period != 0):
          lr_scheduler = torch.optim.lr_scheduler.StepLR(
              optimizer=optimizer,
              step_size=lr_decay_period,
              gamma=lr_decay,
              last_epoch=-1)
      elif (lr_mode == "multistep") or ((lr_mode == "step") and (lr_decay_period == 0)):
          lr_scheduler = torch.optim.lr_scheduler.MultiStepLR(
              optimizer=optimizer,
              milestones=lr_decay_epoch,
              gamma=lr_decay,
              last_epoch=-1)
      elif lr_mode == "cosine":
          for group in optimizer.param_groups:
              group.setdefault("initial_lr", group["lr"])
          lr_scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(
              optimizer=optimizer,
              T_max=num_epochs,
              last_epoch=(num_epochs - 1))
      else:
          raise ValueError("Usupported lr_scheduler: {}".format(lr_mode))
  
      return optimizer, lr_scheduler, start_epoch
  
  
  def save_params(file_stem,
                  state):
      """
      Save current model/trainer parameters.
  
      Parameters:
      ----------
      file_stem : str
          File stem (with path).
      state : dict
          Whole state of model & trainer.
      trainer : Trainer
          Trainer.
      """
      torch.save(
          obj=state["state_dict"],
          f=(file_stem + ".pth"))
      torch.save(
          obj=state,
          f=(file_stem + ".states"))
  
  
  def train_epoch(epoch,
                  net,
                  train_metric,
                  train_data,
                  use_cuda,
                  L,
                  optimizer,
                  # lr_scheduler,
                  batch_size,
                  log_interval):
      """
      Train model on particular epoch.
  
      Parameters:
      ----------
      epoch : int
          Epoch number.
      net : Module
          Model.
      train_metric : EvalMetric
          Metric object instance.
      train_data : DataLoader
          Data loader.
      use_cuda : bool
          Whether to use CUDA.
      L : Loss
          Loss function.
      optimizer : Optimizer
          Optimizer.
      batch_size : int
          Training batch size.
      log_interval : int
          Batch count period for logging.
  
      Returns:
      -------
      float
          Loss value.
      """
      tic = time.time()
      net.train()
      train_metric.reset()
      train_loss = 0.0
  
      btic = time.time()
      for i, (data, target) in enumerate(train_data):
          if use_cuda:
              data = data.cuda(non_blocking=True)
              target = target.cuda(non_blocking=True)
          output = net(data)
          loss = L(output, target)
          optimizer.zero_grad()
          loss.backward()
          optimizer.step()
  
          train_loss += loss.item()
  
          train_metric.update(
              labels=target,
              preds=output)
  
          if log_interval and not (i + 1) % log_interval:
              speed = batch_size * log_interval / (time.time() - btic)
              btic = time.time()
              train_accuracy_msg = report_accuracy(metric=train_metric)
              logging.info("Epoch[{}] Batch [{}]\tSpeed: {:.2f} samples/sec\t{}\tlr={:.5f}".format(
                  epoch + 1, i, speed, train_accuracy_msg, optimizer.param_groups[0]["lr"]))
  
      throughput = int(batch_size * (i + 1) / (time.time() - tic))
      logging.info("[Epoch {}] speed: {:.2f} samples/sec\ttime cost: {:.2f} sec".format(
          epoch + 1, throughput, time.time() - tic))
  
      train_loss /= (i + 1)
      train_accuracy_msg = report_accuracy(metric=train_metric)
      logging.info("[Epoch {}] training: {}\tloss={:.4f}".format(
          epoch + 1, train_accuracy_msg, train_loss))
  
      return train_loss
  
  
  def train_net(batch_size,
                num_epochs,
                start_epoch1,
                train_data,
                val_data,
                net,
                optimizer,
                lr_scheduler,
                lp_saver,
                log_interval,
                num_classes,
                val_metric,
                train_metric,
                use_cuda):
      """
      Main procedure for training model.
  
      Parameters:
      ----------
      batch_size : int
          Training batch size.
      num_epochs : int
          Number of training epochs.
      start_epoch1 : int
          Number of starting epoch (1-based).
      train_data : DataLoader
          Data loader (training subset).
      val_data : DataLoader
          Data loader (validation subset).
      net : Module
          Model.
      optimizer : Optimizer
          Optimizer.
      lr_scheduler : LRScheduler
          Learning rate scheduler.
      lp_saver : TrainLogParamSaver
          Model/trainer state saver.
      log_interval : int
          Batch count period for logging.
      num_classes : int
          Number of model classes.
      val_metric : EvalMetric
          Metric object instance (validation subset).
      train_metric : EvalMetric
          Metric object instance (training subset).
      use_cuda : bool
          Whether to use CUDA.
      """
      assert (num_classes > 0)
  
      L = nn.CrossEntropyLoss()
      if use_cuda:
          L = L.cuda()
  
      assert (type(start_epoch1) == int)
      assert (start_epoch1 >= 1)
      if start_epoch1 > 1:
          logging.info("Start training from [Epoch {}]".format(start_epoch1))
          validate(
              metric=val_metric,
              net=net,
              val_data=val_data,
              use_cuda=use_cuda)
          val_accuracy_msg = report_accuracy(metric=val_metric)
          logging.info("[Epoch {}] validation: {}".format(start_epoch1 - 1, val_accuracy_msg))
  
      gtic = time.time()
      for epoch in range(start_epoch1 - 1, num_epochs):
          lr_scheduler.step()
  
          train_loss = train_epoch(
              epoch=epoch,
              net=net,
              train_metric=train_metric,
              train_data=train_data,
              use_cuda=use_cuda,
              L=L,
              optimizer=optimizer,
              # lr_scheduler,
              batch_size=batch_size,
              log_interval=log_interval)
  
          validate(
              metric=val_metric,
              net=net,
              val_data=val_data,
              use_cuda=use_cuda)
          val_accuracy_msg = report_accuracy(metric=val_metric)
          logging.info("[Epoch {}] validation: {}".format(epoch + 1, val_accuracy_msg))
  
          if lp_saver is not None:
              state = {
                  "epoch": epoch + 1,
                  "state_dict": net.state_dict(),
                  "optimizer": optimizer.state_dict(),
              }
              lp_saver_kwargs = {"state": state}
              val_acc_values = val_metric.get()[1]
              train_acc_values = train_metric.get()[1]
              val_acc_values = val_acc_values if type(val_acc_values) == list else [val_acc_values]
              train_acc_values = train_acc_values if type(train_acc_values) == list else [train_acc_values]
              lp_saver.epoch_test_end_callback(
                  epoch1=(epoch + 1),
                  params=(val_acc_values + train_acc_values + [train_loss, optimizer.param_groups[0]["lr"]]),
                  **lp_saver_kwargs)
  
      logging.info("Total time cost: {:.2f} sec".format(time.time() - gtic))
      if lp_saver is not None:
          opt_metric_name = get_metric_name(val_metric, lp_saver.acc_ind)
          logging.info("Best {}: {:.4f} at {} epoch".format(
              opt_metric_name, lp_saver.best_eval_metric_value, lp_saver.best_eval_metric_epoch))
  
  
  def main():
      """
      Main body of script.
      """
      args = parse_args()
      args.seed = init_rand(seed=args.seed)
  
      _, log_file_exist = initialize_logging(
          logging_dir_path=args.save_dir,
          logging_file_name=args.logging_file_name,
          script_args=args,
          log_packages=args.log_packages,
          log_pip_packages=args.log_pip_packages)
  
      use_cuda, batch_size = prepare_pt_context(
          num_gpus=args.num_gpus,
          batch_size=args.batch_size)
  
      net = prepare_model(
          model_name=args.model,
          use_pretrained=args.use_pretrained,
          pretrained_model_file_path=args.resume.strip(),
          use_cuda=use_cuda)
      real_net = net.module if hasattr(net, "module") else net
      assert (hasattr(real_net, "num_classes"))
      num_classes = real_net.num_classes
  
      ds_metainfo = get_dataset_metainfo(dataset_name=args.dataset)
      ds_metainfo.update(args=args)
  
      train_data = get_train_data_source(
          ds_metainfo=ds_metainfo,
          batch_size=batch_size,
          num_workers=args.num_workers)
      val_data = get_val_data_source(
          ds_metainfo=ds_metainfo,
          batch_size=batch_size,
          num_workers=args.num_workers)
  
      optimizer, lr_scheduler, start_epoch = prepare_trainer(
          net=net,
          optimizer_name=args.optimizer_name,
          wd=args.wd,
          momentum=args.momentum,
          lr_mode=args.lr_mode,
          lr=args.lr,
          lr_decay_period=args.lr_decay_period,
          lr_decay_epoch=args.lr_decay_epoch,
          lr_decay=args.lr_decay,
          num_epochs=args.num_epochs,
          state_file_path=args.resume_state)
  
      if args.save_dir and args.save_interval:
          param_names = ds_metainfo.val_metric_capts + ds_metainfo.train_metric_capts + ["Train.Loss", "LR"]
          lp_saver = TrainLogParamSaver(
              checkpoint_file_name_prefix="{}_{}".format(ds_metainfo.short_label, args.model),
              last_checkpoint_file_name_suffix="last",
              best_checkpoint_file_name_suffix=None,
              last_checkpoint_dir_path=args.save_dir,
              best_checkpoint_dir_path=None,
              last_checkpoint_file_count=2,
              best_checkpoint_file_count=2,
              checkpoint_file_save_callback=save_params,
              checkpoint_file_exts=(".pth", ".states"),
              save_interval=args.save_interval,
              num_epochs=args.num_epochs,
              param_names=param_names,
              acc_ind=ds_metainfo.saver_acc_ind,
              # bigger=[True],
              # mask=None,
              score_log_file_path=os.path.join(args.save_dir, "score.log"),
              score_log_attempt_value=args.attempt,
              best_map_log_file_path=os.path.join(args.save_dir, "best_map.log"))
      else:
          lp_saver = None
  
      train_net(
          batch_size=batch_size,
          num_epochs=args.num_epochs,
          start_epoch1=args.start_epoch,
          train_data=train_data,
          val_data=val_data,
          net=net,
          optimizer=optimizer,
          lr_scheduler=lr_scheduler,
          lp_saver=lp_saver,
          log_interval=args.log_interval,
          num_classes=num_classes,
          val_metric=get_composite_metric(ds_metainfo.val_metric_names, ds_metainfo.val_metric_extra_kwargs),
          train_metric=get_composite_metric(ds_metainfo.train_metric_names, ds_metainfo.train_metric_extra_kwargs),
          use_cuda=use_cuda)
  
  
  if __name__ == "__main__":
      main()
   """
      Script for training model on Keras.
  """
  
  import argparse
  import time
  import logging
  import os
  import numpy as np
  import random
  import keras
  from keras.models import load_model
  from keras.callbacks import ModelCheckpoint
  import mxnet as mx
  from common.logger_utils import initialize_logging
  from keras_.utils import prepare_ke_context, prepare_model, get_data_rec, get_data_generator, backend_agnostic_compile
  
  
  def parse_args():
      """
      Parse python script parameters.
  
      Returns:
      -------
      ArgumentParser
          Resulted args.
      """
      parser = argparse.ArgumentParser(
          description="Train a model for image classification (Keras)",
          formatter_class=argparse.ArgumentDefaultsHelpFormatter)
      parser.add_argument(
          "--rec-train",
          type=str,
          default="../imgclsmob_data/imagenet_rec/train.rec",
          help="the training data")
      parser.add_argument(
          "--rec-train-idx",
          type=str,
          default="../imgclsmob_data/imagenet_rec/train.idx",
          help='the index of training data')
      parser.add_argument(
          "--rec-val",
          type=str,
          default="../imgclsmob_data/imagenet_rec/val.rec",
          help="the validation data")
      parser.add_argument(
          "--rec-val-idx",
          type=str,
          default="../imgclsmob_data/imagenet_rec/val.idx",
          help="the index of validation data")
  
      parser.add_argument(
          "--model",
          type=str,
          required=True,
          help="type of model to use. see model_provider for options")
      parser.add_argument(
          "--use-pretrained",
          action="store_true",
          help="enable using pretrained model from github repo")
      parser.add_argument(
          "--dtype",
          type=str,
          default="float32",
          help="data type for training")
      parser.add_argument(
          "--resume",
          type=str,
          default="",
          help="resume from previously saved parameters if not None")
      parser.add_argument(
          "--resume-state",
          type=str,
          default="",
          help="resume from previously saved optimizer state if not None")
  
      parser.add_argument(
          "--input-size",
          type=int,
          default=224,
          help="size of the input for model")
      parser.add_argument(
          "--resize-inv-factor",
          type=float,
          default=0.875,
          help="inverted ratio for input image crop")
  
      parser.add_argument(
          "--num-gpus",
          type=int,
          default=0,
          help="number of gpus to use")
      parser.add_argument(
          "-j",
          "--num-data-workers",
          dest="num_workers",
          default=4,
          type=int,
          help="number of preprocessing workers")
  
      parser.add_argument(
          "--batch-size",
          type=int,
          default=512,
          help="training batch size per device (CPU/GPU)")
      parser.add_argument(
          "--num-epochs",
          type=int,
          default=120,
          help="number of training epochs")
      parser.add_argument(
          "--start-epoch",
          type=int,
          default=1,
          help="starting epoch for resuming, default is 1 for new training")
      parser.add_argument(
          "--attempt",
          type=int,
          default=1,
          help="current number of training")
  
      parser.add_argument(
          "--optimizer-name",
          type=str,
          default="nag",
          help="optimizer name")
      parser.add_argument(
          "--lr",
          type=float,
          default=0.1,
          help="learning rate")
      parser.add_argument(
          "--momentum",
          type=float,
          default=0.9,
          help="momentum value for optimizer")
      parser.add_argument(
          "--wd",
          type=float,
          default=0.0001,
          help="weight decay rate")
  
      parser.add_argument(
          "--log-interval",
          type=int,
          default=50,
          help="number of batches to wait before logging")
      parser.add_argument(
          "--save-interval",
          type=int,
          default=4,
          help="saving parameters epoch interval, best model will always be saved")
      parser.add_argument(
          "--save-dir",
          type=str,
          default="",
          help="directory of saved models and log-files")
      parser.add_argument(
          "--logging-file-name",
          type=str,
          default="train.log",
          help="filename of training log")
  
      parser.add_argument(
          "--seed",
          type=int,
          default=-1,
          help="Random seed to be fixed")
      parser.add_argument(
          "--log-packages",
          type=str,
          default="keras",
          help="list of python packages for logging")
      parser.add_argument(
          "--log-pip-packages",
          type=str,
          default="keras, keras-mxnet, keras-applications, keras-preprocessing",
          help="list of pip packages for logging")
      args = parser.parse_args()
      return args
  
  
  def init_rand(seed):
      if seed <= 0:
          seed = np.random.randint(10000)
      random.seed(seed)
      np.random.seed(seed)
      mx.random.seed(seed)
      return seed
  
  
  def prepare_trainer(net,
                      optimizer_name,
                      momentum,
                      lr,
                      num_gpus,
                      state_file_path=None):
  
      optimizer_name = optimizer_name.lower()
      if (optimizer_name == "sgd") or (optimizer_name == "nag"):
          optimizer = keras.optimizers.SGD(
              lr=lr,
              momentum=momentum,
              nesterov=(optimizer_name == "nag"))
      else:
          raise ValueError("Usupported optimizer: {}".format(optimizer_name))
  
      backend_agnostic_compile(
          model=net,
          loss="categorical_crossentropy",
          optimizer=optimizer,
          metrics=[keras.metrics.categorical_accuracy, keras.metrics.top_k_categorical_accuracy],
          num_gpus=num_gpus)
  
      if (state_file_path is not None) and state_file_path and os.path.exists(state_file_path):
          net = load_model(filepath=state_file_path)
      return net
  
  
  def train_net(net,
                train_gen,
                val_gen,
                train_num_examples,
                val_num_examples,
                num_epochs,
                checkpoint_filepath,
                start_epoch1):
      checkpointer = ModelCheckpoint(
          filepath=checkpoint_filepath,
          verbose=1,
          save_best_only=True)
  
      tic = time.time()
  
      net.fit_generator(
          generator=train_gen,
          samples_per_epoch=train_num_examples,
          epochs=num_epochs,
          verbose=True,
          callbacks=[checkpointer],
          validation_data=val_gen,
          validation_steps=val_num_examples,
          class_weight=None,
          max_queue_size=10,
          workers=1,
          use_multiprocessing=False,
          shuffle=True,
          initial_epoch=(start_epoch1 - 1))
  
      logging.info("Time cost: {:.4f} sec".format(
          time.time() - tic))
  
  
  def main():
      """
      Main body of script.
      """
      args = parse_args()
      args.seed = init_rand(seed=args.seed)
  
      _, log_file_exist = initialize_logging(
          logging_dir_path=args.save_dir,
          logging_file_name=args.logging_file_name,
          script_args=args,
          log_packages=args.log_packages,
          log_pip_packages=args.log_pip_packages)
  
      batch_size = prepare_ke_context(
          num_gpus=args.num_gpus,
          batch_size=args.batch_size)
  
      net = prepare_model(
          model_name=args.model,
          use_pretrained=args.use_pretrained,
          pretrained_model_file_path=args.resume.strip())
      num_classes = net.classes if hasattr(net, "classes") else 1000
      input_image_size = net.in_size if hasattr(net, "in_size") else (args.input_size, args.input_size)
  
      train_data, val_data = get_data_rec(
          rec_train=args.rec_train,
          rec_train_idx=args.rec_train_idx,
          rec_val=args.rec_val,
          rec_val_idx=args.rec_val_idx,
          batch_size=batch_size,
          num_workers=args.num_workers,
          input_image_size=input_image_size,
          resize_inv_factor=args.resize_inv_factor)
      train_gen = get_data_generator(
          data_iterator=train_data,
          num_classes=num_classes)
      val_gen = get_data_generator(
          data_iterator=val_data,
          num_classes=num_classes)
  
      net = prepare_trainer(
          net=net,
          optimizer_name=args.optimizer_name,
          momentum=args.momentum,
          lr=args.lr,
          num_gpus=args.num_gpus,
          state_file_path=args.resume_state)
  
      train_net(
          net=net,
          train_gen=train_gen,
          val_gen=val_gen,
          train_num_examples=1281167,
          val_num_examples=50048,
          num_epochs=args.num_epochs,
          checkpoint_filepath=os.path.join(args.save_dir, "imagenet_{}.h5".format(args.model)),
          start_epoch1=args.start_epoch)
  
  
  if __name__ == "__main__":
      main()
   """
      SE-ResNet for CIFAR/SVHN, implemented in Chainer.
      Original paper: 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  """
  
  __all__ = ['CIFARSEResNet', 'seresnet20_cifar10', 'seresnet20_cifar100', 'seresnet20_svhn',
             'seresnet56_cifar10', 'seresnet56_cifar100', 'seresnet56_svhn',
             'seresnet110_cifar10', 'seresnet110_cifar100', 'seresnet110_svhn',
             'seresnet164bn_cifar10', 'seresnet164bn_cifar100', 'seresnet164bn_svhn',
             'seresnet272bn_cifar10', 'seresnet272bn_cifar100', 'seresnet272bn_svhn',
             'seresnet542bn_cifar10', 'seresnet542bn_cifar100', 'seresnet542bn_svhn',
             'seresnet1001_cifar10', 'seresnet1001_cifar100', 'seresnet1001_svhn',
             'seresnet1202_cifar10', 'seresnet1202_cifar100', 'seresnet1202_svhn']
  
  import os
  import chainer.functions as F
  import chainer.links as L
  from chainer import Chain
  from functools import partial
  from chainer.serializers import load_npz
  from .common import conv3x3_block, SimpleSequential
  from .seresnet import SEResUnit
  
  
  class CIFARSEResNet(Chain):
      """
      SE-ResNet model for CIFAR from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      channels : list of list of int
          Number of output channels for each unit.
      init_block_channels : int
          Number of output channels for the initial unit.
      bottleneck : bool
          Whether to use a bottleneck or simple block in units.
      in_channels : int, default 3
          Number of input channels.
      in_size : tuple of two ints, default (32, 32)
          Spatial size of the expected input image.
      classes : int, default 10
          Number of classification classes.
      """
      def __init__(self,
                   channels,
                   init_block_channels,
                   bottleneck,
                   in_channels=3,
                   in_size=(32, 32),
                   classes=10):
          super(CIFARSEResNet, self).__init__()
          self.in_size = in_size
          self.classes = classes
  
          with self.init_scope():
              self.features = SimpleSequential()
              with self.features.init_scope():
                  setattr(self.features, "init_block", conv3x3_block(
                      in_channels=in_channels,
                      out_channels=init_block_channels))
                  in_channels = init_block_channels
                  for i, channels_per_stage in enumerate(channels):
                      stage = SimpleSequential()
                      with stage.init_scope():
                          for j, out_channels in enumerate(channels_per_stage):
                              stride = 2 if (j == 0) and (i != 0) else 1
                              setattr(stage, "unit{}".format(j + 1), SEResUnit(
                                  in_channels=in_channels,
                                  out_channels=out_channels,
                                  stride=stride,
                                  bottleneck=bottleneck,
                                  conv1_stride=False))
                              in_channels = out_channels
                      setattr(self.features, "stage{}".format(i + 1), stage)
                  setattr(self.features, "final_pool", partial(
                      F.average_pooling_2d,
                      ksize=8,
                      stride=1))
  
              self.output = SimpleSequential()
              with self.output.init_scope():
                  setattr(self.output, "flatten", partial(
                      F.reshape,
                      shape=(-1, in_channels)))
                  setattr(self.output, "fc", L.Linear(
                      in_size=in_channels,
                      out_size=classes))
  
      def __call__(self, x):
          x = self.features(x)
          x = self.output(x)
          return x
  
  
  def get_seresnet_cifar(classes,
                         blocks,
                         bottleneck,
                         model_name=None,
                         pretrained=False,
                         root=os.path.join("~", ".chainer", "models"),
                         **kwargs):
      """
      Create SE-ResNet model for CIFAR with specific parameters.
  
      Parameters:
      ----------
      classes : int
          Number of classification classes.
      blocks : int
          Number of blocks.
      bottleneck : bool
          Whether to use a bottleneck or simple block in units.
      model_name : str or None, default None
          Model name for loading pretrained model.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      assert (classes in [10, 100])
  
      if bottleneck:
          assert ((blocks - 2) % 9 == 0)
          layers = [(blocks - 2) // 9] * 3
      else:
          assert ((blocks - 2) % 6 == 0)
          layers = [(blocks - 2) // 6] * 3
  
      channels_per_layers = [16, 32, 64]
      init_block_channels = 16
  
      channels = [[ci] * li for (ci, li) in zip(channels_per_layers, layers)]
  
      if bottleneck:
          channels = [[cij * 4 for cij in ci] for ci in channels]
  
      net = CIFARSEResNet(
          channels=channels,
          init_block_channels=init_block_channels,
          bottleneck=bottleneck,
          classes=classes,
          **kwargs)
  
      if pretrained:
          if (model_name is None) or (not model_name):
              raise ValueError("Parameter `model_name` should be properly initialized for loading pretrained model.")
          from .model_store import get_model_file
          load_npz(
              file=get_model_file(
                  model_name=model_name,
                  local_model_store_dir_path=root),
              obj=net)
  
      return net
  
  
  def seresnet20_cifar10(classes=10, **kwargs):
      """
      SE-ResNet-20 model for CIFAR-10 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=20, bottleneck=False, model_name="seresnet20_cifar10", **kwargs)
  
  
  def seresnet20_cifar100(classes=100, **kwargs):
      """
      SE-ResNet-20 model for CIFAR-100 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 100
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=20, bottleneck=False, model_name="seresnet20_cifar100", **kwargs)
  
  
  def seresnet20_svhn(classes=10, **kwargs):
      """
      SE-ResNet-20 model for SVHN from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=20, bottleneck=False, model_name="seresnet20_svhn", **kwargs)
  
  
  def seresnet56_cifar10(classes=10, **kwargs):
      """
      SE-ResNet-56 model for CIFAR-10 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=56, bottleneck=False, model_name="seresnet56_cifar10", **kwargs)
  
  
  def seresnet56_cifar100(classes=100, **kwargs):
      """
      SE-ResNet-56 model for CIFAR-100 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 100
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=56, bottleneck=False, model_name="seresnet56_cifar100", **kwargs)
  
  
  def seresnet56_svhn(classes=10, **kwargs):
      """
      SE-ResNet-56 model for SVHN from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=56, bottleneck=False, model_name="seresnet56_svhn", **kwargs)
  
  
  def seresnet110_cifar10(classes=10, **kwargs):
      """
      SE-ResNet-110 model for CIFAR-10 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=110, bottleneck=False, model_name="seresnet110_cifar10", **kwargs)
  
  
  def seresnet110_cifar100(classes=100, **kwargs):
      """
      SE-ResNet-110 model for CIFAR-100 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 100
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=110, bottleneck=False, model_name="seresnet110_cifar100",
                                **kwargs)
  
  
  def seresnet110_svhn(classes=10, **kwargs):
      """
      SE-ResNet-110 model for SVHN from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=110, bottleneck=False, model_name="seresnet110_svhn", **kwargs)
  
  
  def seresnet164bn_cifar10(classes=10, **kwargs):
      """
      SE-ResNet-164(BN) model for CIFAR-10 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=164, bottleneck=True, model_name="seresnet164bn_cifar10",
                                **kwargs)
  
  
  def seresnet164bn_cifar100(classes=100, **kwargs):
      """
      SE-ResNet-164(BN) model for CIFAR-100 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 100
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=164, bottleneck=True, model_name="seresnet164bn_cifar100",
                                **kwargs)
  
  
  def seresnet164bn_svhn(classes=10, **kwargs):
      """
      SE-ResNet-164(BN) model for SVHN from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=164, bottleneck=True, model_name="seresnet164bn_svhn", **kwargs)
  
  
  def seresnet272bn_cifar10(classes=10, **kwargs):
      """
      SE-ResNet-272(BN) model for CIFAR-10 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=272, bottleneck=True, model_name="seresnet272bn_cifar10",
                                **kwargs)
  
  
  def seresnet272bn_cifar100(classes=100, **kwargs):
      """
      SE-ResNet-272(BN) model for CIFAR-100 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 100
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=272, bottleneck=True, model_name="seresnet272bn_cifar100",
                                **kwargs)
  
  
  def seresnet272bn_svhn(classes=10, **kwargs):
      """
      SE-ResNet-272(BN) model for SVHN from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=272, bottleneck=True, model_name="seresnet272bn_svhn", **kwargs)
  
  
  def seresnet542bn_cifar10(classes=10, **kwargs):
      """
      SE-ResNet-542(BN) model for CIFAR-10 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=542, bottleneck=True, model_name="seresnet542bn_cifar10",
                                **kwargs)
  
  
  def seresnet542bn_cifar100(classes=100, **kwargs):
      """
      SE-ResNet-542(BN) model for CIFAR-100 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 100
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=542, bottleneck=True, model_name="seresnet542bn_cifar100",
                                **kwargs)
  
  
  def seresnet542bn_svhn(classes=10, **kwargs):
      """
      SE-ResNet-542(BN) model for SVHN from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=542, bottleneck=True, model_name="seresnet542bn_svhn", **kwargs)
  
  
  def seresnet1001_cifar10(classes=10, **kwargs):
      """
      SE-ResNet-1001 model for CIFAR-10 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=1001, bottleneck=True, model_name="seresnet1001_cifar10",
                                **kwargs)
  
  
  def seresnet1001_cifar100(classes=100, **kwargs):
      """
      SE-ResNet-1001 model for CIFAR-100 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 100
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=1001, bottleneck=True, model_name="seresnet1001_cifar100",
                                **kwargs)
  
  
  def seresnet1001_svhn(classes=10, **kwargs):
      """
      SE-ResNet-1001 model for SVHN from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=1001, bottleneck=True, model_name="seresnet1001_svhn", **kwargs)
  
  
  def seresnet1202_cifar10(classes=10, **kwargs):
      """
      SE-ResNet-1202 model for CIFAR-10 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=1202, bottleneck=False, model_name="seresnet1202_cifar10",
                                **kwargs)
  
  
  def seresnet1202_cifar100(classes=100, **kwargs):
      """
      SE-ResNet-1202 model for CIFAR-100 from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 100
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=1202, bottleneck=False, model_name="seresnet1202_cifar100",
                                **kwargs)
  
  
  def seresnet1202_svhn(classes=10, **kwargs):
      """
      SE-ResNet-1202 model for SVHN from 'Squeeze-and-Excitation Networks,' https://arxiv.org/abs/1709.01507.
  
      Parameters:
      ----------
      classes : int, default 10
          Number of classification classes.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.chainer/models'
          Location for keeping the model parameters.
      """
      return get_seresnet_cifar(classes=classes, blocks=1202, bottleneck=False, model_name="seresnet1202_svhn", **kwargs)
  
  
  def _test():
      import numpy as np
      import chainer
  
      chainer.global_config.train = False
  
      pretrained = False
  
      models = [
          (seresnet20_cifar10, 10),
          (seresnet20_cifar100, 100),
          (seresnet20_svhn, 10),
          (seresnet56_cifar10, 10),
          (seresnet56_cifar100, 100),
          (seresnet56_svhn, 10),
          (seresnet110_cifar10, 10),
          (seresnet110_cifar100, 100),
          (seresnet110_svhn, 10),
          (seresnet164bn_cifar10, 10),
          (seresnet164bn_cifar100, 100),
          (seresnet164bn_svhn, 10),
          (seresnet272bn_cifar10, 10),
          (seresnet272bn_cifar100, 100),
          (seresnet272bn_svhn, 10),
          (seresnet542bn_cifar10, 10),
          (seresnet542bn_cifar100, 100),
          (seresnet542bn_svhn, 10),
          (seresnet1001_cifar10, 10),
          (seresnet1001_cifar100, 100),
          (seresnet1001_svhn, 10),
          (seresnet1202_cifar10, 10),
          (seresnet1202_cifar100, 100),
          (seresnet1202_svhn, 10),
      ]
  
      for model, classes in models:
  
          net = model(pretrained=pretrained)
          weight_count = net.count_params()
          print("m={}, {}".format(model.__name__, weight_count))
          assert (model != seresnet20_cifar10 or weight_count == 274847)
          assert (model != seresnet20_cifar100 or weight_count == 280697)
          assert (model != seresnet20_svhn or weight_count == 274847)
          assert (model != seresnet56_cifar10 or weight_count == 862889)
          assert (model != seresnet56_cifar100 or weight_count == 868739)
          assert (model != seresnet56_svhn or weight_count == 862889)
          assert (model != seresnet110_cifar10 or weight_count == 1744952)
          assert (model != seresnet110_cifar100 or weight_count == 1750802)
          assert (model != seresnet110_svhn or weight_count == 1744952)
          assert (model != seresnet164bn_cifar10 or weight_count == 1906258)
          assert (model != seresnet164bn_cifar100 or weight_count == 1929388)
          assert (model != seresnet164bn_svhn or weight_count == 1906258)
          assert (model != seresnet272bn_cifar10 or weight_count == 3153826)
          assert (model != seresnet272bn_cifar100 or weight_count == 3176956)
          assert (model != seresnet272bn_svhn or weight_count == 3153826)
          assert (model != seresnet542bn_cifar10 or weight_count == 6272746)
          assert (model != seresnet542bn_cifar100 or weight_count == 6295876)
          assert (model != seresnet542bn_svhn or weight_count == 6272746)
          assert (model != seresnet1001_cifar10 or weight_count == 11574910)
          assert (model != seresnet1001_cifar100 or weight_count == 11598040)
          assert (model != seresnet1001_svhn or weight_count == 11574910)
          assert (model != seresnet1202_cifar10 or weight_count == 19582226)
          assert (model != seresnet1202_cifar100 or weight_count == 19588076)
          assert (model != seresnet1202_svhn or weight_count == 19582226)
  
          x = np.zeros((1, 3, 32, 32), np.float32)
          y = net(x)
          assert (y.shape == (1, classes))
  
  
  if __name__ == "__main__":
      _test()
   """
      InceptionResNetV1 for ImageNet-1K, implemented in TensorFlow.
      Original paper: 'Inception-v4, Inception-ResNet and the Impact of Residual Connections on Learning,'
      https://arxiv.org/abs/1602.07261.
  """
  
  __all__ = ['InceptionResNetV1', 'inceptionresnetv1', 'InceptionAUnit', 'InceptionBUnit', 'InceptionCUnit',
             'ReductionAUnit', 'ReductionBUnit']
  
  import os
  import tensorflow as tf
  import tensorflow.keras.layers as nn
  from .common import MaxPool2d, BatchNorm, conv1x1, conv1x1_block, conv3x3_block, Concurrent, flatten,\
      is_channels_first, SimpleSequential
  from .inceptionv3 import MaxPoolBranch, Conv1x1Branch, ConvSeqBranch
  
  
  class InceptionAUnit(nn.Layer):
      """
      InceptionResNetV1 type Inception-A unit.
  
      Parameters:
      ----------
      in_channels : int
          Number of input channels.
      out_channels_list : list of int
          List for numbers of output channels.
      bn_eps : float
          Small float added to variance in Batch norm.
      data_format : str, default 'channels_last'
          The ordering of the dimensions in tensors.
      """
      def __init__(self,
                   in_channels,
                   out_channels_list,
                   bn_eps,
                   data_format="channels_last",
                   **kwargs):
          super(InceptionAUnit, self).__init__(**kwargs)
          self.scale = 0.17
  
          self.branches = Concurrent(
              data_format=data_format,
              name="branches")
          self.branches.children.append(Conv1x1Branch(
              in_channels=in_channels,
              out_channels=out_channels_list[0],
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch1"))
          self.branches.children.append(ConvSeqBranch(
              in_channels=in_channels,
              out_channels_list=out_channels_list[1:3],
              kernel_size_list=(1, 3),
              strides_list=(1, 1),
              padding_list=(0, 1),
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch2"))
          self.branches.children.append(ConvSeqBranch(
              in_channels=in_channels,
              out_channels_list=out_channels_list[3:6],
              kernel_size_list=(1, 3, 3),
              strides_list=(1, 1, 1),
              padding_list=(0, 1, 1),
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch3"))
          conv_in_channels = out_channels_list[0] + out_channels_list[2] + out_channels_list[5]
          self.conv = conv1x1(
              in_channels=conv_in_channels,
              out_channels=in_channels,
              use_bias=True,
              data_format=data_format,
              name="conv")
          self.activ = nn.ReLU()
  
      def call(self, x, training=None):
          identity = x
          x = self.branches(x, training=training)
          x = self.conv(x, training=training)
          x = self.scale * x + identity
          x = self.activ(x)
          return x
  
  
  class InceptionBUnit(nn.Layer):
      """
      InceptionResNetV1 type Inception-B unit.
  
      Parameters:
      ----------
      in_channels : int
          Number of input channels.
      out_channels_list : list of int
          List for numbers of output channels.
      bn_eps : float
          Small float added to variance in Batch norm.
      data_format : str, default 'channels_last'
          The ordering of the dimensions in tensors.
      """
      def __init__(self,
                   in_channels,
                   out_channels_list,
                   bn_eps,
                   data_format="channels_last",
                   **kwargs):
          super(InceptionBUnit, self).__init__(**kwargs)
          self.scale = 0.10
  
          self.branches = Concurrent(
              data_format=data_format,
              name="branches")
          self.branches.children.append(Conv1x1Branch(
              in_channels=in_channels,
              out_channels=out_channels_list[0],
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch1"))
          self.branches.children.append(ConvSeqBranch(
              in_channels=in_channels,
              out_channels_list=out_channels_list[1:4],
              kernel_size_list=(1, (1, 7), (7, 1)),
              strides_list=(1, 1, 1),
              padding_list=(0, (0, 3), (3, 0)),
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch2"))
          conv_in_channels = out_channels_list[0] + out_channels_list[3]
          self.conv = conv1x1(
              in_channels=conv_in_channels,
              out_channels=in_channels,
              use_bias=True,
              data_format=data_format,
              name="conv")
          self.activ = nn.ReLU()
  
      def call(self, x, training=None):
          identity = x
          x = self.branches(x, training=training)
          x = self.conv(x, training=training)
          x = self.scale * x + identity
          x = self.activ(x)
          return x
  
  
  class InceptionCUnit(nn.Layer):
      """
      InceptionResNetV1 type Inception-C unit.
  
      Parameters:
      ----------
      in_channels : int
          Number of input channels.
      out_channels_list : list of int
          List for numbers of output channels.
      bn_eps : float
          Small float added to variance in Batch norm.
      scale : float, default 1.0
          Scale value for residual branch.
      activate : bool, default True
          Whether activate the convolution block.
      data_format : str, default 'channels_last'
          The ordering of the dimensions in tensors.
      """
      def __init__(self,
                   in_channels,
                   out_channels_list,
                   bn_eps,
                   scale=0.2,
                   activate=True,
                   data_format="channels_last",
                   **kwargs):
          super(InceptionCUnit, self).__init__(**kwargs)
          self.activate = activate
          self.scale = scale
  
          self.branches = Concurrent(
              data_format=data_format,
              name="branches")
          self.branches.children.append(Conv1x1Branch(
              in_channels=in_channels,
              out_channels=out_channels_list[0],
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch1"))
          self.branches.children.append(ConvSeqBranch(
              in_channels=in_channels,
              out_channels_list=out_channels_list[1:4],
              kernel_size_list=(1, (1, 3), (3, 1)),
              strides_list=(1, 1, 1),
              padding_list=(0, (0, 1), (1, 0)),
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch2"))
          conv_in_channels = out_channels_list[0] + out_channels_list[3]
          self.conv = conv1x1(
              in_channels=conv_in_channels,
              out_channels=in_channels,
              use_bias=True,
              data_format=data_format,
              name="conv")
          if self.activate:
              self.activ = nn.ReLU()
  
      def call(self, x, training=None):
          identity = x
          x = self.branches(x, training=training)
          x = self.conv(x, training=training)
          x = self.scale * x + identity
          if self.activate:
              x = self.activ(x)
          return x
  
  
  class ReductionAUnit(nn.Layer):
      """
      InceptionResNetV1 type Reduction-A unit.
  
      Parameters:
      ----------
      in_channels : int
          Number of input channels.
      out_channels_list : list of int
          List for numbers of output channels.
      bn_eps : float
          Small float added to variance in Batch norm.
      data_format : str, default 'channels_last'
          The ordering of the dimensions in tensors.
      """
      def __init__(self,
                   in_channels,
                   out_channels_list,
                   bn_eps,
                   data_format="channels_last",
                   **kwargs):
          super(ReductionAUnit, self).__init__(**kwargs)
          self.branches = Concurrent(
              data_format=data_format,
              name="branches")
          self.branches.children.append(ConvSeqBranch(
              in_channels=in_channels,
              out_channels_list=out_channels_list[0:1],
              kernel_size_list=(3,),
              strides_list=(2,),
              padding_list=(0,),
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch1"))
          self.branches.children.append(ConvSeqBranch(
              in_channels=in_channels,
              out_channels_list=out_channels_list[1:4],
              kernel_size_list=(1, 3, 3),
              strides_list=(1, 1, 2),
              padding_list=(0, 1, 0),
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch2"))
          self.branches.children.append(MaxPoolBranch(
              data_format=data_format,
              name="branch3"))
  
      def call(self, x, training=None):
          x = self.branches(x, training=training)
          return x
  
  
  class ReductionBUnit(nn.Layer):
      """
      InceptionResNetV1 type Reduction-B unit.
  
      Parameters:
      ----------
      in_channels : int
          Number of input channels.
      out_channels_list : list of int
          List for numbers of output channels.
      bn_eps : float
          Small float added to variance in Batch norm.
      data_format : str, default 'channels_last'
          The ordering of the dimensions in tensors.
      """
      def __init__(self,
                   in_channels,
                   out_channels_list,
                   bn_eps,
                   data_format="channels_last",
                   **kwargs):
          super(ReductionBUnit, self).__init__(**kwargs)
          self.branches = Concurrent(
              data_format=data_format,
              name="branches")
          self.branches.children.append(ConvSeqBranch(
              in_channels=in_channels,
              out_channels_list=out_channels_list[0:2],
              kernel_size_list=(1, 3),
              strides_list=(1, 2),
              padding_list=(0, 0),
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch1"))
          self.branches.children.append(ConvSeqBranch(
              in_channels=in_channels,
              out_channels_list=out_channels_list[2:4],
              kernel_size_list=(1, 3),
              strides_list=(1, 2),
              padding_list=(0, 0),
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch2"))
          self.branches.children.append(ConvSeqBranch(
              in_channels=in_channels,
              out_channels_list=out_channels_list[4:7],
              kernel_size_list=(1, 3, 3),
              strides_list=(1, 1, 2),
              padding_list=(0, 1, 0),
              bn_eps=bn_eps,
              data_format=data_format,
              name="branch3"))
          self.branches.children.append(MaxPoolBranch(
              data_format=data_format,
              name="branch4"))
  
      def call(self, x, training=None):
          x = self.branches(x, training=training)
          return x
  
  
  class InceptInitBlock(nn.Layer):
      """
      InceptionResNetV1 specific initial block.
  
      Parameters:
      ----------
      in_channels : int
          Number of input channels.
      bn_eps : float
          Small float added to variance in Batch norm.
      data_format : str, default 'channels_last'
          The ordering of the dimensions in tensors.
      """
      def __init__(self,
                   bn_eps,
                   in_channels,
                   data_format="channels_last",
                   **kwargs):
          super(InceptInitBlock, self).__init__(**kwargs)
          self.conv1 = conv3x3_block(
              in_channels=in_channels,
              out_channels=32,
              strides=2,
              padding=0,
              bn_eps=bn_eps,
              data_format=data_format,
              name="conv1")
          self.conv2 = conv3x3_block(
              in_channels=32,
              out_channels=32,
              strides=1,
              padding=0,
              bn_eps=bn_eps,
              data_format=data_format,
              name="conv2")
          self.conv3 = conv3x3_block(
              in_channels=32,
              out_channels=64,
              strides=1,
              padding=1,
              bn_eps=bn_eps,
              data_format=data_format,
              name="conv3")
          self.pool = MaxPool2d(
              pool_size=3,
              strides=2,
              padding=0,
              data_format=data_format,
              name="pool")
          self.conv4 = conv1x1_block(
              in_channels=64,
              out_channels=80,
              strides=1,
              padding=0,
              bn_eps=bn_eps,
              data_format=data_format,
              name="conv4")
          self.conv5 = conv3x3_block(
              in_channels=80,
              out_channels=192,
              strides=1,
              padding=0,
              bn_eps=bn_eps,
              data_format=data_format,
              name="conv5")
          self.conv6 = conv3x3_block(
              in_channels=192,
              out_channels=256,
              strides=2,
              padding=0,
              bn_eps=bn_eps,
              data_format=data_format,
              name="conv6")
  
      def call(self, x, training=None):
          x = self.conv1(x, training=training)
          x = self.conv2(x, training=training)
          x = self.conv3(x, training=training)
          x = self.pool(x)
          x = self.conv4(x, training=training)
          x = self.conv5(x, training=training)
          x = self.conv6(x, training=training)
          return x
  
  
  class InceptHead(nn.Layer):
      """
      InceptionResNetV1 specific classification block.
  
      Parameters:
      ----------
      in_channels : int
          Number of input channels.
      bn_eps : float
          Small float added to variance in Batch norm.
      dropout_rate : float
          Fraction of the input units to drop. Must be a number between 0 and 1.
      classes : int
          Number of classification classes.
      """
      def __init__(self,
                   in_channels,
                   bn_eps,
                   dropout_rate,
                   classes,
                   data_format="channels_last",
                   **kwargs):
          super(InceptHead, self).__init__(**kwargs)
          self.data_format = data_format
          self.use_dropout = (dropout_rate != 0.0)
  
          if dropout_rate > 0.0:
              self.dropout = nn.Dropout(
                  rate=dropout_rate,
                  name="dropout")
          self.fc1 = nn.Dense(
              units=512,
              input_dim=in_channels,
              use_bias=False,
              name="fc1")
          self.bn = BatchNorm(
              epsilon=bn_eps,
              data_format=data_format,
              name="bn")
          self.fc2 = nn.Dense(
              units=classes,
              input_dim=512,
              name="fc2")
  
      def call(self, x, training=None):
          x = flatten(x, self.data_format)
          if self.use_dropout:
              x = self.dropout(x, training=training)
          x = self.fc1(x)
          x = self.bn(x, training=training)
          x = self.fc2(x)
          return x
  
  
  class InceptionResNetV1(tf.keras.Model):
      """
      InceptionResNetV1 model from 'Inception-v4, Inception-ResNet and the Impact of Residual Connections on Learning,'
      https://arxiv.org/abs/1602.07261.
  
      Parameters:
      ----------
      dropout_rate : float, default 0.0
          Fraction of the input units to drop. Must be a number between 0 and 1.
      bn_eps : float, default 1e-5
          Small float added to variance in Batch norm.
      in_channels : int, default 3
          Number of input channels.
      in_size : tuple of two ints, default (299, 299)
          Spatial size of the expected input image.
      classes : int, default 1000
          Number of classification classes.
      data_format : str, default 'channels_last'
          The ordering of the dimensions in tensors.
      """
      def __init__(self,
                   dropout_rate=0.0,
                   bn_eps=1e-5,
                   in_channels=3,
                   in_size=(299, 299),
                   classes=1000,
                   data_format="channels_last",
                   **kwargs):
          super(InceptionResNetV1, self).__init__(**kwargs)
          self.in_size = in_size
          self.classes = classes
          self.data_format = data_format
          layers = [5, 11, 7]
          in_channels_list = [256, 896, 1792]
          normal_out_channels_list = [[32, 32, 32, 32, 32, 32], [128, 128, 128, 128], [192, 192, 192, 192]]
          reduction_out_channels_list = [[384, 192, 192, 256], [256, 384, 256, 256, 256, 256, 256]]
  
          normal_units = [InceptionAUnit, InceptionBUnit, InceptionCUnit]
          reduction_units = [ReductionAUnit, ReductionBUnit]
  
          self.features = SimpleSequential(name="features")
          self.features.add(InceptInitBlock(
              in_channels=in_channels,
              bn_eps=bn_eps,
              data_format=data_format,
              name="init_block"))
          in_channels = in_channels_list[0]
          for i, layers_per_stage in enumerate(layers):
              stage = SimpleSequential(name="stage{}".format(i + 1))
              for j in range(layers_per_stage):
                  if (j == 0) and (i != 0):
                      unit = reduction_units[i - 1]
                      out_channels_list_per_stage = reduction_out_channels_list[i - 1]
                  else:
                      unit = normal_units[i]
                      out_channels_list_per_stage = normal_out_channels_list[i]
                  if (i == len(layers) - 1) and (j == layers_per_stage - 1):
                      unit_kwargs = {"scale": 1.0, "activate": False}
                  else:
                      unit_kwargs = {}
                  stage.add(unit(
                      in_channels=in_channels,
                      out_channels_list=out_channels_list_per_stage,
                      bn_eps=bn_eps,
                      data_format=data_format,
                      name="unit{}".format(j + 1),
                      **unit_kwargs))
                  if (j == 0) and (i != 0):
                      in_channels = in_channels_list[i]
              self.features.add(stage)
          self.features.add(nn.AveragePooling2D(
              pool_size=8,
              strides=1,
              data_format=data_format,
              name="final_pool"))
  
          self.output1 = InceptHead(
              in_channels=in_channels,
              bn_eps=bn_eps,
              dropout_rate=dropout_rate,
              classes=classes,
              name="output1")
  
      def call(self, x, training=None):
          x = self.features(x, training=training)
          x = self.output1(x, training=training)
          return x
  
  
  def get_inceptionresnetv1(model_name=None,
                            pretrained=False,
                            root=os.path.join("~", ".tensorflow", "models"),
                            **kwargs):
      """
      Create InceptionResNetV1 model with specific parameters.
  
      Parameters:
      ----------
      model_name : str or None, default None
          Model name for loading pretrained model.
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.tensorflow/models'
          Location for keeping the model parameters.
      """
      net = InceptionResNetV1(**kwargs)
  
      if pretrained:
          if (model_name is None) or (not model_name):
              raise ValueError("Parameter `model_name` should be properly initialized for loading pretrained model.")
          from .model_store import get_model_file
          in_channels = kwargs["in_channels"] if ("in_channels" in kwargs) else 3
          input_shape = (1,) + (in_channels,) + net.in_size if net.data_format == "channels_first" else\
              (1,) + net.in_size + (in_channels,)
          net.build(input_shape=input_shape)
          net.load_weights(
              filepath=get_model_file(
                  model_name=model_name,
                  local_model_store_dir_path=root))
  
      return net
  
  
  def inceptionresnetv1(**kwargs):
      """
      InceptionResNetV1 model from 'Inception-v4, Inception-ResNet and the Impact of Residual Connections on Learning,'
      https://arxiv.org/abs/1602.07261.
  
      Parameters:
      ----------
      pretrained : bool, default False
          Whether to load the pretrained weights for model.
      root : str, default '~/.tensorflow/models'
          Location for keeping the model parameters.
      """
      return get_inceptionresnetv1(model_name="inceptionresnetv1", bn_eps=1e-3, **kwargs)
  
  
  def _test():
      import numpy as np
      import tensorflow.keras.backend as K
  
      data_format = "channels_last"
      pretrained = False
  
      models = [
          inceptionresnetv1,
      ]
  
      for model in models:
  
          net = model(pretrained=pretrained, data_format=data_format)
  
          batch = 14
          x = tf.random.normal((batch, 3, 299, 299) if is_channels_first(data_format) else (batch, 299, 299, 3))
          y = net(x)
          assert (tuple(y.shape.as_list()) == (batch, 1000))
  
          weight_count = sum([np.prod(K.get_value(w).shape) for w in net.trainable_weights])
          print("m={}, {}".format(model.__name__, weight_count))
          assert (model != inceptionresnetv1 or weight_count == 23995624)
  
  
  if __name__ == "__main__":
      _test()
  
apis: numpy.prod
apis: numpy.random.randint numpy.random.seed torch.nn.CrossEntropyLoss
apis: numpy.random.randint numpy.random.seed
apis: numpy.zeros
apis: tensorflow.keras.layers.Dropout tensorflow.keras.layers.ReLU tensorflow.keras.backend.get_value tensorflow.keras.layers.Dense tensorflow.keras.layers.AveragePooling2D