def __init__(self, op, data_name_list, hyperparameter_list, frac=1.0):
    """Initializes a DataHandler.
    Args:
      op: Operation protocol buffer.
      data_name_list: List of data names that should be put together. (Usually
        refers to a list of different modalities, e.g., ['data', 'label'] or
        ['image', 'audio'].)
      hyperparameter_list: List of hyperparameters, one for each modality.
      frac: What fraction of the total memory should this data handler use.
    """
    filenames = []
    numdim_list = []
    datasetsize = None
    left_window = []
    right_window = []
    stats_files = []
    shift = []
    add_noise = []
    shift_amt_x = []
    shift_amt_y = []
    keys = []
    typesize = 4
    if isinstance(op, str):
      op = util.ReadOperation(op)
    self.verbose = op.verbose
    verbose = self.verbose
    data_proto_file = os.path.join(op.data_proto_prefix, op.data_proto)
    dataset_proto = util.ReadData(data_proto_file)
    seq = False
    is_train = False
    for name, hyp in zip(data_name_list, hyperparameter_list):
      data_proto = next(d for d in dataset_proto.data if d.name == name)
      file_pattern = os.path.join(dataset_proto.prefix, data_proto.file_pattern)
      filenames.append(sorted(glob.glob(file_pattern)))
      stats_files.append(os.path.join(dataset_proto.prefix, data_proto.stats_file))
      numdims = np.prod(np.array(data_proto.dimensions))
      if not data_proto.sparse:
        numdims *= data_proto.num_labels
      numdim_list.append(numdims)
      seq = seq or data_proto.seq
      left_window.append(hyp.left_window)
      right_window.append(hyp.right_window)
      add_noise.append(hyp.add_noise)
      shift.append(hyp.shift)
      shift_amt_x.append(hyp.shift_amt_x)
      shift_amt_y.append(hyp.shift_amt_y)
      keys.append(data_proto.key)
      is_train = 'train' in name  # HACK - Fix this!
      if datasetsize is None:
        datasetsize = data_proto.size
      else:
        assert datasetsize == data_proto.size, 'Size of %s is not %d' % (
          name, datasetsize)

    # Add space for padding.
    if seq:
      max_rw = max(right_window)
      max_lw = max(left_window)
      actual_datasetsize = datasetsize
      datasetsize += len(filenames[0]) * (max_rw + max_lw)

    numdims = sum(numdim_list)
    batchsize = op.batchsize
    randomize = op.randomize
    self.get_last_piece = op.get_last_piece
    # Compute size of each cache.
    total_disk_space = datasetsize * numdims * typesize
    max_gpu_capacity = int(frac*GetBytes(dataset_proto.gpu_memory))
    max_cpu_capacity = int(frac*GetBytes(dataset_proto.main_memory))

    # Each capacity should correspond to integral number of batches.
    vectorsize_bytes = typesize * numdims
    batchsize_bytes = vectorsize_bytes * batchsize
    max_gpu_capacity = (max_gpu_capacity / batchsize_bytes) * batchsize_bytes
    #max_cpu_capacity = (max_cpu_capacity / batchsize_bytes) * batchsize_bytes

    # Don't need more than total dataset size.
    gpu_capacity = min(total_disk_space, max_gpu_capacity) 
    cpu_capacity = min(total_disk_space, max_cpu_capacity) 
    num_gpu_batches = gpu_capacity / batchsize_bytes
    num_cpu_batches = cpu_capacity / batchsize_bytes

    gpu_left_overs = gpu_capacity / vectorsize_bytes - num_gpu_batches * batchsize
    cpu_left_overs = cpu_capacity / vectorsize_bytes - num_cpu_batches * batchsize
    
    if self.verbose:
      if seq:
        num_valid_gpu_vectors = (gpu_capacity/vectorsize_bytes) - len(filenames[0])*(max_rw+max_lw)
        print num_valid_gpu_vectors

      else:
        print 'Batches in GPU memory: %d + leftovers %d' % (num_gpu_batches,
                                                            gpu_left_overs)
        print 'Batches in main memory: %d + leftovers %d' % (num_cpu_batches,
                                                             cpu_left_overs)
        print 'Batches in disk: %d + leftovers %d' % ((datasetsize / batchsize),
                                                      datasetsize % batchsize)
    
    if seq:
      import sequence_datahandler as seq_dh
      self.disk = seq_dh.SequenceDisk(
        filenames, numdim_list, datasetsize, keys=keys, left_window=left_window,
        right_window=right_window, verbose=verbose)
      self.cpu_cache = seq_dh.SequenceCache(
        self.disk, cpu_capacity, numdim_list, typesize = typesize,
        randomize=randomize, left_window=left_window,
        right_window=right_window, verbose=verbose)
      self.gpu_cache = seq_dh.SequenceGPUCache(
        self.cpu_cache, gpu_capacity, numdim_list, typesize = typesize,
        randomize=randomize, left_window=left_window,
        right_window=right_window, verbose=verbose, batchsize=batchsize)
    else:
      self.disk = Disk(filenames, numdim_list, datasetsize, keys=keys,
                       verbose=self.verbose)
      self.cpu_cache = Cache(self.disk, cpu_capacity, numdim_list,
                             typesize = typesize, randomize=randomize,
                             verbose=self.verbose)
      self.gpu_cache = GPUCache(self.cpu_cache, gpu_capacity, numdim_list,
                                typesize = typesize, randomize=randomize,
                                verbose=self.verbose, shift=shift, add_noise=add_noise,
                                center_only=not is_train, shift_amt_x=shift_amt_x, shift_amt_y=shift_amt_y)
    for i, stats_file in enumerate(stats_files):
      if hyperparameter_list[i].normalize and hyperparameter_list[i].activation != deepnet_pb2.Hyperparams.REPLICATED_SOFTMAX:
        self.gpu_cache.SetDataStats(i, stats_file)
    self.batchsize = batchsize
    if seq:
      datasetsize = actual_datasetsize
    self.num_batches = datasetsize / batchsize
    if self.get_last_piece and datasetsize % batchsize > 0:
      self.num_batches += 1
Initializes a DataHandler.
    Args:
      op: Operation protocol buffer.
      data_name_list: List of data names that should be put together. (Usually
        refers to a list of different modalities, e.g., ['data', 'label'] or
        ['image', 'audio'].)
      hyperparameter_list: List of hyperparameters, one for each modality.
      frac: What fraction of the total memory should this data handler use.
    
deepnet/datahandler.py