对具有不同图像大小的数据集使用张量流TFRecords

时间:2016-08-04 08:35:58

标签: tensorflow

在tensorflow教程中,我们将使用MNIST数据集提供TFRecords的示例。 MNIST数据集将转换为TFRecords文件,如下所示:

def convert_to(data_set, name):
  images = data_set.images
  labels = data_set.labels
  num_examples = data_set.num_examples

  if images.shape[0] != num_examples:
    raise ValueError('Images size %d does not match label size %d.' %
                     (images.shape[0], num_examples))
  rows = images.shape[1]
  cols = images.shape[2]
  depth = images.shape[3]

  filename = os.path.join(FLAGS.directory, name + '.tfrecords')
  print('Writing', filename)
  writer = tf.python_io.TFRecordWriter(filename)
  for index in range(num_examples):
    image_raw = images[index].tostring()
    example = tf.train.Example(features=tf.train.Features(feature={
        'height': _int64_feature(rows),
        'width': _int64_feature(cols),
        'depth': _int64_feature(depth),
        'label': _int64_feature(int(labels[index])),
        'image_raw': _bytes_feature(image_raw)}))
    writer.write(example.SerializeToString())
  writer.close()

然后它被重新加工并解码如下:

def read_and_decode(filename_queue):
  reader = tf.TFRecordReader()
  _, serialized_example = reader.read(filename_queue)
  features = tf.parse_single_example(
      serialized_example,
      # Defaults are not specified since both keys are required.
      features={
          'image_raw': tf.FixedLenFeature([], tf.string),
          'label': tf.FixedLenFeature([], tf.int64),
      })

  # Convert from a scalar string tensor (whose single string has
  # length mnist.IMAGE_PIXELS) to a uint8 tensor with shape
  # [mnist.IMAGE_PIXELS].
  image = tf.decode_raw(features['image_raw'], tf.uint8)
  image.set_shape([mnist.IMAGE_PIXELS])

  # OPTIONAL: Could reshape into a 28x28 image and apply distortions
  # here.  Since we are not applying any distortions in this
  # example, and the next step expects the image to be flattened
  # into a vector, we don't bother.

  # Convert from [0, 255] -> [-0.5, 0.5] floats.
  image = tf.cast(image, tf.float32) * (1. / 255) - 0.5

  # Convert label from a scalar uint8 tensor to an int32 scalar.
  label = tf.cast(features['label'], tf.int32)

  return image, label

问题:有没有办法从TFRecords中读取不同大小的图像?因为此时

image.set_shape([mnist.IMAGE_PIXELS])

需要知道所有张量尺寸。这意味着我不能做像

这样的事情
width = tf.cast(features['width'], tf.int32)
height = tf.cast(features['height'], tf.int32) 
tf.reshape(image, [width, height, 3])

那么在这种情况下如何使用TFRecords? 另外我无法理解为什么教程作者在TFRecords文件中保存高度和宽度,如果他们以后不使用它,并在他们读取和解码图像时使用预定义的常量。

1 个答案:

答案 0 :(得分:1)

对于此特定情况下的训练,没有理由保持宽度和高度,但是由于图像被序列化为单个字节流,未来您可能想知道数据最初具有什么形状而不是784字节 - 实质上,它们只是创建自包含的示例。

对于不同大小的图像,您必须记住,在某些时候您需要将要素张量映射到权重,并且由于给定网络的权重数量是固定的,因此必须是特征张量。要考虑的另一点是数据规范化:如果您使用不同形状的图像,它们是否具有相同的均值和方差?你可能会选择忽略这一点,但如果你不这样做,你也必须为它提出一个解决方案。

如果您只是要求使用不同尺寸的图片,例如100x100x3而不是28x28x1,您当然可以使用

image.set_shape([100, 100, 3])

为了重塑单个张量的30000"元素"总数为单一等级-3张量。 或者,如果您正在使用批次(待定大小),您可以使用

image_batch.set_shape([None, 100, 100, 3])

请注意,这不是张量的列表,而是等级4张量,因此该批次中的所有图片都必须具有相同的尺寸;即在同一批次中拥有100x100x3图像后跟28x28x1图像是不可能的。

批处理之前,虽然你可以自由地拥有你想要的任何大小和形状,你也可以从记录中加载形状 - 这是他们在MNIST示例中没有做到的。例如,您可以应用任何image processing operations以获得固定大小的增强图像以供进一步处理。

另请注意,图像的序列化表示可能确实具有不同的长度和形状。例如,您可以决定存储JPEG or PNG bytes而不是原始像素值;他们显然会有不同的尺寸。

最后,还有tf.FixedLenFeature(),但他们正在创建SparseTensor表示。这通常与非二进制图像无关。