使用TensorFlow TFRecords处理具有不同图像尺寸的数据集

5
在TensorFlow教程中,提供了使用TFRecords处理MNIST数据集的示例。将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个回答

1
在这种情况下,训练时没有必要保留宽度和高度,但由于图像被序列化为单个字节流,未来您可能会想知道该数据最初的形状而不是784字节 - 本质上,他们只是创建自包含的示例。
至于不同大小的图像,您必须记住,在某些时候,您需要将功能张量映射到权重,并且由于给定网络的权重数量是固定的,因此功能张量的维度也必须是固定的。另一个要考虑的问题是数据归一化:如果您使用不同形状的图像,它们是否具有相同的均值和方差?您可以选择忽略该点,但如果不这样做,则还必须想出解决方案。
如果您只是要求使用不同大小的图像,例如100x100x3而不是28x28x1,那么您当然可以使用。
image.set_shape([100, 100, 3])

为了将一个包含30000个“元素”的张量重塑为一个三维张量。 或者,如果您正在处理大小未确定的批次,则可以使用。
image_batch.set_shape([None, 100, 100, 3])

请注意,这不是张量列表而是单个四阶张量,因此批次中的所有图像必须具有相同的尺寸;即在同一批次中放置一个100x100x3图像,后跟一个28x28x1图像是不可能的。
在分批之前,您可以自由地拥有任何大小和形状,并且还可以从记录中加载形状 - 这是MNIST示例中没有做到的。例如,您可以应用任何image processing operations以获得固定大小的增强图像以进行进一步处理。
还要注意,图像的序列化表示可能确实具有不同的长度和形状。例如,您可以决定存储JPEG或PNG字节而不是原始像素值;它们显然会有不同的大小。
最后还有一个 tf.FixedLenFeature(),但它们创建的是SparseTensor表示。虽然这通常与非二进制图像无关。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接