Тензорный поток "операция отображения" для тензора?
Я приспосабливаю пример свертки cifar10 к моей проблеме. Я хотел бы изменить ввод данных из дизайна, который каждый раз считывает изображения из файла в проект, который работает с уже установленным в памяти набором изображений. Оригинальная функция inputs()
выглядит следующим образом:
read_input = cifar10_input.read_cifar10(filename_queue)
reshaped_image = tf.cast(read_input.uint8image, tf.float32)
# Crop the central [height, width] of the image.
resized_image = tf.image.resize_image_with_crop_or_pad(reshaped_image,
width, height)
В исходной версии read_input
- тензор, содержащий одно изображение.
Я сохраняю все свои изображения в ОЗУ, поэтому вместо использования filename_queue
у меня есть один огромный images_tensor = tf.constant(images)
, где images_tensor.shape
есть (что-то, 32, 32, 3).
Мой вопрос очень-очень простой: как лучше всего применить некоторую функцию (tf.image.resize_image_with_crop_or_pad
в моем случае) ко всем элементам images_tensor
?
Итерация проблематична в тензорном потоке с ограниченными фрагментами (TensorFlow - индексирование тензоподобных тензоров). Есть ли решение для этого, используя только одну команду?
Ответы
Ответ 1
Есть несколько ответов - не так элегантно, как функция карты. Это лучше всего зависит от вашего желания по эффективности использования памяти.
(a) Вы можете использовать enqueue_many
, чтобы выбросить их в tf.FIFOQueue
, а затем удалить из очереди и tf.image.resize_image_with_crop_or_pad
изображение за раз, и выполнить его все обратно в один большой smoosh. Это, вероятно, медленно. Требуется N вызовов для выполнения N изображений.
(b) Вы можете использовать один канал-заполнитель и запускать его для изменения размера и обрезать их по своему исходному исходному источнику данных. Это, пожалуй, лучший вариант с точки зрения памяти, потому что вам никогда не нужно хранить нераспределенные данные в памяти.
(c) Вы можете использовать tf.control_flow_ops.While
op для перебора всей партии и создания результата в tf.Variable
. В частности, если вы воспользуетесь параллельным выполнением, разрешенным while, это, скорее всего, самый быстрый подход.
Я бы выбрал вариант (c), если вы не хотите минимизировать использование памяти, и в этом случае фильтрация его по пути (вариант b) будет лучшим выбором.
Ответ 2
Начиная с версии 0.8 есть map_fn
. Из документации:
map_fn (fn, elems, dtype = None, parallel_iterations = 10, back_prop = True, swap_memory = False, name = None)
карта в списке тензоров, распакованных из elems
по размерности 0.
Этот оператор карты повторно применяет вызываемый fn
к последовательности элементов от первого до последнего. Элементы изготовлены из тензоров, распакованных из elems
. dtype
- это тип данных возвращаемого значения fn
. Пользователи должны предоставить dtype
если он отличается от типа данных elems
.
Предположим, что elems
распаковывается в values
, список тензоров. Форма тензора результата имеет вид [len(values)] + fn(values[0]).shape
.
Args:
fn: вызываемый для выполнения.
elems: тензор, распаковываемый для применения fn
.
dtype: (необязательно) тип вывода fn
.
parallel_iterations: (необязательно) Количество итераций, разрешенных для параллельного выполнения. back_prop: (необязательно) True разрешает обратное распространение. swap_memory: (необязательно) True включает обмен памяти GPU-CPU. name: (необязательно) префикс имени для возвращаемых тензоров.
Возвращает:
Тензор, который упаковывает результаты применения fn
к списку тензоров, распакованных от elems
, от первого до последнего.
поднимает:
Ошибка типа: если fn
не вызывается.
Пример:
elems = [1, 2, 3, 4, 5, 6]
squares = map_fn(lambda x: x * x, elems)
# squares == [1, 4, 9, 16, 25, 36]
'''
Ответ 3
Tensorflow предоставляет несколько функций высшего порядка, одной из которых является tf.map_fn
. Использование очень просто: вы определяете свой маппинг и применяете его к тензору:
variable = tf.Variable(...)
mapping = lambda x: f(x)
res = tf.map_fn(mapping, variable)