docs: def process_record_dataset(dataset, is_training, batch_size, shuffle_buffer,
                             parse_record_fn, num_epochs=1, num_gpus=None,
                             examples_per_epoch=None, dtype=tf.float32):
    """Given a Dataset with raw records, return an iterator over the records.
  
    Args:
      dataset: A Dataset representing raw records
      is_training: A boolean denoting whether the input is for training.
      batch_size: The number of samples per batch.
      shuffle_buffer: The buffer size to use when shuffling records. A larger
        value results in better randomness, but smaller values reduce startup
        time and use less memory.
      parse_record_fn: A function that takes a raw record and returns the
        corresponding (image, label) pair.
      num_epochs: The number of epochs to repeat the dataset.
      num_gpus: The number of gpus used for training.
      examples_per_epoch: The number of examples in an epoch.
      dtype: Data type to use for images/features.
  
    Returns:
      Dataset of (image, label) pairs ready for iteration.
    """
  
    # We prefetch a batch at a time, This can help smooth out the time taken to
    # load input files as we go through shuffling and processing.
    dataset = dataset.prefetch(buffer_size=batch_size)
    if is_training:
      # Shuffle the records. Note that we shuffle before repeating to ensure
      # that the shuffling respects epoch boundaries.
      mlperf_log.resnet_print(key=mlperf_log.INPUT_ORDER)
      dataset = dataset.shuffle(buffer_size=shuffle_buffer)
  
    # If we are training over multiple epochs before evaluating, repeat the
    # dataset for the appropriate number of epochs.
    dataset = dataset.repeat(num_epochs)
  
    # Parse the raw records into images and labels. Testing has shown that setting
    # num_parallel_batches > 1 produces no improvement in throughput, since
    # batch_size is almost always much greater than the number of CPU cores.
    dataset = dataset.apply(
        tf.contrib.data.map_and_batch(
            lambda value: parse_record_fn(value, is_training, dtype),
            batch_size=batch_size,
            num_parallel_batches=1))
  
    # Operations between the final prefetch and the get_next call to the iterator
    # will happen synchronously during run time. We prefetch here again to
    # background all of the above processing work and keep it out of the
    # critical training path. Setting buffer_size to tf.contrib.data.AUTOTUNE
    # allows DistributionStrategies to adjust how many batches to fetch based
    # on how many devices are present.
    dataset = dataset.prefetch(buffer_size=tf.contrib.data.AUTOTUNE)
  
    return dataset