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

ser*_*rat 5 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()
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

问题:有没有办法从TFRecords读取不同大小的图像?因为在这一点上

image.set_shape([mnist.IMAGE_PIXELS])
Run Code Online (Sandbox Code Playgroud)

所有张量大小都需要知道.这意味着我不能做类似的事情

width = tf.cast(features['width'], tf.int32)
height = tf.cast(features['height'], tf.int32) 
tf.reshape(image, [width, height, 3])
Run Code Online (Sandbox Code Playgroud)

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

sun*_*ide 1

对于这种特殊情况下的训练,没有理由保留宽度和高度,但是由于图像被序列化为单个字节流,将来您可能想知道数据最初的形状而不是784字节 - 本质上,它们只是创建独立的示例。

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

如果您只是要求使用不同尺寸的图像,即100x100x3代替28x28x1,您当然可以使用

image.set_shape([100, 100, 3])
Run Code Online (Sandbox Code Playgroud)

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

image_batch.set_shape([None, 100, 100, 3])
Run Code Online (Sandbox Code Playgroud)

请注意,这不是张量列表,而是单个4 阶张量,因此该批次中的所有图像都必须具有相同的尺寸;即,不可能在同一批次中同时出现一个100x100x3图像和一个图像。28x28x1

批处理之前,您可以自由地拥有您想要的任何大小和形状,并且您也可以从记录中加载形状 - 他们在 MNIST 示例中没有这样做。例如,您可以应用任何图像处理操作以获得固定大小的增强图像以进行进一步处理。

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

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