text: import argparse
  import os
  import sys
  import shutil
  import json
  import glob
  import signal
  import pickle
  
  import torch
  import torch.nn as nn
  import torch.nn.parallel
  import torch.backends.cudnn as cudnn
  import torch.optim
  import torch.utils.data
  
  from data_loader_jpeg import VideoFolder
  from callbacks import PlotLearning, MonitorLRDecay, AverageMeter
  from model import ConvColumn
  from model import C3D
  from model import LRCN
  from torchvision.transforms import *
  
  parser = argparse.ArgumentParser(
      description='PyTorch Jester Training using JPEG')
  parser.add_argument('--config', '-c', help='json config file path')
  parser.add_argument(
      '--eval_only', '-e', help="evaluate trained model on validation data.")
  parser.add_argument(
      '--resume', '-r', help="resume training from given checkpoint.")
  parser.add_argument('--gpus', '-g', help="gpu ids for use.")
  parser.add_argument(
      '--optimizer', '-o', default='sgd', help="optimizer of choice")
  
  args = parser.parse_args()
  if len(sys.argv) < 2:
      parser.print_help()
      sys.exit(1)
  
  gpus = [int(i) for i in args.gpus.split(',')]
  print("=> active GPUs: {}".format(args.gpus))
  best_prec1 = 0
  
  # load config file
  with open(args.config) as data_file:
      config = json.load(data_file)
  
  
  def main():
      global args, best_prec1
  
      # set run output folder
      model_name = config["model_name"]
      output_dir = config["output_dir"]
      print("=> Output folder for this run -- {}".format(model_name))
      save_dir = os.path.join(output_dir, model_name)
      if not os.path.exists(save_dir):
          os.makedirs(save_dir)
          os.makedirs(os.path.join(save_dir, 'plots'))
  
      # adds a handler for Ctrl+C
      def signal_handler(signal, frame):
          """
          Remove the output dir, if you exit with Ctrl+C and
          if there are less then 3 files.
          It prevents the noise of experimental runs.
          """
          num_files = len(glob.glob(save_dir + "/*"))
          if num_files < 1:
              shutil.rmtree(save_dir)
          print('You pressed Ctrl+C!')
          sys.exit(0)
  
      # assign Ctrl+C signal handler
      signal.signal(signal.SIGINT, signal_handler)
  
      # create model
      if config['model'] == 'ConvColumn':
          model = ConvColumn(config['num_classes'],
                             (config['kernel_depth'], config['kernel_height'],
                              config['kernel_width']))
      if config['model'] == 'C3D':
          model = C3D(config['num_classes'])
      if config['model'] == 'LRCN':
          model = LRCN(config['num_classes'],
                       (config['kernel_depth'], config['kernel_height'],
                        config['kernel_width']))
  
      # multi GPU setting
      model = torch.nn.DataParallel(model, device_ids=gpus).cuda()
  
      # optionally resume from a checkpoint
      if args.resume:
          if os.path.isfile(config['checkpoint']):
              print("=> loading checkpoint '{}'".format(args.resume))
              checkpoint = torch.load(config['checkpoint'])
              args.start_epoch = checkpoint['epoch']
              best_prec1 = checkpoint['best_prec1']
              model.load_state_dict(checkpoint['state_dict'])
              print("=> loaded checkpoint '{}' (epoch {})".format(
                  config['checkpoint'], checkpoint['epoch']))
          else:
              print("=> no checkpoint found at '{}'".format(
                  config['checkpoint']))
  
      # find best cudnn configuration
      cudnn.benchmark = False
  
      transform = Compose([
          CenterCrop(84),
          ToTensor(),
          Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
      ])
  
      train_data = VideoFolder(
          root=config['train_data_folder'],
          csv_file_input=config['train_data_csv'],
          csv_file_labels=config['labels_csv'],
          clip_size=config['clip_size'],
          nclips=1,
          step_size=config['step_size'],
          is_val=False,
          transform=transform,
      )
  
      print(" > Using {} processes for data loader.".format(
          config["num_workers"]))
      train_loader = torch.utils.data.DataLoader(
          train_data,
          batch_size=config['batch_size'],
          shuffle=True,
          num_workers=config['num_workers'],
          pin_memory=True,
          drop_last=True)
  
      val_data = VideoFolder(
          root=config['val_data_folder'],
          csv_file_input=config['val_data_csv'],
          csv_file_labels=config['labels_csv'],
          clip_size=config['clip_size'],
          nclips=1,
          step_size=config['step_size'],
          is_val=True,
          transform=transform,
      )
  
      val_loader = torch.utils.data.DataLoader(
          val_data,
          batch_size=config['batch_size'],
          shuffle=False,
          num_workers=config['num_workers'],
          pin_memory=True,
          drop_last=False)
  
      assert len(train_data.classes) == config["num_classes"]
  
      # define loss function (criterion) and pptimizer
      criterion = nn.CrossEntropyLoss().cuda()
  
      # define optimizer
      lr = config["lr"]
      last_lr = config["last_lr"]
      momentum = config['momentum']
      weight_decay = config['weight_decay']
  
      if args.optimizer == 'adadelta':
          optimizer = torch.optim.Adadelta(
              model.parameters(), weight_decay=weight_decay)
      elif args.optimizer == 'adam':
          optimizer = torch.optim.Adam(
              model.parameters(), weight_decay=weight_decay)
      elif args.optimizer == 'sgd':
  
          optimizer = torch.optim.SGD(
              model.parameters(),
              lr,
              momentum=momentum,
              weight_decay=weight_decay)
      else:
          raise ValueError('Unsupported optimizer: ' + args.optimizer)
  
      if args.eval_only:
          validate(val_loader, model, criterion, train_data.classes_dict)
          return
  
      # set callbacks
      plotter = PlotLearning(
          os.path.join(save_dir, "plots"), config["num_classes"])
      lr_decayer = MonitorLRDecay(0.6, 3)
      val_loss = 9999999
  
      # set end condition by num epochs
      num_epochs = int(config["num_epochs"])
      if num_epochs == -1:
          num_epochs = 999999
  
      print(" > Training is getting started...")
      print(" > Training takes {} epochs.".format(num_epochs))
      start_epoch = args.start_epoch if args.resume else 0
  
      for epoch in range(start_epoch, num_epochs):
          lr = lr_decayer(val_loss, lr)
          print(" > Current LR : {}".format(lr))
  
          if lr < last_lr and last_lr > 0:
              print(" > Training is done by reaching the last learning rate {}".
                    format(last_lr))
              sys.exit(1)
  
          # train for one epoch
          train_loss, train_top1, train_top5 = train(train_loader, model,
                                                     criterion, optimizer, epoch)
  
          # evaluate on validation set
          val_loss, val_top1, val_top5 = validate(val_loader, model, criterion)
  
          # plot learning
          plotter_dict = {}
          plotter_dict['loss'] = train_loss
          plotter_dict['val_loss'] = val_loss
          plotter_dict['acc'] = train_top1
          plotter_dict['val_acc'] = val_top1
          plotter_dict['learning_rate'] = lr
          plotter.plot(plotter_dict)
  
          # remember best prec@1 and save checkpoint
          is_best = val_top1 > best_prec1
          best_prec1 = max(val_top1, best_prec1)
          save_checkpoint({
              'epoch': epoch + 1,
              'arch': config['model'],
              'state_dict': model.state_dict(),
              'best_prec1': best_prec1,
          }, is_best, config)
  
  
  def train(train_loader, model, criterion, optimizer, epoch):
      losses = AverageMeter()
      top1 = AverageMeter()
      top5 = AverageMeter()
  
      # switch to train mode
      model.train()
  
      for i, (input, target) in enumerate(train_loader):
  
          input_vars = torch.autograd.Variable(input.cuda())
          target_var = torch.autograd.Variable(target.cuda(async=True))
  
          model.zero_grad()
  
          # compute output and loss
          output = model(input_vars)
          loss = criterion(output, target_var)
  
          # measure accuracy and record loss
          prec1, prec5 = accuracy(output.data, target, topk=(1, 5))
          losses.update(loss.data[0], input.size(0))
          top1.update(prec1[0], input.size(0))
          top5.update(prec5[0], input.size(0))
  
          # compute gradient and do SGD step
          optimizer.zero_grad()
          loss.backward()
          optimizer.step()
  
          if i % config["print_freq"] == 0:
              print('Epoch: [{0}][{1}/{2}]\t'
                    'Loss {loss.val:.4f} ({loss.avg:.4f})\t'
                    'Prec@1 {top1.val:.3f} ({top1.avg:.3f})\t'
                    'Prec@5 {top5.val:.3f} ({top5.avg:.3f})'.format(
                        epoch,
                        i,
                        len(train_loader),
                        loss=losses,
                        top1=top1,
                        top5=top5))
      return losses.avg, top1.avg, top5.avg
  
  
  def validate(val_loader, model, criterion, class_to_idx=None):
      losses = AverageMeter()
      top1 = AverageMeter()
      top5 = AverageMeter()
  
      # switch to evaluate mode
      model.eval()
  
      logits_matrix = []
      targets_list = []
  
      for i, (input, target) in enumerate(val_loader):
  
          input_vars = torch.autograd.Variable(input.cuda(), volatile=True)
          target_var = torch.autograd.Variable(
              target.cuda(async=True), volatile=True)
  
          # compute output and loss
          output = model(input_vars)
          loss = criterion(output, target_var)
  
          if args.eval_only:
              logits_matrix.append(output.cpu().data.numpy())
              targets_list.append(target.cpu().numpy())
  
          # measure accuracy and record loss
          prec1, prec5 = accuracy(output.data, target, topk=(1, 5))
          losses.update(loss.data[0], input.size(0))
          top1.update(prec1[0], input.size(0))
          top5.update(prec5[0], input.size(0))
  
          if i % config["print_freq"] == 0:
              print('Test: [{0}/{1}]\t'
                    'Loss {loss.val:.4f} ({loss.avg:.4f})\t'
                    'Prec@1 {top1.val:.3f} ({top1.avg:.3f})\t'
                    'Prec@5 {top5.val:.3f} ({top5.avg:.3f})'.format(
                        i, len(val_loader), loss=losses, top1=top1, top5=top5))
  
      print(' * Prec@1 {top1.avg:.3f} Prec@5 {top5.avg:.3f}'.format(
          top1=top1, top5=top5))
  
      if args.eval_only:
          logits_matrix = np.concatenate(logits_matrix)
          targets_list = np.concatenate(targets_list)
          print(logits_matrix.shape, targets_list.shape)
          save_results(logits_matrix, targets_list, class_to_idx, config)
      return losses.avg, top1.avg, top5.avg
  
  
  def save_results(logits_matrix, targets_list, class_to_idx, config):
      print("Saving inference results ...")
      path_to_save = os.path.join(config['output_dir'], config['model_name'],
                                  "test_results.pkl")
      with open(path_to_save, "wb") as f:
          pickle.dump([logits_matrix, targets_list, class_to_idx], f)
  
  
  def save_checkpoint(state, is_best, config, filename='checkpoint.pth.tar'):
      checkpoint_path = os.path.join(config['output_dir'], config['model_name'],
                                     filename)
      model_path = os.path.join(config['output_dir'], config['model_name'],
                                'model_best.pth.tar')
      torch.save(state, checkpoint_path)
      if is_best:
          shutil.copyfile(checkpoint_path, model_path)
  
  
  def accuracy(output, target, topk=(1, )):
      """Computes the precision@k for the specified values of k"""
      maxk = max(topk)
      batch_size = target.size(0)
  
      _, pred = output.cpu().topk(maxk, 1, True, True)
      pred = pred.t()
      correct = pred.eq(target.view(1, -1).expand_as(pred))
  
      res = []
      for k in topk:
          correct_k = correct[:k].view(-1).float().sum(0)
          res.append(correct_k.mul_(100.0 / batch_size))
      return res
  
  
  if __name__ == '__main__':
      main()
  