使用`dataset.map()`后TensorFlow网络接收到错误的张量形状

时间:2018-08-15 18:41:52

标签: tensorflow

下面以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的批处理大小)。

谢谢!

1 个答案:

答案 0 :(得分:1)

  1. 形状在空间维度上为None,因为原则上您可以加载任何大小的图像。无法保证它们将是64x64,因此Tensorflow使用None形状来允许任何大小的输入。由于您知道图像的大小将始终相同,因此可以使用Tensor的{​​{1}}方法提供此信息。只需在解析函数中包含一行set_shape即可。注意,这似乎可以修改张量。甚至有一个使用图像here的示例。

  2. 您没有批处理数据,因此根本没有添加批处理轴。数据集的元素只是形状(64、64、3)的图像,并且迭代器将这些元素一一返回。如果要批量处理1个大小,则应使用image_float.set_shape((64, 64, 3))。现在,数据集的元素是形状为(1、64、64、3)的图像“批次”。当然,您也可以使用任何其他方法在前面添加轴,例如dataset = dataset.batch(1)