首页 > 解决方案 > TensorFlow 网络在使用“dataset.map()”后接收到错误的张量形状

问题描述

按照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)为什么我的网络接收到 shape 的输入[None, None, 3],正如我们所见,迭代器读取的数据是 shape [64, 64, 3]

2) 为什么输入的形状实际上不是[1, 64, 64, 3]4 维?我认为第一个维度是 1,因为这是批量大小(我没有批量处理数据,所以实际上这是批量大小为 1)。

谢谢!

标签: tensorflow

解决方案


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

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


推荐阅读