【问题标题】:Tensorflow 2.6.0 Error during model.fit, after using tf.py_function: ValueError: Expect x to be a non-empty array or dataset使用 tf.py_function 后,Tensorflow 2.6.0 在 model.fit 期间出错:ValueError: Expect x to be a non-empty array or dataset
【发布时间】:2021-12-19 21:36:26
【问题描述】:

Tensorflow:2.6.0,Ubuntu 20.04.3 LTS,GPU:GeForce MX130,CUDA 版本:11.2

我有一个数据集,其中包含 32 位图像文件和 8 位掩码文件,均为 tiff 格式。这是一个巨大的数据集。因此,我想以 tf.data.Dataset 格式而不是 numpy 数组加载我的数据(因为这可以加快加载速度并避免内存问题)。使用 tf.io.read_file(img_path) 解码我的 tiff 文件,然后使用 tfio.experimental.image.decode_tiff(img) 在这里不起作用,因为它会引发以下错误: TIFFReadDirectory:警告,遇到标记为 42113 (0xa481) 的未知字段。 TIFFReadDirectory:警告,遇到标记为 42113 (0xa481) 的未知字段。 内存:抱歉,无法处理具有 32 位样本的图像。

因此我决定使用 tiffile 库来解码数据,如下所示: img = tiff.imread(img_path)

这是我的一段代码:

full_dataset = tf.data.Dataset.list_files(dataset_path + "*.tif", shuffle=False)
full_dataset = full_dataset.shuffle(buffer_size=100, seed=42)

train_dataset = full_dataset.take(train_size)
test_dataset = full_dataset.skip(train_size)
val_dataset = test_dataset.skip(val_size)
test_dataset = test_dataset.take(test_size)

AUTOTUNE = tf.data.experimental.AUTOTUNE

train_dataset = train_dataset.map(lambda x: tf.py_function(preprocess, inp=[x], Tout= [tf.float32, tf.uint8]))
val_dataset = val_dataset.map(lambda x: tf.py_function(preprocess, inp=[x], Tout=[tf.float32, tf.uint8]))
test_dataset = test_dataset.map(lambda x: tf.py_function(preprocess, inp=[x], Tout=[tf.float32, tf.uint8]))

我在这里使用 tf.py_function 是因为我想在 map 函数中使用 tiff 库来读取图像。为此,我需要图像路径为 python 字符串格式。我注意到,如果我使用通常的 map 函数,路径将作为字符串类型的张量发送给函数。

这里是预处理函数:

def preprocess(img_path: str):
  f_name = bytes.decode(img_path.numpy())     # for this you need tf.py_function
  img = tiff.imread(f_name)

  img = img[:, :, [0, 2, 3]]  # The image has 4 channels, I need only 3 of them. Therefore extracting those using indices
  img[:, :, 0] = img[:, :, 0] / img[:, :, 0].max() # normaliing values in all 3 channels
  img[:, :, 1] = img[:, :, 1] / img[:, :, 1].max()
  img[:, :, 2] = img[:, :, 2] / img[:, :, 2].max()


  mask_path = tf.strings.regex_replace(img_path, "Images/", "Masks/mask_")
  mask = tf.io.read_file(mask_path)
  mask = tfio.experimental.image.decode_tiff(mask)
  mask = mask[:, :, 0:1]  # 1 channel for mask

  img = tf.image.resize(img, (128, 128))
  mask = tf.image.resize(mask, (128, 128))

  mask = tf.cast(mask, tf.float32) / 255.0  # normalizing mask

  img = tf.image.convert_image_dtype(img, tf.float32)
  mask = tf.image.convert_image_dtype(mask, tf.uint8) # since the tf.py_function is expecting Tout to be tf.float32 and tf.uint8 

  return img, mask

在此之后,我将开始训练我的模型:

train_dataset = train_dataset.batch(10)
train_dataset = train_dataset.prefetch(buffer_size=AUTOTUNE)

val_dataset = val_dataset.batch(10)
val_dataset = val_dataset.prefetch(buffer_size=AUTOTUNE)

test_dataset = test_dataset.batch(10)
test_dataset = test_dataset.prefetch(buffer_size=AUTOTUNE)

为了确认我的数据集不为空,我将在此之后绘制图像并从中蒙版。效果很好。

    for images_batch, masks_batch in train_dataset.take(1):
      fig, arr = plt.subplots(1, 2, figsize=(14, 10))
      print(images_batch.shape)
      print(masks_batch.shape)
      arr[0].imshow(images_batch[0], interpolation='nearest')
      arr[1].imshow(masks_batch[0], cmap='gray')
      plt.show()

它还打印图像的大小和遮罩批次: (10, 128, 128, 3) (10, 128, 128, 1)

打印数据集:

print(train_dataset)
print(val_dataset)
print(test_dataset)

给出以下输出:

<PrefetchDataset shapes: ((None, 128, 128, None), (None, 128, 128, None)), types: (tf.float32, tf.uint8)>

<PrefetchDataset shapes: ((None, 128, 128, None), (None, 128, 128, None)), types: (tf.float32, tf.uint8)>

<PrefetchDataset shapes: ((None, 128, 128, None), (None, 128, 128, None)), types: (tf.float32, tf.uint8)>

现在拟合模型:

model.fit(train_dataset, epochs=20,
          steps_per_epoch=STEPS_PER_EPOCH,
          validation_steps=VALIDATION_STEPS,
          batch_size=10,
          validation_data=val_dataset,
          callbacks=callbacks)

给出以下错误:

line 39, in train_using_tf_data
    history = model.fit(train_dataset, epochs=attributes.EPOCHS,
  File "/home/user/TfProjects/venv/lib/python3.8/site-packages/tensorflow/python/keras/engine/training.py", line 1204, in fit
    raise ValueError('Expect x to be a non-empty array or dataset.')
ValueError: Expect x to be a non-empty array or dataset.

我以为我在预处理函数之后返回了一个 tf.data.Dataset。我还可以从返回的数据集中绘制数据。数据集在哪里可能是空的? 我的猜测是 tf.py_fucntion 在某种程度上搞砸了。但我不明白在哪里以及如何解决它。有人知道吗?

【问题讨论】:

    标签: python tiff ubuntu-20.04 tensorflow2.x


    【解决方案1】:

    好的,我已经找到了我的问题的解决方案,我将在此处发布答案,供任何遇到相同问题的人使用! 我忘记更新传递给 model.fit 函数的 STEPS_PER_EPOCH 变量。它把值设为零。我用STEPS_PER_EPOCH = train_size // BATCH_SIZE 更新了它。然后它就像一个魅力!问题不在于包装器tf.py_function。 这是我的粗心大意。但是花了很长时间才发现哪里出错了!我建议所有遇到类似错误的人重新检查您传递给 model.fit 函数的每个属性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-24
      • 2020-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-19
      • 2020-07-08
      • 2022-11-08
      相关资源
      最近更新 更多