text: import mxnet as mx
  import numpy as np
  import os, time, logging, argparse, shutil
  
  from mxnet import gluon, image, init, nd
  from mxnet import autograd as ag
  from mxnet.gluon import nn
  from mxnet.gluon.data.vision import transforms
  import gluoncv as gcv
  gcv.utils.check_version('0.6.0')
  from gluoncv.utils import makedirs
  from gluoncv.model_zoo import get_model
  
  def parse_opts():
      parser = argparse.ArgumentParser(description='Transfer learning on MINC-2500 dataset',
                                       formatter_class=argparse.ArgumentDefaultsHelpFormatter)
      parser.add_argument('--data', type=str, default='',
                          help='directory for the prepared data folder')
      parser.add_argument('--model', required=True, type=str,
                          help='name of the pretrained model from model zoo.')
      parser.add_argument('-j', '--workers', dest='num_workers', default=4, type=int,
                          help='number of preprocessing workers')
      parser.add_argument('--num-gpus', default=0, type=int,
                          help='number of gpus to use, 0 indicates cpu only')
      parser.add_argument('--epochs', default=40, type=int,
                          help='number of training epochs')
      parser.add_argument('-b', '--batch-size', default=64, type=int,
                          help='mini-batch size')
      parser.add_argument('--lr', '--learning-rate', default=0.001, type=float,
                          help='initial learning rate')
      parser.add_argument('--momentum', default=0.9, type=float,
                          help='momentum')
      parser.add_argument('--weight-decay', '--wd', dest='wd', default=1e-4, type=float,
                          help='weight decay (default: 1e-4)')
      parser.add_argument('--lr-factor', default=0.75, type=float,
                          help='learning rate decay ratio')
      parser.add_argument('--lr-steps', default='10,20,30', type=str,
                          help='list of learning rate decay epochs as in str')
      opts = parser.parse_args()
      return opts
  
  # Preparation
  opts = parse_opts()
  classes = 23
  
  model_name = opts.model
  
  epochs = opts.epochs
  lr = opts.lr
  batch_size = opts.batch_size
  momentum = opts.momentum
  wd = opts.wd
  
  lr_factor = opts.lr_factor
  lr_steps = [int(s) for s in opts.lr_steps.split(',')] + [np.inf]
  
  num_gpus = opts.num_gpus
  num_workers = opts.num_workers
  ctx = [mx.gpu(i) for i in range(num_gpus)] if num_gpus > 0 else [mx.cpu()]
  batch_size = batch_size * max(num_gpus, 1)
  
  logging.basicConfig(level=logging.INFO,
                      handlers = [logging.StreamHandler()])
  
  train_path = os.path.join(opts.data, 'train')
  val_path = os.path.join(opts.data, 'val')
  test_path = os.path.join(opts.data, 'test')
  
  jitter_param = 0.4
  lighting_param = 0.1
  normalize = transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
  
  transform_train = transforms.Compose([
      transforms.Resize(480),
      transforms.RandomResizedCrop(224),
      transforms.RandomFlipLeftRight(),
      transforms.RandomColorJitter(brightness=jitter_param, contrast=jitter_param,
                                   saturation=jitter_param),
      transforms.RandomLighting(lighting_param),
      transforms.ToTensor(),
      normalize
  ])
  
  transform_test = transforms.Compose([
      transforms.Resize(256),
      transforms.CenterCrop(224),
      transforms.ToTensor(),
      normalize
  ])
  
  def test(net, val_data, ctx):
      metric = mx.metric.Accuracy()
      for i, batch in enumerate(val_data):
          data = gluon.utils.split_and_load(batch[0], ctx_list=ctx, batch_axis=0, even_split=False)
          label = gluon.utils.split_and_load(batch[1], ctx_list=ctx, batch_axis=0, even_split=False)
          outputs = [net(X) for X in data]
          metric.update(label, outputs)
  
      return metric.get()
  
  def train(train_path, val_path, test_path):
      # Initialize the net with pretrained model
      finetune_net = get_model(model_name, pretrained=True)
      with finetune_net.name_scope():
          finetune_net.output = nn.Dense(classes)
      finetune_net.output.initialize(init.Xavier(), ctx = ctx)
      finetune_net.collect_params().reset_ctx(ctx)
      finetune_net.hybridize()
  
      # Define DataLoader
      train_data = gluon.data.DataLoader(
          gluon.data.vision.ImageFolderDataset(train_path).transform_first(transform_train),
          batch_size=batch_size, shuffle=True, num_workers=num_workers)
  
      val_data = gluon.data.DataLoader(
          gluon.data.vision.ImageFolderDataset(val_path).transform_first(transform_test),
          batch_size=batch_size, shuffle=False, num_workers = num_workers)
  
      test_data = gluon.data.DataLoader(
          gluon.data.vision.ImageFolderDataset(test_path).transform_first(transform_test),
          batch_size=batch_size, shuffle=False, num_workers = num_workers)
  
      # Define Trainer
      trainer = gluon.Trainer(finetune_net.collect_params(), 'sgd', {
          'learning_rate': lr, 'momentum': momentum, 'wd': wd})
      metric = mx.metric.Accuracy()
      L = gluon.loss.SoftmaxCrossEntropyLoss()
      lr_counter = 0
      num_batch = len(train_data)
  
      # Start Training
      for epoch in range(epochs):
          if epoch == lr_steps[lr_counter]:
              trainer.set_learning_rate(trainer.learning_rate*lr_factor)
              lr_counter += 1
  
          tic = time.time()
          train_loss = 0
          metric.reset()
  
          for i, batch in enumerate(train_data):
              data = gluon.utils.split_and_load(batch[0], ctx_list=ctx, batch_axis=0, even_split=False)
              label = gluon.utils.split_and_load(batch[1], ctx_list=ctx, batch_axis=0, even_split=False)
              with ag.record():
                  outputs = [finetune_net(X) for X in data]
                  loss = [L(yhat, y) for yhat, y in zip(outputs, label)]
              for l in loss:
                  l.backward()
  
              trainer.step(batch_size)
              train_loss += sum([l.mean().asscalar() for l in loss]) / len(loss)
  
              metric.update(label, outputs)
  
          _, train_acc = metric.get()
          train_loss /= num_batch
  
          _, val_acc = test(finetune_net, val_data, ctx)
  
          logging.info('[Epoch %d] Train-acc: %.3f, loss: %.3f | Val-acc: %.3f | time: %.1f' %
                   (epoch, train_acc, train_loss, val_acc, time.time() - tic))
  
      _, test_acc = test(finetune_net, test_data, ctx)
      logging.info('[Finished] Test-acc: %.3f' % (test_acc))
  
  if __name__ == "__main__":
      train(train_path, val_path, test_path)
  