Как загрузить изображения из URL с помощью набора данных TensorFlow 2 - PullRequest
0 голосов
/ 27 февраля 2020

Я хочу использовать объект набора данных TensorFlow 2 для подачи изображений в CNN. Мои изображения расположены на AWS S3, но я буду использовать изображения из Википедии в моем примере (проблема та же).

image_urls = [
    'https://upload.wikimedia.org/wikipedia/commons/6/60/Matterhorn_from_Domh%C3%BCtte_-_2.jpg',
    'https://upload.wikimedia.org/wikipedia/commons/6/6e/Matterhorn_from_Klein_Matterhorn.jpg',
]
dataset = tf.data.Dataset.from_tensor_slices(image_urls)

def read_image_from_url(url):
    img_array = None
    with urlopen(url) as request:
        img_array = np.asarray(bytearray(request.read()), dtype=np.uint8)
    img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
    return cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  #as RGB image (cv2 is BGR by default)

Когда я проверяю свою функцию с одним элементом набора данных, он работает:

url = next(iter(dataset)).numpy().decode('utf-8')
img = read_image_from_url(url)
plt.imshow(img)

Но когда я сопоставляю свою функцию с набором данных для создания нового набора данных, обслуживающего изображения, происходит сбой:

dataset_images = dataset.map(lambda x: read_image_from_url(x.numpy().decode('utf-8')))

AttributeError: in converted code:

    <ipython-input-6-e8eb89833196>:2 None  *
        map_func=lambda x: read_image_from_url(x.numpy().decode('utf-8')),

    AttributeError: 'Tensor' object has no attribute 'numpy'

Очевидно, набор данных предоставляет другой тип d, когда повторяется с next или с map. Любая идея, как я могу это исправить?

1 Ответ

2 голосов
/ 27 февраля 2020

Ну, это было намного сложнее, чем нужно:

import tensorflow as tf
import numpy as np 
import cv2
from urllib.request import urlopen
import matplotlib.pyplot as plt
image_urls = [
    'https://upload.wikimedia.org/wikipedia/commons/6/60/Matterhorn_from_Domh%C3%BCtte_-_2.jpg',
    'https://upload.wikimedia.org/wikipedia/commons/6/6e/Matterhorn_from_Klein_Matterhorn.jpg',
]
dataset = tf.data.Dataset.from_tensor_slices(image_urls)

def get(url):
    with urlopen(str(url.numpy().decode("utf-8"))) as request:
        img_array = np.asarray(bytearray(request.read()), dtype=np.uint8)
    img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
    return cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

def read_image_from_url(url):
    return tf.py_function(get, [url], tf.uint8)


dataset_images = dataset.map(lambda x: read_image_from_url(x))

for d in dataset_images:
  print(d)

Почему первый сработал, а затем потерпел неудачу в tf.Dataset? Ну, tf.Dataset определяется в graph mode, а не в eager mode, как первый. Режим графика быстрее, а tf.Dataset оптимизирован для скорости, так что это имеет смысл. Вы не можете сделать .numpy() в графическом режиме, так как все должно быть определено в tensorflow ops. py_func оборачивает python функцию в tf.Operation, которая выполняется в eager mode, и это именно то, что нам нужно.

Примечание. Я попытался tf.keras.utils.get_file(), но столкнулся с похожими проблемами, которые вы здесь описываете. Надеюсь, это поможет!

...