在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文件中保存高度和宽度,如果他们以后不使用它,并在他们读取和解码图像时使用预定义的常量。
答案 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表示。这通常与非二进制图像无关。