#python #tiff #ubuntu-20.04 #tensorflow2.x
Вопрос:
Tensorflow: 2.6.0, Ubuntu 20.04.3 LTS, графический процессор: GeForce MX130, версия CUDA: 11.2
У меня есть набор данных, содержащий 32-разрядные файлы изображений и 8-разрядные файлы масок, оба в формате tiff. Это огромный набор данных. Поэтому я хотел бы загрузить свои данные в tf.data.Формат набора данных вместо массивов numpy (так как это ускоряет загрузку и позволяет избежать проблем с памятью). Декодирование моих файлов tiff с помощью tf.io.read_file(img_path), а затем 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, потому что я хотел бы использовать библиотеку 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)
To confirm that my dataset isn’t empty I’m plotting an image and mask from it after this. That works fine.
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.данные.Набор данных после функции предварительной обработки. Я также могу построить график данных из возвращенного набора данных. Где здесь может оказаться пустой набор данных?
Я предполагаю, что tf.py_fucntion каким-то образом все портит. Но я не понимаю, где и как это исправить. У кого-нибудь есть какие-нибудь идеи?
Ответ №1:
Хорошо, я нашел решение своей проблемы, и я публикую ответ здесь для всех, кто застрял с тем же самым! Я забыл обновить STEPS_PER_EPOCH
переменную, которую я передаю в модель.функция подгонки. Он принимал значение за ноль. Я обновил его с STEPS_PER_EPOCH = train_size // BATCH_SIZE
помощью . А потом это сработало как заклинание! Проблема не в обертке tf.py_function
. Это была небрежность с моей стороны. Но потребовалось так много времени, чтобы понять, где все идет не так! Я рекомендую всем, у кого есть подобная ошибка, перепроверить все атрибуты, которые вы передаете в свою модель.функция подгонки.