【问题标题】:Wrong shape Dataset Tensorflow错误的形状数据集Tensorflow
【发布时间】:2021-02-04 08:57:42
【问题描述】:

我是 tensorflow 的新手,我正在尝试使用 tensorflow.Dataset 提供一些数据。我使用具有 8 个不同类别的 Cityscape 数据集。这是我的代码:

import os
import cv2
import numpy as np
import tensorflow as tf

H = 256
W = 256
id2cat = np.array([0,0,0,0,0,0,0, 1,1,1,1, 2,2,2,2,2,2, 3,3,3,3, 4,4, 5, 6,6, 7,7,7,7,7,7,7,7,7])

def readImage(x):
    x = cv2.imread(x, cv2.IMREAD_COLOR)
    x = cv2.resize(x, (W, H))
    x = x / 255.0
    x = x.astype(np.float32)
    return x
    
def readMask(path):
    mask = cv2.imread(path, 0)
    mask = cv2.resize(mask, (W, H))
    mask = id2cat[mask]
    return mask.astype(np.int32)

def preprocess(x, y):
    def f(x, y):
        image = readImage(x)
        mask = readMask(y)
            
        return image, mask
        
    image, mask = tf.numpy_function(f, [x, y], [tf.float32, tf.int32])
    mask = tf.one_hot(mask, 3, dtype=tf.int32)
    image.set_shape([H, W, 3])
    mask.set_shape([H, W, 3])
    
    return image, mask
        

def tf_dataset(x, y, batch=8):
    dataset = tf.data.Dataset.from_tensor_slices((x, y))
    dataset = dataset.shuffle(buffer_size=5000)
    dataset = dataset.map(preprocess)
    dataset = dataset.batch(batch)
    dataset = dataset.repeat()
    dataset = dataset.prefetch(2)
    return dataset

def loadCityscape():
    trainPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'datasets\\Cityscape\\train')
    imagesPath = os.path.join(trainPath, 'images')
    maskPath = os.path.join(trainPath, 'masks')
    
    images = []
    masks = []
     
    print('Loading images and masks for Cityscape dataset...')
    for image in os.listdir(imagesPath):
        images.append(readImage(os.path.join(imagesPath, image)))
    for mask in os.listdir(maskPath):
        if 'label' in mask:
            masks.append(readMask(os.path.join(maskPath, mask)))
    print('Loaded {} images\n'.format(len(images)))
    
    return images, masks

images, masks = loadCityscape()

dataset = tf_dataset(images, masks, batch=8) 

print(dataset)

最后的打印(数据集)显示:

<PrefetchDataset shapes: ((None, 256, 256, 3), (None, 256, 256, 3)), types: (tf.float32, tf.int32)>

为什么我得到的是 (None, 256, 256, 3) 而不是 (8, 256, 256, 3)?我对如何迭代这个数据集也有一些疑问。

非常感谢。

【问题讨论】:

    标签: python tensorflow


    【解决方案1】:

    Tensorflow 是一个基于图形的数学框架,可为您抽象出您面临的所有复杂矢量或矩阵运算,尤其是在机器学习方面。

    尽管开发人员每次都指定需要在模型中传递多少个输入向量来进行训练是很不方便的,因此他们决定为您抽象它。

    只要输出与输入维度匹配(但任何内部操作的维度也应匹配!),您不会对模型输入一个或数千个样本感兴趣。

    所以None 大小是一个可能改变形状的占位符,通常是输入的批量大小。

    我们需要一个占位符,因为 (None, 2)(2,) 的形状不同,因为在第一种情况下,我们知道我们将面对 2 个维度。

    即使None 维度在您“编译”模型时是未知的,也只会在严格需要它时进行评估,换句话说,当您运行它时。通过这种方式,您的模型将很乐意在 64 的批量大小(如 128 个样本)上运行。

    对于其余的(非标量)Tensor 的行为类似于普通的 numpy 数组:

    tensor1 = tf.constant([ 0, 1, 2, 3]) # shape (4, )
    tensor2 = tf.constant([ [0], [1], [2], [3]]) # shape (4, 1)
    for x in tensor1:
      print(x) # 0, 1, 2, 3
    for x in tensor2:
      print(x) # Tensor([0]), Tensor([1]), Tensor([2]), Tensor([3])
    

    唯一的区别是它可以分配到任何支持的设备内存(CPU / Cuda GPU)。

    遍历数据集就像以(通常)恒定大小对其进行切片,其中该常量是您的批量大小,它将填充空的 None 维度。

    这行代码将负责将您的数据集分割成由其样本组成的“子张量”(“子数组”):

    dataset = dataset.batch(N)
    # iterating over it:
    for batch in dataset: # I'm taking N samples here
      ...
    

    您的“运行时”形状将为(N, 256, 256, 3),但如果您尝试从数据集中获取一个元素,它的形状中仍可能包含None...这是因为我们无法保证,例如,数据集的维度完全可以被批量大小整除,因此一些可变形状的尾随样本仍然是可能的。您很难摆脱 None 维度,但在您的模型的一些自定义方法中,您可以实现这一点。

    如果您仍然对张量不满意,可以使用 tensor.numpy() 方法返回一个 numpy 数组,但代价是复制它(通常是复制到您的 CPU)。这并非在流程的每个步骤中都可用。

    在 tensorflow 中定义数据集的方法有很多种,我建议阅读他们认为应该如何构建 input pipeline,因为如果您了解 tensorflow 在更高抽象级别上对您的代码的使用程度,它将使您的生活更轻松.

    【讨论】:

      猜你喜欢
      • 2019-09-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-25
      • 1970-01-01
      • 2023-03-13
      • 2021-05-18
      • 2020-12-14
      相关资源
      最近更新 更多