readme: # Cycle GAN
  
  import math
  import torch
  import torch.nn as nn
  import torch.nn.functional as F
  import torchvision
  import torchvision.transforms as transforms
  import numpy as np
  import matplotlib.pyplot as plt
  import torch.optim as optim
  from torchsummary import summary
  import torchvision.models as models
  import torchvision.transforms.functional as ff
  import torchvision.datasets as dsets
  from PIL import Image
  import itertools
  %matplotlib inline
  
  import warnings
  device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
  from google.colab import drive
  drive.mount('/content/drive')
  torch.manual_seed(0)
  warnings.filterwarnings('ignore')
  
  import copy
  import os
  import shutil
  
  import numpy as np
  import torch
  
  
  def mkdir(paths):
      if not isinstance(paths, (list, tuple)):
          paths = [paths]
      for path in paths:
          if not os.path.isdir(path):
              os.makedirs(path)
  
  
  def cuda_devices(gpu_ids):
      gpu_ids = [str(i) for i in gpu_ids]
      os.environ['CUDA_VISIBLE_DEVICES'] = ','.join(gpu_ids)
  
  
  def cuda(xs):
      if torch.cuda.is_available():
          if not isinstance(xs, (list, tuple)):
              return xs.cuda()
          else:
              return [x.cuda() for x in xs]
      else:
          return xs
  
  
  def save_checkpoint(state, save_path, is_best=False, max_keep=None):
      # save checkpoint
      torch.save(state, save_path)
  #     print('saved')
  
      # deal with max_keep
      save_dir = os.path.dirname(save_path)
      list_path = os.path.join(save_dir, 'latest_checkpoint')
  
      save_path = os.path.basename(save_path)
      if os.path.exists(list_path):
          with open(list_path) as f:
              ckpt_list = f.readlines()
              ckpt_list = [save_path + '\n'] + ckpt_list
      else:
          ckpt_list = [save_path + '\n']
          
      print(ckpt_list)
  
      if max_keep is not None:
          for ckpt in ckpt_list[max_keep:]:
              ckpt = os.path.join(save_dir, ckpt[:-1])
              if os.path.exists(ckpt):
                  os.remove(ckpt)
          ckpt_list[max_keep:] = []
  
      with open(list_path, 'w') as f:
          f.writelines(ckpt_list)
  
      # copy best
      if is_best:
          shutil.copyfile(save_path, os.path.join(save_dir, 'best_model.ckpt'))
          
  def save_checkpoint_per_epoch(state, save_path, epoch, max_keep=1, is_best=False):
      # save checkpoint
      torch.save(state, save_path)
  #     print('saved')
  
      # deal with max_keep
      save_dir = os.path.dirname(save_path)
      list_path = os.path.join(save_dir, 'latest_checkpoint_epoch_{}'.format(str(epoch)))
      
      absolute_latest_path = os.path.join(save_dir, 'latest_checkpoint')
  
      save_path = os.path.basename(save_path)
      if os.path.exists(list_path):
          with open(list_path) as f:
              ckpt_list = f.readlines()
              ckpt_list = [save_path + '\n'] + ckpt_list
      else:
          ckpt_list = [save_path + '\n']
  
      if max_keep is not None:
          for ckpt in ckpt_list[max_keep:]:
              ckpt = os.path.join(save_dir, ckpt[:-1])
              if os.path.exists(ckpt):
                  os.remove(ckpt)
          ckpt_list[max_keep:] = []
  
      with open(list_path, 'w') as f:
          f.writelines(ckpt_list)
          
      with open(absolute_latest_path, 'w') as f:
          f.write(save_path)
      
  
      # copy best
      if is_best:
          shutil.copyfile(save_path, os.path.join(save_dir, 'best_model.ckpt'))
  
  
  def load_checkpoint(ckpt_dir_or_file, map_location=None, load_best=False):
      if os.path.isdir(ckpt_dir_or_file):
          if load_best:
              ckpt_path = os.path.join(ckpt_dir_or_file, 'best_model.ckpt')
          else:
              with open(os.path.join(ckpt_dir_or_file, 'latest_checkpoint')) as f:
                  ckpt_path = os.path.join(ckpt_dir_or_file, f.readline()[:-1])
      else:
          ckpt_path = ckpt_dir_or_file
      print(ckpt_path)
      ckpt = torch.load(ckpt_path, map_location=map_location)
      print(' [*] Loading checkpoint from %s succeed!' % ckpt_path)
      return ckpt
  
  
  def reorganize(dataset_dir):
      dirs = {}
      dirs['Apple'] = os.path.join(dataset_dir, 'Apple')
      dirs['Windows'] = os.path.join(dataset_dir, 'Windows')
      dirs['Test_Apple'] = os.path.join(dataset_dir, 'Test_Apple')
      dirs['Test_Windows'] = os.path.join(dataset_dir, 'Test_Windows')
      mkdir(list(dirs.values()))
  
      for key in dirs:
          try:
              os.remove(os.path.join(dirs[key], '0'))
          except:
              pass
          os.symlink(os.path.abspath(os.path.join(dataset_dir, key)),
                     os.path.join(dirs[key], '0'))
  
      return dirs
  
  def weights_init_normal(m):
      classname = m.__class__.__name__
      if classname.find('Conv') != -1:
          torch.nn.init.normal_(m.weight.data, 0.0, 0.02)
      elif classname.find('BatchNorm2d') != -1:
          torch.nn.init.normal_(m.weight.data, 1.0, 0.02)
          torch.nn.init.constant(m.bias.data, 0.0)
          
  def truncated_normal_(tensor, mean=0, std=1):
      size = tensor.shape
      tmp = tensor.new_empty(size + (4,)).normal_()
      valid = (tmp < 2) & (tmp > -2