下面以https://www.tensorflow.org/guide/datasets#preprocessing_data_with_datasetmap的示例为例,我想创建一个tf.Dataset
,它接受图像的路径,并将其映射到图像张量。
我的第一个尝试是以下操作,这与上面链接中的示例非常相似:
def input_parser(image_path):
image_data_string = tf.read_file(image_path)
image_decoded = tf.image.decode_png(image_data_string, channels=3)
image_float = tf.image.convert_image_dtype(image_decoded, dtype=tf.float32)
return image_float
def train_model():
image_paths = ['test_image1.png', .test_image2.png', 'test_image3.png']
dataset = tf.data.Dataset.from_tensor_slices(image_paths)
dataset = dataset.map(map_func=input_parser)
iterator = dataset.make_initializable_iterator()
input_images = iterator.get_next()
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
sess.run(iterator.initializer)
for i in range(3):
x = sess.run(input_images)
print(x.shape)
这似乎可以正常工作,并打印出来:
(64, 64, 3)
(64, 64, 3)
(64, 64, 3)
确实是我图片的尺寸。
因此,我然后尝试将这些数据实际馈送到网络中进行训练,并相应地修改了代码:
def input_parser(image_path):
image_data_string = tf.read_file(image_path)
image_decoded = tf.image.decode_png(image_data_string, channels=3)
image_float = tf.image.convert_image_dtype(image_decoded, dtype=tf.float32)
return image_float
def train_model():
image_paths = ['test_image1.png', .test_image2.png', 'test_image3.png']
dataset = tf.data.Dataset.from_tensor_slices(image_paths)
dataset = dataset.map(map_func=input_parser)
iterator = dataset.make_initializable_iterator()
input_images = iterator.get_next()
x = tf.layers.conv2d(inputs=input_images, filters=50, kernel_size=[5, 5], name='layer1')
x = tf.layers.flatten(x, name='layer2')
prediction = tf.layers.dense(inputs=x, units=4, name='layer3')
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
sess.run(iterator.initializer)
for i in range(3):
p = sess.run(prediction)
print(p)
然后这给了我以下错误消息:
ValueError: Input 0 of layer layer1 is incompatible with the layer: expected ndim=4, found ndim=3. Full shape received: [None, None, 3]
对此我有两个问题:
1)为什么我们的网络为什么收到形状为[None, None, 3]
的输入,如我们所见,迭代器读取的数据形状为[64, 64, 3]
。
2)为什么输入的形状实际上不是[1, 64, 64, 3]
,即具有4个尺寸?我认为第一个维度将是1,因为这是批处理大小(我不是在批处理数据,因此实际上这是1的批处理大小)。
谢谢!
答案 0 :(得分:1)
形状在空间维度上为None
,因为原则上您可以加载任何大小的图像。无法保证它们将是64x64,因此Tensorflow使用None
形状来允许任何大小的输入。由于您知道图像的大小将始终相同,因此可以使用Tensor
的{{1}}方法提供此信息。只需在解析函数中包含一行set_shape
即可。注意,这似乎可以修改张量。甚至有一个使用图像here的示例。
您没有批处理数据,因此根本没有添加批处理轴。数据集的元素只是形状(64、64、3)的图像,并且迭代器将这些元素一一返回。如果要批量处理1个大小,则应使用image_float.set_shape((64, 64, 3))
。现在,数据集的元素是形状为(1、64、64、3)的图像“批次”。当然,您也可以使用任何其他方法在前面添加轴,例如dataset = dataset.batch(1)
。