简体   繁体   English

形状错误数据集 Tensorflow

[英]Wrong shape Dataset Tensorflow

Im new to tensorflow and Im trying to feed some data with tensorflow.Dataset.我是 tensorflow 的新手,我试图用 tensorflow.Dataset 提供一些数据。 Im using Cityscape dataset with 8 different classes.我使用具有 8 个不同类别的 Cityscape 数据集。 Here is my code:这是我的代码:

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)

That last print(dataset) shows:最后一个 print(dataset) 显示:

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

Why am I obtaining (None, 256, 256, 3) instead of (8, 256, 256, 3)?为什么我得到的是 (None, 256, 256, 3) 而不是 (8, 256, 256, 3)? I also have some doubts about how to iterate over this dataset.我对如何迭代这个数据集也有一些疑问。

Thanks a lot.非常感谢。

Tensorflow is a graph based mathematical framework that abstracts for you all of those complex vectorial or matricial operations you face, particularly in machine learning. Tensorflow是一个基于图形的数学框架,可以为您抽象出您面临的所有复杂矢量或矩阵运算,尤其是在机器学习中。

What the developers though is that it would be unconfortable to specify every single time how many input vectors you need to pass in your model for the training, so they decided to abstract it for you.开发人员虽然每次都指定需要在 model 中传递多少个输入向量来进行训练是不方便的,因此他们决定为您抽象它。

You will not interested if your model is fed with one single or thousands samples as long as the output matches with the input dimension (but also any internal operation should match in dimensions.).只要 output 与输入维度匹配(但任何内部操作也应在维度上匹配),如果您的 model 输入一个或数千个样本,您将不会感兴趣。

So the None size is a placeholder for a possible changing shape, that is usually the batch size of the input.所以None大小是可能改变形状的占位符,通常是输入的批量大小。

We need a placeholder because (None, 2) is a different shape with respect of just (2,) , because in the first case we know we will face 2 dimensions.我们需要一个占位符,因为(None, 2)(2,)的形状不同,因为在第一种情况下,我们知道我们将面对 2 个维度。

Even if the None dimension is unknown when you "compile" your model, it will be evaluated only when it is strictly needed, in other words when you run it.即使在“编译” model 时“ None ”维度是未知的,也只会在严格需要时评估它,换句话说,当您运行它时。 In this way your model will be happy to run on a batch size of 64 as like as 128 samples.这样,您的 model 将很高兴在 64 的批量大小上运行,例如 128 个样本。

For the rest a (non-scalar) Tensor behaves like a normal numpy array:对于 rest,(非标量) 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])

The only difference is that it can be allocated into any supported device memory (CPU / Cuda GPU).唯一的区别是它可以分配到任何支持的设备 memory(CPU / Cuda GPU)。

Iterating through the dataset is just like slicing it at (usually) constant sizes, where that constant is your batch size, which will fill that empty None dimension.遍历数据集就像以(通常)恒定大小对其进行切片,其中该常量是您的批量大小,它将填充空的None维度。

This line of code will be responsible of slicing your dataset into "sub-tensors" ("sub-arrays") composed by its samples:这行代码将负责将您的数据集切成由其样本组成的“子张量”(“子数组”):

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

Your "runtime" shape will be (N, 256, 256, 3) , but if you will try to take an element from the dataset it could still have None in the shape... That's because we can't guarantee, for example, that the dimension of the dataset is exactly divisible by the batch size, so some trailing samples of a variable shape could still be possible.您的“运行时”形状将是(N, 256, 256, 3) ,但是如果您尝试从数据集中获取一个元素,它仍然可能在形状中具有None ...这是因为我们无法保证,例如,数据集的维度完全可以被批量大小整除,因此一些可变形状的尾随样本仍然是可能的。 You will hardly get rid off that None dimension, but in some custom methods of your model you could achieve that.您很难摆脱None维度,但在 model 的一些自定义方法中,您可以实现这一点。

If you are still unconfortable with tensors there is the tensor.numpy() method that gives you back a numpy array, but at the cost of copying it (usually to your CPU).如果您仍然对张量不满意,则可以使用tensor.numpy()方法返回 numpy 数组,但代价是复制它(通常是复制到您的 CPU)。 This is not available in every step of the process.这并非在流程的每个步骤中都可用。

There are many way to define a dataset in tensorflow, I suggest to read how they think you should build an input pipeline , because it will make your life easier if you understand how much tensorflow takes your code at higher levels of abstraction.在 tensorflow 中定义数据集的方法有很多,我建议阅读他们认为应该如何构建输入管道,因为如果您了解 tensorflow 将您的代码置于更高的抽象级别,它将使您的生活更轻松。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM