text: """
     CIFAR-10 data normalization reference:
     https://github.com/Armour/pytorch-nn-practice/blob/master/utils/meanstd.py
  """
  
  import random
  import os
  import numpy as np
  from PIL import Image
  import torch
  import torchvision
  import torchvision.transforms as transforms
  from torch.utils.data.sampler import SubsetRandomSampler
  
  # types == train，返回trainloader；否则返回devloader
  def fetch_dataloader(types, params):
      """
      Fetch and return train/dev dataloader with hyperparameters (params.subset_percent = 1.)
      """
  
      # using random crops and horizontal flip for train set
      # 对训练集进行random crops和水平翻转
      # augmentation是增强的意思
      if params.augmentation == "yes":
          # transforms.Compose串联多个图片变换的操作
          # RandomCrop剪裁，RandomHorizontalFlip随机水平翻转，ToTensor将PIL Image或者 ndarray 转换为tensor
          # Normalize标准化
          train_transformer = transforms.Compose([
              transforms.RandomCrop(32, padding=4),
              transforms.RandomHorizontalFlip(),  # randomly flip image horizontally
              transforms.ToTensor(),
              transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261))])
  
      # data augmentation can be turned off
      else:
          train_transformer = transforms.Compose([
              transforms.ToTensor(),
              transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261))])
  
      # transformer for dev set
      # dev set：该集合是用于在训练模型中评估模型，以促进模型优化的。
      dev_transformer = transforms.Compose([
          transforms.ToTensor(),
          transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261))])
  
      trainset = torchvision.datasets.CIFAR10(root='./data-cifar10', train=True,
          download=True, transform=train_transformer)
      trainloader = torch.utils.data.DataLoader(trainset, batch_size=params.batch_size,
          shuffle=True, num_workers=params.num_workers, pin_memory=params.cuda)
  
      devset = torchvision.datasets.CIFAR10(root='./data-cifar10', train=False,
          download=True, transform=dev_transformer)
      devloader = torch.utils.data.DataLoader(devset, batch_size=params.batch_size,
          shuffle=False, num_workers=params.num_workers, pin_memory=params.cuda)
  
      if types == 'train':
          dl = trainloader
      else:
          dl = devloader
  
      return dl
  
  
  # 取子集
  def fetch_subset_dataloader(types, params):
      """
      Use only a subset of dataset for KD training, depending on params.subset_percent
      """
  
      # using random crops and horizontal flip for train set
      if params.augmentation == "yes":
          train_transformer = transforms.Compose([
              transforms.RandomCrop(32, padding=4),
              transforms.RandomHorizontalFlip(),  # randomly flip image horizontally
              transforms.ToTensor(),
              transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261))])
  
      # data augmentation can be turned off
      else:
          train_transformer = transforms.Compose([
              transforms.ToTensor(),
              transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261))])
  
      # transformer for dev set
      dev_transformer = transforms.Compose([
          transforms.ToTensor(),
          transforms.Normalize((0.4914, 0.4822, 0.4465), (0.247, 0.243, 0.261))])
  
      trainset = torchvision.datasets.CIFAR10(root='./data-cifar10', train=True,
          download=True, transform=train_transformer)
  
      devset = torchvision.datasets.CIFAR10(root='./data-cifar10', train=False,
          download=True, transform=dev_transformer)
  
      trainset_size = len(trainset)
      indices = list(range(trainset_size))
      #np.floor向下取整，split是subset的大小
      split = int(np.floor(params.subset_percent * trainset_size))
      np.random.seed(230)
      # 随机打乱数据
      np.random.shuffle(indices)
  
      # SubsetRandomSampler随机采样
      train_sampler = SubsetRandomSampler(indices[:split])
  
      trainloader = torch.utils.data.DataLoader(trainset, batch_size=params.batch_size,
          sampler=train_sampler, num_workers=params.num_workers, pin_memory=params.cuda)
  
      devloader = torch.utils.data.DataLoader(devset, batch_size=params.batch_size,
          shuffle=False, num_workers=params.num_workers, pin_memory=params.cuda)
  
      if types == 'train':
          dl = trainloader
      else:
          dl = devloader
  
      return dl